summaryrefslogtreecommitdiff
path: root/linux/dev/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'linux/dev/drivers')
-rw-r--r--linux/dev/drivers/block/ide-cd.c2773
1 files changed, 0 insertions, 2773 deletions
diff --git a/linux/dev/drivers/block/ide-cd.c b/linux/dev/drivers/block/ide-cd.c
deleted file mode 100644
index 7cb8251..0000000
--- a/linux/dev/drivers/block/ide-cd.c
+++ /dev/null
@@ -1,2773 +0,0 @@
-/* #define VERBOSE_IDE_CD_ERRORS 1 */
-/*
- * linux/drivers/block/ide-cd.c
- * ATAPI cd-rom driver. To be used with ide.c.
- * See Documentation/cdrom/ide-cd for usage information.
- *
- * Copyright (C) 1994, 1995, 1996 scott snyder <snyder@fnald0.fnal.gov>
- * Copyright (C) 1996, 1997 Erik Andersen <andersee@debian.org>
- *
- * May be copied or modified under the terms of the GNU General Public License
- * see linux/COPYING for more information.
- *
- * 1.00 Oct 31, 1994 -- Initial version.
- * 1.01 Nov 2, 1994 -- Fixed problem with starting request in
- * cdrom_check_status.
- * 1.03 Nov 25, 1994 -- leaving unmask_intr[] as a user-setting (as for disks)
- * (from mlord) -- minor changes to cdrom_setup()
- * -- renamed ide_dev_s to ide_drive_t, enable irq on command
- * 2.00 Nov 27, 1994 -- Generalize packet command interface;
- * add audio ioctls.
- * 2.01 Dec 3, 1994 -- Rework packet command interface to handle devices
- * which send an interrupt when ready for a command.
- * 2.02 Dec 11, 1994 -- Cache the TOC in the driver.
- * Don't use SCMD_PLAYAUDIO_TI; it's not included
- * in the current version of ATAPI.
- * Try to use LBA instead of track or MSF addressing
- * when possible.
- * Don't wait for READY_STAT.
- * 2.03 Jan 10, 1995 -- Rewrite block read routines to handle block sizes
- * other than 2k and to move multiple sectors in a
- * single transaction.
- * 2.04 Apr 21, 1995 -- Add work-around for Creative Labs CD220E drives.
- * Thanks to Nick Saw <cwsaw@pts7.pts.mot.com> for
- * help in figuring this out. Ditto for Acer and
- * Aztech drives, which seem to have the same problem.
- * 2.04b May 30, 1995 -- Fix to match changes in ide.c version 3.16 -ml
- * 2.05 Jun 8, 1995 -- Don't attempt to retry after an illegal request
- * or data protect error.
- * Use HWIF and DEV_HWIF macros as in ide.c.
- * Always try to do a request_sense after
- * a failed command.
- * Include an option to give textual descriptions
- * of ATAPI errors.
- * Fix a bug in handling the sector cache which
- * showed up if the drive returned data in 512 byte
- * blocks (like Pioneer drives). Thanks to
- * Richard Hirst <srh@gpt.co.uk> for diagnosing this.
- * Properly supply the page number field in the
- * MODE_SELECT command.
- * PLAYAUDIO12 is broken on the Aztech; work around it.
- * 2.05x Aug 11, 1995 -- lots of data structure renaming/restructuring in ide.c
- * (my apologies to Scott, but now ide-cd.c is independent)
- * 3.00 Aug 22, 1995 -- Implement CDROMMULTISESSION ioctl.
- * Implement CDROMREADAUDIO ioctl (UNTESTED).
- * Use input_ide_data() and output_ide_data().
- * Add door locking.
- * Fix usage count leak in cdrom_open, which happened
- * when a read-write mount was attempted.
- * Try to load the disk on open.
- * Implement CDROMEJECT_SW ioctl (off by default).
- * Read total cdrom capacity during open.
- * Rearrange logic in cdrom_decode_status. Issue
- * request sense commands for failed packet commands
- * from here instead of from cdrom_queue_packet_command.
- * Fix a race condition in retrieving error information.
- * Suppress printing normal unit attention errors and
- * some drive not ready errors.
- * Implement CDROMVOLREAD ioctl.
- * Implement CDROMREADMODE1/2 ioctls.
- * Fix race condition in setting up interrupt handlers
- * when the `serialize' option is used.
- * 3.01 Sep 2, 1995 -- Fix ordering of reenabling interrupts in
- * cdrom_queue_request.
- * Another try at using ide_[input,output]_data.
- * 3.02 Sep 16, 1995 -- Stick total disk capacity in partition table as well.
- * Make VERBOSE_IDE_CD_ERRORS dump failed command again.
- * Dump out more information for ILLEGAL REQUEST errs.
- * Fix handling of errors occurring before the
- * packet command is transferred.
- * Fix transfers with odd bytelengths.
- * 3.03 Oct 27, 1995 -- Some Creative drives have an id of just `CD'.
- * `DCI-2S10' drives are broken too.
- * 3.04 Nov 20, 1995 -- So are Vertos drives.
- * 3.05 Dec 1, 1995 -- Changes to go with overhaul of ide.c and ide-tape.c
- * 3.06 Dec 16, 1995 -- Add support needed for partitions.
- * More workarounds for Vertos bugs (based on patches
- * from Holger Dietze <dietze@aix520.informatik.uni-leipzig.de>).
- * Try to eliminate byteorder assumptions.
- * Use atapi_cdrom_subchnl struct definition.
- * Add STANDARD_ATAPI compilation option.
- * 3.07 Jan 29, 1996 -- More twiddling for broken drives: Sony 55D,
- * Vertos 300.
- * Add NO_DOOR_LOCKING configuration option.
- * Handle drive_cmd requests w/NULL args (for hdparm -t).
- * Work around sporadic Sony55e audio play problem.
- * 3.07a Feb 11, 1996 -- check drive->id for NULL before dereferencing, to fix
- * problem with "hde=cdrom" with no drive present. -ml
- * 3.08 Mar 6, 1996 -- More Vertos workarounds.
- * 3.09 Apr 5, 1996 -- Add CDROMCLOSETRAY ioctl.
- * Switch to using MSF addressing for audio commands.
- * Reformat to match kernel tabbing style.
- * Add CDROM_GET_UPC ioctl.
- * 3.10 Apr 10, 1996 -- Fix compilation error with STANDARD_ATAPI.
- * 3.11 Apr 29, 1996 -- Patch from Heiko Eissfeldt <heiko@colossus.escape.de>
- * to remove redundant verify_area calls.
- * 3.12 May 7, 1996 -- Rudimentary changer support. Based on patches
- * from Gerhard Zuber <zuber@berlin.snafu.de>.
- * Let open succeed even if there's no loaded disc.
- * 3.13 May 19, 1996 -- Fixes for changer code.
- * 3.14 May 29, 1996 -- Add work-around for Vertos 600.
- * (From Hennus Bergman <hennus@sky.ow.nl>.)
- * 3.15 July 2, 1996 -- Added support for Sanyo 3 CD changers
- * from Ben Galliart <bgallia@luc.edu> with
- * special help from Jeff Lightfoot
- * <jeffml@netcom.com>
- * 3.15a July 9, 1996 -- Improved Sanyo 3 CD changer identification
- * 3.16 Jul 28, 1996 -- Fix from Gadi to reduce kernel stack usage for ioctl.
- * 3.17 Sep 17, 1996 -- Tweak audio reads for some drives.
- * Start changing CDROMLOADFROMSLOT to CDROM_SELECT_DISC.
- *
- * 3.19 Nov 5, 1996 -- New ide-cd maintainer:
- * Erik B. Andersen <andersee@debian.org>
- * 3.20 Jan 13,1997 -- Bug Fixes:
- * Fix errors on CDROMSTOP (If you have a "Dolphin",
- * you must define IHAVEADOLPHIN)
- * Added identifier so new Sanyo CD-changer works
- * Better detection if door locking isn't supported
- * 3.21 Jun 16,1997 -- Add work-around for GCD-R580B
- *
- * NOTE: Direct audio reads will only work on some types of drive.
- * So far, i've received reports of success for Sony and Toshiba drives.
- *
- * ALSO NOTE:
- *
- * The ide cdrom driver has undergone extensive changes for the
- * latest development kernel. If you wish to add new features to
- * this driver, make your changes to the latest version in the
- * development kernel. Only Bug fixes will be accepted for this
- * version.
- *
- * For those wishing to work on this driver, please be sure you download
- * and comply with the latest ATAPI standard. This document can be
- * obtained by anonymous ftp from fission.dt.wdc.com in directory:
- * /pub/standards/atapi/spec/SFF8020-r2.6/PDF/8020r26.pdf
- *
- */
-
-
-/***************************************************************************/
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/malloc.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/errno.h>
-#include <linux/hdreg.h>
-#include <linux/cdrom.h>
-#include <linux/ucdrom.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/byteorder.h>
-#include <asm/segment.h>
-#include <asm/unaligned.h>
-
-#include "ide.h"
-
-
-
-/* Turn this on to have the driver print out the meanings of the
- ATAPI error codes. This will use up additional kernel-space
- memory, though. */
-
-#ifndef VERBOSE_IDE_CD_ERRORS
-#define VERBOSE_IDE_CD_ERRORS 0
-#endif
-
-
-/* Turning this on will remove code to work around various nonstandard
- ATAPI implementations. If you know your drive follows the standard,
- this will give you a slightly smaller kernel. */
-
-#ifndef STANDARD_ATAPI
-#define STANDARD_ATAPI 0
-#endif
-
-
-/* Turning this on will disable the door-locking functionality.
- This is apparently needed for supermount. */
-
-#ifndef NO_DOOR_LOCKING
-#define NO_DOOR_LOCKING 0
-#endif
-
-
-/* Size of buffer to allocate, in blocks, for audio reads. */
-
-#ifndef CDROM_NBLOCKS_BUFFER
-#define CDROM_NBLOCKS_BUFFER 8
-#endif
-
-
-/************************************************************************/
-
-#define SECTOR_SIZE 512
-#define SECTOR_BITS 9
-#define SECTORS_PER_FRAME (CD_FRAMESIZE / SECTOR_SIZE)
-
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-
-/* special command codes for strategy routine. */
-#define PACKET_COMMAND 4315
-#define REQUEST_SENSE_COMMAND 4316
-#define RESET_DRIVE_COMMAND 4317
-
-/* Some ATAPI command opcodes (just like SCSI).
- (Some other cdrom-specific codes are in cdrom.h.) */
-#define TEST_UNIT_READY 0x00
-#define REQUEST_SENSE 0x03
-#define START_STOP 0x1b
-#define ALLOW_MEDIUM_REMOVAL 0x1e
-#define READ_CAPACITY 0x25
-#define READ_10 0x28
-#define MODE_SENSE_10 0x5a
-#define MODE_SELECT_10 0x55
-#define READ_CD 0xbe
-
-#define LOAD_UNLOAD 0xa6
-
-
-/* ATAPI sense keys (mostly copied from scsi.h). */
-
-#define NO_SENSE 0x00
-#define RECOVERED_ERROR 0x01
-#define NOT_READY 0x02
-#define MEDIUM_ERROR 0x03
-#define HARDWARE_ERROR 0x04
-#define ILLEGAL_REQUEST 0x05
-#define UNIT_ATTENTION 0x06
-#define DATA_PROTECT 0x07
-#define ABORTED_COMMAND 0x0b
-#define MISCOMPARE 0x0e
-
-/* We want some additional flags for cd-rom drives.
- To save space in the ide_drive_t struct, use some fields which
- doesn't make sense for cd-roms -- `bios_sect' and `bios_head'. */
-
-/* Configuration flags. These describe the capabilities of the drive.
- They generally do not change after initialization, unless we learn
- more about the drive from stuff failing. */
-struct ide_cd_config_flags {
- __u8 drq_interrupt : 1; /* Device sends an interrupt when ready
- for a packet command. */
- __u8 no_doorlock : 1; /* Drive cannot lock the door. */
-#if ! STANDARD_ATAPI
- __u8 old_readcd : 1; /* Drive uses old READ CD opcode. */
- __u8 playmsf_as_bcd : 1; /* PLAYMSF command takes BCD args. */
- __u8 tocaddr_as_bcd : 1; /* TOC addresses are in BCD. */
- __u8 toctracks_as_bcd : 1; /* TOC track numbers are in BCD. */
- __u8 subchan_as_bcd : 1; /* Subchannel info is in BCD. */
-#endif /* not STANDARD_ATAPI */
- __u8 reserved : 1;
-};
-#define CDROM_CONFIG_FLAGS(drive) ((struct ide_cd_config_flags *)&((drive)->bios_sect))
-
-
-/* State flags. These give information about the current state of the
- drive, and will change during normal operation. */
-struct ide_cd_state_flags {
- __u8 media_changed : 1; /* Driver has noticed a media change. */
- __u8 toc_valid : 1; /* Saved TOC information is current. */
- __u8 door_locked : 1; /* We think that the drive door is locked. */
- __u8 eject_on_close: 1; /* Drive should eject when device is closed. */
- __u8 sanyo_slot : 2; /* Sanyo 3 CD changer support */
- __u8 reserved : 2;
-};
-#define CDROM_STATE_FLAGS(drive) ((struct ide_cd_state_flags *)&((drive)->bios_head))
-
-
-#define SECTOR_BUFFER_SIZE CD_FRAMESIZE
-
-
-
-/****************************************************************************
- * Routines to read and write data from/to the drive, using
- * the routines input_ide_data() and output_ide_data() from ide.c.
- *
- * These routines will round up any request for an odd number of bytes,
- * so if an odd bytecount is specified, be sure that there's at least one
- * extra byte allocated for the buffer.
- */
-
-
-static inline
-void cdrom_in_bytes (ide_drive_t *drive, void *buffer, uint bytecount)
-{
- ++bytecount;
- ide_input_data (drive, buffer, bytecount / 4);
- if ((bytecount & 0x03) >= 2) {
- insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
- }
-}
-
-
-static inline
-void cdrom_out_bytes (ide_drive_t *drive, void *buffer, uint bytecount)
-{
- ++bytecount;
- ide_output_data (drive, buffer, bytecount / 4);
- if ((bytecount & 0x03) >= 2) {
- outsw (IDE_DATA_REG,
- ((byte *)buffer) + (bytecount & ~0x03), 1);
- }
-}
-
-
-
-/****************************************************************************
- * Descriptions of ATAPI error codes.
- */
-
-#define ARY_LEN(a) ((sizeof(a) / sizeof(a[0])))
-
-#if VERBOSE_IDE_CD_ERRORS
-
-/* From Table 124 of the ATAPI 1.2 spec. */
-
-char *sense_key_texts[16] = {
- "No sense data",
- "Recovered error",
- "Not ready",
- "Medium error",
- "Hardware error",
- "Illegal request",
- "Unit attention",
- "Data protect",
- "(reserved)",
- "(reserved)",
- "(reserved)",
- "Aborted command",
- "(reserved)",
- "(reserved)",
- "Miscompare",
- "(reserved)",
-};
-
-
-/* From Table 125 of the ATAPI 1.2 spec. */
-
-struct {
- short asc_ascq;
- char *text;
-} sense_data_texts[] = {
- { 0x0000, "No additional sense information" },
- { 0x0011, "Audio play operation in progress" },
- { 0x0012, "Audio play operation paused" },
- { 0x0013, "Audio play operation successfully completed" },
- { 0x0014, "Audio play operation stopped due to error" },
- { 0x0015, "No current audio status to return" },
-
- { 0x0200, "No seek complete" },
-
- { 0x0400, "Logical unit not ready - cause not reportable" },
- { 0x0401,
- "Logical unit not ready - in progress (sic) of becoming ready" },
- { 0x0402, "Logical unit not ready - initializing command required" },
- { 0x0403, "Logical unit not ready - manual intervention required" },
-
- { 0x0600, "No reference position found" },
-
- { 0x0900, "Track following error" },
- { 0x0901, "Tracking servo failure" },
- { 0x0902, "Focus servo failure" },
- { 0x0903, "Spindle servo failure" },
-
- { 0x1100, "Unrecovered read error" },
- { 0x1106, "CIRC unrecovered error" },
-
- { 0x1500, "Random positioning error" },
- { 0x1501, "Mechanical positioning error" },
- { 0x1502, "Positioning error detected by read of medium" },
-
- { 0x1700, "Recovered data with no error correction applied" },
- { 0x1701, "Recovered data with retries" },
- { 0x1702, "Recovered data with positive head offset" },
- { 0x1703, "Recovered data with negative head offset" },
- { 0x1704, "Recovered data with retries and/or CIRC applied" },
- { 0x1705, "Recovered data using previous sector ID" },
-
- { 0x1800, "Recovered data with error correction applied" },
- { 0x1801, "Recovered data with error correction and retries applied" },
- { 0x1802, "Recovered data - the data was auto-reallocated" },
- { 0x1803, "Recovered data with CIRC" },
- { 0x1804, "Recovered data with L-EC" },
- { 0x1805, "Recovered data - recommend reassignment" },
- { 0x1806, "Recovered data - recommend rewrite" },
-
- { 0x1a00, "Parameter list length error" },
-
- { 0x2000, "Invalid command operation code" },
-
- { 0x2100, "Logical block address out of range" },
-
- { 0x2400, "Invalid field in command packet" },
-
- { 0x2600, "Invalid field in parameter list" },
- { 0x2601, "Parameter not supported" },
- { 0x2602, "Parameter value invalid" },
- { 0x2603, "Threshold parameters not supported" },
-
- { 0x2800, "Not ready to ready transition, medium may have changed" },
-
- { 0x2900, "Power on, reset or bus device reset occurred" },
-
- { 0x2a00, "Parameters changed" },
- { 0x2a01, "Mode parameters changed" },
-
- { 0x3000, "Incompatible medium installed" },
- { 0x3001, "Cannot read medium - unknown format" },
- { 0x3002, "Cannot read medium - incompatible format" },
-
- { 0x3700, "Rounded parameter" },
-
- { 0x3900, "Saving parameters not supported" },
-
- { 0x3a00, "Medium not present" },
-
- { 0x3f00, "ATAPI CD-ROM drive operating conditions have changed" },
- { 0x3f01, "Microcode has been changed" },
- { 0x3f02, "Changed operating definition" },
- { 0x3f03, "Inquiry data has changed" },
-
- { 0x4000, "Diagnostic failure on component (ASCQ)" },
-
- { 0x4400, "Internal ATAPI CD-ROM drive failure" },
-
- { 0x4e00, "Overlapped commands attempted" },
-
- { 0x5300, "Media load or eject failed" },
- { 0x5302, "Medium removal prevented" },
-
- { 0x5700, "Unable to recover table of contents" },
-
- { 0x5a00, "Operator request or state change input (unspecified)" },
- { 0x5a01, "Operator medium removal request" },
-
- { 0x5b00, "Threshold condition met" },
-
- { 0x5c00, "Status change" },
-
- { 0x6300, "End of user area encountered on this track" },
-
- { 0x6400, "Illegal mode for this track" },
-
- { 0xbf00, "Loss of streaming" },
-};
-#endif
-
-
-
-/****************************************************************************
- * Generic packet command support and error handling routines.
- */
-
-
-static
-void cdrom_analyze_sense_data (ide_drive_t *drive,
- struct atapi_request_sense *reqbuf,
- struct packet_command *failed_command)
-{
- /* Don't print not ready or unit attention errors for READ_SUBCHANNEL.
- Workman (and probably other programs) uses this command to poll
- the drive, and we don't want to fill the syslog
- with useless errors. */
- if (failed_command &&
- failed_command->c[0] == SCMD_READ_SUBCHANNEL &&
- (reqbuf->sense_key == NOT_READY ||
- reqbuf->sense_key == UNIT_ATTENTION))
- return;
-
-#if VERBOSE_IDE_CD_ERRORS
- {
- int i;
- char *s;
- char buf[80];
-
- printk ("ATAPI device %s:\n", drive->name);
-
- printk (" Error code: 0x%02x\n", reqbuf->error_code);
-
- if (reqbuf->sense_key >= 0 &&
- reqbuf->sense_key < ARY_LEN (sense_key_texts))
- s = sense_key_texts[reqbuf->sense_key];
- else
- s = "(bad sense key)";
-
- printk (" Sense key: 0x%02x - %s\n", reqbuf->sense_key, s);
-
- if (reqbuf->asc == 0x40) {
- sprintf (buf, "Diagnostic failure on component 0x%02x",
- reqbuf->ascq);
- s = buf;
- } else {
- int lo, hi;
- int key = (reqbuf->asc << 8);
- if ( ! (reqbuf->ascq >= 0x80 && reqbuf->ascq <= 0xdd) )
- key |= reqbuf->ascq;
-
- lo = 0;
- hi = ARY_LEN (sense_data_texts);
- s = NULL;
-
- while (hi > lo) {
- int mid = (lo + hi) / 2;
- if (sense_data_texts[mid].asc_ascq == key) {
- s = sense_data_texts[mid].text;
- break;
- }
- else if (sense_data_texts[mid].asc_ascq > key)
- hi = mid;
- else
- lo = mid+1;
- }
- }
-
- if (s == NULL) {
- if (reqbuf->asc > 0x80)
- s = "(vendor-specific error)";
- else
- s = "(reserved error code)";
- }
-
- printk (" Additional sense data: 0x%02x, 0x%02x - %s\n",
- reqbuf->asc, reqbuf->ascq, s);
-
- if (failed_command != NULL) {
- printk (" Failed packet command: ");
- for (i=0; i<sizeof (failed_command->c); i++)
- printk ("%02x ", failed_command->c[i]);
- printk ("\n");
- }
-
- if (reqbuf->sense_key == ILLEGAL_REQUEST &&
- (reqbuf->sense_key_specific[0] & 0x80) != 0) {
- printk (" Error in %s byte %d",
- (reqbuf->sense_key_specific[0] & 0x40) != 0
- ? "command packet"
- : "command data",
- (reqbuf->sense_key_specific[1] << 8) +
- reqbuf->sense_key_specific[2]);
-
- if ((reqbuf->sense_key_specific[0] & 0x40) != 0) {
- printk (" bit %d",
- reqbuf->sense_key_specific[0] & 0x07);
- }
-
- printk ("\n");
- }
- }
-
-#else /* not VERBOSE_IDE_CD_ERRORS */
-
- /* Suppress printing unit attention and `in progress of becoming ready'
- errors when we're not being verbose. */
-
- if (reqbuf->sense_key == UNIT_ATTENTION ||
- (reqbuf->sense_key == NOT_READY && (reqbuf->asc == 4 ||
- reqbuf->asc == 0x3a)))
- return;
-
- printk ("%s: code: 0x%02x key: 0x%02x asc: 0x%02x ascq: 0x%02x\n",
- drive->name,
- reqbuf->error_code, reqbuf->sense_key,
- reqbuf->asc, reqbuf->ascq);
-#endif /* not VERBOSE_IDE_CD_ERRORS */
-}
-
-
-/* Fix up a possibly partially-processed request so that we can
- start it over entirely, or even put it back on the request queue. */
-static void restore_request (struct request *rq)
-{
- if (rq->buffer != rq->bh->b_data) {
- int n = (rq->buffer - rq->bh->b_data) / SECTOR_SIZE;
- rq->buffer = rq->bh->b_data;
- rq->nr_sectors += n;
- rq->sector -= n;
- }
- rq->current_nr_sectors = rq->bh->b_size >> SECTOR_BITS;
-}
-
-
-static void cdrom_queue_request_sense (ide_drive_t *drive,
- struct semaphore *sem,
- struct atapi_request_sense *reqbuf,
- struct packet_command *failed_command)
-{
- struct request *rq;
- struct packet_command *pc;
- int len;
-
- /* If the request didn't explicitly specify where
- to put the sense data, use the statically allocated structure. */
- if (reqbuf == NULL)
- reqbuf = &drive->cdrom_info.sense_data;
-
- /* Make up a new request to retrieve sense information. */
-
- pc = &HWIF(drive)->request_sense_pc;
- memset (pc, 0, sizeof (*pc));
-
- /* The request_sense structure has an odd number of (16-bit) words,
- which won't work well with 32-bit transfers. However, we don't care
- about the last two bytes, so just truncate the structure down
- to an even length. */
- len = sizeof (*reqbuf) / 4;
- len *= 4;
-
- pc->c[0] = REQUEST_SENSE;
- pc->c[4] = len;
- pc->buffer = (char *)reqbuf;
- pc->buflen = len;
- pc->sense_data = (struct atapi_request_sense *)failed_command;
-
- /* stuff the sense request in front of our current request */
-
- rq = &HWIF(drive)->request_sense_request;
- ide_init_drive_cmd (rq);
- rq->cmd = REQUEST_SENSE_COMMAND;
- rq->buffer = (char *)pc;
- rq->sem = sem;
- (void) ide_do_drive_cmd (drive, rq, ide_preempt);
-}
-
-
-static void cdrom_end_request (int uptodate, ide_drive_t *drive)
-{
- struct request *rq = HWGROUP(drive)->rq;
-
- if (rq->cmd == REQUEST_SENSE_COMMAND && uptodate) {
- struct packet_command *pc = (struct packet_command *)
- rq->buffer;
- cdrom_analyze_sense_data (drive,
- (struct atapi_request_sense *)
- (pc->buffer - pc->c[4]),
- (struct packet_command *)
- pc->sense_data);
- }
-
- ide_end_request (uptodate, HWGROUP(drive));
-}
-
-
-/* Mark that we've seen a media change, and invalidate our internal
- buffers. */
-static void cdrom_saw_media_change (ide_drive_t *drive)
-{
- CDROM_STATE_FLAGS (drive)->media_changed = 1;
- CDROM_STATE_FLAGS (drive)->toc_valid = 0;
- drive->cdrom_info.nsectors_buffered = 0;
-}
-
-
-/* Returns 0 if the request should be continued.
- Returns 1 if the request was ended. */
-static int cdrom_decode_status (ide_drive_t *drive, int good_stat,
- int *stat_ret)
-{
- struct request *rq = HWGROUP(drive)->rq;
- int stat, err, sense_key, cmd;
-
- /* Check for errors. */
- stat = GET_STAT();
- *stat_ret = stat;
-
- if (OK_STAT (stat, good_stat, BAD_R_STAT))
- return 0;
-
- /* Got an error. */
- err = IN_BYTE (IDE_ERROR_REG);
- sense_key = err >> 4;
-
- if (rq == NULL)
- printk ("%s : missing request in cdrom_decode_status\n",
- drive->name);
- else {
- cmd = rq->cmd;
-
- if (cmd == REQUEST_SENSE_COMMAND) {
- /* We got an error trying to get sense info
- from the drive (probably while trying
- to recover from a former error). Just give up. */
-
- struct packet_command *pc = (struct packet_command *)
- rq->buffer;
- pc->stat = 1;
- cdrom_end_request (1, drive);
- ide_error (drive, "request sense failure", stat);
- return 1;
-
- } else if (cmd == PACKET_COMMAND) {
- /* All other functions, except for READ. */
-
- struct packet_command *pc = (struct packet_command *)
- rq->buffer;
- struct semaphore *sem = NULL;
-
- /* Check for tray open. */
- if (sense_key == NOT_READY) {
- cdrom_saw_media_change (drive);
-
- /* Print an error message to the syslog.
- Exception: don't print anything if this
- is a read subchannel command. This is
- because workman constantly polls the drive
- with this command, and we don't want
- to uselessly fill up the syslog. */
- if (pc->c[0] != SCMD_READ_SUBCHANNEL)
- printk ("%s : tray open or drive not ready\n",
- drive->name);
- } else if (sense_key == UNIT_ATTENTION) {
- /* Check for media change. */
- cdrom_saw_media_change (drive);
- printk ("%s: media changed\n", drive->name);
- } else {
- /* Otherwise, print an error. */
- ide_dump_status (drive, "packet command error",
- stat);
- }
-
- /* Set the error flag and complete the request.
- Then, if we have a CHECK CONDITION status,
- queue a request sense command. We must be careful,
- though: we don't want the thread in
- cdrom_queue_packet_command to wake up until
- the request sense has completed. We do this
- by transferring the semaphore from the packet
- command request to the request sense request. */
-
- if ((stat & ERR_STAT) != 0) {
- sem = rq->sem;
- rq->sem = NULL;
- }
-
- pc->stat = 1;
- cdrom_end_request (1, drive);
-
- if ((stat & ERR_STAT) != 0)
- cdrom_queue_request_sense (drive, sem,
- pc->sense_data, pc);
- } else {
- /* Handle errors from READ requests. */
-
- if (sense_key == NOT_READY) {
- /* Tray open. */
- cdrom_saw_media_change (drive);
-
- /* Fail the request. */
- printk ("%s : tray open\n", drive->name);
- cdrom_end_request (0, drive);
- } else if (sense_key == UNIT_ATTENTION) {
- /* Media change. */
- cdrom_saw_media_change (drive);
-
- /* Arrange to retry the request.
- But be sure to give up if we've retried
- too many times. */
- if (++rq->errors > ERROR_MAX)
- cdrom_end_request (0, drive);
- } else if (sense_key == ILLEGAL_REQUEST ||
- sense_key == DATA_PROTECT) {
- /* No point in retrying after an illegal
- request or data protect error.*/
- ide_dump_status (drive, "command error", stat);
- cdrom_end_request (0, drive);
- } else if ((err & ~ABRT_ERR) != 0) {
- /* Go to the default handler
- for other errors. */
- ide_error (drive, "cdrom_decode_status", stat);
- return 1;
- } else if ((++rq->errors > ERROR_MAX)) {
- /* We've racked up too many retries. Abort. */
- cdrom_end_request (0, drive);
- }
-
- /* If we got a CHECK_CONDITION status,
- queue a request sense command. */
- if ((stat & ERR_STAT) != 0)
- cdrom_queue_request_sense (drive,
- NULL, NULL, NULL);
- }
- }
-
- /* Retry, or handle the next request. */
- return 1;
-}
-
-
-/* Set up the device registers for transferring a packet command on DEV,
- expecting to later transfer XFERLEN bytes. HANDLER is the routine
- which actually transfers the command to the drive. If this is a
- drq_interrupt device, this routine will arrange for HANDLER to be
- called when the interrupt from the drive arrives. Otherwise, HANDLER
- will be called immediately after the drive is prepared for the transfer. */
-
-static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen,
- ide_handler_t *handler)
-{
- /* Wait for the controller to be idle. */
- if (ide_wait_stat (drive, 0, BUSY_STAT, WAIT_READY)) return 1;
-
- /* Set up the controller registers. */
- OUT_BYTE (0, IDE_FEATURE_REG);
- OUT_BYTE (0, IDE_NSECTOR_REG);
- OUT_BYTE (0, IDE_SECTOR_REG);
-
- OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);
- OUT_BYTE (xferlen >> 8 , IDE_HCYL_REG);
- OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
-
- if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
- ide_set_handler (drive, handler, WAIT_CMD);
- OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
- } else {
- OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
- (*handler) (drive);
- }
-
- return 0;
-}
-
-
-/* Send a packet command to DRIVE described by CMD_BUF and CMD_LEN.
- The device registers must have already been prepared
- by cdrom_start_packet_command.
- HANDLER is the interrupt handler to call when the command completes
- or there's data ready. */
-static int cdrom_transfer_packet_command (ide_drive_t *drive,
- char *cmd_buf, int cmd_len,
- ide_handler_t *handler)
-{
- if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
- /* Here we should have been called after receiving an interrupt
- from the device. DRQ should how be set. */
- int stat_dum;
-
- /* Check for errors. */
- if (cdrom_decode_status (drive, DRQ_STAT, &stat_dum)) return 1;
- } else {
- /* Otherwise, we must wait for DRQ to get set. */
- if (ide_wait_stat (drive, DRQ_STAT, BUSY_STAT, WAIT_READY))
- return 1;
- }
-
- /* Arm the interrupt handler. */
- ide_set_handler (drive, handler, WAIT_CMD);
-
- /* Send the command to the device. */
- cdrom_out_bytes (drive, cmd_buf, cmd_len);
-
- return 0;
-}
-
-
-
-/****************************************************************************
- * Block read functions.
- */
-
-/*
- * Buffer up to SECTORS_TO_TRANSFER sectors from the drive in our sector
- * buffer. Once the first sector is added, any subsequent sectors are
- * assumed to be continuous (until the buffer is cleared). For the first
- * sector added, SECTOR is its sector number. (SECTOR is then ignored until
- * the buffer is cleared.)
- */
-static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector,
- int sectors_to_transfer)
-{
- struct cdrom_info *info = &drive->cdrom_info;
-
- /* Number of sectors to read into the buffer. */
- int sectors_to_buffer = MIN (sectors_to_transfer,
- (SECTOR_BUFFER_SIZE >> SECTOR_BITS) -
- info->nsectors_buffered);
-
- char *dest;
-
- /* If we don't yet have a sector buffer, try to allocate one.
- If we can't get one atomically, it's not fatal -- we'll just throw
- the data away rather than caching it. */
- if (info->sector_buffer == NULL) {
- info->sector_buffer = (char *) kmalloc (SECTOR_BUFFER_SIZE,
- GFP_ATOMIC);
-
- /* If we couldn't get a buffer,
- don't try to buffer anything... */
- if (info->sector_buffer == NULL)
- sectors_to_buffer = 0;
- }
-
- /* If this is the first sector in the buffer, remember its number. */
- if (info->nsectors_buffered == 0)
- info->sector_buffered = sector;
-
- /* Read the data into the buffer. */
- dest = info->sector_buffer + info->nsectors_buffered * SECTOR_SIZE;
- while (sectors_to_buffer > 0) {
- cdrom_in_bytes (drive, dest, SECTOR_SIZE);
- --sectors_to_buffer;
- --sectors_to_transfer;
- ++info->nsectors_buffered;
- dest += SECTOR_SIZE;
- }
-
- /* Throw away any remaining data. */
- while (sectors_to_transfer > 0) {
- char dum[SECTOR_SIZE];
- cdrom_in_bytes (drive, dum, sizeof (dum));
- --sectors_to_transfer;
- }
-}
-
-
-/*
- * Check the contents of the interrupt reason register from the cdrom
- * and attempt to recover if there are problems. Returns 0 if everything's
- * ok; nonzero if the request has been terminated.
- */
-static inline
-int cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason)
-{
- ireason &= 3;
- if (ireason == 2) return 0;
-
- if (ireason == 0) {
- /* Whoops... The drive is expecting to receive data from us! */
- printk ("%s: cdrom_read_intr: "
- "Drive wants to transfer data the wrong way!\n",
- drive->name);
-
- /* Throw some data at the drive so it doesn't hang
- and quit this request. */
- while (len > 0) {
- int dum = 0;
- cdrom_out_bytes (drive, &dum, sizeof (dum));
- len -= sizeof (dum);
- }
- } else {
- /* Drive wants a command packet, or invalid ireason... */
- printk ("%s: cdrom_read_intr: bad interrupt reason %d\n",
- drive->name, ireason);
- }
-
- cdrom_end_request (0, drive);
- return -1;
-}
-
-
-/*
- * Interrupt routine. Called when a read request has completed.
- */
-static void cdrom_read_intr (ide_drive_t *drive)
-{
- int stat;
- int ireason, len, sectors_to_transfer, nskip;
-
- struct request *rq = HWGROUP(drive)->rq;
-
- /* Check for errors. */
- if (cdrom_decode_status (drive, 0, &stat)) return;
-
- /* Read the interrupt reason and the transfer length. */
- ireason = IN_BYTE (IDE_NSECTOR_REG);
- len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG);
-
- /* If DRQ is clear, the command has completed. */
- if ((stat & DRQ_STAT) == 0) {
- /* If we're not done filling the current buffer, complain.
- Otherwise, complete the command normally. */
- if (rq->current_nr_sectors > 0) {
- printk ("%s: cdrom_read_intr: data underrun (%ld blocks)\n",
- drive->name, rq->current_nr_sectors);
- cdrom_end_request (0, drive);
- } else
- cdrom_end_request (1, drive);
-
- return;
- }
-
- /* Check that the drive is expecting to do the same thing we are. */
- if (cdrom_read_check_ireason (drive, len, ireason)) return;
-
- /* Assume that the drive will always provide data in multiples
- of at least SECTOR_SIZE, as it gets hairy to keep track
- of the transfers otherwise. */
- if ((len % SECTOR_SIZE) != 0) {
- printk ("%s: cdrom_read_intr: Bad transfer size %d\n",
- drive->name, len);
- printk (" This drive is not supported by this version of the driver\n");
- cdrom_end_request (0, drive);
- return;
- }
-
- /* The number of sectors we need to read from the drive. */
- sectors_to_transfer = len / SECTOR_SIZE;
-
- /* First, figure out if we need to bit-bucket
- any of the leading sectors. */
- nskip = MIN ((int)(rq->current_nr_sectors -
- (rq->bh->b_size >> SECTOR_BITS)),
- sectors_to_transfer);
-
- while (nskip > 0) {
- /* We need to throw away a sector. */
- char dum[SECTOR_SIZE];
- cdrom_in_bytes (drive, dum, sizeof (dum));
-
- --rq->current_nr_sectors;
- --nskip;
- --sectors_to_transfer;
- }
-
- /* Now loop while we still have data to read from the drive. */
- while (sectors_to_transfer > 0) {
- int this_transfer;
-
- /* If we've filled the present buffer but there's another
- chained buffer after it, move on. */
- if (rq->current_nr_sectors == 0 &&
- rq->nr_sectors > 0)
- cdrom_end_request (1, drive);
-
- /* If the buffers are full, cache the rest of the data in our
- internal buffer. */
- if (rq->current_nr_sectors == 0) {
- cdrom_buffer_sectors (drive,
- rq->sector, sectors_to_transfer);
- sectors_to_transfer = 0;
- } else {
- /* Transfer data to the buffers.
- Figure out how many sectors we can transfer
- to the current buffer. */
- this_transfer = MIN (sectors_to_transfer,
- rq->current_nr_sectors);
-
- /* Read this_transfer sectors
- into the current buffer. */
- while (this_transfer > 0) {
- cdrom_in_bytes (drive
- , rq->buffer, SECTOR_SIZE);
- rq->buffer += SECTOR_SIZE;
- --rq->nr_sectors;
- --rq->current_nr_sectors;
- ++rq->sector;
- --this_transfer;
- --sectors_to_transfer;
- }
- }
- }
-
- /* Done moving data!
- Wait for another interrupt. */
- ide_set_handler (drive, &cdrom_read_intr, WAIT_CMD);
-}
-
-
-/*
- * Try to satisfy some of the current read request from our cached data.
- * Returns nonzero if the request has been completed, zero otherwise.
- */
-static int cdrom_read_from_buffer (ide_drive_t *drive)
-{
- struct cdrom_info *info = &drive->cdrom_info;
- struct request *rq = HWGROUP(drive)->rq;
-
- /* Can't do anything if there's no buffer. */
- if (info->sector_buffer == NULL) return 0;
-
- /* Loop while this request needs data and the next block is present
- in our cache. */
- while (rq->nr_sectors > 0 &&
- rq->sector >= info->sector_buffered &&
- rq->sector < info->sector_buffered + info->nsectors_buffered) {
- if (rq->current_nr_sectors == 0)
- cdrom_end_request (1, drive);
-
- memcpy (rq->buffer,
- info->sector_buffer +
- (rq->sector - info->sector_buffered) * SECTOR_SIZE,
- SECTOR_SIZE);
- rq->buffer += SECTOR_SIZE;
- --rq->current_nr_sectors;
- --rq->nr_sectors;
- ++rq->sector;
- }
-
- /* If we've satisfied the current request,
- terminate it successfully. */
- if (rq->nr_sectors == 0) {
- cdrom_end_request (1, drive);
- return -1;
- }
-
- /* Move on to the next buffer if needed. */
- if (rq->current_nr_sectors == 0)
- cdrom_end_request (1, drive);
-
- /* If this condition does not hold, then the kluge i use to
- represent the number of sectors to skip at the start of a transfer
- will fail. I think that this will never happen, but let's be
- paranoid and check. */
- if (rq->current_nr_sectors < (rq->bh->b_size >> SECTOR_BITS) &&
- (rq->sector % SECTORS_PER_FRAME) != 0) {
- printk ("%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
- drive->name, rq->sector);
- cdrom_end_request (0, drive);
- return -1;
- }
-
- return 0;
-}
-
-
-
-/*
- * Routine to send a read packet command to the drive.
- * This is usually called directly from cdrom_start_read.
- * However, for drq_interrupt devices, it is called from an interrupt
- * when the drive is ready to accept the command.
- */
-static void cdrom_start_read_continuation (ide_drive_t *drive)
-{
- struct packet_command pc;
- struct request *rq = HWGROUP(drive)->rq;
-
- int nsect, sector, nframes, frame, nskip;
-
- /* Number of sectors to transfer. */
- nsect = rq->nr_sectors;
-
-#if !STANDARD_ATAPI
- if (nsect > drive->cdrom_info.max_sectors)
- nsect = drive->cdrom_info.max_sectors;
-#endif /* not STANDARD_ATAPI */
-
- /* Starting sector. */
- sector = rq->sector;
-
- /* If the requested sector doesn't start on a cdrom block boundary,
- we must adjust the start of the transfer so that it does,
- and remember to skip the first few sectors.
- If the CURRENT_NR_SECTORS field is larger than the size
- of the buffer, it will mean that we're to skip a number
- of sectors equal to the amount by which CURRENT_NR_SECTORS
- is larger than the buffer size. */
- nskip = (sector % SECTORS_PER_FRAME);
- if (nskip > 0) {
- /* Sanity check... */
- if (rq->current_nr_sectors !=
- (rq->bh->b_size >> SECTOR_BITS)) {
- printk ("%s: cdrom_start_read_continuation: buffer botch (%ld)\n",
- drive->name, rq->current_nr_sectors);
- cdrom_end_request (0, drive);
- return;
- }
-
- sector -= nskip;
- nsect += nskip;
- rq->current_nr_sectors += nskip;
- }
-
- /* Convert from sectors to cdrom blocks, rounding up the transfer
- length if needed. */
- nframes = (nsect + SECTORS_PER_FRAME-1) / SECTORS_PER_FRAME;
- frame = sector / SECTORS_PER_FRAME;
-
- /* Largest number of frames was can transfer at once is 64k-1. */
- nframes = MIN (nframes, 65535);
-
- /* Set up the command */
- memset (&pc.c, 0, sizeof (pc.c));
- pc.c[0] = READ_10;
- pc.c[7] = (nframes >> 8);
- pc.c[8] = (nframes & 0xff);
- put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]);
-
- /* Send the command to the drive and return. */
- (void) cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c),
- &cdrom_read_intr);
-}
-
-
-/*
- * Start a read request from the CD-ROM.
- */
-static void cdrom_start_read (ide_drive_t *drive, unsigned int block)
-{
- struct request *rq = HWGROUP(drive)->rq;
- int minor = MINOR (rq->rq_dev);
-
- /* If the request is relative to a partition, fix it up to refer to the
- absolute address. */
- if ((minor & PARTN_MASK) != 0) {
- rq->sector = block;
- minor &= ~PARTN_MASK;
- rq->rq_dev = MKDEV (MAJOR(rq->rq_dev), minor);
- }
-
- /* We may be retrying this request after an error. Fix up
- any weirdness which might be present in the request packet. */
- restore_request (rq);
-
- /* Satisfy whatever we can of this request from our cached sector. */
- if (cdrom_read_from_buffer (drive))
- return;
-
- /* Clear the local sector buffer. */
- drive->cdrom_info.nsectors_buffered = 0;
-
- /* Start sending the read request to the drive. */
- cdrom_start_packet_command (drive, 32768,
- cdrom_start_read_continuation);
-}
-
-
-
-
-/****************************************************************************
- * Execute all other packet commands.
- */
-
-/* Forward declarations. */
-static int
-cdrom_lockdoor (ide_drive_t *drive, int lockflag,
- struct atapi_request_sense *reqbuf);
-
-
-
-/* Interrupt routine for packet command completion. */
-static void cdrom_pc_intr (ide_drive_t *drive)
-{
- int ireason, len, stat, thislen;
- struct request *rq = HWGROUP(drive)->rq;
- struct packet_command *pc = (struct packet_command *)rq->buffer;
-
- /* Check for errors. */
- if (cdrom_decode_status (drive, 0, &stat)) return;
-
- /* Read the interrupt reason and the transfer length. */
- ireason = IN_BYTE (IDE_NSECTOR_REG);
- len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG);
-
- /* If DRQ is clear, the command has completed.
- Complain if we still have data left to transfer. */
- if ((stat & DRQ_STAT) == 0) {
- /* Some of the trailing request sense fields are optional, and
- some drives don't send them. Sigh. */
- if (pc->c[0] == REQUEST_SENSE &&
- pc->buflen > 0 &&
- pc->buflen <= 5) {
- while (pc->buflen > 0) {
- *pc->buffer++ = 0;
- --pc->buflen;
- }
- }
-
- if (pc->buflen == 0)
- cdrom_end_request (1, drive);
- else {
- printk ("%s: cdrom_pc_intr: data underrun %d\n",
- drive->name, pc->buflen);
- pc->stat = 1;
- cdrom_end_request (1, drive);
- }
- return;
- }
-
- /* Figure out how much data to transfer. */
- thislen = pc->buflen;
- if (thislen < 0) thislen = -thislen;
- if (thislen > len) thislen = len;
-
- /* The drive wants to be written to. */
- if ((ireason & 3) == 0) {
- /* Check that we want to write. */
- if (pc->buflen > 0) {
- printk ("%s: cdrom_pc_intr: Drive wants "
- "to transfer data the wrong way!\n",
- drive->name);
- pc->stat = 1;
- thislen = 0;
- }
-
- /* Transfer the data. */
- cdrom_out_bytes (drive, pc->buffer, thislen);
-
- /* If we haven't moved enough data to satisfy the drive,
- add some padding. */
- while (len > thislen) {
- int dum = 0;
- cdrom_out_bytes (drive, &dum, sizeof (dum));
- len -= sizeof (dum);
- }
-
- /* Keep count of how much data we've moved. */
- pc->buffer += thislen;
- pc->buflen += thislen;
- }
-
- /* Same drill for reading. */
- else if ((ireason & 3) == 2) {
- /* Check that we want to read. */
- if (pc->buflen < 0) {
- printk ("%s: cdrom_pc_intr: Drive wants to "
- "transfer data the wrong way!\n",
- drive->name);
- pc->stat = 1;
- thislen = 0;
- }
-
- /* Transfer the data. */
- cdrom_in_bytes (drive, pc->buffer, thislen);
-
- /* If we haven't moved enough data to satisfy the drive,
- add some padding. */
- while (len > thislen) {
- int dum = 0;
- cdrom_in_bytes (drive, &dum, sizeof (dum));
- len -= sizeof (dum);
- }
-
- /* Keep count of how much data we've moved. */
- pc->buffer += thislen;
- pc->buflen -= thislen;
- } else {
- printk ("%s: cdrom_pc_intr: The drive "
- "appears confused (ireason = 0x%2x)\n",
- drive->name, ireason);
- pc->stat = 1;
- }
-
- /* Now we wait for another interrupt. */
- ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD);
-}
-
-
-static void cdrom_do_pc_continuation (ide_drive_t *drive)
-{
- struct request *rq = HWGROUP(drive)->rq;
- struct packet_command *pc = (struct packet_command *)rq->buffer;
-
- /* Send the command to the drive and return. */
- cdrom_transfer_packet_command (drive, pc->c,
- sizeof (pc->c), &cdrom_pc_intr);
-}
-
-
-static void cdrom_do_packet_command (ide_drive_t *drive)
-{
- int len;
- struct request *rq = HWGROUP(drive)->rq;
- struct packet_command *pc = (struct packet_command *)rq->buffer;
-
- len = pc->buflen;
- if (len < 0) len = -len;
-
- pc->stat = 0;
-
- /* Start sending the command to the drive. */
- cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation);
-}
-
-
-#ifndef MACH
-/* Sleep for TIME jiffies.
- Not to be called from an interrupt handler. */
-static
-void cdrom_sleep (int time)
-{
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + time;
- schedule ();
-}
-#endif
-
-static
-int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc)
-{
- struct atapi_request_sense my_reqbuf;
- int retries = 10;
- struct request req;
-
- /* If our caller has not provided a place to stick any sense data,
- use our own area. */
- if (pc->sense_data == NULL)
- pc->sense_data = &my_reqbuf;
- pc->sense_data->sense_key = 0;
-
- /* Start of retry loop. */
- do {
- ide_init_drive_cmd (&req);
- req.cmd = PACKET_COMMAND;
- req.buffer = (char *)pc;
- (void) ide_do_drive_cmd (drive, &req, ide_wait);
-
- if (pc->stat != 0) {
- /* The request failed. Retry if it was due to a unit
- attention status
- (usually means media was changed). */
- struct atapi_request_sense *reqbuf = pc->sense_data;
-
- if (reqbuf->sense_key == UNIT_ATTENTION)
- ;
- else if (reqbuf->sense_key == NOT_READY &&
- reqbuf->asc == 4) {
- /* The drive is in the process of loading
- a disk. Retry, but wait a little to give
- the drive time to complete the load. */
- cdrom_sleep (HZ);
- } else
- /* Otherwise, don't retry. */
- retries = 0;
-
- --retries;
- }
-
- /* End of retry loop. */
- } while (pc->stat != 0 && retries >= 0);
-
-
- /* Return an error if the command failed. */
- if (pc->stat != 0)
- return -EIO;
- else {
- /* The command succeeded. If it was anything other than
- a request sense, eject, or door lock command,
- and we think that the door is presently, lock it again.
- (The door was probably unlocked via an explicit
- CDROMEJECT ioctl.) */
- if (CDROM_STATE_FLAGS (drive)->door_locked == 0 &&
- (pc->c[0] != REQUEST_SENSE &&
- pc->c[0] != ALLOW_MEDIUM_REMOVAL &&
- pc->c[0] != START_STOP)) {
- (void) cdrom_lockdoor (drive, 1, NULL);
- }
- return 0;
- }
-}
-
-
-/****************************************************************************
- * cdrom driver request routine.
- */
-
-void ide_do_rw_cdrom (ide_drive_t *drive, unsigned long block)
-{
- struct request *rq = HWGROUP(drive)->rq;
-
- if (rq -> cmd == PACKET_COMMAND || rq -> cmd == REQUEST_SENSE_COMMAND)
- cdrom_do_packet_command (drive);
- else if (rq -> cmd == RESET_DRIVE_COMMAND) {
- cdrom_end_request (1, drive);
- ide_do_reset (drive);
- return;
- } else if (rq -> cmd != READ) {
- printk ("ide-cd: bad cmd %d\n", rq -> cmd);
- cdrom_end_request (0, drive);
- } else
- cdrom_start_read (drive, block);
-}
-
-
-
-/****************************************************************************
- * Ioctl handling.
- *
- * Routines which queue packet commands take as a final argument a pointer
- * to an atapi_request_sense struct. If execution of the command results
- * in an error with a CHECK CONDITION status, this structure will be filled
- * with the results of the subsequent request sense command. The pointer
- * can also be NULL, in which case no sense information is returned.
- */
-
-#if ! STANDARD_ATAPI
-static inline
-int bin2bcd (int x)
-{
- return (x%10) | ((x/10) << 4);
-}
-
-
-static inline
-int bcd2bin (int x)
-{
- return (x >> 4) * 10 + (x & 0x0f);
-}
-
-static
-void msf_from_bcd (struct atapi_msf *msf)
-{
- msf->minute = bcd2bin (msf->minute);
- msf->second = bcd2bin (msf->second);
- msf->frame = bcd2bin (msf->frame);
-}
-
-#endif /* not STANDARD_ATAPI */
-
-
-static inline
-void lba_to_msf (int lba, byte *m, byte *s, byte *f)
-{
- lba += CD_BLOCK_OFFSET;
- lba &= 0xffffff; /* negative lbas use only 24 bits */
- *m = lba / (CD_SECS * CD_FRAMES);
- lba %= (CD_SECS * CD_FRAMES);
- *s = lba / CD_FRAMES;
- *f = lba % CD_FRAMES;
-}
-
-
-static inline
-int msf_to_lba (byte m, byte s, byte f)
-{
- return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_BLOCK_OFFSET;
-}
-
-
-static int
-cdrom_check_status (ide_drive_t *drive,
- struct atapi_request_sense *reqbuf)
-{
- struct packet_command pc;
-
- memset (&pc, 0, sizeof (pc));
-
- pc.sense_data = reqbuf;
- pc.c[0] = TEST_UNIT_READY;
-
- /* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to
- switch CDs instead of supporting the LOAD_UNLOAD opcode */
-
- pc.c[7] = CDROM_STATE_FLAGS (drive)->sanyo_slot % 3;
-
- return cdrom_queue_packet_command (drive, &pc);
-}
-
-
-/* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */
-static int
-cdrom_lockdoor (ide_drive_t *drive, int lockflag,
- struct atapi_request_sense *reqbuf)
-{
- struct atapi_request_sense my_reqbuf;
- int stat;
- struct packet_command pc;
-
- if (reqbuf == NULL)
- reqbuf = &my_reqbuf;
-
- /* If the drive cannot lock the door, just pretend. */
- if (CDROM_CONFIG_FLAGS (drive)->no_doorlock)
- stat = 0;
- else {
- memset (&pc, 0, sizeof (pc));
- pc.sense_data = reqbuf;
-
- pc.c[0] = ALLOW_MEDIUM_REMOVAL;
- pc.c[4] = (lockflag != 0);
- stat = cdrom_queue_packet_command (drive, &pc);
- }
-
- if (stat == 0)
- CDROM_STATE_FLAGS (drive)->door_locked = lockflag;
- else {
- /* If we got an illegal field error, the drive
- probably cannot lock the door. */
- if (reqbuf->sense_key == ILLEGAL_REQUEST &&
- (reqbuf->asc == 0x24 || reqbuf->asc == 0x20)) {
- printk ("%s: door locking not supported\n",
- drive->name);
- CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
- stat = 0;
- CDROM_STATE_FLAGS (drive)->door_locked = lockflag;
- }
- }
- return stat;
-}
-
-
-/* Eject the disk if EJECTFLAG is 0.
- If EJECTFLAG is 1, try to reload the disk. */
-static int
-cdrom_eject (ide_drive_t *drive, int ejectflag,
- struct atapi_request_sense *reqbuf)
-{
- struct packet_command pc;
-
- memset (&pc, 0, sizeof (pc));
- pc.sense_data = reqbuf;
-
- pc.c[0] = START_STOP;
- pc.c[4] = 2 + (ejectflag != 0);
- return cdrom_queue_packet_command (drive, &pc);
-}
-
-
-static int
-cdrom_pause (ide_drive_t *drive, int pauseflag,
- struct atapi_request_sense *reqbuf)
-{
- struct packet_command pc;
-
- memset (&pc, 0, sizeof (pc));
- pc.sense_data = reqbuf;
-
- pc.c[0] = SCMD_PAUSE_RESUME;
- pc.c[8] = !pauseflag;
- return cdrom_queue_packet_command (drive, &pc);
-}
-
-
-static int
-cdrom_startstop (ide_drive_t *drive, int startflag,
- struct atapi_request_sense *reqbuf)
-{
- struct packet_command pc;
-
- memset (&pc, 0, sizeof (pc));
- pc.sense_data = reqbuf;
-
- pc.c[0] = START_STOP;
- pc.c[1] = 1;
- pc.c[4] = startflag;
- return cdrom_queue_packet_command (drive, &pc);
-}
-
-
-static int
-cdrom_read_capacity (ide_drive_t *drive, unsigned *capacity,
- struct atapi_request_sense *reqbuf)
-{
- struct {
- unsigned lba;
- unsigned blocklen;
- } capbuf;
-
- int stat;
- struct packet_command pc;
-
- memset (&pc, 0, sizeof (pc));
- pc.sense_data = reqbuf;
-
- pc.c[0] = READ_CAPACITY;
- pc.buffer = (char *)&capbuf;
- pc.buflen = sizeof (capbuf);
-
- stat = cdrom_queue_packet_command (drive, &pc);
- if (stat == 0)
- *capacity = ntohl (capbuf.lba);
-
- return stat;
-}
-
-
-static int
-cdrom_read_tocentry (ide_drive_t *drive, int trackno, int msf_flag,
- int format, char *buf, int buflen,
- struct atapi_request_sense *reqbuf)
-{
- struct packet_command pc;
-
- memset (&pc, 0, sizeof (pc));
- pc.sense_data = reqbuf;
-
- pc.buffer = buf;
- pc.buflen = buflen;
- pc.c[0] = SCMD_READ_TOC;
- pc.c[6] = trackno;
- pc.c[7] = (buflen >> 8);
- pc.c[8] = (buflen & 0xff);
- pc.c[9] = (format << 6);
- if (msf_flag) pc.c[1] = 2;
- return cdrom_queue_packet_command (drive, &pc);
-}
-
-
-/* Try to read the entire TOC for the disk into our internal buffer. */
-static int
-cdrom_read_toc (ide_drive_t *drive,
- struct atapi_request_sense *reqbuf)
-{
- int stat, ntracks, i;
- struct atapi_toc *toc = drive->cdrom_info.toc;
- struct {
- struct atapi_toc_header hdr;
- struct atapi_toc_entry ent;
- } ms_tmp;
-
- if (toc == NULL) {
- /* Try to allocate space. */
- toc = (struct atapi_toc *) kmalloc (sizeof (struct atapi_toc),
- GFP_KERNEL);
- drive->cdrom_info.toc = toc;
- }
-
- if (toc == NULL) {
- printk ("%s: No cdrom TOC buffer!\n", drive->name);
- return -EIO;
- }
-
- /* Check to see if the existing data is still valid.
- If it is, just return. */
- if (CDROM_STATE_FLAGS (drive)->toc_valid)
- (void) cdrom_check_status (drive, NULL);
-
- if (CDROM_STATE_FLAGS (drive)->toc_valid) return 0;
-
- /* First read just the header, so we know how long the TOC is. */
- stat = cdrom_read_tocentry (drive, 0, 1, 0, (char *)&toc->hdr,
- sizeof (struct atapi_toc_header) +
- sizeof (struct atapi_toc_entry),
- reqbuf);
- if (stat) return stat;
-
-#if ! STANDARD_ATAPI
- if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) {
- toc->hdr.first_track = bcd2bin (toc->hdr.first_track);
- toc->hdr.last_track = bcd2bin (toc->hdr.last_track);
- }
-#endif /* not STANDARD_ATAPI */
-
- ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
- if (ntracks <= 0) return -EIO;
- if (ntracks > MAX_TRACKS) ntracks = MAX_TRACKS;
-
- /* Now read the whole schmeer. */
- stat = cdrom_read_tocentry (drive, 0, 1, 0, (char *)&toc->hdr,
- sizeof (struct atapi_toc_header) +
- (ntracks+1) *
- sizeof (struct atapi_toc_entry),
- reqbuf);
- if (stat) return stat;
- toc->hdr.toc_length = ntohs (toc->hdr.toc_length);
-
-#if ! STANDARD_ATAPI
- if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) {
- toc->hdr.first_track = bcd2bin (toc->hdr.first_track);
- toc->hdr.last_track = bcd2bin (toc->hdr.last_track);
- }
-#endif /* not STANDARD_ATAPI */
-
- for (i=0; i<=ntracks; i++) {
-#if ! STANDARD_ATAPI
- if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd) {
- if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd)
- toc->ent[i].track = bcd2bin (toc->ent[i].track);
- msf_from_bcd (&toc->ent[i].addr.msf);
- }
-#endif /* not STANDARD_ATAPI */
- toc->ent[i].addr.lba = msf_to_lba (toc->ent[i].addr.msf.minute,
- toc->ent[i].addr.msf.second,
- toc->ent[i].addr.msf.frame);
- }
-
- /* Read the multisession information. */
- stat = cdrom_read_tocentry (drive, 0, 1, 1,
- (char *)&ms_tmp, sizeof (ms_tmp),
- reqbuf);
- if (stat) return stat;
-
-#if ! STANDARD_ATAPI
- if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd)
- msf_from_bcd (&ms_tmp.ent.addr.msf);
-#endif /* not STANDARD_ATAPI */
-
- toc->last_session_lba = msf_to_lba (ms_tmp.ent.addr.msf.minute,
- ms_tmp.ent.addr.msf.second,
- ms_tmp.ent.addr.msf.frame);
-
- toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track);
-
- /* Now try to get the total cdrom capacity. */
- stat = cdrom_read_capacity (drive, &toc->capacity, reqbuf);
- if (stat) toc->capacity = 0x1fffff;
-
- HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS]
- = toc->capacity * SECTORS_PER_FRAME;
- drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
-
- /* Remember that we've read this stuff. */
- CDROM_STATE_FLAGS (drive)->toc_valid = 1;
-
- return 0;
-}
-
-
-static int
-cdrom_read_subchannel (ide_drive_t *drive, int format,
- char *buf, int buflen,
- struct atapi_request_sense *reqbuf)
-{
- struct packet_command pc;
-
- memset (&pc, 0, sizeof (pc));
- pc.sense_data = reqbuf;
-
- pc.buffer = buf;
- pc.buflen = buflen;
- pc.c[0] = SCMD_READ_SUBCHANNEL;
- pc.c[1] = 2; /* MSF addressing */
- pc.c[2] = 0x40; /* request subQ data */
- pc.c[3] = format,
- pc.c[7] = (buflen >> 8);
- pc.c[8] = (buflen & 0xff);
- return cdrom_queue_packet_command (drive, &pc);
-}
-
-
-/* modeflag: 0 = current, 1 = changeable mask, 2 = default, 3 = saved */
-static int
-cdrom_mode_sense (ide_drive_t *drive, int pageno, int modeflag,
- char *buf, int buflen,
- struct atapi_request_sense *reqbuf)
-{
- struct packet_command pc;
-
- memset (&pc, 0, sizeof (pc));
- pc.sense_data = reqbuf;
-
- pc.buffer = buf;
- pc.buflen = buflen;
- pc.c[0] = MODE_SENSE_10;
- pc.c[2] = pageno | (modeflag << 6);
- pc.c[7] = (buflen >> 8);
- pc.c[8] = (buflen & 0xff);
- return cdrom_queue_packet_command (drive, &pc);
-}
-
-
-static int
-cdrom_mode_select (ide_drive_t *drive, int pageno, char *buf, int buflen,
- struct atapi_request_sense *reqbuf)
-{
- struct packet_command pc;
-
- memset (&pc, 0, sizeof (pc));
- pc.sense_data = reqbuf;
-
- pc.buffer = buf;
- pc.buflen = - buflen;
- pc.c[0] = MODE_SELECT_10;
- pc.c[1] = 0x10;
- pc.c[2] = pageno;
- pc.c[7] = (buflen >> 8);
- pc.c[8] = (buflen & 0xff);
- return cdrom_queue_packet_command (drive, &pc);
-}
-
-
-static int
-cdrom_play_lba_range_1 (ide_drive_t *drive, int lba_start, int lba_end,
- struct atapi_request_sense *reqbuf)
-{
- struct packet_command pc;
-
- memset (&pc, 0, sizeof (pc));
- pc.sense_data = reqbuf;
-
- pc.c[0] = SCMD_PLAYAUDIO_MSF;
- lba_to_msf (lba_start, &pc.c[3], &pc.c[4], &pc.c[5]);
- lba_to_msf (lba_end-1, &pc.c[6], &pc.c[7], &pc.c[8]);
-
-#if ! STANDARD_ATAPI
- if (CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd) {
- pc.c[3] = bin2bcd (pc.c[3]);
- pc.c[4] = bin2bcd (pc.c[4]);
- pc.c[5] = bin2bcd (pc.c[5]);
- pc.c[6] = bin2bcd (pc.c[6]);
- pc.c[7] = bin2bcd (pc.c[7]);
- pc.c[8] = bin2bcd (pc.c[8]);
- }
-#endif /* not STANDARD_ATAPI */
-
- return cdrom_queue_packet_command (drive, &pc);
-}
-
-
-/* Play audio starting at LBA LBA_START and finishing with the
- LBA before LBA_END. */
-static int
-cdrom_play_lba_range (ide_drive_t *drive, int lba_start, int lba_end,
- struct atapi_request_sense *reqbuf)
-{
- int i, stat;
- struct atapi_request_sense my_reqbuf;
-
- if (reqbuf == NULL)
- reqbuf = &my_reqbuf;
-
- /* Some drives, will, for certain audio cds,
- give an error if you ask them to play the entire cd using the
- values which are returned in the TOC. The play will succeed,
- however, if the ending address is adjusted downwards
- by a few frames. */
- for (i=0; i<75; i++) {
- stat = cdrom_play_lba_range_1 (drive, lba_start, lba_end,
- reqbuf);
-
- if (stat == 0 ||
- !(reqbuf->sense_key == ILLEGAL_REQUEST &&
- reqbuf->asc == 0x24))
- return stat;
-
- --lba_end;
- if (lba_end <= lba_start) break;
- }
-
- return stat;
-}
-
-
-static
-int cdrom_get_toc_entry (ide_drive_t *drive, int track,
- struct atapi_toc_entry **ent,
- struct atapi_request_sense *reqbuf)
-{
- int stat, ntracks;
- struct atapi_toc *toc;
-
- /* Make sure our saved TOC is valid. */
- stat = cdrom_read_toc (drive, reqbuf);
- if (stat) return stat;
-
- toc = drive->cdrom_info.toc;
-
- /* Check validity of requested track number. */
- ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
- if (track == CDROM_LEADOUT)
- *ent = &toc->ent[ntracks];
- else if (track < toc->hdr.first_track ||
- track > toc->hdr.last_track)
- return -EINVAL;
- else
- *ent = &toc->ent[track - toc->hdr.first_track];
-
- return 0;
-}
-
-
-static int
-cdrom_read_block (ide_drive_t *drive, int format, int lba, int nblocks,
- char *buf, int buflen,
- struct atapi_request_sense *reqbuf)
-{
- struct packet_command pc;
- struct atapi_request_sense my_reqbuf;
- int stat;
-
- if (reqbuf == NULL)
- reqbuf = &my_reqbuf;
-
- memset (&pc, 0, sizeof (pc));
- pc.sense_data = reqbuf;
-
- pc.buffer = buf;
- pc.buflen = buflen;
-
-#if ! STANDARD_ATAPI
- if (CDROM_CONFIG_FLAGS (drive)->old_readcd)
- pc.c[0] = 0xd4;
- else
-#endif /* not STANDARD_ATAPI */
- pc.c[0] = READ_CD;
-
- pc.c[1] = (format << 2);
- put_unaligned(htonl(lba), (unsigned int *) &pc.c[2]);
- pc.c[8] = (nblocks & 0xff);
- pc.c[7] = ((nblocks>>8) & 0xff);
- pc.c[6] = ((nblocks>>16) & 0xff);
- if (format <= 1)
- pc.c[9] = 0xf8;
- else
- pc.c[9] = 0x10;
-
- stat = cdrom_queue_packet_command (drive, &pc);
-
-#if ! STANDARD_ATAPI
- /* If the drive doesn't recognize the READ CD opcode, retry the command
- with an older opcode for that command. */
- if (stat && reqbuf->sense_key == ILLEGAL_REQUEST &&
- reqbuf->asc == 0x20 &&
- CDROM_CONFIG_FLAGS (drive)->old_readcd == 0) {
- printk ("%s: Drive does not recognize READ_CD;"
- "trying opcode 0xd4\n",
- drive->name);
- CDROM_CONFIG_FLAGS (drive)->old_readcd = 1;
- return cdrom_read_block (drive, format, lba, nblocks,
- buf, buflen, reqbuf);
- }
-#endif /* not STANDARD_ATAPI */
-
- return stat;
-}
-
-
-/* If SLOT<0, unload the current slot. Otherwise, try to load SLOT. */
-static int
-cdrom_load_unload (ide_drive_t *drive, int slot,
- struct atapi_request_sense *reqbuf)
-{
- /* if the drive is a Sanyo 3 CD changer then TEST_UNIT_READY
- (used in the cdrom_check_status function) is used to
- switch CDs instead of LOAD_UNLOAD */
-
- if (CDROM_STATE_FLAGS (drive)->sanyo_slot > 0) {
-
- if ((slot == 1) || (slot == 2)) {
- CDROM_STATE_FLAGS (drive)->sanyo_slot = slot;
- } else if (slot >= 0) {
- CDROM_STATE_FLAGS (drive)->sanyo_slot = 3;
- } else {
- return 0;
- }
-
- return cdrom_check_status (drive, NULL);
-
- } else {
-
- /* ATAPI Rev. 2.2+ standard for requesting switching of
- CDs in a multiplatter device */
-
- struct packet_command pc;
-
- memset (&pc, 0, sizeof (pc));
- pc.sense_data = reqbuf;
-
- pc.c[0] = LOAD_UNLOAD;
- pc.c[4] = 2 + (slot >= 0);
- pc.c[8] = slot;
- return cdrom_queue_packet_command (drive, &pc);
-
- }
-}
-
-
-int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode,
- struct file *file, unsigned int cmd, unsigned long arg)
-{
- switch (cmd) {
- case CDROMEJECT: {
- int stat;
-
- if (drive->usage > 1)
- return -EBUSY;
-
- stat = cdrom_lockdoor (drive, 0, NULL);
- if (stat) return stat;
-
- return cdrom_eject (drive, 0, NULL);
- }
-
- case CDROMCLOSETRAY: {
- int stat;
- if (drive->usage > 1)
- return -EBUSY;
-
- stat = cdrom_eject (drive, 1, NULL);
- if (stat) return stat;
-
- return cdrom_lockdoor (drive, 1, NULL);
- }
-
- case CDROMEJECT_SW: {
- CDROM_STATE_FLAGS (drive)->eject_on_close = arg;
- return 0;
- }
-
- case CDROMPAUSE:
- return cdrom_pause (drive, 1, NULL);
-
- case CDROMRESUME:
- return cdrom_pause (drive, 0, NULL);
-
- case CDROMSTART:
- return cdrom_startstop (drive, 1, NULL);
-
- case CDROMSTOP: {
-#ifdef IHAVEADOLPHIN
- /* Certain Drives require this. Most don't
- and will produce errors upon CDROMSTOP
- pit says the Dolphin needs this. If you
- own a dolphin, just define IHAVEADOLPHIN somewhere */
- int stat;
- stat = cdrom_startstop (drive, 0, NULL);
- if (stat) return stat;
- return cdrom_eject (drive, 1, NULL);
-#endif /* end of IHAVEADOLPHIN */
- return cdrom_startstop (drive, 0, NULL);
- }
-
- case CDROMPLAYMSF: {
- struct cdrom_msf msf;
- int stat, lba_start, lba_end;
-
- stat = verify_area (VERIFY_READ, (void *)arg, sizeof (msf));
- if (stat) return stat;
-
- memcpy_fromfs (&msf, (void *) arg, sizeof(msf));
-
- lba_start = msf_to_lba (msf.cdmsf_min0, msf.cdmsf_sec0,
- msf.cdmsf_frame0);
- lba_end = msf_to_lba (msf.cdmsf_min1, msf.cdmsf_sec1,
- msf.cdmsf_frame1) + 1;
-
- if (lba_end <= lba_start) return -EINVAL;
-
- return cdrom_play_lba_range (drive, lba_start, lba_end, NULL);
- }
-
- /* Like just about every other Linux cdrom driver, we ignore the
- index part of the request here. */
- case CDROMPLAYTRKIND: {
- int stat, lba_start, lba_end;
- struct cdrom_ti ti;
- struct atapi_toc_entry *first_toc, *last_toc;
-
- stat = verify_area (VERIFY_READ, (void *)arg, sizeof (ti));
- if (stat) return stat;
-
- memcpy_fromfs (&ti, (void *) arg, sizeof(ti));
-
- stat = cdrom_get_toc_entry (drive, ti.cdti_trk0, &first_toc,
- NULL);
- if (stat) return stat;
- stat = cdrom_get_toc_entry (drive, ti.cdti_trk1, &last_toc,
- NULL);
- if (stat) return stat;
-
- if (ti.cdti_trk1 != CDROM_LEADOUT) ++last_toc;
- lba_start = first_toc->addr.lba;
- lba_end = last_toc->addr.lba;
-
- if (lba_end <= lba_start) return -EINVAL;
-
- return cdrom_play_lba_range (drive, lba_start, lba_end, NULL);
- }
-
- case CDROMREADTOCHDR: {
- int stat;
- struct cdrom_tochdr tochdr;
- struct atapi_toc *toc;
-
- stat = verify_area (VERIFY_WRITE, (void *) arg,
- sizeof (tochdr));
- if (stat) return stat;
-
- /* Make sure our saved TOC is valid. */
- stat = cdrom_read_toc (drive, NULL);
- if (stat) return stat;
-
- toc = drive->cdrom_info.toc;
- tochdr.cdth_trk0 = toc->hdr.first_track;
- tochdr.cdth_trk1 = toc->hdr.last_track;
-
- memcpy_tofs ((void *) arg, &tochdr, sizeof (tochdr));
-
- return stat;
- }
-
- case CDROMREADTOCENTRY: {
- int stat;
- struct cdrom_tocentry tocentry;
- struct atapi_toc_entry *toce;
-
- stat = verify_area (VERIFY_WRITE, (void *) arg,
- sizeof (tocentry));
- if (stat) return stat;
-
- memcpy_fromfs (&tocentry, (void *) arg, sizeof (tocentry));
-
- stat = cdrom_get_toc_entry (drive, tocentry.cdte_track, &toce,
- NULL);
- if (stat) return stat;
-
- tocentry.cdte_ctrl = toce->control;
- tocentry.cdte_adr = toce->adr;
-
- if (tocentry.cdte_format == CDROM_MSF) {
- /* convert to MSF */
- lba_to_msf (toce->addr.lba,
- &tocentry.cdte_addr.msf.minute,
- &tocentry.cdte_addr.msf.second,
- &tocentry.cdte_addr.msf.frame);
- } else
- tocentry.cdte_addr.lba = toce->addr.lba;
-
- memcpy_tofs ((void *) arg, &tocentry, sizeof (tocentry));
-
- return stat;
- }
-
- case CDROMSUBCHNL: {
- struct atapi_cdrom_subchnl scbuf;
- int stat;
- struct cdrom_subchnl subchnl;
-
- stat = verify_area (VERIFY_WRITE, (void *) arg,
- sizeof (subchnl));
- if (stat) return stat;
-
- memcpy_fromfs (&subchnl, (void *) arg, sizeof (subchnl));
-
- stat = cdrom_read_subchannel (drive, 1, /* current position */
- (char *)&scbuf, sizeof (scbuf),
- NULL);
- if (stat) return stat;
-
-#if ! STANDARD_ATAPI
- if (CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd) {
- msf_from_bcd (&scbuf.acdsc_absaddr.msf);
- msf_from_bcd (&scbuf.acdsc_reladdr.msf);
- }
- if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd)
- scbuf.acdsc_trk = bcd2bin (scbuf.acdsc_trk);
-#endif /* not STANDARD_ATAPI */
-
- if (subchnl.cdsc_format == CDROM_MSF) {
- subchnl.cdsc_absaddr.msf.minute =
- scbuf.acdsc_absaddr.msf.minute;
- subchnl.cdsc_absaddr.msf.second =
- scbuf.acdsc_absaddr.msf.second;
- subchnl.cdsc_absaddr.msf.frame =
- scbuf.acdsc_absaddr.msf.frame;
-
- subchnl.cdsc_reladdr.msf.minute =
- scbuf.acdsc_reladdr.msf.minute;
- subchnl.cdsc_reladdr.msf.second =
- scbuf.acdsc_reladdr.msf.second;
- subchnl.cdsc_reladdr.msf.frame =
- scbuf.acdsc_reladdr.msf.frame;
- } else {
- subchnl.cdsc_absaddr.lba =
- msf_to_lba (scbuf.acdsc_absaddr.msf.minute,
- scbuf.acdsc_absaddr.msf.second,
- scbuf.acdsc_absaddr.msf.frame);
- subchnl.cdsc_reladdr.lba =
- msf_to_lba (scbuf.acdsc_reladdr.msf.minute,
- scbuf.acdsc_reladdr.msf.second,
- scbuf.acdsc_reladdr.msf.frame);
- }
-
- subchnl.cdsc_audiostatus = scbuf.acdsc_audiostatus;
- subchnl.cdsc_ctrl = scbuf.acdsc_ctrl;
- subchnl.cdsc_trk = scbuf.acdsc_trk;
- subchnl.cdsc_ind = scbuf.acdsc_ind;
-
- memcpy_tofs ((void *) arg, &subchnl, sizeof (subchnl));
-
- return stat;
- }
-
- case CDROMVOLCTRL: {
- struct cdrom_volctrl volctrl;
- char buffer[24], mask[24];
- int stat;
-
- stat = verify_area (VERIFY_READ, (void *) arg,
- sizeof (volctrl));
- if (stat) return stat;
- memcpy_fromfs (&volctrl, (void *) arg, sizeof (volctrl));
-
- stat = cdrom_mode_sense (drive, 0x0e, 0, buffer,
- sizeof (buffer), NULL);
- if (stat) return stat;
- stat = cdrom_mode_sense (drive, 0x0e, 1, mask,
- sizeof (buffer), NULL);
- if (stat) return stat;
-
- buffer[1] = buffer[2] = 0;
-
- buffer[17] = volctrl.channel0 & mask[17];
- buffer[19] = volctrl.channel1 & mask[19];
- buffer[21] = volctrl.channel2 & mask[21];
- buffer[23] = volctrl.channel3 & mask[23];
-
- return cdrom_mode_select (drive, 0x0e, buffer,
- sizeof (buffer), NULL);
- }
-
- case CDROMVOLREAD: {
- struct cdrom_volctrl volctrl;
- char buffer[24];
- int stat;
-
- stat = verify_area (VERIFY_WRITE, (void *) arg,
- sizeof (volctrl));
- if (stat) return stat;
-
- stat = cdrom_mode_sense (drive, 0x0e, 0, buffer,
- sizeof (buffer), NULL);
- if (stat) return stat;
-
- volctrl.channel0 = buffer[17];
- volctrl.channel1 = buffer[19];
- volctrl.channel2 = buffer[21];
- volctrl.channel3 = buffer[23];
-
- memcpy_tofs ((void *) arg, &volctrl, sizeof (volctrl));
-
- return 0;
- }
-
- case CDROMMULTISESSION: {
- struct cdrom_multisession ms_info;
- struct atapi_toc *toc;
- int stat;
-
- stat = verify_area (VERIFY_WRITE, (void *)arg,
- sizeof (ms_info));
- if (stat) return stat;
-
- memcpy_fromfs (&ms_info, (void *)arg, sizeof (ms_info));
-
- /* Make sure the TOC information is valid. */
- stat = cdrom_read_toc (drive, NULL);
- if (stat) return stat;
-
- toc = drive->cdrom_info.toc;
-
- if (ms_info.addr_format == CDROM_MSF)
- lba_to_msf (toc->last_session_lba,
- &ms_info.addr.msf.minute,
- &ms_info.addr.msf.second,
- &ms_info.addr.msf.frame);
- else if (ms_info.addr_format == CDROM_LBA)
- ms_info.addr.lba = toc->last_session_lba;
- else
- return -EINVAL;
-
- ms_info.xa_flag = toc->xa_flag;
-
- memcpy_tofs ((void *)arg, &ms_info, sizeof (ms_info));
-
- return 0;
- }
-
- /* Read 2352 byte blocks from audio tracks. */
- case CDROMREADAUDIO: {
- int stat, lba;
- struct atapi_toc *toc;
- struct cdrom_read_audio ra;
- char *buf;
-
- /* Make sure the TOC is up to date. */
- stat = cdrom_read_toc (drive, NULL);
- if (stat) return stat;
-
- toc = drive->cdrom_info.toc;
-
- stat = verify_area (VERIFY_READ, (char *)arg, sizeof (ra));
- if (stat) return stat;
-
- memcpy_fromfs (&ra, (void *)arg, sizeof (ra));
-
- if (ra.nframes < 0 || ra.nframes > toc->capacity)
- return -EINVAL;
- else if (ra.nframes == 0)
- return 0;
-
- stat = verify_area (VERIFY_WRITE, (char *)ra.buf,
- ra.nframes * CD_FRAMESIZE_RAW);
- if (stat) return stat;
-
- if (ra.addr_format == CDROM_MSF)
- lba = msf_to_lba (ra.addr.msf.minute,
- ra.addr.msf.second,
- ra.addr.msf.frame);
- else if (ra.addr_format == CDROM_LBA)
- lba = ra.addr.lba;
- else
- return -EINVAL;
-
- if (lba < 0 || lba >= toc->capacity)
- return -EINVAL;
-
- buf = (char *) kmalloc (CDROM_NBLOCKS_BUFFER*CD_FRAMESIZE_RAW,
- GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- while (ra.nframes > 0) {
- int this_nblocks = ra.nframes;
- if (this_nblocks > CDROM_NBLOCKS_BUFFER)
- this_nblocks = CDROM_NBLOCKS_BUFFER;
- stat = cdrom_read_block
- (drive, 1, lba, this_nblocks,
- buf, this_nblocks * CD_FRAMESIZE_RAW, NULL);
- if (stat) break;
-
- memcpy_tofs (ra.buf, buf,
- this_nblocks * CD_FRAMESIZE_RAW);
- ra.buf += this_nblocks * CD_FRAMESIZE_RAW;
- ra.nframes -= this_nblocks;
- lba += this_nblocks;
- }
-
- kfree (buf);
- return stat;
- }
- case CDROMREADRAW:
- case CDROMREADMODE1:
- case CDROMREADMODE2: {
- struct cdrom_msf msf;
- int blocksize, format, stat, lba;
- struct atapi_toc *toc;
- char *buf;
-
- if (cmd == CDROMREADMODE1) {
- blocksize = CD_FRAMESIZE;
- format = 2;
- } else if (cmd == CDROMREADMODE2) {
- blocksize = CD_FRAMESIZE_RAW0;
- format = 3;
- } else {
- blocksize = CD_FRAMESIZE_RAW;
- format = 0;
- }
-
- stat = verify_area (VERIFY_WRITE, (char *)arg, blocksize);
- if (stat) return stat;
-
- memcpy_fromfs (&msf, (void *)arg, sizeof (msf));
-
- lba = msf_to_lba (msf.cdmsf_min0,
- msf.cdmsf_sec0,
- msf.cdmsf_frame0);
-
- /* DON'T make sure the TOC is up to date. */
- /* stat = cdrom_read_toc (drive, NULL);
- if (stat) return stat;
-
- toc = drive->cdrom_info.toc;
-
- if (lba < 0 || lba >= toc->capacity)
- return -EINVAL; */
-
- buf = (char *) kmalloc (CD_FRAMESIZE_RAW, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- stat = cdrom_read_block (drive, format, lba, 1, buf, blocksize,
- NULL);
- if (stat == 0)
- memcpy_tofs ((char *)arg, buf, blocksize);
-
- kfree (buf);
- return stat;
- }
-
- case CDROM_GET_UPC: {
- int stat;
- char mcnbuf[24];
- struct cdrom_mcn mcn;
-
- stat = verify_area (VERIFY_WRITE, (void *) arg,
- sizeof (mcn));
- if (stat) return stat;
-
- stat = cdrom_read_subchannel (drive, 2, /* get MCN */
- mcnbuf, sizeof (mcnbuf),
- NULL);
- if (stat) return stat;
-
- memcpy (mcn.medium_catalog_number, mcnbuf+9,
- sizeof (mcn.medium_catalog_number)-1);
- mcn.medium_catalog_number[sizeof (mcn.medium_catalog_number)-1]
- = '\0';
-
- memcpy_tofs ((void *) arg, &mcn, sizeof (mcn));
-
- return stat;
- }
-
- case CDROMLOADFROMSLOT:
- printk ("%s: Use CDROM_SELECT_DISC "
- " instead of CDROMLOADFROMSLOT.\n", drive->name);
- /* Fall through. */
-
- case CDROM_SELECT_DISC: {
- struct atapi_request_sense my_reqbuf;
- int stat;
-
- if (drive->usage > 1)
- return -EBUSY;
-
- (void) cdrom_load_unload (drive, -1, NULL);
-
- cdrom_saw_media_change (drive);
- if (arg == -1) {
- (void) cdrom_lockdoor (drive, 0, NULL);
- return 0;
- }
- (void) cdrom_load_unload (drive, (int)arg, NULL);
-
- stat = cdrom_check_status (drive, &my_reqbuf);
- if (stat && my_reqbuf.sense_key == NOT_READY) {
- return -ENOENT;
- }
-
- /* And try to read the TOC information now. */
- return cdrom_read_toc (drive, &my_reqbuf);
- }
-
-#if 0 /* Doesn't work reliably yet. */
- case CDROMRESET: {
- struct request req;
- ide_init_drive_cmd (&req);
- req.cmd = RESET_DRIVE_COMMAND;
- return ide_do_drive_cmd (drive, &req, ide_wait);
- }
-#endif
-
-
-#ifdef TEST
- case 0x1234: {
- int stat;
- struct packet_command pc;
- int len, lena;
-
- memset (&pc, 0, sizeof (pc));
-
- stat = verify_area (VERIFY_READ, (void *) arg, sizeof (pc.c));
- if (stat) return stat;
- memcpy_fromfs (&pc.c, (void *) arg, sizeof (pc.c));
- arg += sizeof (pc.c);
-
- stat = verify_area (VERIFY_READ, (void *) arg, sizeof (len));
- if (stat) return stat;
- memcpy_fromfs (&len, (void *) arg , sizeof (len));
- arg += sizeof (len);
-
- if (len > 0) {
- stat = verify_area (VERIFY_WRITE, (void *) arg, len);
- if (stat) return stat;
- }
-
- lena = len;
- if (lena < 0) lena = 0;
-
- {
- char buf[lena];
- if (len > 0) {
- pc.buflen = len;
- pc.buffer = buf;
- }
-
- stat = cdrom_queue_packet_command (drive, &pc);
-
- if (len > 0)
- memcpy_tofs ((void *)arg, buf, len);
- }
-
- return stat;
- }
-#endif
-
- default:
- return -EPERM;
- }
-
-}
-
-
-
-/****************************************************************************
- * Other driver requests (open, close, check media change).
- */
-
-int ide_cdrom_check_media_change (ide_drive_t *drive)
-{
- int retval;
-
- (void) cdrom_check_status (drive, NULL);
-
- retval = CDROM_STATE_FLAGS (drive)->media_changed;
- CDROM_STATE_FLAGS (drive)->media_changed = 0;
-
- return retval;
-}
-
-
-int ide_cdrom_open (struct inode *ip, struct file *fp, ide_drive_t *drive)
-{
- /* no write access */
- if (fp->f_mode & 2) {
- --drive->usage;
- return -EROFS;
- }
-
- /* If this is the first open, check the drive status. */
- if (drive->usage == 1) {
- int stat;
- struct atapi_request_sense my_reqbuf;
- my_reqbuf.sense_key = 0;
-
- /* Get the drive status. */
- stat = cdrom_check_status (drive, &my_reqbuf);
-
- /* If the tray is open, try to close it. */
- if (stat && my_reqbuf.sense_key == NOT_READY) {
- cdrom_eject (drive, 1, &my_reqbuf);
- stat = cdrom_check_status (drive, &my_reqbuf);
- }
-
- /* If things worked ok, lock the door and read the
- TOC information. */
- if (stat == 0 || my_reqbuf.sense_key == UNIT_ATTENTION) {
- (void) cdrom_lockdoor (drive, 1, &my_reqbuf);
- (void) cdrom_read_toc (drive, &my_reqbuf);
- }
- }
-
- return 0;
-}
-
-
-/*
- * Close down the device. Invalidate all cached blocks.
- */
-
-void ide_cdrom_release (struct inode *inode, struct file *file,
- ide_drive_t *drive)
-{
- if (drive->usage == 0) {
- invalidate_buffers (inode->i_rdev);
-
- /* Unlock the door. */
- (void) cdrom_lockdoor (drive, 0, NULL);
-
- /* Do an eject if we were requested to do so. */
- if (CDROM_STATE_FLAGS (drive)->eject_on_close)
- (void) cdrom_eject (drive, 0, NULL);
- }
-}
-
-
-
-/****************************************************************************
- * Device initialization.
- */
-
-void ide_cdrom_setup (ide_drive_t *drive)
-{
- blksize_size[HWIF(drive)->major][drive->select.b.unit << PARTN_BITS] =
- CD_FRAMESIZE;
-
- drive->special.all = 0;
- drive->ready_stat = 0;
-
- CDROM_STATE_FLAGS (drive)->media_changed = 0;
- CDROM_STATE_FLAGS (drive)->toc_valid = 0;
- CDROM_STATE_FLAGS (drive)->door_locked = 0;
-
- /* Turn this off by default, since many people don't like it. */
- CDROM_STATE_FLAGS (drive)->eject_on_close= 0;
-
-#if NO_DOOR_LOCKING
- CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
-#else
- CDROM_CONFIG_FLAGS (drive)->no_doorlock = 0;
-#endif
-
- /* by default Sanyo 3 CD changer support is turned off and
- ATAPI Rev 2.2+ standard support for CD changers is used */
- CDROM_STATE_FLAGS (drive)->sanyo_slot = 0;
-
- if (drive->id != NULL)
- CDROM_CONFIG_FLAGS (drive)->drq_interrupt =
- ((drive->id->config & 0x0060) == 0x20);
- else
- CDROM_CONFIG_FLAGS (drive)->drq_interrupt = 0;
-
-#if ! STANDARD_ATAPI
- drive->cdrom_info.max_sectors = 252;
-
- CDROM_CONFIG_FLAGS (drive)->old_readcd = 0;
- CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd = 0;
- CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd = 0;
- CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 0;
- CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 0;
-
- if (drive->id != NULL) {
- if (strcmp (drive->id->model, "V003S0DS") == 0 &&
- drive->id->fw_rev[4] == '1' &&
- drive->id->fw_rev[6] <= '2') {
- /* Vertos 300.
- Some versions of this drive like to talk BCD. */
- CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd = 1;
- CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd = 1;
- CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
- CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
- }
-
- else if (strcmp (drive->id->model, "V006E0DS") == 0 &&
- drive->id->fw_rev[4] == '1' &&
- drive->id->fw_rev[6] <= '2') {
- /* Vertos 600 ESD. */
- CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd = 1;
- }
-
- else if (strcmp (drive->id->model, "GCD-R580B") == 0)
- drive->cdrom_info.max_sectors = 124;
-
- else if (strcmp (drive->id->model,
- "NEC CD-ROM DRIVE:260") == 0 &&
- strcmp (drive->id->fw_rev, "1.01") == 0) {
- /* Old NEC260 (not R). */
- CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd = 1;
- CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
- CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
- }
-
- else if (strcmp (drive->id->model, "WEARNES CDD-120") == 0 &&
- strcmp (drive->id->fw_rev, "A1.1") == 0) {
- /* Wearnes */
- CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
- CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
- }
-
- /* Sanyo 3 CD changer uses a non-standard command
- for CD changing */
- else if ((strcmp(drive->id->model, "CD-ROM CDR-C3 G") == 0) ||
- (strcmp(drive->id->model, "CD-ROM CDR-C3G") == 0) ||
- (strcmp(drive->id->model, "CD-ROM CDR_C36") == 0)) {
- /* uses CD in slot 0 when value is set to 3 */
- CDROM_STATE_FLAGS (drive)->sanyo_slot = 3;
- }
-
- }
-#endif /* not STANDARD_ATAPI */
-
- drive->cdrom_info.toc = NULL;
- drive->cdrom_info.sector_buffer = NULL;
- drive->cdrom_info.sector_buffered = 0;
- drive->cdrom_info.nsectors_buffered = 0;
-}
-
-
-
-/*
- * TODO (for 2.1?):
- * Avoid printing error messages for expected errors from the drive.
- * Integrate with generic cdrom driver.
- * Query the drive to find what features are available
- * before trying to use them.
- * Integrate spindown time adjustment patch.
- * Modularize.
- * CDROMRESET ioctl.
- * Better support for changers.
- */
-
-
-
-/*==========================================================================*/
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */