diff options
Diffstat (limited to 'linux/dev/drivers/block')
-rw-r--r-- | linux/dev/drivers/block/ide-cd.c | 2773 |
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: - */ |