diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- linux-2.2.15/arch/sparc64/kernel/ioctl32.c Thu May 4 15:21:22 2000 +++ linux/arch/sparc64/kernel/ioctl32.c Thu May 4 01:19:23 2000 @@ -1437,11 +1437,21 @@ __kernel_caddr_t32 buf; }; +struct cdrom_generic_command32 { + unsigned char cmd[CDROM_PACKET_SIZE]; + __kernel_caddr_t32 buffer; + unsigned int buflen; + int stat; + __kernel_caddr_t32 sense; + __kernel_caddr_t32 reserved[3]; +}; + static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) { mm_segment_t old_fs = get_fs(); struct cdrom_read cdread; struct cdrom_read_audio cdreadaudio; + struct cdrom_generic_command cgc; __kernel_caddr_t32 addr; char *data = 0; void *karg; @@ -1476,6 +1486,17 @@ return -ENOMEM; cdreadaudio.buf = data; break; + case CDROM_SEND_PACKET: + karg = &cgc; + err = copy_from_user(cgc.cmd, &((struct cdrom_generic_command32 *)arg)->cmd, sizeof(cgc.cmd)); + err |= __get_user(addr, &((struct cdrom_generic_command32 *)arg)->buffer); + err |= __get_user(cgc.buflen, &((struct cdrom_generic_command32 *)arg)->buflen); + if (err) + return -EFAULT; + if ((data = kmalloc(cgc.buflen, GFP_KERNEL)) == NULL) + return -ENOMEM; + cgc.buffer = data; + break; default: do { static int count = 0; @@ -1501,11 +1522,14 @@ case CDROMREADAUDIO: err = copy_to_user((char *)A(addr), data, cdreadaudio.nframes * 2352); break; + case CDROM_SEND_PACKET: + err = copy_to_user((char *)A(addr), data, cgc.buflen); default: break; } -out: if (data) kfree(data); - return err; +out: if (data) + kfree(data); + return err ? -EFAULT : 0; } struct loop_info32 { @@ -2248,6 +2272,12 @@ case CDROM_LOCKDOOR: case CDROM_DEBUG: case CDROM_GET_CAPABILITY: + case DVD_READ_STRUCT: + case DVD_WRITE_STRUCT: + case DVD_AUTH: + case CDROM_SEND_PACKET: + case CDROM_NEXT_WRITABLE: + case CDROM_LAST_WRITTEN: /* Big L */ case LOOP_SET_FD: diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- linux-2.2.15/drivers/block/ide-cd.c Thu May 4 15:21:22 2000 +++ linux/drivers/block/ide-cd.c Thu May 4 02:15:04 2000 @@ -2,7 +2,7 @@ * linux/drivers/block/ide-cd.c * Copyright (C) 1994, 1995, 1996 scott snyder * Copyright (C) 1996-1998 Erik Andersen - * Copyright (C) 1998, 1999 Jens Axboe + * Copyright (C) 1998-2000 Jens Axboe * * May be copied or modified under the terms of the GNU General Public * License. See linux/COPYING for more information. @@ -12,29 +12,20 @@ * * Suggestions are welcome. Patches that work are more welcome though. ;-) * 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: + * and comply with the latest Mt. Fuji (SFF8090 version 4) and ATAPI + * (SFF-8020i rev 2.6) standards. These documents can be obtained by + * anonymous ftp from: * ftp://fission.dt.wdc.com/pub/standards/SFF_atapi/spec/SFF8020-r2.6/PS/8020r26.ps + * ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r10.pdf * - * Drives that deviate from the ATAPI standard will be accomodated as much + * Drives that deviate from these standards will be accomodated as much * as possible via compile time or command-line options. Since I only have * a few drives, you generally need to send me patches... * * ---------------------------------- * TO DO LIST: - * -Implement Microsoft Media Status Notification per the spec at - * http://www.microsoft.com/hwdev/respec/storspec.htm - * This will allow us to get automagically notified when the media changes - * on ATAPI drives (something the stock ATAPI spec is lacking). Looks - * very cool. I discovered its existance the other day at work... - * -Query the drive to find what features are available before trying to - * use them (like trying to close the tray in drives that can't). * -Make it so that Pioneer CD DR-A24X and friends don't get screwed up on * boot - * -Integrate DVD-ROM support in driver. Thanks to Merete Gotsæd-Petersen - * of Pioneer Denmark for providing me with a drive for testing. - * -Implement Features and Profiles. - * * * ---------------------------------- * 1.00 Oct 31, 1994 -- Initial version. @@ -243,20 +234,58 @@ * Useful when using ide-cd in conjunction with * ide-scsi. TODO: non-modular way of doing the * same. - * - * 4.54 Sep 09, 1999 - Fixed start/stop error on some drives if the - * drive was locked. - * - Fixed read_toc header, size given was too large. - * - Fixed possible leaks in ioctl. - * - CDROMREADTOCENTRY now honors the cdte_format - * field, instead of forcing CDROM_LBA. - * - Mask out things the drive can't do instead of - * just telling people what the driver can do. + * + * 4.54 Aug 5, 1999 - Support for MMC2 class commands through the generic + * packet interface to cdrom.c. + * - Unified audio ioctl support, most of it. + * - cleaned up various deprecated verify_area(). + * - Added ide_cdrom_packet() as the interface for + * the Uniform generic_packet(). + * - bunch of other stuff, will fill in logs later. + * - report 1 slot for non-changers, like the other + * cd-rom drivers. don't report select disc for + * non-changers as well. + * - mask out audio playing, if the device can't do it. + * + * 4.55 Sep 1, 1999 - Eliminated the rest of the audio ioctls, except + * for CDROMREADTOC[ENTRY|HEADER]. Some of the drivers + * use this independently of the actual audio handling. + * They will disappear later when I get the time to + * do it cleanly. + * - Minimize the TOC reading - only do it when we + * know a media change has occured. + * - Moved all the CDROMREADx ioctls to the Uniform layer. + * - Heiko Eissfeldt supplied + * some fixes for CDI. + * - CD-ROM leaving door locked fix from Andries + * Brouwer + * - Erik Andersen unified + * commands across the various drivers and how + * sense errors are handled. + * + * 4.56 Sep 12, 1999 - Removed changer support - it is now in the + * Uniform layer. + * - Added partition based multisession handling. + * - Mode sense and mode select moved to the + * Uniform layer. + * - Fixed a problem with WPI CDS-32X drive - it + * failed the capabilities + * + * 4.57 never happened + * + * 4.58 May 1, 2000 - Fixed possible oops in ide_cdrom_get_last_session() + * - Fix locking mania and make ide_cdrom_reset relock + * - Stop spewing errors to log when magicdev polls with + * TEST_UNIT_READY on some drives. + * - Cleanup ACER50 stuff. + * - Integrate the ide_cdrom_packet from 2.3 to + * support DVD CSS ioctls. * *************************************************************************/ + +#define IDECD_VERSION "4.58" -#define IDECD_VERSION "4.54" - +#include #include #include #include @@ -266,6 +295,7 @@ #include #include #include + #include #include #include @@ -293,12 +323,11 @@ static -void cdrom_analyze_sense_data (ide_drive_t *drive, - struct atapi_request_sense *reqbuf, - struct packet_command *failed_command) +void cdrom_analyze_sense_data (ide_drive_t *drive, struct packet_command *pc, + struct request_sense *sense) { - if (reqbuf->sense_key == NOT_READY || - reqbuf->sense_key == UNIT_ATTENTION) { + if (sense->sense_key == NOT_READY || + sense->sense_key == UNIT_ATTENTION) { /* Make good and sure we've seen this potential media change. Some drives (i.e. Creative) fail to present the correct sense key in the error register. */ @@ -309,22 +338,21 @@ 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) + if (pc && (pc->c[0] == GPCMD_READ_SUBCHANNEL)) return; } - if (failed_command && (failed_command->c[0] == TEST_UNIT_READY)) + if (pc && (pc->c[0] == GPCMD_TEST_UNIT_READY)) return; - if (reqbuf->error_code == 0x70 && reqbuf->sense_key == 0x02 - && ((reqbuf->asc == 0x3a && reqbuf->ascq == 0x00) || - (reqbuf->asc == 0x04 && reqbuf->ascq == 0x01))) + if (sense->error_code == 0x70 && sense->sense_key == 0x02 + && ((sense->asc == 0x3a && sense->ascq == 0x00) || + (sense->asc == 0x04 && sense->ascq == 0x01))) { /* * Suppress the following errors: - * "Medium not present", and "in progress of becoming ready", - * to keep the noise level down to a dull roar. + * "Medium not present", "in progress of becoming ready", + * and "writing" to keep the noise level down to a dull roar. */ return; } @@ -336,35 +364,38 @@ char buf[80]; printk ("ATAPI device %s:\n", drive->name); - if (reqbuf->error_code==0x70) + if (sense->error_code == 0x70) printk(" Error: "); - else if (reqbuf->error_code==0x71) + else if (sense->error_code == 0x71) printk(" Deferred Error: "); + else if (sense->error_code == 0x7f) + printk(" Vendor-specific Error: "); else printk(" Unknown Error Type: "); - if ( reqbuf->sense_key < ARY_LEN (sense_key_texts)) - s = sense_key_texts[reqbuf->sense_key]; + if (sense->sense_key < ARY_LEN(sense_key_texts)) + s = sense_key_texts[sense->sense_key]; else s = "bad sense key!"; - printk ("%s -- (Sense key=0x%02x)\n", s, reqbuf->sense_key); + printk ("%s -- (Sense key=0x%02x)\n", s, sense->sense_key); - if (reqbuf->asc == 0x40) { + if (sense->asc == 0x40) { sprintf (buf, "Diagnostic failure on component 0x%02x", - reqbuf->ascq); + sense->ascq); s = buf; } else { int lo=0, mid, hi=ARY_LEN (sense_data_texts); - unsigned short key = (reqbuf->asc << 8); - if ( ! (reqbuf->ascq >= 0x80 && reqbuf->ascq <= 0xdd) ) - key |= reqbuf->ascq; - + unsigned long key = (sense->sense_key << 16); + key |= (sense->asc << 8); + if ( ! (sense->ascq >= 0x80 && sense->ascq <= 0xdd) ) + key |= sense->ascq; s = NULL; while (hi > lo) { mid = (lo + hi) / 2; - if (sense_data_texts[mid].asc_ascq == key) { + if (sense_data_texts[mid].asc_ascq == key || + sense_data_texts[mid].asc_ascq == (0xff0000|key)) { s = sense_data_texts[mid].text; break; } @@ -376,53 +407,60 @@ } if (s == NULL) { - if (reqbuf->asc > 0x80) + if (sense->asc > 0x80) s = "(vendor-specific error)"; else s = "(reserved error code)"; } printk (" %s -- (asc=0x%02x, ascq=0x%02x)\n", - s, reqbuf->asc, reqbuf->ascq); + s, sense->asc, sense->ascq); - if (failed_command != NULL) { + if (pc != NULL) { int lo=0, mid, hi= ARY_LEN (packet_command_texts); s = NULL; while (hi > lo) { mid = (lo + hi) / 2; - if (packet_command_texts[mid].packet_command == failed_command->c[0]) { + if (packet_command_texts[mid].packet_command == pc->c[0]) { s = packet_command_texts[mid].text; break; } - else if (packet_command_texts[mid].packet_command > failed_command->c[0]) + else if (packet_command_texts[mid].packet_command > pc->c[0]) hi = mid; else lo = mid+1; } printk (" The failed \"%s\" packet command was: \n \"", s); - for (i=0; ic); i++) - printk ("%02x ", failed_command->c[i]); - printk ("\"\n"); + for (i = 0; i < sizeof(pc->c); i++) + printk("%02x ", pc->c[i]); + printk("\"\n"); + } + + /* The SKSV bit specifies validity of the sense_key_specific + * in the next two commands. It is bit 7 of the first byte. + * In the case of NOT_READY, if SKSV is set the drive can + * give us nice ETA readings. + */ + if (sense->sense_key == NOT_READY && (sense->sks[0] & 0x80)) { + int progress = (sense->sks[1] << 8 | sense->sks[2]) * 100; + printk(" Command is %02d%% complete\n", progress / 0xffff); + } - if (reqbuf->sense_key == ILLEGAL_REQUEST && - (reqbuf->sense_key_specific[0] & 0x80) != 0) { + if (sense->sense_key == ILLEGAL_REQUEST && + (sense->sks[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); - } + (sense->sks[0] & 0x40) != 0 ? + "command packet" : "command data", + (sense->sks[1] << 8) + sense->sks[2]); + + if ((sense->sks[0] & 0x40) != 0) + printk (" bit %d", sense->sks[0] & 0x07); - printk ("\n"); + printk("\n"); } } @@ -431,92 +469,57 @@ /* 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))) + if (sense->sense_key == UNIT_ATTENTION || + (sense->sense_key == NOT_READY && (sense->asc == 4 || + sense->asc == 0x3a))) return; - printk ("%s: error code: 0x%02x sense_key: 0x%02x asc: 0x%02x ascq: 0x%02x\n", - drive->name, - reqbuf->error_code, reqbuf->sense_key, - reqbuf->asc, reqbuf->ascq); + printk("%s: error code: 0x%02x sense_key: 0x%02x asc: 0x%02x ascq: 0x%02x\n", + drive->name, sense->error_code, sense->sense_key, + sense->asc, sense->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) +static void cdrom_queue_request_sense(ide_drive_t *drive, + struct semaphore *sem, + struct request_sense *sense, + struct packet_command *failed_cmd) { struct cdrom_info *info = drive->driver_data; struct request *rq; - struct packet_command *pc; - int len; + struct packet_command *pc = &info->request_sense_pc; - /* If the request didn't explicitly specify where - to put the sense data, use the statically allocated structure. */ - if (reqbuf == NULL) - reqbuf = &info->sense_data; - - /* Make up a new request to retrieve sense information. */ - - pc = &info->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] = (unsigned char) len; - pc->buffer = (char *)reqbuf; - pc->buflen = len; - pc->sense_data = (struct atapi_request_sense *)failed_command; + if (sense == NULL) + sense = &info->sense_data; - /* stuff the sense request in front of our current request */ + memset(pc, 0, sizeof(struct packet_command)); + pc->c[0] = GPCMD_REQUEST_SENSE; + pc->c[4] = pc->buflen = 18; + pc->buffer = (char *) sense; + pc->sense = (struct request_sense *) failed_cmd; + /* stuff the sense request in front of our current request */ rq = &info->request_sense_request; - ide_init_drive_cmd (rq); + ide_init_drive_cmd(rq); rq->cmd = REQUEST_SENSE_COMMAND; - rq->buffer = (char *)pc; + rq->buffer = (char *) pc; rq->sem = sem; - (void) ide_do_drive_cmd (drive, rq, ide_preempt); + (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; + 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); + (struct packet_command *) pc->sense, + (struct request_sense *) pc->buffer - pc->c[4]); } if (rq->cmd == READ && !rq->current_nr_sectors) uptodate = 1; + ide_end_request (uptodate, HWGROUP(drive)); } @@ -527,8 +530,9 @@ int *stat_ret) { struct request *rq = HWGROUP(drive)->rq; - int stat, err, sense_key, cmd; - + int stat, cmd, err, sense_key; + struct packet_command *pc; + /* Check for errors. */ stat = GET_STAT(); *stat_ret = stat; @@ -536,8 +540,8 @@ if (OK_STAT (stat, good_stat, BAD_R_STAT)) return 0; - /* Got an error. */ - err = IN_BYTE (IDE_ERROR_REG); + /* Get the IDE error register. */ + err = GET_ERR(); sense_key = err >> 4; if (rq == NULL) @@ -551,8 +555,7 @@ 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 = (struct packet_command *) rq->buffer; pc->stat = 1; cdrom_end_request (1, drive); *startstop = ide_error (drive, "request sense failure", stat); @@ -561,23 +564,12 @@ } else if (cmd == PACKET_COMMAND) { /* All other functions, except for READ. */ - struct packet_command *pc = (struct packet_command *) - rq->buffer; struct semaphore *sem = NULL; + pc = (struct packet_command *) rq->buffer; /* Check for tray open. */ if (sense_key == NOT_READY) { cdrom_saw_media_change (drive); -#if 0 /* let the upper layers do the complaining */ - /* 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); -#endif } else if (sense_key == UNIT_ATTENTION) { /* Check for media change. */ cdrom_saw_media_change (drive); @@ -607,8 +599,8 @@ cdrom_end_request (1, drive); if ((stat & ERR_STAT) != 0) - cdrom_queue_request_sense (drive, sem, - pc->sense_data, pc); + cdrom_queue_request_sense(drive, sem, pc->sense, + pc); } else { /* Handle errors from READ requests. */ @@ -647,8 +639,7 @@ /* 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); + cdrom_queue_request_sense(drive, NULL, NULL, NULL); } } @@ -657,6 +648,17 @@ return 1; } +static int cdrom_timer_expiry(ide_drive_t *drive) +{ + struct request *rq = HWGROUP(drive)->rq; + struct packet_command *pc = (struct packet_command *) rq->buffer; + unsigned long wait = 0; + + if (pc->c[0] == GPCMD_BLANK || pc->c[0] == GPCMD_FORMAT_UNIT) + wait = 60*60*HZ; + + return wait; +} /* Set up the device registers for transferring a packet command on DEV, expecting to later transfer XFERLEN bytes. HANDLER is the routine @@ -672,7 +674,7 @@ struct cdrom_info *info = drive->driver_data; /* Wait for the controller to be idle. */ - if (ide_wait_stat (&startstop, drive, 0, BUSY_STAT, WAIT_READY)) + if (ide_wait_stat(&startstop, drive, 0, BUSY_STAT, WAIT_READY)) return startstop; if (info->dma) @@ -685,13 +687,14 @@ OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG); OUT_BYTE (xferlen >> 8 , IDE_HCYL_REG); - OUT_BYTE (drive->ctl, IDE_CONTROL_REG); + if (IDE_CONTROL_REG) + OUT_BYTE (drive->ctl, IDE_CONTROL_REG); if (info->dma) (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { - ide_set_handler (drive, handler, WAIT_CMD); + ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry); OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */ return ide_started; } else { @@ -700,14 +703,13 @@ } } - /* 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 ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive, - char *cmd_buf, int cmd_len, + unsigned char *cmd_buf, int cmd_len, ide_handler_t *handler) { if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { @@ -727,7 +729,7 @@ } /* Arm the interrupt handler. */ - ide_set_handler (drive, handler, WAIT_CMD); + ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry); /* Send the command to the device. */ atapi_output_bytes (drive, cmd_buf, cmd_len); @@ -760,25 +762,16 @@ 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) + /* If we couldn't get a buffer, don't try to buffer anything... */ + if (info->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; + dest = info->buffer + info->nsectors_buffered * SECTOR_SIZE; while (sectors_to_buffer > 0) { atapi_input_bytes (drive, dest, SECTOR_SIZE); --sectors_to_buffer; @@ -795,7 +788,6 @@ } } - /* * Check the contents of the interrupt reason register from the cdrom * and attempt to recover if there are problems. Returns 0 if everything's @@ -820,6 +812,12 @@ atapi_output_bytes (drive, &dum, sizeof (dum)); len -= sizeof (dum); } + } else if (ireason == 1) { + /* Some drives (ASUS) seem to tell us that status + * info is available. just get it and ignore. + */ + GET_STAT(); + return 0; } else { /* Drive wants a command packet, or invalid ireason... */ printk ("%s: cdrom_read_intr: bad interrupt reason %d\n", @@ -830,7 +828,6 @@ return -1; } - /* * Interrupt routine. Called when a read request has completed. */ @@ -907,8 +904,7 @@ /* 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)), + nskip = MIN ((int)(rq->current_nr_sectors - (rq->bh->b_size >> SECTOR_BITS)), sectors_to_transfer); while (nskip > 0) { @@ -934,8 +930,7 @@ /* 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); + cdrom_buffer_sectors(drive, rq->sector, sectors_to_transfer); sectors_to_transfer = 0; } else { /* Transfer data to the buffers. @@ -947,8 +942,7 @@ /* Read this_transfer sectors into the current buffer. */ while (this_transfer > 0) { - atapi_input_bytes (drive, - rq->buffer, SECTOR_SIZE); + atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE); rq->buffer += SECTOR_SIZE; --rq->nr_sectors; --rq->current_nr_sectors; @@ -961,11 +955,10 @@ /* Done moving data! Wait for another interrupt. */ - ide_set_handler (drive, &cdrom_read_intr, WAIT_CMD); + ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL); return ide_started; } - /* * Try to satisfy some of the current read request from our cached data. * Returns nonzero if the request has been completed, zero otherwise. @@ -976,7 +969,7 @@ struct request *rq = HWGROUP(drive)->rq; /* Can't do anything if there's no buffer. */ - if (info->sector_buffer == NULL) return 0; + if (info->buffer == NULL) return 0; /* Loop while this request needs data and the next block is present in our cache. */ @@ -987,7 +980,7 @@ cdrom_end_request (1, drive); memcpy (rq->buffer, - info->sector_buffer + + info->buffer + (rq->sector - info->sector_buffered) * SECTOR_SIZE, SECTOR_SIZE); rq->buffer += SECTOR_SIZE; @@ -1022,8 +1015,6 @@ return 0; } - - /* * Routine to send a read packet command to the drive. * This is usually called directly from cdrom_start_read. @@ -1052,14 +1043,13 @@ 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", + if (rq->current_nr_sectors != (rq->bh->b_size >> SECTOR_BITS) && + (rq->sector % CD_FRAMESIZE != 0)) { + printk ("%s: cdrom_start_read_continuation: buffer botch (%lu)\n", drive->name, rq->current_nr_sectors); cdrom_end_request (0, drive); return ide_stopped; } - sector -= nskip; nsect += nskip; rq->current_nr_sectors += nskip; @@ -1076,19 +1066,21 @@ (65534 / CD_FRAMESIZE) : 65535); /* Set up the command */ - memset (&pc.c, 0, sizeof (pc.c)); - pc.c[0] = READ_10; + memset(&pc.c, 0, sizeof(pc.c)); + pc.c[0] = GPCMD_READ_10; pc.c[7] = (nframes >> 8); pc.c[8] = (nframes & 0xff); - put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]); + put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]); /* Send the command to the drive and return. */ - return cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), &cdrom_read_intr); + return cdrom_transfer_packet_command(drive, pc.c, sizeof (pc.c), + &cdrom_read_intr); } + #define IDECD_SEEK_THRESHOLD (1000) /* 1000 blocks */ -#define IDECD_SEEK_TIMER (2 * WAIT_MIN_SLEEP) /* 40 ms */ -#define IDECD_SEEK_TIMEOUT WAIT_CMD /* 10 sec */ +#define IDECD_SEEK_TIMER (5 * WAIT_MIN_SLEEP) /* 100 ms */ +#define IDECD_SEEK_TIMEOUT WAIT_CMD /* 10 sec */ static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive) { @@ -1103,7 +1095,7 @@ if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) { if (--retry == 0) { - printk ("%s: disabled DSC seek overlap\n", drive->name); + printk("%s: disabled DSC seek overlap\n", drive->name); drive->dsc_overlap = 0; } } @@ -1123,8 +1115,8 @@ frame = sector / SECTORS_PER_FRAME; memset (&pc.c, 0, sizeof (pc.c)); - pc.c[0] = SEEK; - put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]); + pc.c[0] = GPCMD_SEEK; + put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]); return cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), &cdrom_seek_intr); } @@ -1137,6 +1129,19 @@ return cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation); } +/* 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; +} + /* * Start a read request from the CD-ROM. */ @@ -1159,57 +1164,53 @@ restore_request (rq); /* Satisfy whatever we can of this request from our cached sector. */ - if (cdrom_read_from_buffer (drive)) + if (cdrom_read_from_buffer(drive)) return ide_stopped; /* Clear the local sector buffer. */ info->nsectors_buffered = 0; - if (drive->using_dma && (rq->sector % SECTORS_PER_FRAME == 0) && (rq->nr_sectors % SECTORS_PER_FRAME == 0)) + /* use dma, if possible. */ + if (drive->using_dma && (rq->sector % SECTORS_PER_FRAME == 0) && + (rq->nr_sectors % SECTORS_PER_FRAME == 0)) info->dma = 1; else info->dma = 0; /* Start sending the read request to the drive. */ - return cdrom_start_packet_command (drive, 32768, cdrom_start_read_continuation); + return 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); - - +static int cdrom_lockdoor(ide_drive_t *drive, int lockflag, + struct request_sense *sense); /* Interrupt routine for packet command completion. */ -static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive) +static ide_startstop_t 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; + struct packet_command *pc = (struct packet_command *) rq->buffer; ide_startstop_t startstop; /* Check for errors. */ - if (cdrom_decode_status (&startstop, drive, 0, &stat)) + if (cdrom_decode_status(&startstop, drive, 0, &stat)) return startstop; /* 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); + 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 && + if (pc->c[0] == GPCMD_REQUEST_SENSE && pc->buflen > 0 && pc->buflen <= 5) { while (pc->buflen > 0) { @@ -1236,70 +1237,52 @@ /* 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. */ - atapi_output_bytes (drive, pc->buffer, thislen); + atapi_output_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; - atapi_output_bytes (drive, &dum, sizeof (dum)); - len -= sizeof (dum); + atapi_output_bytes(drive, &dum, sizeof (dum)); + len -= sizeof(dum); } /* Keep count of how much data we've moved. */ pc->buffer += thislen; - pc->buflen += 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. */ - atapi_input_bytes (drive, pc->buffer, thislen); + atapi_input_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; - atapi_input_bytes (drive, &dum, sizeof (dum)); - len -= sizeof (dum); + atapi_input_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 " + 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); + ide_set_handler(drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry); return ide_started; } @@ -1310,7 +1293,8 @@ struct packet_command *pc = (struct packet_command *)rq->buffer; /* Send the command to the drive and return. */ - return cdrom_transfer_packet_command (drive, pc->c, sizeof (pc->c), &cdrom_pc_intr); + return cdrom_transfer_packet_command (drive, pc->c, + sizeof (pc->c), &cdrom_pc_intr); } @@ -1322,11 +1306,8 @@ struct cdrom_info *info = drive->driver_data; info->dma = 0; - - len = pc->buflen; - if (len < 0) len = -len; - pc->stat = 0; + len = pc->buflen; /* Start sending the command to the drive. */ return cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation); @@ -1343,17 +1324,14 @@ } static -int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc) +int cdrom_queue_packet_command(ide_drive_t *drive, struct packet_command *pc) { - struct atapi_request_sense my_reqbuf; int retries = 10; + struct request_sense sense; 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; + if (pc->sense == NULL) + pc->sense = &sense; /* Start of retry loop. */ do { @@ -1369,85 +1347,77 @@ /* 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; + struct request_sense *reqbuf = pc->sense; if (reqbuf->sense_key == UNIT_ATTENTION) cdrom_saw_media_change (drive); else if (reqbuf->sense_key == NOT_READY && - reqbuf->asc == 4) { + reqbuf->asc == 4 && reqbuf->ascq != 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 + } 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 && drive->usage && - (pc->c[0] != REQUEST_SENSE && - pc->c[0] != ALLOW_MEDIUM_REMOVAL && - pc->c[0] != START_STOP)) { - (void) cdrom_lockdoor (drive, 1, NULL); - } - return 0; - } + return pc->stat ? -EIO : 0; } - /**************************************************************************** * cdrom driver request routine. */ static ide_startstop_t ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block) { - if (rq -> cmd == PACKET_COMMAND || rq -> cmd == REQUEST_SENSE_COMMAND) - return cdrom_do_packet_command (drive); - else if (rq -> cmd == RESET_DRIVE_COMMAND) { - cdrom_end_request (1, drive); - return ide_do_reset (drive); - } else if (rq -> cmd != READ) { - printk ("ide-cd: bad cmd %d\n", rq -> cmd); - cdrom_end_request (0, drive); - return ide_stopped; - } else { - ide_startstop_t action; - struct cdrom_info *info = drive->driver_data; + ide_startstop_t action; + struct cdrom_info *info = drive->driver_data; - if (CDROM_CONFIG_FLAGS(drive)->seeking) { - unsigned long elpased = jiffies - info->start_seek; - int stat = GET_STAT(); - - if ((stat & SEEK_STAT) != SEEK_STAT) { - if (elpased < IDECD_SEEK_TIMEOUT) { - ide_stall_queue (drive, IDECD_SEEK_TIMER); - return ide_stopped; + switch (rq->cmd) { + case READ: { + if (CDROM_CONFIG_FLAGS(drive)->seeking) { + unsigned long elpased = jiffies - info->start_seek; + int stat = GET_STAT(); + + if ((stat & SEEK_STAT) != SEEK_STAT) { + if (elpased < IDECD_SEEK_TIMEOUT) { + ide_stall_queue(drive, IDECD_SEEK_TIMER); + return ide_stopped; + } + printk ("%s: DSC timeout\n", drive->name); } - printk ("%s: DSC timeout\n", drive->name); + CDROM_CONFIG_FLAGS(drive)->seeking = 0; } - CDROM_CONFIG_FLAGS(drive)->seeking = 0; + if (IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap) + action = cdrom_start_seek (drive, block); + else + action = cdrom_start_read (drive, block); + info->last_block = block; + return action; + } + + case PACKET_COMMAND: + case REQUEST_SENSE_COMMAND: { + return cdrom_do_packet_command(drive); + } + + case RESET_DRIVE_COMMAND: { + cdrom_end_request(1, drive); + return ide_do_reset(drive); + } + + default: { + printk("ide-cd: bad cmd %d\n", rq -> cmd); + cdrom_end_request(0, drive); + return ide_stopped; } - if (IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap) - action = cdrom_start_seek (drive, block); - else - action = cdrom_start_read (drive, block); - info->last_block = block; - return action; } } @@ -1457,7 +1427,7 @@ * 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 + * to a 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. @@ -1506,58 +1476,54 @@ return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET; } - -static int -cdrom_check_status (ide_drive_t *drive, - struct atapi_request_sense *reqbuf) +static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense) { struct packet_command pc; + struct cdrom_info *info = drive->driver_data; + struct cdrom_device_info *cdi = &info->devinfo; - memset (&pc, 0, sizeof (pc)); - - pc.sense_data = reqbuf; - pc.c[0] = TEST_UNIT_READY; + memset(&pc, 0, sizeof(pc)); + pc.c[0] = GPCMD_TEST_UNIT_READY; + pc.sense = sense; #if ! STANDARD_ATAPI /* 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; + pc.c[7] = cdi->sanyo_slot % 3; #endif /* not STANDARD_ATAPI */ - return cdrom_queue_packet_command (drive, &pc); + 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) +cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense) { - struct atapi_request_sense my_reqbuf; - int stat; + struct request_sense my_sense; struct packet_command pc; + int stat; - if (reqbuf == NULL) - reqbuf = &my_reqbuf; + if (sense == NULL) + sense = &my_sense; /* 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; + memset(&pc, 0, sizeof(pc)); + pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; pc.c[4] = (lockflag != 0); + pc.sense = sense; stat = cdrom_queue_packet_command (drive, &pc); } /* If we got an illegal field error, the drive probably cannot lock the door. */ if (stat != 0 && - reqbuf->sense_key == ILLEGAL_REQUEST && - (reqbuf->asc == 0x24 || reqbuf->asc == 0x20)) { + sense->sense_key == ILLEGAL_REQUEST && + (sense->asc == 0x24 || sense->asc == 0x20)) { printk ("%s: door locking not supported\n", drive->name); CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1; @@ -1565,7 +1531,7 @@ } /* no medium, that's alright. */ - if (stat != 0 && reqbuf->sense_key == NOT_READY && reqbuf->asc == 0x3a) + if (stat != 0 && sense->sense_key == NOT_READY && sense->asc == 0x3a) stat = 0; if (stat == 0) @@ -1577,115 +1543,81 @@ /* 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) +static int cdrom_eject(ide_drive_t *drive, int ejectflag, + struct request_sense *sense) { struct packet_command pc; - if (CDROM_CONFIG_FLAGS (drive)->no_eject==1 && ejectflag==0) + if (CDROM_CONFIG_FLAGS(drive)->no_eject && !ejectflag) return -EDRIVE_CANT_DO_THIS; - + /* reload fails on some drives, if the tray is locked */ - if (CDROM_STATE_FLAGS (drive)->door_locked && ejectflag) + if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag) return 0; - 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; + memset(&pc, 0, sizeof (pc)); + pc.c[0] = GPCMD_START_STOP_UNIT; + pc.c[4] = 0x02 + (ejectflag != 0); + pc.sense = sense; return cdrom_queue_packet_command (drive, &pc); } -static int -cdrom_read_capacity (ide_drive_t *drive, unsigned *capacity, - struct atapi_request_sense *reqbuf) +static int cdrom_read_capacity(ide_drive_t *drive, unsigned *capacity, + struct request_sense *sense) { struct { - unsigned lba; - unsigned blocklen; + __u32 lba; + __u32 blocklen; } capbuf; int stat; struct packet_command pc; - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; + memset(&pc, 0, sizeof (pc)); - pc.c[0] = READ_CAPACITY; + pc.c[0] = GPCMD_READ_CDVD_CAPACITY; pc.buffer = (char *)&capbuf; - pc.buflen = sizeof (capbuf); + pc.buflen = sizeof(capbuf); + pc.sense = sense; - stat = cdrom_queue_packet_command (drive, &pc); + stat = cdrom_queue_packet_command(drive, &pc); if (stat == 0) - *capacity = ntohl (capbuf.lba); + *capacity = be32_to_cpu(capbuf.lba) + 1; 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) +static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag, + int format, char *buf, int buflen, + struct request_sense *sense) { struct packet_command pc; - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; + memset(&pc, 0, sizeof(pc)); + pc.sense = sense; pc.buffer = buf; pc.buflen = buflen; - pc.c[0] = SCMD_READ_TOC; + pc.c[0] = GPCMD_READ_TOC_PMA_ATIP; 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; + + 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) +static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) { int stat, ntracks, i; struct cdrom_info *info = drive->driver_data; struct atapi_toc *toc = info->toc; + int minor = drive->select.b.unit << PARTN_BITS; struct { struct atapi_toc_header hdr; struct atapi_toc_entry ent; @@ -1693,26 +1625,25 @@ if (toc == NULL) { /* Try to allocate space. */ - toc = (struct atapi_toc *) kmalloc (sizeof (struct atapi_toc), + toc = (struct atapi_toc *) kmalloc(sizeof(struct atapi_toc), GFP_KERNEL); + info->toc = toc; if (toc == NULL) { printk ("%s: No cdrom TOC buffer!\n", drive->name); return -ENOMEM; } - info->toc = toc; } /* 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); + (void) cdrom_check_status(drive, sense); 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), - reqbuf); + sizeof(struct atapi_toc_header), sense); if (stat) return stat; #if ! STANDARD_ATAPI @@ -1727,12 +1658,46 @@ if (ntracks > MAX_TRACKS) ntracks = MAX_TRACKS; /* Now read the whole schmeer. */ - stat = cdrom_read_tocentry (drive, 0, 1, 0, (char *)&toc->hdr, + stat = cdrom_read_tocentry (drive, toc->hdr.first_track, 1, 0, (char *)&toc->hdr, sizeof (struct atapi_toc_header) + - (ntracks+1) * - sizeof (struct atapi_toc_entry), - reqbuf); + (ntracks + 1) * + sizeof (struct atapi_toc_entry), sense); + + if (stat && toc->hdr.first_track > 1) { + /* Cds with CDI tracks only don't have any TOC entries, + despite of this the returned values are + first_track == last_track = number of CDI tracks + 1, + so that this case is indistinguishable from the same + layout plus an additional audio track. + If we get an error for the regular case, we assume + a CDI without additional audio tracks. In this case + the readable TOC is empty (CDI tracks are not included) + and only holds the Leadout entry. Heiko Eißfeldt */ + ntracks = 0; + stat = cdrom_read_tocentry (drive, CDROM_LEADOUT, 1, + 0, (char *)&toc->hdr, + sizeof (struct atapi_toc_header) + + (ntracks+1) * + sizeof (struct atapi_toc_entry), + sense); + if (stat) { + return stat; + } +#if ! STANDARD_ATAPI + if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) { + toc->hdr.first_track = bin2bcd(CDROM_LEADOUT); + toc->hdr.last_track = bin2bcd(CDROM_LEADOUT); + } else +#endif /* not STANDARD_ATAPI */ + { + toc->hdr.first_track = CDROM_LEADOUT; + toc->hdr.last_track = CDROM_LEADOUT; + } + } else if (stat) { + return stat; + } if (stat) return stat; + toc->hdr.toc_length = ntohs (toc->hdr.toc_length); #if ! STANDARD_ATAPI @@ -1756,10 +1721,17 @@ } /* Read the multisession information. */ - stat = cdrom_read_tocentry (drive, 0, 1, 1, - (char *)&ms_tmp, sizeof (ms_tmp), - reqbuf); - if (stat) return stat; + if (toc->hdr.first_track != CDROM_LEADOUT) { + /* Read the multisession information. */ + stat = cdrom_read_tocentry(drive, 0, 1, 1, (char *)&ms_tmp, + sizeof (ms_tmp), sense); + if (stat) return stat; + } else { + ms_tmp.ent.addr.msf.minute = 0; + ms_tmp.ent.addr.msf.second = 2; + ms_tmp.ent.addr.msf.frame = 0; + ms_tmp.hdr.first_track = ms_tmp.hdr.last_track = CDROM_LEADOUT; + } #if ! STANDARD_ATAPI if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd) @@ -1773,191 +1745,105 @@ 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 0 + stat = cdrom_get_last_written(MKDEV(HWIF(drive)->major, minor), + (long *)&toc->capacity); + if (stat) +#endif + stat = cdrom_read_capacity(drive, &toc->capacity, sense); if (stat) toc->capacity = 0x1fffff; - HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS] - = (toc->capacity * SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9); + /* for general /dev/cdrom like mounting, one big disc */ drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME; + HWIF(drive)->gd->sizes[minor] = (toc->capacity * SECTORS_PER_FRAME) >> + (BLOCK_SIZE_BITS - 9); /* Remember that we've read this stuff. */ CDROM_STATE_FLAGS (drive)->toc_valid = 1; + /* should be "if multisession", but it does no harm. */ + if (ntracks == 1) + return 0; + + /* setup each minor to respond to a session */ + minor++; + i = toc->hdr.first_track; + while ((i <= ntracks) && ((minor & CD_PART_MASK) < CD_PART_MAX)) { + drive->part[minor & PARTN_MASK].start_sect = 0; + drive->part[minor & PARTN_MASK].nr_sects = + (toc->ent[i].addr.lba * + SECTORS_PER_FRAME) << (BLOCK_SIZE_BITS - 9); + HWIF(drive)->gd->sizes[minor] = (toc->ent[i].addr.lba * + SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9); + i++; + minor++; + } + return 0; } -static int -cdrom_read_subchannel (ide_drive_t *drive, int format, - char *buf, int buflen, - struct atapi_request_sense *reqbuf) +static int cdrom_read_subchannel(ide_drive_t *drive, int format, char *buf, + int buflen, struct request_sense *sense) { struct packet_command pc; - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; + memset(&pc, 0, sizeof(pc)); + pc.sense = sense; - pc.buffer = buf; + pc.buffer = buf; pc.buflen = buflen; - pc.c[0] = SCMD_READ_SUBCHANNEL; + pc.c[0] = GPCMD_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); + return cdrom_queue_packet_command(drive, &pc); } /* ATAPI cdrom drives are free to select the speed you request or any slower rate :-( Requesting too fast a speed will _not_ produce an error. */ -static int -cdrom_select_speed (ide_drive_t *drive, int speed, - struct atapi_request_sense *reqbuf) +static int cdrom_select_speed(ide_drive_t *drive, int speed, + struct request_sense *sense) { struct packet_command pc; - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; + memset(&pc, 0, sizeof(pc)); + pc.sense = sense; if (speed == 0) - speed = 0xffff; /* set to max */ + speed = 0xffff; /* set to max */ else - speed *= 177; /* Nx to kbytes/s */ + speed *= 177; /* Nx to kbytes/s */ - pc.c[0] = SET_CD_SPEED; + pc.c[0] = GPCMD_SET_SPEED; /* Read Drive speed in kbytes/second MSB */ pc.c[2] = (speed >> 8) & 0xff; /* Read Drive speed in kbytes/second LSB */ pc.c[3] = speed & 0xff; - if ( CDROM_CONFIG_FLAGS(drive)->cd_r || - CDROM_CONFIG_FLAGS(drive)->cd_rw ) { + if (CDROM_CONFIG_FLAGS(drive)->cd_r || + CDROM_CONFIG_FLAGS(drive)->cd_rw || + CDROM_CONFIG_FLAGS(drive)->dvd_r) { /* Write Drive speed in kbytes/second MSB */ pc.c[4] = (speed >> 8) & 0xff; /* Write Drive speed in kbytes/second LSB */ pc.c[5] = speed & 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 = 0; - 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; + return cdrom_queue_packet_command(drive, &pc); } -static -int cdrom_get_toc_entry (ide_drive_t *drive, int track, - struct atapi_toc_entry **ent, - struct atapi_request_sense *reqbuf) +static int cdrom_get_toc_entry(ide_drive_t *drive, int track, + struct atapi_toc_entry **ent) { struct cdrom_info *info = drive->driver_data; - 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 = info->toc; + struct atapi_toc *toc = info->toc; + int ntracks; /* Check validity of requested track number. */ ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; + if (toc->hdr.first_track == CDROM_LEADOUT) ntracks = 0; if (track == CDROM_LEADOUT) *ent = &toc->ent[ntracks]; else if (track < toc->hdr.first_track || @@ -1970,377 +1856,75 @@ } -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; - - 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)->nec260) - pc.c[0] = 0xd4; - else -#endif /* not STANDARD_ATAPI */ - pc.c[0] = READ_CD; +/* the generic packet interface to cdrom.c */ +static int ide_cdrom_packet(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc) +{ + struct packet_command pc; + ide_drive_t *drive = (ide_drive_t*) cdi->handle; - 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; /* returns 2352 for any format */ - else - pc.c[9] = 0x10; + /* here we queue the commands from the uniform CD-ROM + layer. the packet must be complete, as we do not + touch it at all. */ + memset(&pc, 0, sizeof(pc)); + memcpy(pc.c, cgc->cmd, CDROM_PACKET_SIZE); + pc.buffer = cgc->buffer; + pc.buflen = cgc->buflen; + cgc->stat = cdrom_queue_packet_command(drive, &pc); + cgc->sense = pc.sense; - return cdrom_queue_packet_command (drive, &pc); + return cgc->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) +static +int ide_cdrom_dev_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, + unsigned long arg) { -#if ! STANDARD_ATAPI - /* 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, reqbuf); - - } - else -#endif /*not STANDARD_ATAPI */ - { - - /* 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); - - } -} - - -/* This gets the mechanism status per ATAPI draft spec 2.6 */ -static int -cdrom_read_mech_status (ide_drive_t *drive, 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] = MECHANISM_STATUS; - pc.c[8] = (buflen >> 8); - pc.c[9] = (buflen & 0xff); - return cdrom_queue_packet_command (drive, &pc); -} - - -/* Read the drive mechanism status and slot table into our internal buffer. - If the buffer does not yet exist, allocate it. */ -static int -cdrom_read_changer_info (ide_drive_t *drive) -{ - int nslots; - struct cdrom_info *info = drive->driver_data; - - if (info->changer_info) - nslots = info->changer_info->hdr.nslots; - - else { - struct atapi_mechstat_header mechbuf; - int stat; - - stat = cdrom_read_mech_status (drive, - (char *)&mechbuf, - sizeof (mechbuf), - NULL); - if (stat) - return stat; - - nslots = mechbuf.nslots; - info->changer_info = - (struct atapi_changer_info *) - kmalloc (sizeof (struct atapi_changer_info) + - nslots * sizeof (struct atapi_slot), - GFP_KERNEL); - - if (info->changer_info == NULL) - return -ENOMEM; - } - - return cdrom_read_mech_status - (drive, - (char *)&info->changer_info->hdr, - sizeof (struct atapi_mechstat_header) + - nslots * sizeof (struct atapi_slot), - NULL); -} - - -static -int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi, - unsigned int cmd, unsigned long arg) - -{ - ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct cdrom_info *info = drive->driver_data; + struct cdrom_generic_command cgc; + char buffer[16]; + int stat; + init_cdrom_command(&cgc, buffer, sizeof(buffer)); + /* These will be moved into the Uniform layer shortly... */ switch (cmd) { - 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 { /* for RAW and MODE2. */ - blocksize = CD_FRAMESIZE_RAW; - format = 0; - } - - copy_from_user_ret(&msf, (void *)arg, sizeof (msf), -EFAULT); - - lba = msf_to_lba(msf.cdmsf_min0, - msf.cdmsf_sec0, - msf.cdmsf_frame0); - - /* Make sure the TOC is up to date. */ - if (cmd != CDROMREADRAW) { - stat = cdrom_read_toc (drive, NULL); - if (stat) - return stat; - - toc = info->toc; - - if (lba < 0 || lba >= toc->capacity) - return -EINVAL; - } - - buf = (char *) kmalloc (blocksize, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - stat = cdrom_read_block (drive, format, lba, 1, buf, - blocksize, NULL); - - if (stat == 0) { - if (cmd == CDROMREADMODE2) { - /* For Mode2, skip the Sync, Header, and Subheader */ - if (copy_to_user((char *)arg, buf+16, CD_FRAMESIZE_RAW0)) - stat = -EFAULT; - } else { - if (copy_to_user((char *)arg, buf, blocksize)) - stat = -EFAULT; - } - } - - kfree (buf); - return stat; - } - - /* 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 = info->toc; - - stat = verify_area (VERIFY_READ, (char *)arg, sizeof (ra)); - if (stat) return stat; - - copy_from_user (&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; - - copy_to_user (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 CDROMSETSPINDOWN: { char spindown; - char buffer[16]; - int stat; - - stat = verify_area (VERIFY_READ, (void *) arg, - sizeof (char)); - if (stat) return stat; - copy_from_user (&spindown, (void *) arg, sizeof(char)); + if (copy_from_user(&spindown, (void *) arg, sizeof(char))) + return -EFAULT; - stat = cdrom_mode_sense (drive, PAGE_CDROM, 0, buffer, - sizeof (buffer), NULL); - if (stat) return stat; + if ((stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0))) + return stat; buffer[11] = (buffer[11] & 0xf0) | (spindown & 0x0f); - return cdrom_mode_select (drive, PAGE_CDROM, buffer, - sizeof (buffer), NULL); + return cdrom_mode_select(cdi, &cgc); } case CDROMGETSPINDOWN: { char spindown; - char buffer[16]; - int stat; - - stat = verify_area (VERIFY_WRITE, (void *) arg, - sizeof (char)); - if (stat) return stat; - stat = cdrom_mode_sense (drive, PAGE_CDROM, 0, buffer, - sizeof (buffer), NULL); - if (stat) return stat; + if ((stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0))) + return stat; spindown = buffer[11] & 0x0f; - copy_to_user ((void *) arg, &spindown, sizeof (char)); + if (copy_to_user((void *) arg, &spindown, sizeof (char))) + return -EFAULT; return 0; } -#ifdef ALLOW_TEST_PACKETS - 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; - copy_from_user (&pc.c, (void *) arg, sizeof (pc.c)); - arg += sizeof (pc.c); - - stat = verify_area (VERIFY_READ, (void *) arg, sizeof (len)); - if (stat) return stat; - copy_from_user (&len, (void *) arg , sizeof (len)); - arg += sizeof (len); - - lena = len; - if (lena < 0) lena = -lena; - - { - char buf[lena]; - if (len > 0) { - stat = verify_area (VERIFY_WRITE, - (void *) arg, len); - if (stat) return stat; - } - else if (len < 0) { - stat = verify_area (VERIFY_READ, - (void *) arg, -len); - if (stat) return stat; - copy_from_user (buf, (void*)arg, -len); - } - - if (len != 0) { - pc.buflen = len; - pc.buffer = buf; - } - - stat = cdrom_queue_packet_command (drive, &pc); - - if (len > 0) - copy_to_user ((void *)arg, buf, len); - } - - return stat; - } -#endif - default: return -EINVAL; } } - - static int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi, unsigned int cmd, void *arg) @@ -2350,54 +1934,13 @@ struct cdrom_info *info = drive->driver_data; switch (cmd) { - case CDROMSUBCHNL: { - struct atapi_cdrom_subchnl scbuf; - int stat; - struct cdrom_subchnl *subchnl = (struct cdrom_subchnl *)arg; - - 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 */ - - 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; - - subchnl->cdsc_audiostatus = scbuf.acdsc_audiostatus; - subchnl->cdsc_ctrl = scbuf.acdsc_ctrl; - subchnl->cdsc_trk = scbuf.acdsc_trk; - subchnl->cdsc_ind = scbuf.acdsc_ind; - - return 0; - } - case CDROMREADTOCHDR: { int stat; struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg; struct atapi_toc *toc; /* Make sure our saved TOC is valid. */ - stat = cdrom_read_toc (drive, NULL); + stat = cdrom_read_toc(drive, NULL); if (stat) return stat; toc = info->toc; @@ -2412,8 +1955,7 @@ struct cdrom_tocentry *tocentry = (struct cdrom_tocentry*) arg; struct atapi_toc_entry *toce; - stat = cdrom_get_toc_entry (drive, tocentry->cdte_track, &toce, - NULL); + stat = cdrom_get_toc_entry (drive, tocentry->cdte_track, &toce); if (stat) return stat; tocentry->cdte_ctrl = toce->control; @@ -2423,314 +1965,92 @@ &tocentry->cdte_addr.msf.minute, &tocentry->cdte_addr.msf.second, &tocentry->cdte_addr.msf.frame); - } else { + } else tocentry->cdte_addr.lba = toce->addr.lba; - } - - return 0; - } - - case CDROMPLAYMSF: { - struct cdrom_msf *msf = (struct cdrom_msf *) arg; - int lba_start, lba_end; - - 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 cdrom_ti *)arg; - struct atapi_toc_entry *first_toc, *last_toc; - - 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 CDROMVOLCTRL: { - struct cdrom_volctrl *volctrl = (struct cdrom_volctrl *) arg; - char buffer[24], mask[24]; - int stat; - - stat = cdrom_mode_sense (drive, PAGE_AUDIO, 0, buffer, - sizeof (buffer), NULL); - if (stat) return stat; - stat = cdrom_mode_sense (drive, PAGE_AUDIO, 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, PAGE_AUDIO, buffer, - sizeof (buffer), NULL); - } - - case CDROMVOLREAD: { - struct cdrom_volctrl *volctrl = (struct cdrom_volctrl *) arg; - char buffer[24]; - int stat; - - stat = cdrom_mode_sense (drive, PAGE_AUDIO, 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]; return 0; } - 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 CDROMPAUSE: - return cdrom_pause (drive, 1, NULL); - - case CDROMRESUME: - return cdrom_pause (drive, 0, NULL); - - default: return -EINVAL; } } - static -int ide_cdrom_reset (struct cdrom_device_info *cdi) +int ide_cdrom_reset(struct cdrom_device_info *cdi) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; + struct request_sense sense; struct request req; + int ret; - ide_init_drive_cmd (&req); + ide_init_drive_cmd(&req); req.cmd = RESET_DRIVE_COMMAND; - return ide_do_drive_cmd (drive, &req, ide_wait); + ret = ide_do_drive_cmd(drive, &req, ide_wait); + + /* A reset will unlock the door. If it was previously locked, + * lock it again. + */ + if (CDROM_STATE_FLAGS(drive)->door_locked) + (void) cdrom_lockdoor(drive, 1, &sense); + + return ret; } static -int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position) +int ide_cdrom_tray_move(struct cdrom_device_info *cdi, int position) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct atapi_request_sense rq; + struct request_sense sense; if (position) { - int stat = cdrom_lockdoor (drive, 0, &rq); + int stat = cdrom_lockdoor(drive, 0, &sense); if (stat) return stat; } - return cdrom_eject (drive, !position, NULL); + return cdrom_eject(drive, !position, &sense); } - static int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; - return cdrom_lockdoor (drive, lock, NULL); -} - -/* - * the buffer struct used by ide_cdrom_get_capabilities() - */ -struct get_capabilities_buf { - char pad[8]; - struct atapi_capabilities_page cap; /* this is 4 bytes short of ATAPI standard */ - char extra_cap[4]; /* Acer 50X needs the regulation size buffer */ -}; - -static -int ide_cdrom_get_capabilities (ide_drive_t *drive, struct get_capabilities_buf *buf) -{ - int stat, attempts = 3, buflen = sizeof(*buf); - - /* - * Most drives don't care about the buffer size; they return as much info as there's room for. - * But some older drives (?) had trouble with the standard size, preferring 4 bytes less. - * And the modern Acer 50X rejects anything smaller than the standard size. - */ - if (!(drive->id && !strcmp(drive->id->model,"ATAPI CD ROM DRIVE 50X MAX"))) - buflen -= sizeof(buf->extra_cap); /* for all drives except Acer 50X */ - - do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ - stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0, (char *)buf, buflen, NULL); - if (stat == 0) { - /* - * The ACER/AOpen 24X cdrom has the speed fields byte-swapped from the standard. - */ - if (!(drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4))) { - buf->cap.curspeed = ntohs(buf->cap.curspeed); - buf->cap.maxspeed = ntohs(buf->cap.maxspeed); - } - CDROM_STATE_FLAGS (drive)->current_speed = (((unsigned int)buf->cap.curspeed) + (176/2)) / 176; - CDROM_CONFIG_FLAGS(drive)->max_speed = (((unsigned int)buf->cap.maxspeed) + (176/2)) / 176; - return 0; - } - } while (--attempts); - return stat; + return cdrom_lockdoor(drive, lock, NULL); } -static -int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed) -{ - int stat; - struct get_capabilities_buf buf; - ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct atapi_request_sense reqbuf; - stat=cdrom_select_speed (drive, speed, &reqbuf); - if (stat<0) - return stat; - - /* Now with that done, update the speed fields */ - if (ide_cdrom_get_capabilities(drive,&buf)) - return 0; - - cdi->speed = CDROM_STATE_FLAGS (drive)->current_speed; - return 0; -} static -int ide_cdrom_select_disc (struct cdrom_device_info *cdi, int slot) +int ide_cdrom_select_speed(struct cdrom_device_info *cdi, int speed) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct cdrom_info *info = drive->driver_data; - - struct atapi_request_sense my_reqbuf; + struct request_sense sense; int stat; - int nslots, curslot; - - if ( ! CDROM_CONFIG_FLAGS (drive)->is_changer) - return -EDRIVE_CANT_DO_THIS; - -#if ! STANDARD_ATAPI - if (CDROM_STATE_FLAGS (drive)->sanyo_slot > 0) { - nslots = 3; - curslot = CDROM_STATE_FLAGS (drive)->sanyo_slot; - if (curslot == 3) - curslot = 0; - } else -#endif /* not STANDARD_ATAPI */ - { - stat = cdrom_read_changer_info (drive); - if (stat) - return stat; - - nslots = info->changer_info->hdr.nslots; - curslot = info->changer_info->hdr.curslot; - } - - if (slot == curslot) - return curslot; - - if (slot == CDSL_CURRENT) - return curslot; - - if (slot != CDSL_NONE && (slot < 0 || slot >= nslots)) - return -EINVAL; - if (drive->usage > 1) - return -EBUSY; - - if (slot == CDSL_NONE) { - (void) cdrom_load_unload (drive, -1, NULL); - cdrom_saw_media_change (drive); - (void) cdrom_lockdoor (drive, 0, NULL); - return 0; - } - else { - int was_locked; - - if ( -#if ! STANDARD_ATAPI - CDROM_STATE_FLAGS (drive)->sanyo_slot == 0 && -#endif - info->changer_info->slots[slot].disc_present == 0) { - return -ENOMEDIUM; - } - - was_locked = CDROM_STATE_FLAGS (drive)->door_locked; - if (was_locked) - (void) cdrom_lockdoor (drive, 0, NULL); - - stat = cdrom_load_unload (drive, slot, NULL); - cdrom_saw_media_change (drive); - if (stat) - return stat; - - stat = cdrom_check_status (drive, &my_reqbuf); - if (stat && my_reqbuf.sense_key == NOT_READY) - return -ENOENT; - - if (stat == 0 || my_reqbuf.sense_key == UNIT_ATTENTION) { - stat = cdrom_read_toc (drive, &my_reqbuf); - if (stat) - return stat; - } - - if (was_locked) - (void) cdrom_lockdoor (drive, 1, NULL); + if ((stat = cdrom_select_speed(drive, speed, &sense)) < 0) + return stat; - return slot; - } + cdi->speed = CDROM_STATE_FLAGS(drive)->current_speed; + return 0; } - static int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct cdrom_info *info = drive->driver_data; if (slot_nr == CDSL_CURRENT) { + struct request_sense sense; + int stat = cdrom_check_status(drive, &sense); + if (stat == 0 || sense.sense_key == UNIT_ATTENTION) + return CDS_DISC_OK; - struct atapi_request_sense my_reqbuf; - int stat = cdrom_check_status (drive, &my_reqbuf); - if (stat == 0 || my_reqbuf.sense_key == UNIT_ATTENTION) + if (sense.sense_key == NOT_READY && sense.asc == 0x04 && + sense.ascq == 0x04) return CDS_DISC_OK; - if (my_reqbuf.sense_key == NOT_READY) { + if (sense.sense_key == NOT_READY) { /* ATAPI doesn't have anything that can help us decide whether the drive is really emtpy or the tray is just open. irk. */ @@ -2739,47 +2059,29 @@ return CDS_DRIVE_NOT_READY; } - -#if ! STANDARD_ATAPI - else if (CDROM_STATE_FLAGS (drive)->sanyo_slot > 0) - return CDS_NO_INFO; -#endif /* not STANDARD_ATAPI */ - - else { - struct atapi_changer_info *ci; - int stat = cdrom_read_changer_info (drive); - if (stat < 0) - return stat; - ci = info->changer_info; - - if (ci->slots[slot_nr].disc_present) - return CDS_DISC_OK; - else - return CDS_NO_DISC; - } + return -EINVAL; } static int ide_cdrom_get_last_session (struct cdrom_device_info *cdi, struct cdrom_multisession *ms_info) { - int stat; struct atapi_toc *toc; ide_drive_t *drive = (ide_drive_t*) cdi->handle; struct cdrom_info *info = drive->driver_data; - - /* Make sure the TOC information is valid. */ - stat = cdrom_read_toc (drive, NULL); - if (stat) return stat; + struct request_sense sense; + int ret; toc = info->toc; + if (!CDROM_STATE_FLAGS(drive)->toc_valid || toc == NULL) + if ((ret = cdrom_read_toc(drive, &sense))) + return ret; ms_info->addr.lba = toc->last_session_lba; ms_info->xa_flag = toc->xa_flag; return 0; } - static int ide_cdrom_get_mcn (struct cdrom_device_info *cdi, struct cdrom_mcn *mcn_info) @@ -2788,10 +2090,9 @@ char mcnbuf[24]; ide_drive_t *drive = (ide_drive_t*) cdi->handle; - stat = cdrom_read_subchannel (drive, 2, /* get MCN */ - mcnbuf, sizeof (mcnbuf), - NULL); - if (stat) return stat; +/* get MCN */ + if ((stat = cdrom_read_subchannel(drive, 2, mcnbuf, sizeof (mcnbuf), NULL))) + return stat; memcpy (mcn_info->medium_catalog_number, mcnbuf+9, sizeof (mcn_info->medium_catalog_number)-1); @@ -2812,37 +2113,15 @@ int slot_nr) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; - struct cdrom_info *info = drive->driver_data; - int retval; - + if (slot_nr == CDSL_CURRENT) { - (void) cdrom_check_status (drive, NULL); + (void) cdrom_check_status(drive, NULL); retval = CDROM_STATE_FLAGS (drive)->media_changed; CDROM_STATE_FLAGS (drive)->media_changed = 0; + return retval; } - -#if ! STANDARD_ATAPI - else if (CDROM_STATE_FLAGS (drive)->sanyo_slot > 0) { - retval = 0; - } -#endif /* not STANDARD_ATAPI */ - - else { - struct atapi_changer_info *ci; - int stat = cdrom_read_changer_info (drive); - if (stat < 0) - return stat; - ci = info->changer_info; - - /* This test may be redundant with cdrom.c. */ - if (slot_nr < 0 || slot_nr >= ci->hdr.nslots) - return -EINVAL; - - retval = ci->slots[slot_nr].change; - } - - return retval; + return -EINVAL; } @@ -2877,7 +2156,7 @@ ide_cdrom_tray_move, /* tray_move */ ide_cdrom_lock_door, /* lock_door */ ide_cdrom_select_speed, /* select_speed */ - ide_cdrom_select_disc, /* select_disc */ + NULL, /* select_disc */ ide_cdrom_get_last_session, /* get_last_session */ ide_cdrom_get_mcn, /* get_mcn */ ide_cdrom_reset, /* reset */ @@ -2885,9 +2164,11 @@ ide_cdrom_dev_ioctl, /* dev_ioctl */ CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN - | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET - | CDC_IOCTLS | CDC_DRIVE_STATUS, /* capability */ - 0 /* n_minors */ + | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS + | CDC_DRIVE_STATUS | CDC_CD_R | CDC_CD_RW | CDC_DVD + | CDC_DVD_R| CDC_DVD_RAM | CDC_GENERIC_PACKET, /* capability */ + 0, /* n_minors */ + ide_cdrom_packet }; static int ide_cdrom_register (ide_drive_t *drive, int nslots) @@ -2896,90 +2177,145 @@ struct cdrom_device_info *devinfo = &info->devinfo; int minor = (drive->select.b.unit)<dev = MKDEV (HWIF(drive)->major, minor); + devinfo->dev = MKDEV (HWIF(drive)->major, minor | CD_PART_MASK); devinfo->ops = &ide_cdrom_dops; devinfo->mask = 0; *(int *)&devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed; *(int *)&devinfo->capacity = nslots; devinfo->handle = (void *) drive; strcpy(devinfo->name, drive->name); - + /* set capability mask to match the probe. */ + if (!CDROM_CONFIG_FLAGS (drive)->cd_r) + devinfo->mask |= CDC_CD_R; + if (!CDROM_CONFIG_FLAGS (drive)->cd_rw) + devinfo->mask |= CDC_CD_RW; + if (!CDROM_CONFIG_FLAGS (drive)->dvd) + devinfo->mask |= CDC_DVD; + if (!CDROM_CONFIG_FLAGS (drive)->dvd_r) + devinfo->mask |= CDC_DVD_R; + if (!CDROM_CONFIG_FLAGS (drive)->dvd_ram) + devinfo->mask |= CDC_DVD_RAM; if (!CDROM_CONFIG_FLAGS (drive)->is_changer) devinfo->mask |= CDC_SELECT_DISC; if (!CDROM_CONFIG_FLAGS (drive)->audio_play) devinfo->mask |= CDC_PLAY_AUDIO; if (!CDROM_CONFIG_FLAGS (drive)->close_tray) devinfo->mask |= CDC_CLOSE_TRAY; - + return register_cdrom (devinfo); } +static +int ide_cdrom_get_capabilities(ide_drive_t *drive, struct atapi_capabilities_page *cap) +{ + struct cdrom_info *info = drive->driver_data; + struct cdrom_device_info *cdi = &info->devinfo; + struct cdrom_generic_command cgc; + int stat, attempts = 3, size = sizeof(*cap); + + /* + * ACER50 (and others?) require the full spec length mode sense + * page capabilities size, but older drives break. + */ + if (!(drive->id && !strcmp(drive->id->model,"ATAPI CD ROM DRIVE 50X MAX"))) + size -= 4; + + /* we have to cheat a little here. the packet will eventually + * be queued with ide_cdrom_packet(), which extracts the + * drive from cdi->handle. Since this device hasn't been + * registered with the Uniform layer yet, it can't do this. + * Same goes for cdi->ops. + */ + cdi->handle = (ide_drive_t *) drive; + cdi->ops = &ide_cdrom_dops; + init_cdrom_command(&cgc, cap, size); + do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ + stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0); + if (!stat) + break; + } while (--attempts); + return stat; +} static int ide_cdrom_probe_capabilities (ide_drive_t *drive) { - int stat, nslots = 0; - struct get_capabilities_buf buf; + struct cdrom_info *info = drive->driver_data; + struct cdrom_device_info *cdi = &info->devinfo; + struct atapi_capabilities_page cap; + int nslots = 1; if (CDROM_CONFIG_FLAGS (drive)->nec260) { - CDROM_CONFIG_FLAGS (drive)->no_eject = 0; - CDROM_CONFIG_FLAGS (drive)->audio_play = 1; + CDROM_CONFIG_FLAGS (drive)->no_eject = 0; + CDROM_CONFIG_FLAGS (drive)->audio_play = 1; return nslots; } - if (ide_cdrom_get_capabilities(drive,&buf)) + if (ide_cdrom_get_capabilities(drive, &cap)) return 0; - if (buf.cap.lock == 0) + + if (cap.lock == 0) CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1; - if (buf.cap.eject) + if (cap.eject) CDROM_CONFIG_FLAGS (drive)->no_eject = 0; - if (buf.cap.cd_r_write) + if (cap.cd_r_write) CDROM_CONFIG_FLAGS (drive)->cd_r = 1; - if (buf.cap.cd_rw_write) + if (cap.cd_rw_write) CDROM_CONFIG_FLAGS (drive)->cd_rw = 1; - if (buf.cap.test_write) + if (cap.test_write) CDROM_CONFIG_FLAGS (drive)->test_write = 1; - if (buf.cap.dvd_ram_read || buf.cap.dvd_r_read || buf.cap.dvd_rom) + if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom) CDROM_CONFIG_FLAGS (drive)->dvd = 1; - if (buf.cap.dvd_ram_write) + if (cap.dvd_ram_write) CDROM_CONFIG_FLAGS (drive)->dvd_r = 1; - if (buf.cap.dvd_r_write) - CDROM_CONFIG_FLAGS (drive)->dvd_rw = 1; - if (buf.cap.audio_play) + if (cap.dvd_r_write) + CDROM_CONFIG_FLAGS (drive)->dvd_ram = 1; + if (cap.audio_play) CDROM_CONFIG_FLAGS (drive)->audio_play = 1; - if (buf.cap.mechtype == 0) + if (cap.mechtype == 0) CDROM_CONFIG_FLAGS (drive)->close_tray = 0; #if ! STANDARD_ATAPI - if (CDROM_STATE_FLAGS (drive)->sanyo_slot > 0) { + if (cdi->sanyo_slot > 0) { CDROM_CONFIG_FLAGS (drive)->is_changer = 1; nslots = 3; } else #endif /* not STANDARD_ATAPI */ - if (buf.cap.mechtype == mechtype_individual_changer || - buf.cap.mechtype == mechtype_cartridge_changer) { - struct atapi_mechstat_header mechbuf; - - stat = cdrom_read_mech_status (drive, (char*)&mechbuf, - sizeof (mechbuf), NULL); - if (!stat) { + if (cap.mechtype == mechtype_individual_changer || + cap.mechtype == mechtype_cartridge_changer) { + if ((nslots = cdrom_number_of_slots(cdi)) > 1) { CDROM_CONFIG_FLAGS (drive)->is_changer = 1; CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 1; - nslots = mechbuf.nslots; } } - printk ("%s: ATAPI %dX %s", - drive->name, CDROM_CONFIG_FLAGS (drive)->max_speed, - (CDROM_CONFIG_FLAGS (drive)->dvd) ? "DVD-ROM" : "CD-ROM"); + /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */ + if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) { + CDROM_STATE_FLAGS (drive)->current_speed = + (((unsigned int)cap.curspeed) + (176/2)) / 176; + CDROM_CONFIG_FLAGS (drive)->max_speed = + (((unsigned int)cap.maxspeed) + (176/2)) / 176; + } else { + CDROM_STATE_FLAGS (drive)->current_speed = + (ntohs(cap.curspeed) + (176/2)) / 176; + CDROM_CONFIG_FLAGS (drive)->max_speed = + (ntohs(cap.maxspeed) + (176/2)) / 176; + } - if (CDROM_CONFIG_FLAGS (drive)->dvd_r|CDROM_CONFIG_FLAGS (drive)->dvd_rw) + /* don't print speed if the drive reported 0. + */ + printk("%s: ATAPI", drive->name); + if (CDROM_CONFIG_FLAGS(drive)->max_speed) + printk(" %dX", CDROM_CONFIG_FLAGS(drive)->max_speed); + printk(" %s", CDROM_CONFIG_FLAGS(drive)->dvd ? "DVD-ROM" : "CD-ROM"); + + if (CDROM_CONFIG_FLAGS (drive)->dvd_r|CDROM_CONFIG_FLAGS (drive)->dvd_ram) printk (" DVD%s%s", - (CDROM_CONFIG_FLAGS (drive)->dvd_r)? "-RAM" : "", - (CDROM_CONFIG_FLAGS (drive)->dvd_rw)? "/RW" : ""); + (CDROM_CONFIG_FLAGS (drive)->dvd_r)? "-R" : "", + (CDROM_CONFIG_FLAGS (drive)->dvd_ram)? "AM" : ""); if (CDROM_CONFIG_FLAGS (drive)->cd_r|CDROM_CONFIG_FLAGS (drive)->cd_rw) printk (" CD%s%s", @@ -2991,7 +2327,7 @@ else printk (" drive"); - printk (", %dkB Cache\n", ntohs(buf.cap.buffer_size)); + printk (", %dkB Cache\n", be16_to_cpu(cap.buffer_size)); return nslots; } @@ -3011,19 +2347,17 @@ int ide_cdrom_setup (ide_drive_t *drive) { struct cdrom_info *info = drive->driver_data; + struct cdrom_device_info *cdi = &info->devinfo; + int minor = drive->select.b.unit << PARTN_BITS; int nslots; - kdev_t dev = MKDEV (HWIF (drive)->major, - drive->select.b.unit << PARTN_BITS); + set_device_ro(MKDEV(HWIF(drive)->major, minor), 1); + set_blocksize(MKDEV(HWIF(drive)->major, minor), CD_FRAMESIZE); - set_device_ro (dev, 1); - blksize_size[HWIF(drive)->major][drive->select.b.unit << PARTN_BITS] = - CD_FRAMESIZE; + drive->special.all = 0; + drive->ready_stat = 0; - drive->special.all = 0; - drive->ready_stat = 0; - - CDROM_STATE_FLAGS (drive)->media_changed = 0; + CDROM_STATE_FLAGS (drive)->media_changed = 1; CDROM_STATE_FLAGS (drive)->toc_valid = 0; CDROM_STATE_FLAGS (drive)->door_locked = 0; @@ -3045,25 +2379,29 @@ CDROM_CONFIG_FLAGS (drive)->test_write = 0; CDROM_CONFIG_FLAGS (drive)->dvd = 0; CDROM_CONFIG_FLAGS (drive)->dvd_r = 0; - CDROM_CONFIG_FLAGS (drive)->dvd_rw = 0; + CDROM_CONFIG_FLAGS (drive)->dvd_ram = 0; CDROM_CONFIG_FLAGS (drive)->no_eject = 1; CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 0; CDROM_CONFIG_FLAGS (drive)->audio_play = 0; CDROM_CONFIG_FLAGS (drive)->close_tray = 1; - + /* limit transfer size per interrupt. */ CDROM_CONFIG_FLAGS (drive)->limit_nframes = 0; if (drive->id != NULL) { + /* a testament to the nice quality of Samsung drives... */ if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2430")) CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1; else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2432")) CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1; + /* the 3231 model does not support the SET_CD_SPEED command */ + else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-3231")) + cdi->mask |= CDC_SELECT_SPEED; } #if ! STANDARD_ATAPI /* 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; + cdi->sanyo_slot = 0; CDROM_CONFIG_FLAGS (drive)->nec260 = 0; CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd = 0; @@ -3115,18 +2453,20 @@ (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; + cdi->sanyo_slot = 3; } } #endif /* not STANDARD_ATAPI */ - info->toc = NULL; - info->sector_buffer = NULL; - info->sector_buffered = 0; - info->nsectors_buffered = 0; + info->toc = NULL; + info->buffer = NULL; + info->sector_buffered = 0; + info->nsectors_buffered = 0; info->changer_info = NULL; + info->last_block = 0; + info->start_seek = 0; nslots = ide_cdrom_probe_capabilities (drive); @@ -3151,9 +2491,12 @@ static int ide_cdrom_open (struct inode *ip, struct file *fp, ide_drive_t *drive) { + struct cdrom_info *info = drive->driver_data; int rc; MOD_INC_USE_COUNT; + if (info->buffer == NULL) + info->buffer = (char *) kmalloc(SECTOR_BUFFER_SIZE, GFP_KERNEL); rc = cdrom_fops.open (ip, fp); if (rc) { drive->usage--; @@ -3178,7 +2521,6 @@ (drive->select.b.unit)<sector_buffer != NULL) - kfree (info->sector_buffer); + if (info->buffer != NULL) + kfree(info->buffer); if (info->toc != NULL) - kfree (info->toc); + kfree(info->toc); if (info->changer_info != NULL) - kfree (info->changer_info); + kfree(info->changer_info); if (devinfo->handle == drive && unregister_cdrom (devinfo)) printk ("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name); - kfree (info); + kfree(info); drive->driver_data = NULL; return 0; } @@ -3235,11 +2577,6 @@ MODULE_PARM(ignore, "s"); MODULE_DESCRIPTION("ATAPI CD-ROM Driver"); -int init_module (void) -{ - return ide_cdrom_init(); -} - void cleanup_module(void) { ide_drive_t *drive; @@ -3252,6 +2589,11 @@ } ide_unregister_module (&ide_cdrom_module); } + +int init_module(void) +{ + return ide_cdrom_init(); +} #endif /* MODULE */ int ide_cdrom_init (void) @@ -3263,11 +2605,12 @@ MOD_INC_USE_COUNT; while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, NULL, failed++)) != NULL) { /* skip drives that we were told to ignore */ - if (ignore != NULL) + if (ignore != NULL) { if (strstr(ignore, drive->name)) { printk("ide-cd: ignoring drive %s\n", drive->name); continue; } + } info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL); if (info == NULL) { printk ("%s: Can't allocate a cdrom structure\n", drive->name); @@ -3294,11 +2637,3 @@ MOD_DEC_USE_COUNT; return 0; } - - -/*==========================================================================*/ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/drivers/block/ide-cd.h linux/drivers/block/ide-cd.h --- linux-2.2.15/drivers/block/ide-cd.h Thu May 4 15:21:22 2000 +++ linux/drivers/block/ide-cd.h Thu May 4 02:00:49 2000 @@ -1,12 +1,13 @@ #ifndef _IDE_CD_H #define _IDE_CD_H /* - * linux/drivers/block/ide_modes.h + * linux/drivers/block/ide_cd.h * - * Copyright (C) 1996 Erik Andersen - * Copyright (C) 1998, 1999 Jens Axboe + * Copyright (C) 1996, 1997, 1998 Erik Andersen + * Copyright (C) 1998, 1999, 2000 Jens Axboe */ +#include #include /* Turn this on to have the driver print out the meanings of the @@ -34,19 +35,13 @@ #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 SECTOR_SIZE 512 +#define SECTOR_BITS 9 +#define SECTORS_PER_FRAME (CD_FRAMESIZE / SECTOR_SIZE) +#define SECTOR_BUFFER_SIZE (CD_FRAMESIZE * 32) +#define SECTORS_BUFFER (SECTOR_BUFFER_SIZE / SECTOR_SIZE) #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -55,96 +50,37 @@ #define REQUEST_SENSE_COMMAND 4316 #define RESET_DRIVE_COMMAND 4317 -/* - * For controlling drive spindown time. - */ -#define CDROMGETSPINDOWN 0x531d -#define CDROMSETSPINDOWN 0x531e - - -/* 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 INQUIRY 0x12 -#define START_STOP 0x1b -#define ALLOW_MEDIUM_REMOVAL 0x1e -#define READ_CAPACITY 0x25 -#define READ_10 0x28 -#define SEEK 0x2b -#define READ_HEADER 0x44 -#define STOP_PLAY_SCAN 0x4e -#define MODE_SELECT_10 0x55 -#define MODE_SENSE_10 0x5a -#define LOAD_UNLOAD 0xa6 -#define READ_12 0xa8 -#define READ_CD_MSF 0xb9 -#define SCAN 0xba -#define SET_CD_SPEED 0xbb -#define PLAY_CD 0xbc -#define MECHANISM_STATUS 0xbd -#define READ_CD 0xbe - -/* DVD Opcodes */ -#define DVD_GET_PERFORMANCE 0xac - - -/* Page codes for mode sense/set */ - -#define PAGE_READERR 0x01 -#define PAGE_CDROM 0x0d -#define PAGE_AUDIO 0x0e -#define PAGE_CAPABILITIES 0x2a -#define PAGE_ALL 0x3f - - -/* ATAPI sense keys (from table 140 of ATAPI 2.6) */ - -#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 CDROM drives. - To save space in the ide_drive_t struct, use some fields which - doesn't make sense for CDROMs -- `bios_cyl' 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. */ - __u8 no_eject : 1; /* Drive cannot eject the disc. */ - __u8 nec260 : 1; /* Drive is a pre-1.2 NEC 260 drive. */ - __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. */ - __u8 is_changer : 1; /* Drive is a changer. */ - __u8 cd_r : 1; /* Drive can write to CD-R media . */ - __u8 cd_rw : 1; /* Drive can write to CD-R/W media . */ - __u8 dvd : 1; /* Drive is a DVD-ROM */ - __u8 dvd_r : 1; /* Drive can write DVD-RAM */ - __u8 dvd_rw : 1; /* Drive can write DVD-R/W */ - __u8 test_write : 1; /* Drive can fake writes */ - __u8 supp_disc_present: 1; /* Changer can report exact contents - of slots. */ - __u8 limit_nframes : 1; /* Drive does not provide data in - multiples of SECTOR_SIZE when more - than one interrupt is needed. */ - __u8 seeking : 1; /* Seeking in progress */ - __u8 audio_play : 1; /* can do audio related commands */ - __u8 close_tray : 1; /* can close the tray */ - __u8 reserved : 4; - byte max_speed; /* Max speed of the drive */ + __u8 drq_interrupt : 1; /* Device sends an interrupt when ready + for a packet command. */ + __u8 no_doorlock : 1; /* Drive cannot lock the door. */ + __u8 no_eject : 1; /* Drive cannot eject the disc. */ + __u8 nec260 : 1; /* Drive is a pre-1.2 NEC 260 drive. */ + __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. */ + __u8 is_changer : 1; /* Drive is a changer. */ + __u8 cd_r : 1; /* Drive can write to CD-R media . */ + __u8 cd_rw : 1; /* Drive can write to CD-R/W media . */ + __u8 dvd : 1; /* Drive is a DVD-ROM */ + __u8 dvd_r : 1; /* Drive can write DVD-R */ + __u8 dvd_ram : 1; /* Drive can write DVD-RAM */ + __u8 test_write : 1; /* Drive can fake writes */ + __u8 supp_disc_present : 1; /* Changer can report exact contents + of slots. */ + __u8 limit_nframes : 1; /* Drive does not provide data in + multiples of SECTOR_SIZE when more + than one interrupt is needed. */ + __u8 seeking : 1; /* Seeking in progress */ + __u8 audio_play : 1; /* can do audio related commands */ + __u8 close_tray : 1; /* can close the tray */ + __u8 reserved : 4; + byte max_speed; /* Max speed of the drive */ }; #define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags)) @@ -155,51 +91,17 @@ __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 sanyo_slot : 2; /* Sanyo 3 CD changer support */ - __u8 reserved : 3; + __u8 reserved : 5; byte current_speed; /* Current speed of the drive */ }; -#define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags)) - -struct atapi_request_sense { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned char valid : 1; - unsigned char error_code : 7; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned char error_code : 7; - unsigned char valid : 1; -#else -#error "Please fix " -#endif - byte reserved1; -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned char reserved3 : 2; - unsigned char ili : 1; - unsigned char reserved2 : 1; - unsigned char sense_key : 4; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned char sense_key : 4; - unsigned char reserved2 : 1; - unsigned char ili : 1; - unsigned char reserved3 : 2; -#else -#error "Please fix " -#endif - byte info[4]; - byte sense_len; - byte command_info[4]; - byte asc; - byte ascq; - byte fru; - byte sense_key_specific[3]; -}; +#define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags)) struct packet_command { char *buffer; int buflen; int stat; - struct atapi_request_sense *sense_data; + struct request_sense *sense; unsigned char c[12]; }; @@ -278,16 +180,12 @@ }; -typedef enum { - mechtype_caddy = 0, - mechtype_tray = 1, - mechtype_popup = 2, - mechtype_individual_changer = 4, - mechtype_cartridge_changer = 5 -} mechtype_t; - +/* This should probably go into cdrom.h along with the other + * generic stuff now in the Mt. Fuji spec. + */ struct atapi_capabilities_page { + struct mode_page_header header; #if defined(__BIG_ENDIAN_BITFIELD) __u8 parameters_saveable : 1; __u8 reserved1 : 1; @@ -500,8 +398,7 @@ /* Current speed (in kB/s). */ unsigned short curspeed; - /* Truncate the structure here, so we don't have headaches reading - from older drives. */ + char pad[4]; }; @@ -552,13 +449,11 @@ byte reserved2[3]; }; - struct atapi_changer_info { struct atapi_mechstat_header hdr; struct atapi_slot slots[0]; }; - /* Extra per-device info for cdrom drives. */ struct cdrom_info { @@ -567,21 +462,13 @@ struct atapi_toc *toc; - /* Sector buffer. If a read request wants only the first part - of a cdrom block, we cache the rest of the block here, - in the expectation that the data is going to be wanted soon. - SECTOR_BUFFERED is the number of the first buffered sector, - and NSECTORS_BUFFERED is the number of sectors in the buffer. - Before the buffer is allocated, we should have - SECTOR_BUFFER == NULL and NSECTORS_BUFFERED == 0. */ - - unsigned long sector_buffered; - unsigned long nsectors_buffered; - char *sector_buffer; + unsigned long sector_buffered; + unsigned long nsectors_buffered; + unsigned char *buffer; /* The result of the last successful request sense command on this device. */ - struct atapi_request_sense sense_data; + struct request_sense sense_data; struct request request_sense_request; struct packet_command request_sense_pc; @@ -598,21 +485,91 @@ struct cdrom_device_info devinfo; }; - -#define SECTOR_BUFFER_SIZE CD_FRAMESIZE - - /**************************************************************************** * Descriptions of ATAPI error codes. */ #define ARY_LEN(a) ((sizeof(a) / sizeof(a[0]))) +/* This stuff should be in cdrom.h, since it is now generic... */ + +/* ATAPI sense keys (from table 140 of ATAPI 2.6) */ +#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 + + + +/* This stuff should be in cdrom.h, since it is now generic... */ #if VERBOSE_IDE_CD_ERRORS -/* From Table 124 of the ATAPI 1.2 spec. - Unchanged in Table 140 of the ATAPI 2.6 draft standard. */ + /* The generic packet command opcodes for CD/DVD Logical Units, + * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ +const struct { + unsigned short packet_command; + const char * const text; +} packet_command_texts[] = { + { GPCMD_TEST_UNIT_READY, "Test Unit Ready" }, + { GPCMD_REQUEST_SENSE, "Request Sense" }, + { GPCMD_FORMAT_UNIT, "Format Unit" }, + { GPCMD_INQUIRY, "Inquiry" }, + { GPCMD_START_STOP_UNIT, "Start/Stop Unit" }, + { GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" }, + { GPCMD_READ_FORMAT_CAPACITIES, "Read Format Capacities" }, + { GPCMD_READ_CDVD_CAPACITY, "Read Cd/Dvd Capacity" }, + { GPCMD_READ_10, "Read 10" }, + { GPCMD_WRITE_10, "Write 10" }, + { GPCMD_SEEK, "Seek" }, + { GPCMD_WRITE_AND_VERIFY_10, "Write and Verify 10" }, + { GPCMD_VERIFY_10, "Verify 10" }, + { GPCMD_FLUSH_CACHE, "Flush Cache" }, + { GPCMD_READ_SUBCHANNEL, "Read Subchannel" }, + { GPCMD_READ_TOC_PMA_ATIP, "Read Table of Contents" }, + { GPCMD_READ_HEADER, "Read Header" }, + { GPCMD_PLAY_AUDIO_10, "Play Audio 10" }, + { GPCMD_GET_CONFIGURATION, "Get Configuration" }, + { GPCMD_PLAY_AUDIO_MSF, "Play Audio MSF" }, + { GPCMD_PLAYAUDIO_TI, "Play Audio TrackIndex" }, + { GPCMD_GET_EVENT_STATUS_NOTIFICATION, "Get Event Status Notification" }, + { GPCMD_PAUSE_RESUME, "Pause/Resume" }, + { GPCMD_STOP_PLAY_SCAN, "Stop Play/Scan" }, + { GPCMD_READ_DISC_INFO, "Read Disc Info" }, + { GPCMD_READ_TRACK_RZONE_INFO, "Read Track Rzone Info" }, + { GPCMD_RESERVE_RZONE_TRACK, "Reserve Rzone Track" }, + { GPCMD_SEND_OPC, "Send OPC" }, + { GPCMD_MODE_SELECT_10, "Mode Select 10" }, + { GPCMD_REPAIR_RZONE_TRACK, "Repair Rzone Track" }, + { GPCMD_MODE_SENSE_10, "Mode Sense 10" }, + { GPCMD_CLOSE_TRACK, "Close Track" }, + { GPCMD_BLANK, "Blank" }, + { GPCMD_SEND_EVENT, "Send Event" }, + { GPCMD_SEND_KEY, "Send Key" }, + { GPCMD_REPORT_KEY, "Report Key" }, + { GPCMD_LOAD_UNLOAD, "Load/Unload" }, + { GPCMD_SET_READ_AHEAD, "Set Read-ahead" }, + { GPCMD_READ_12, "Read 12" }, + { GPCMD_GET_PERFORMANCE, "Get Performance" }, + { GPCMD_SEND_DVD_STRUCTURE, "Send DVD Structure" }, + { GPCMD_READ_DVD_STRUCTURE, "Read DVD Structure" }, + { GPCMD_SET_STREAMING, "Set Streaming" }, + { GPCMD_READ_CD_MSF, "Read CD MSF" }, + { GPCMD_SCAN, "Scan" }, + { GPCMD_SET_SPEED, "Set Speed" }, + { GPCMD_PLAY_CD, "Play CD" }, + { GPCMD_MECHANISM_STATUS, "Mechanism Status" }, + { GPCMD_READ_CD, "Read CD" }, +}; + + +/* From Table 303 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ const char * const sense_key_texts[16] = { "No sense data", "Recovered error", @@ -632,162 +589,145 @@ "(reserved)", }; - -/* From Table 37 of the ATAPI 2.6 draft standard. */ -const struct { - unsigned short packet_command; - const char * const text; -} packet_command_texts[] = { - { TEST_UNIT_READY, "Test Unit Ready" }, - { REQUEST_SENSE, "Request Sense" }, - { INQUIRY, "Inquiry" }, - { START_STOP, "Start Stop Unit" }, - { ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" }, - { READ_CAPACITY, "Read CD-ROM Capacity" }, - { READ_10, "Read(10)" }, - { SEEK, "Seek" }, - { SCMD_READ_TOC, "Read TOC" }, - { SCMD_READ_SUBCHANNEL, "Read Sub-Channel" }, - { READ_HEADER, "Read Header" }, - { STOP_PLAY_SCAN, "Stop Play/Scan" }, - { SCMD_PLAYAUDIO10, "Play Audio" }, - { SCMD_PLAYAUDIO_MSF, "Play Audio MSF" }, - { SCMD_PAUSE_RESUME, "Pause/Resume" }, - { MODE_SELECT_10, "Mode Select" }, - { MODE_SENSE_10, "Mode Sense" }, - { LOAD_UNLOAD, "Load/Unload CD" }, - { READ_12, "Read(12)" }, - { READ_CD_MSF, "Read CD MSF" }, - { SCAN, "Scan" }, - { SET_CD_SPEED, "Set CD Speed" }, - { PLAY_CD, "Play CD" }, - { MECHANISM_STATUS, "Mechanism Status" }, - { READ_CD, "Read CD" }, - { DVD_GET_PERFORMANCE, "Get Performance" }, -}; - - -/* From Table 125 of the ATAPI 1.2 spec., - with additions from Tables 141 and 142 of the ATAPI 2.6 draft standard. */ - +/* From Table 304 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ const struct { - unsigned short asc_ascq; + unsigned long asc_ascq; const char * const 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" }, - - { 0x0100, "Mechanical positioning or changer error" }, - - { 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" }, - - { 0x0501, "Media load - eject failed" }, - - { 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 or changer 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" }, - /* Following two not in 2.6. */ - { 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" }, - /* Following code not in 2.6. */ - { 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" }, - - /* Following code not in 2.6. */ - { 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" }, - /* Following two not in 2.6. */ - { 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" }, - - /* Following two not in 2.6. */ - { 0x5b00, "Threshold condition met" }, - { 0x5c00, "Status change" }, - - { 0x6300, "End of user area encountered on this track" }, - - { 0x6400, "Illegal mode for this track or incompatible medium" }, - - /* Following error is misspelled in ATAPI 2.6 */ - { 0xb900, "Play operation oborted [sic]" }, - - { 0xbf00, "Loss of streaming" }, + { 0x000000, "No additional sense information" }, + { 0x000011, "Play operation in progress" }, + { 0x000012, "Play operation paused" }, + { 0x000013, "Play operation successfully completed" }, + { 0x000014, "Play operation stopped due to error" }, + { 0x000015, "No current audio status to return" }, + { 0x010c0a, "Write error - padding blocks added" }, + { 0x011700, "Recovered data with no error correction applied" }, + { 0x011701, "Recovered data with retries" }, + { 0x011702, "Recovered data with positive head offset" }, + { 0x011703, "Recovered data with negative head offset" }, + { 0x011704, "Recovered data with retries and/or CIRC applied" }, + { 0x011705, "Recovered data using previous sector ID" }, + { 0x011800, "Recovered data with error correction applied" }, + { 0x011801, "Recovered data with error correction and retries applied"}, + { 0x011802, "Recovered data - the data was auto-reallocated" }, + { 0x011803, "Recovered data with CIRC" }, + { 0x011804, "Recovered data with L-EC" }, + { 0x015d00, + "Failure prediction threshold exceeded - Predicted logical unit failure" }, + { 0x015d01, + "Failure prediction threshold exceeded - Predicted media failure" }, + { 0x015dff, "Failure prediction threshold exceeded - False" }, + { 0x017301, "Power calibration area almost full" }, + { 0x020400, "Logical unit not ready - cause not reportable" }, + /* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */ + { 0x020401, + "Logical unit not ready - in progress [sic] of becoming ready" }, + { 0x020402, "Logical unit not ready - initializing command required" }, + { 0x020403, "Logical unit not ready - manual intervention required" }, + { 0x020404, "Logical unit not ready - format in progress" }, + { 0x020407, "Logical unit not ready - operation in progress" }, + { 0x020408, "Logical unit not ready - long write in progress" }, + { 0x020600, "No reference position found (media may be upside down)" }, + { 0x023000, "Incompatible medium installed" }, + { 0x023a00, "Medium not present" }, + { 0x025300, "Media load or eject failed" }, + { 0x025700, "Unable to recover table of contents" }, + { 0x030300, "Peripheral device write fault" }, + { 0x030301, "No write current" }, + { 0x030302, "Excessive write errors" }, + { 0x030c00, "Write error" }, + { 0x030c01, "Write error - Recovered with auto reallocation" }, + { 0x030c02, "Write error - auto reallocation failed" }, + { 0x030c03, "Write error - recommend reassignment" }, + { 0x030c04, "Compression check miscompare error" }, + { 0x030c05, "Data expansion occurred during compress" }, + { 0x030c06, "Block not compressible" }, + { 0x030c07, "Write error - recovery needed" }, + { 0x030c08, "Write error - recovery failed" }, + { 0x030c09, "Write error - loss of streaming" }, + { 0x031100, "Unrecovered read error" }, + { 0x031106, "CIRC unrecovered error" }, + { 0x033101, "Format command failed" }, + { 0x033200, "No defect spare location available" }, + { 0x033201, "Defect list update failure" }, + { 0x035100, "Erase failure" }, + { 0x037200, "Session fixation error" }, + { 0x037201, "Session fixation error writin lead-in" }, + { 0x037202, "Session fixation error writin lead-out" }, + { 0x037300, "CD control error" }, + { 0x037302, "Power calibration area is full" }, + { 0x037303, "Power calibration area error" }, + { 0x037304, "Program memory area / RMA update failure" }, + { 0x037305, "Program memory area / RMA is full" }, + { 0x037306, "Program memory area / RMA is (almost) full" }, + + { 0x040200, "No seek complete" }, + { 0x040300, "Write fault" }, + { 0x040900, "Track following error" }, + { 0x040901, "Tracking servo failure" }, + { 0x040902, "Focus servo failure" }, + { 0x040903, "Spindle servo failure" }, + { 0x041500, "Random positioning error" }, + { 0x041501, "Mechanical positioning or changer error" }, + { 0x041502, "Positioning error detected by read of medium" }, + { 0x043c00, "Mechanical positioning or changer error" }, + { 0x044000, "Diagnostic failure on component (ASCQ)" }, + { 0x044400, "Internal CD/DVD logical unit failure" }, + { 0x04b600, "Media load mechanism failed" }, + { 0x051a00, "Parameter list length error" }, + { 0x052000, "Invalid command operation code" }, + { 0x052100, "Logical block address out of range" }, + { 0x052102, "Invalid address for write" }, + { 0x052400, "Invalid field in command packet" }, + { 0x052600, "Invalid field in parameter list" }, + { 0x052601, "Parameter not supported" }, + { 0x052602, "Parameter value invalid" }, + { 0x052700, "Write protected media" }, + { 0x052c00, "Command sequence error" }, + { 0x052c03, "Current program area is not empty" }, + { 0x052c04, "Current program area is empty" }, + { 0x053001, "Cannot read medium - unknown format" }, + { 0x053002, "Cannot read medium - incompatible format" }, + { 0x053900, "Saving parameters not supported" }, + { 0x054e00, "Overlapped commands attempted" }, + { 0x055302, "Medium removal prevented" }, + { 0x055500, "System resource failure" }, + { 0x056300, "End of user area encountered on this track" }, + { 0x056400, "Illegal mode for this track or incompatible medium" }, + { 0x056f00, "Copy protection key exchange failure - Authentication failure" }, + { 0x056f01, "Copy protection key exchange failure - Key not present" }, + { 0x056f02, "Copy protection key exchange failure - Key not established" }, + { 0x056f03, "Read of scrambled sector without authentication" }, + { 0x056f04, "Media region code is mismatched to logical unit" }, + { 0x056f05, "Drive region must be permanent / region reset count error" }, + { 0x057203, "Session fixation error - incomplete track in session" }, + { 0x057204, "Empty or partially written reserved track" }, + { 0x057205, "No more RZONE reservations are allowed" }, + { 0x05bf00, "Loss of streaming" }, + { 0x062800, "Not ready to ready transition, medium may have changed" }, + { 0x062900, "Power on, reset or hardware reset occurred" }, + { 0x062a00, "Parameters changed" }, + { 0x062a01, "Mode parameters changed" }, + { 0x062e00, "Insufficient time for operation" }, + { 0x063f00, "Logical unit operating conditions have changed" }, + { 0x063f01, "Microcode has been changed" }, + { 0x065a00, "Operator request or state change input (unspecified)" }, + { 0x065a01, "Operator medium removal request" }, + { 0x0bb900, "Play operation aborted" }, + + /* Here we use 0xff for the key (not a valid key) to signify + * that these can have _any_ key value associated with them... */ + { 0xff0401, "Logical unit is in process of becoming ready" }, + { 0xff0400, "Logical unit not ready, cause not reportable" }, + { 0xff0402, "Logical unit not ready, initializing command required" }, + { 0xff0403, "Logical unit not ready, manual intervention required" }, + { 0xff0500, "Logical unit does not respond to selection" }, + { 0xff0800, "Logical unit communication failure" }, + { 0xff0802, "Logical unit communication parity error" }, + { 0xff0801, "Logical unit communication time-out" }, + { 0xff2500, "Logical unit not supported" }, + { 0xff4c00, "Logical unit failed self-configuration" }, + { 0xff3e00, "Logical unit has not self-configured yet" }, }; #endif diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c --- linux-2.2.15/drivers/block/ide-disk.c Thu May 4 15:21:22 2000 +++ linux/drivers/block/ide-disk.c Thu May 4 01:19:23 2000 @@ -138,7 +138,7 @@ return ide_error(drive, "read_intr", stat); } /* no data yet, so wait for another interrupt */ - ide_set_handler(drive, &read_intr, WAIT_CMD); + ide_set_handler(drive, &read_intr, WAIT_CMD, NULL); return ide_started; } #endif @@ -167,7 +167,7 @@ if (i > 0) { if (msect) goto read_next; - ide_set_handler (drive, &read_intr, WAIT_CMD); + ide_set_handler (drive, &read_intr, WAIT_CMD, NULL); return ide_started; } return ide_stopped; @@ -201,7 +201,7 @@ ide_end_request(1, hwgroup); if (i > 0) { idedisk_output_data (drive, rq->buffer, SECTOR_WORDS); - ide_set_handler (drive, &write_intr, WAIT_CMD); + ide_set_handler (drive, &write_intr, WAIT_CMD, NULL); return ide_started; } return ide_stopped; @@ -309,7 +309,7 @@ if (rq->nr_sectors) { if (ide_multwrite(drive, drive->mult_count)) return ide_stopped; - ide_set_handler (drive, &multwrite_intr, WAIT_CMD); + ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL); return ide_started; } } else { @@ -432,7 +432,7 @@ if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive))) return ide_started; #endif /* CONFIG_BLK_DEV_IDEDMA */ - ide_set_handler(drive, &read_intr, WAIT_CMD); + ide_set_handler(drive, &read_intr, WAIT_CMD, NULL); OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG); return ide_started; } @@ -462,7 +462,7 @@ * Except when you get an error it seems... */ hwgroup->wrq = *rq; /* scratchpad */ - ide_set_handler (drive, &multwrite_intr, WAIT_CMD); + ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL); if (ide_multwrite(drive, drive->mult_count)) { unsigned long flags; spin_lock_irqsave(&io_request_lock, flags); @@ -472,7 +472,7 @@ return ide_stopped; } } else { - ide_set_handler (drive, &write_intr, WAIT_CMD); + ide_set_handler (drive, &write_intr, WAIT_CMD, NULL); idedisk_output_data(drive, rq->buffer, SECTOR_WORDS); } return ide_started; diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c --- linux-2.2.15/drivers/block/ide-dma.c Thu May 4 15:21:22 2000 +++ linux/drivers/block/ide-dma.c Thu May 4 01:19:23 2000 @@ -328,7 +328,7 @@ drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; - ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);/* issue cmd to drive */ + ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);/* issue cmd to drive */ OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); case ide_dma_begin: /* Note that this is done *after* the cmd has diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c --- linux-2.2.15/drivers/block/ide-floppy.c Thu May 4 15:21:22 2000 +++ linux/drivers/block/ide-floppy.c Thu May 4 01:19:23 2000 @@ -916,7 +916,7 @@ if (temp > pc->buffer_size) { printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n"); idefloppy_discard_data (drive,bcount.all); - ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD); + ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD,NULL); return ide_started; } #if IDEFLOPPY_DEBUG_LOG @@ -938,7 +938,7 @@ pc->actually_transferred+=bcount.all; /* Update the current position */ pc->current_position+=bcount.all; - ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD); /* And set the interrupt handler again */ + ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD,NULL); /* And set the interrupt handler again */ return ide_started; } @@ -957,7 +957,7 @@ printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n"); return ide_do_reset (drive); } - ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD); /* Set the interrupt routine */ + ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); /* Set the interrupt routine */ atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */ return ide_started; } @@ -1026,7 +1026,7 @@ #endif /* CONFIG_BLK_DEV_IDEDMA */ if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) { - ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD); + ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD, NULL); OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */ return ide_started; } else { diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c --- linux-2.2.15/drivers/block/ide-pmac.c Thu May 4 15:21:22 2000 +++ linux/drivers/block/ide-pmac.c Thu May 4 01:19:23 2000 @@ -359,7 +359,7 @@ drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; - ide_set_handler(drive, &ide_dma_intr, WAIT_CMD); + ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA, IDE_COMMAND_REG); case ide_dma_begin: diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c --- linux-2.2.15/drivers/block/ide-tape.c Thu May 4 15:21:22 2000 +++ linux/drivers/block/ide-tape.c Thu May 4 01:19:23 2000 @@ -2013,7 +2013,7 @@ if (temp > pc->buffer_size) { printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n"); idetape_discard_data (drive,bcount.all); - ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD); + ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD,NULL); return ide_started; } #if IDETAPE_DEBUG_LOG @@ -2035,7 +2035,7 @@ pc->actually_transferred+=bcount.all; /* Update the current position */ pc->current_position+=bcount.all; - ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD); /* And set the interrupt handler again */ + ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD,NULL); /* And set the interrupt handler again */ return ide_started; } @@ -2109,7 +2109,7 @@ printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n"); return ide_do_reset (drive); } - ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD); /* Set the interrupt routine */ + ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); /* Set the interrupt routine */ atapi_output_bytes (drive,pc->c,12); /* Send the actual packet */ return ide_started; } @@ -2175,7 +2175,7 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA */ if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) { - ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD); + ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL); OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); return ide_started; } else { diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/drivers/block/ide.c linux/drivers/block/ide.c --- linux-2.2.15/drivers/block/ide.c Thu May 4 15:21:22 2000 +++ linux/drivers/block/ide.c Thu May 4 01:19:23 2000 @@ -467,7 +467,8 @@ * timer is started to prevent us from waiting forever in case * something goes wrong (see the ide_timer_expiry() handler later on). */ -void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout) +void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, + unsigned int timeout, ide_expiry_t *expiry) { unsigned long flags; ide_hwgroup_t *hwgroup = HWGROUP(drive); @@ -477,8 +478,9 @@ printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n", drive->name, hwgroup->handler, handler); } - hwgroup->handler = handler; - hwgroup->timer.expires = jiffies + timeout; + hwgroup->handler = handler; + hwgroup->expiry = expiry; + hwgroup->timer.expires = jiffies + timeout; add_timer(&hwgroup->timer); spin_unlock_irqrestore(&io_request_lock, flags); } @@ -535,7 +537,7 @@ printk("%s: ATAPI reset complete\n", drive->name); } else { if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) { - ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20); + ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL); return ide_started; /* continue polling */ } hwgroup->poll_timeout = 0; /* end of polling */ @@ -560,7 +562,7 @@ if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) { if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) { - ide_set_handler (drive, &reset_pollfunc, HZ/20); + ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL); return ide_started; /* continue polling */ } printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp); @@ -642,7 +644,7 @@ udelay (20); OUT_BYTE (WIN_SRST, IDE_COMMAND_REG); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20); + ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL); __restore_flags (flags); /* local CPU only */ return ide_started; } @@ -668,7 +670,7 @@ OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */ udelay(10); /* more than enough time */ hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - ide_set_handler (drive, &reset_pollfunc, HZ/20); + ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL); #endif /* OK_TO_RESET_CONTROLLER */ __restore_flags (flags); /* local CPU only */ @@ -858,7 +860,7 @@ */ void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler) { - ide_set_handler (drive, handler, WAIT_CMD); + ide_set_handler (drive, handler, WAIT_CMD, NULL); OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */ OUT_BYTE(nsect,IDE_NSECTOR_REG); OUT_BYTE(cmd,IDE_COMMAND_REG); @@ -1287,7 +1289,9 @@ { ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data; ide_handler_t *handler; + ide_expiry_t *expiry; unsigned long flags; + unsigned long wait; spin_lock_irqsave(&io_request_lock, flags); del_timer(&hwgroup->timer); @@ -1306,6 +1310,7 @@ hwgroup->handler = NULL; if (!drive) { printk("ide_timer_expiry: hwgroup->drive was NULL\n"); + hwgroup->handler = NULL; } else { ide_hwif_t *hwif; ide_startstop_t startstop; @@ -1313,6 +1318,17 @@ hwgroup->busy = 1; /* paranoia */ printk("%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name); } + if ((expiry = hwgroup->expiry) != NULL) { + /* continue */ + if ((wait = expiry(drive)) != 0) { + /* reset timer */ + hwgroup->timer.expires = jiffies + wait; + add_timer(&hwgroup->timer); + spin_unlock_irqrestore(&io_request_lock, flags); + return; + } + } + hwgroup->handler = NULL; /* * We need to simulate a real interrupt when invoking the handler() * function, which means we need to globally mask the specific IRQ: diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/drivers/block/ide.h linux/drivers/block/ide.h --- linux-2.2.15/drivers/block/ide.h Thu May 4 15:21:22 2000 +++ linux/drivers/block/ide.h Thu May 4 01:52:21 2000 @@ -365,6 +365,12 @@ */ typedef ide_startstop_t (ide_handler_t)(ide_drive_t *); +/* + * when ide_timer_expiry fires, invoke a handler of this type + * to decide what to do. + */ +typedef int (ide_expiry_t)(ide_drive_t *); + typedef struct hwgroup_s { ide_handler_t *handler;/* irq handler, if active */ volatile int busy; /* BOOL: protects all fields below */ @@ -375,6 +381,7 @@ struct timer_list timer; /* failsafe timer */ struct request wrq; /* local copy of current write rq */ unsigned long poll_timeout; /* timeout value during long polls */ + ide_expiry_t *expiry; /* queried upon timeouts */ } ide_hwgroup_t; /* @@ -545,7 +552,7 @@ * This is used on exit from the driver, to designate the next irq handler * and also to start the safety timer. */ -void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout); +void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry); /* * Error reporting, in human readable form (luxurious, but a memory hog). diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/drivers/block/paride/pcd.c linux/drivers/block/paride/pcd.c --- linux-2.2.15/drivers/block/paride/pcd.c Thu May 4 15:21:22 2000 +++ linux/drivers/block/paride/pcd.c Thu May 4 01:19:23 2000 @@ -143,8 +143,8 @@ #include #include -#include #include +#include #ifndef MODULE @@ -214,8 +214,11 @@ static int pcd_get_mcn (struct cdrom_device_info *cdi, struct cdrom_mcn *mcn); static int pcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg); +static int pcd_packet(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc); static int pcd_detect(void); +static void pcd_probe_capabilities(void); static void do_pcd_read_drq(void); static void do_pcd_request(void); static void do_pcd_read(void); @@ -276,14 +279,18 @@ pcd_drive_reset, pcd_audio_ioctl, 0, /* dev_ioctl */ - CDC_CLOSE_TRAY | - CDC_OPEN_TRAY | - CDC_LOCK | - CDC_MCN | - CDC_MEDIA_CHANGED | - CDC_RESET | - CDC_PLAY_AUDIO, - 0 + CDC_CLOSE_TRAY | + CDC_OPEN_TRAY | + CDC_LOCK | + CDC_MCN | + CDC_MEDIA_CHANGED | + CDC_RESET | + CDC_PLAY_AUDIO | + CDC_GENERIC_PACKET | + CDC_CD_R | + CDC_CD_RW, + 0, + pcd_packet, }; static void pcd_init_units( void ) @@ -325,6 +332,9 @@ if (pcd_detect()) return -1; + /* get the atapi capabilities page */ + pcd_probe_capabilities(); + if (register_blkdev(MAJOR_NR,name,&cdrom_fops)) { printk("pcd: unable to get major number %d\n",MAJOR_NR); return -1; @@ -525,6 +535,16 @@ return r; } +static int pcd_packet(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc) +{ + char *un_cmd; + int unit = DEVICE_NR(cdi->dev); + + un_cmd = cgc->cmd; + return pcd_atapi(unit,un_cmd,cgc->buflen,cgc->buffer, "generic packet"); +} + #define DBMSG(msg) ((verbose>1)?(msg):NULL) static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr) @@ -667,6 +687,32 @@ return -1; } +static void pcd_probe_capabilities( void ) + +{ int unit, r; + char buffer[32]; + char cmd[12]={0x5a,1<<3,0x2a,0,0,0,0,18,0,0,0,0}; + + for (unit=0;unit> 6) == 0) + PCD.info.mask |= CDC_CLOSE_TRAY; + } +} + static int pcd_detect( void ) { char id[18]; @@ -836,66 +882,9 @@ switch (cmd) { - case CDROMPAUSE: - - { char cmd[12]={SCMD_PAUSE_RESUME,0,0,0,0,0,0,0,0,0,0,0}; - - return (pcd_atapi(unit,cmd,0,NULL,"pause")) * EIO; - } - - case CDROMRESUME: - - { char cmd[12]={SCMD_PAUSE_RESUME,0,0,0,0,0,0,0,1,0,0,0}; - - return (pcd_atapi(unit,cmd,0,NULL,"resume")) * EIO; - } - - case CDROMPLAYMSF: - - { char cmd[12]={SCMD_PLAYAUDIO_MSF,0,0,0,0,0,0,0,0,0,0,0}; - struct cdrom_msf* msf = (struct cdrom_msf*)arg; - - cmd[3] = msf->cdmsf_min0; - cmd[4] = msf->cdmsf_sec0; - cmd[5] = msf->cdmsf_frame0; - cmd[6] = msf->cdmsf_min1; - cmd[7] = msf->cdmsf_sec1; - cmd[8] = msf->cdmsf_frame1; - - return (pcd_atapi(unit,cmd,0,NULL,"play msf")) * EIO; - } - - case CDROMPLAYBLK: - - { char cmd[12]={SCMD_PLAYAUDIO10,0,0,0,0,0,0,0,0,0,0,0}; - struct cdrom_blk* blk = (struct cdrom_blk*)arg; - - cmd[2] = blk->from >> 24; - cmd[3] = blk->from >> 16; - cmd[4] = blk->from >> 8; - cmd[5] = blk->from; - cmd[7] = blk->len >> 8; - cmd[8] = blk->len; - - return (pcd_atapi(unit,cmd,0,NULL,"play block")) * EIO; - } - - case CDROMPLAYTRKIND: - - { char cmd[12]={SCMD_PLAYAUDIO_TI,0,0,0,0,0,0,0,0,0,0,0}; - struct cdrom_ti* ti = (struct cdrom_ti*)arg; - - cmd[4] = ti->cdti_trk0; - cmd[5] = ti->cdti_ind0; - cmd[7] = ti->cdti_trk1; - cmd[8] = ti->cdti_ind1; - - return (pcd_atapi(unit,cmd,0,NULL,"play track")) * EIO; - } - case CDROMREADTOCHDR: - { char cmd[12]={SCMD_READ_TOC,0,0,0,0,0,0,0,12,0,0,0}; + { char cmd[12]={GPCMD_READ_TOC_PMA_ATIP,0,0,0,0,0,0,0,12,0,0,0}; struct cdrom_tochdr* tochdr = (struct cdrom_tochdr*)arg; char buffer[32]; int r; @@ -910,7 +899,7 @@ case CDROMREADTOCENTRY: - { char cmd[12]={SCMD_READ_TOC,0,0,0,0,0,0,0,12,0,0,0}; + { char cmd[12]={GPCMD_READ_TOC_PMA_ATIP,0,0,0,0,0,0,0,12,0,0,0}; struct cdrom_tocentry* tocentry = (struct cdrom_tocentry*)arg; unsigned char buffer[32]; @@ -936,97 +925,6 @@ return r * EIO; } - case CDROMSTOP: - - { char cmd[12]={0x1b,1,0,0,0,0,0,0,0,0,0,0}; - - return (pcd_atapi(unit,cmd,0,NULL,"stop")) * EIO; - } - - case CDROMSTART: - - { char cmd[12]={0x1b,1,0,0,1,0,0,0,0,0,0,0}; - - return (pcd_atapi(unit,cmd,0,NULL,"start")) * EIO; - } - - case CDROMVOLCTRL: - - { char cmd[12]={0x5a,0,0,0,0,0,0,0,0,0,0,0}; - char buffer[32]; - char mask[32]; - struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg; - - cmd[2] = 0xe; - cmd[4] = 28; - - if (pcd_atapi(unit,cmd,28,buffer,"mode sense vol")) - return -EIO; - - cmd[2] = 0x4e; - - if (pcd_atapi(unit,cmd,28,buffer,"mode sense vol mask")) - return -EIO; - - buffer[0] = 0; - - buffer[21] = volctrl->channel0 & mask[21]; - buffer[23] = volctrl->channel1 & mask[23]; - buffer[25] = volctrl->channel2 & mask[25]; - buffer[27] = volctrl->channel3 & mask[27]; - - cmd[0] = 0x55; - cmd[1] = 0x10; - - return pcd_atapi(unit,cmd,28,buffer,"mode select vol") * EIO; - } - - case CDROMVOLREAD: - - { char cmd[12]={0x5a,0,0,0,0,0,0,0,0,0,0,0}; - char buffer[32]; - struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg; - int r; - - cmd[2] = 0xe; - cmd[4] = 28; - - r = pcd_atapi(unit,cmd,28,buffer,"mode sense vol read"); - - volctrl->channel0 = buffer[21]; - volctrl->channel1 = buffer[23]; - volctrl->channel2 = buffer[25]; - volctrl->channel3 = buffer[27]; - - return r * EIO; - } - - - case CDROMSUBCHNL: - - { char cmd[12]={SCMD_READ_SUBCHANNEL,2,0x40,1,0,0,0,0,16,0,0,0}; - struct cdrom_subchnl* subchnl = (struct cdrom_subchnl*)arg; - char buffer[32]; - - if (pcd_atapi(unit,cmd,16,buffer,"read subchannel")) - return -EIO; - - subchnl->cdsc_audiostatus = buffer[1]; - subchnl->cdsc_format = CDROM_MSF; - subchnl->cdsc_ctrl = buffer[5] & 0xf; - subchnl->cdsc_trk = buffer[6]; - subchnl->cdsc_ind = buffer[7]; - - subchnl->cdsc_reladdr.msf.minute = buffer[13]; - subchnl->cdsc_reladdr.msf.second = buffer[14]; - subchnl->cdsc_reladdr.msf.frame = buffer[15]; - subchnl->cdsc_absaddr.msf.minute = buffer[9]; - subchnl->cdsc_absaddr.msf.second = buffer[10]; - subchnl->cdsc_absaddr.msf.frame = buffer[11]; - - return 0; - } - default: return -ENOSYS; @@ -1035,7 +933,7 @@ static int pcd_get_mcn (struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) -{ char cmd[12]={SCMD_READ_SUBCHANNEL,0,0x40,2,0,0,0,0,24,0,0,0}; +{ char cmd[12]={GPCMD_READ_SUBCHANNEL,0,0x40,2,0,0,0,0,24,0,0,0}; char buffer[32]; int k; int unit = DEVICE_NR(cdi->dev); diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/drivers/block/pdc4030.c linux/drivers/block/pdc4030.c --- linux-2.2.15/drivers/block/pdc4030.c Thu May 4 15:21:22 2000 +++ linux/drivers/block/pdc4030.c Thu May 4 01:19:23 2000 @@ -239,8 +239,8 @@ if(stat & DRQ_STAT) goto read_again; if(stat & BUSY_STAT) { - ide_set_handler (drive, &promise_read_intr, WAIT_CMD); - return ide_started;; + ide_set_handler (drive, &promise_read_intr, WAIT_CMD, NULL); + return ide_started; } printk("Ah! promise read intr: sectors left !DRQ !BUSY\n"); return ide_error(drive, "promise read intr", stat); @@ -259,7 +259,7 @@ if (IN_BYTE(IDE_NSECTOR_REG) != 0) { if (time_before(jiffies, hwgroup->poll_timeout)) { - ide_set_handler (drive, &promise_write_pollfunc, 1); + ide_set_handler (drive, &promise_write_pollfunc, 1, NULL); return ide_started; /* continue polling... */ } printk("%s: write timed-out!\n",drive->name); @@ -294,7 +294,7 @@ if (ide_multwrite(drive, rq->nr_sectors - 4)) return ide_stopped; hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - ide_set_handler (drive, &promise_write_pollfunc, 1); + ide_set_handler (drive, &promise_write_pollfunc, 1, NULL); return ide_started; } else { if (ide_multwrite(drive, rq->nr_sectors)) @@ -304,8 +304,8 @@ i -= rq->current_nr_sectors; ide_end_request(1, hwgroup); } - return ide_stopped; } + return ide_stopped; } /* @@ -319,7 +319,7 @@ byte stat; if (rq->cmd == READ) { - ide_set_handler(drive, &promise_read_intr, WAIT_CMD); + ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL); OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG); /* The card's behaviour is odd at this point. If the data is available, DRQ will be true, and no interrupt will be diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/drivers/block/trm290.c linux/drivers/block/trm290.c --- linux-2.2.15/drivers/block/trm290.c Thu May 4 15:21:22 2000 +++ linux/drivers/block/trm290.c Thu May 4 01:19:23 2000 @@ -193,7 +193,7 @@ outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */ if (drive->media != ide_disk) return 0; - ide_set_handler(drive, &ide_dma_intr, WAIT_CMD); + ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); return 0; case ide_dma_begin: diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- linux-2.2.15/drivers/cdrom/cdrom.c Thu May 4 15:21:22 2000 +++ linux/drivers/cdrom/cdrom.c Thu May 4 01:25:59 2000 @@ -1,7 +1,7 @@ /* linux/drivers/cdrom/cdrom.c. Copyright (c) 1996, 1997 David A. van Leeuwen. Copyright (c) 1997, 1998 Erik Andersen - Copyright (c) 1998, 1999 Jens Axboe + Copyright (c) 1998, 1999, 2000 Jens Axboe May be copied or modified under the terms of the GNU General Public License. See linux/COPYING for more information. @@ -22,12 +22,6 @@ based tunable parameters such as whether the tray should auto-close for that drive. Suggestions (or patches) for this welcome! - -- Change the CDROMREADMODE1, CDROMREADMODE2, CDROMREADAUDIO, and - CDROMREADRAW ioctls so they go through the Uniform CD-ROM driver. - - -- Sync options and capability flags. - - Revision History ---------------------------------- @@ -126,14 +120,99 @@ CDC_CLOSE_TRAY. -- proc info didn't mask against capabilities mask. - 2.56 Sep 9, 1999 - Jens Axboe - -- Define CDROM_CAN() for checking capabilities. - -- Fix up capability reporting, for proc and ioctl. - + 3.00 Aug 5, 1999 - Jens Axboe + -- Unified audio ioctl handling across CD-ROM drivers. A lot of the + code was duplicated before. Drives that support the generic packet + interface are now being fed packets from here instead. + -- First attempt at adding support for MMC2 commands - for DVD and + CD-R(W) drives. Only the DVD parts are in now - the interface used is + the same as for the audio ioctls. + -- ioctl cleanups. if a drive couldn't play audio, it didn't get + a change to perform device specific ioctls as well. + -- Defined CDROM_CAN(CDC_XXX) for checking the capabilities. + -- Put in sysctl files for autoclose, autoeject, check_media, debug, + and lock. + -- /proc/sys/dev/cdrom/info has been updated to also contain info about + CD-Rx and DVD capabilities. + -- Now default to checking media type. + -- CDROM_SEND_PACKET ioctl added. The infrastructure was in place for + doing this anyway, with the generic_packet addition. + + 3.01 Aug 6, 1999 - Jens Axboe + -- Fix up the sysctl handling so that the option flags get set + correctly. + -- Fix up ioctl handling so the device specific ones actually get + called :). + + 3.02 Aug 8, 1999 - Jens Axboe + -- Fixed volume control on SCSI drives (or others with longer audio + page). + -- Fixed a couple of DVD minors. Thanks to Andrew T. Veliath + for telling me and for having defined the various + DVD structures and ioctls in the first place! He designed the original + DVD patches for ide-cd and while I rearranged and unified them, the + interface is still the same. + + 3.03 Sep 1, 1999 - Jens Axboe + -- Moved the rest of the audio ioctls from the CD-ROM drivers here. Only + CDROMREADTOCENTRY and CDROMREADTOCHDR are left. + -- Moved the CDROMREADxxx ioctls in here. + -- Defined the cdrom_get_last_written and cdrom_get_next_block as ioctls + and exported functions. + -- Erik Andersen modified all SCMD_ commands + to now read GPCMD_ for the new generic packet interface. All low level + drivers are updated as well. + -- Various other cleanups. + + 3.04 Sep 12, 1999 - Jens Axboe + -- Fixed a couple of possible memory leaks (if an operation failed and + we didn't free the buffer before returning the error). + -- Integrated Uniform CD Changer handling from Richard Sharman + . + -- Defined CD_DVD and CD_CHANGER log levels. + -- Fixed the CDROMREADxxx ioctls. + -- CDROMPLAYTRKIND uses the GPCMD_PLAY_AUDIO_MSF command - too few + drives supported it. We loose the index part, however. + -- Small modifications to accomodate opens of /dev/hdc1, required + for ide-cd to handle multisession discs. + -- Export cdrom_mode_sense and cdrom_mode_select. + -- init_cdrom_command() for setting up a cgc command. + + 3.05 Oct 24, 1999 - Jens Axboe + -- Changed the interface for CDROM_SEND_PACKET. Before it was virtually + impossible to send the drive data in a sensible way. + -- Lowered stack usage in mmc_ioctl(), dvd_read_disckey(), and + dvd_read_manufact. + -- Added setup of write mode for packet writing. + -- Fixed CDDA ripping with cdda2wav - accept much larger requests of + number of frames and split the reads in blocks of 8. + + 3.06 Dec 13, 1999 - Jens Axboe + -- Added support for changing the region of DVD drives. + -- Added sense data to generic command. + + 3.07 Feb 2, 2000 - Jens Axboe + -- Do same "read header length" trick in cdrom_get_disc_info() as + we do in cdrom_get_track_info() -- some drive don't obbey specs and + fail if they can't supply the full Mt Fuji size table. + -- Deleted stuff related to setting up write modes. It has a different + home now. + -- Clear header length in mode_select unconditionally. + -- Removed the register_disk() that was added, not needed here. + + 3.08 May 1, 2000 - Jens Axboe + -- Always return -EROFS for write opens + -- Convert to module_init/module_exit style init and remove some + of the #ifdef MODULE stuff + -- Fix several dvd errors - DVD_LU_SEND_ASF should pass agid, + DVD_HOST_SEND_RPC_STATE did not set buffer size in cdb, and + dvd_do_auth passed uninitialized data to drive because init_cdrom_command + did not clear a 0 sized buffer. + -------------------------------------------------------------------------*/ -#define REVISION "Revision: 2.56" -#define VERSION "Id: cdrom.c 2.56 1999/09/09" +#define REVISION "Revision: 3.08" +#define VERSION "Id: cdrom.c 3.08 2000/05/01" /* I use an error-log mask to give fine grain control over the type of messages dumped to the system logs. The available masks include: */ @@ -144,6 +223,8 @@ #define CD_OPEN 0x8 #define CD_CLOSE 0x10 #define CD_COUNT_TRACKS 0x20 +#define CD_CHANGER 0x40 +#define CD_DVD 0x80 /* Define this to remove _all_ the debugging messages */ /* #define ERRLOGMASK CD_NOTHING */ @@ -151,7 +232,6 @@ /* #define ERRLOGMASK (CD_WARNING|CD_OPEN|CD_COUNT_TRACKS|CD_CLOSE) */ /* #define ERRLOGMASK (CD_WARNING|CD_REG_UNREG|CD_DO_IOCTL|CD_OPEN|CD_CLOSE|CD_COUNT_TRACKS) */ - #include #include #include @@ -164,6 +244,7 @@ #include #include #include +#include #include #include #include @@ -176,6 +257,7 @@ static int autoclose=1; static int autoeject=0; static int lockdoor = 1; +/* will we ever get to use this... sigh. */ static int check_media_type = 0; MODULE_PARM(debug, "i"); MODULE_PARM(autoclose, "i"); @@ -202,7 +284,8 @@ a lot of places. This macro makes the code more clear. */ #define CDROM_CAN(type) (cdi->ops->capability & ~cdi->mask & type) -#define FM_WRITE 0x2 /* file mode write bit */ +/* used in the audio ioctls */ +#define CHECKAUDIO if ((ret=check_for_audio_disc(cdi, cdo))) return ret /* Not-exported routines. */ static int cdrom_open(struct inode *ip, struct file *fp); @@ -215,6 +298,12 @@ struct cdrom_device_ops * cdo); static void sanitize_format(union cdrom_addr *addr, u_char * curr, u_char requested); +static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, + unsigned long arg); + +int cdrom_get_last_written(kdev_t dev, long *last_written); +int cdrom_get_next_writable(kdev_t dev, long *next_writable); + #ifdef CONFIG_SYSCTL static void cdrom_sysctl_register(void); #endif /* CONFIG_SYSCTL */ @@ -248,7 +337,7 @@ int register_cdrom(struct cdrom_device_info *cdi) { static char banner_printed = 0; - int major = MAJOR (cdi->dev); + int major = MAJOR(cdi->dev); struct cdrom_device_ops *cdo = cdi->ops; int *change_capability = (int *)&cdo->capability; /* hack */ @@ -259,7 +348,7 @@ if (cdo->open == NULL || cdo->release == NULL) return -2; if ( !banner_printed ) { - printk(KERN_INFO "Uniform CDROM driver " REVISION "\n"); + printk(KERN_INFO "Uniform CD-ROM driver " REVISION "\n"); banner_printed = 1; #ifdef CONFIG_SYSCTL cdrom_sysctl_register(); @@ -270,12 +359,12 @@ ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY); ENSURE(lock_door, CDC_LOCK); ENSURE(select_speed, CDC_SELECT_SPEED); - ENSURE(select_disc, CDC_SELECT_DISC); ENSURE(get_last_session, CDC_MULTI_SESSION); ENSURE(get_mcn, CDC_MCN); ENSURE(reset, CDC_RESET); ENSURE(audio_ioctl, CDC_PLAY_AUDIO); ENSURE(dev_ioctl, CDC_IOCTLS); + ENSURE(generic_packet, CDC_GENERIC_PACKET); cdi->mc_flags = 0; cdo->n_minors = 0; cdi->options = CDO_USE_FFLAGS; @@ -299,7 +388,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg) { struct cdrom_device_info *cdi, *prev; - int major = MAJOR (unreg->dev); + int major = MAJOR(unreg->dev); cdinfo(CD_OPEN, "entering unregister_cdrom\n"); @@ -325,13 +414,25 @@ } static -struct cdrom_device_info *cdrom_find_device (kdev_t dev) +struct cdrom_device_info *cdrom_find_device(kdev_t dev) { struct cdrom_device_info *cdi; cdi = topCdromPtr; while (cdi != NULL && cdi->dev != dev) cdi = cdi->next; + + /* we need to find the device this way when IDE devices such + * as /dev/hdc2 are opened. SCSI drives will be found above and + * so will /dev/hdc, for instance. + */ + if (cdi == NULL) { + kdev_t cd_dev = MKDEV(MAJOR(dev), MINOR(dev) | CD_PART_MASK); + cdi = topCdromPtr; + while (cdi != NULL && cdi->dev != cd_dev) + cdi = cdi->next; + } + return cdi; } @@ -346,22 +447,26 @@ static int cdrom_open(struct inode *ip, struct file *fp) { + struct cdrom_device_info *cdi; kdev_t dev = ip->i_rdev; - struct cdrom_device_info *cdi = cdrom_find_device(dev); - int purpose = !!(fp->f_flags & O_NONBLOCK); - int ret=0; + int ret; cdinfo(CD_OPEN, "entering cdrom_open\n"); - if (cdi == NULL) + if ((cdi = cdrom_find_device(dev)) == NULL) return -ENODEV; - if (fp->f_mode & FM_WRITE) + + if (fp->f_mode & FMODE_WRITE) return -EROFS; - purpose = purpose || !(cdi->options & CDO_USE_FFLAGS); - if (purpose) - ret = cdi->ops->open(cdi, purpose); + + /* if this was a O_NONBLOCK open and we should honor the flags, + * do a quick open without drive/disc integrity checks. */ + if ((fp->f_flags & O_NONBLOCK) && (cdi->options & CDO_USE_FFLAGS)) + ret = cdi->ops->open(cdi, 1); else ret = open_for_data(cdi); + if (!ret) cdi->use_count++; + cdinfo(CD_OPEN, "Use count for \"/dev/%s\" now %d\n", cdi->name, cdi->use_count); /* Do this on open. Don't wait for mount, because they might not be mounting, but opening with O_NONBLOCK */ @@ -428,7 +533,11 @@ * for example, need bit CDO_CHECK_TYPE cleared! */ if (tracks.data==0) { if (cdi->options & CDO_CHECK_TYPE) { + /* give people a warning shot, now that CDO_CHECK_TYPE + is the default case! */ cdinfo(CD_OPEN, "bummer. wrong media type.\n"); + cdinfo(CD_WARNING, "pid %d must open device O_NONBLOCK!\n", + (unsigned int)current->pid); ret=-EMEDIUMTYPE; goto clean_up_and_return; } @@ -452,7 +561,7 @@ if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { cdo->lock_door(cdi, 1); cdinfo(CD_OPEN, "door locked.\n"); - } + } cdinfo(CD_OPEN, "device opened successfully.\n"); return ret; @@ -533,17 +642,17 @@ int cdrom_release(struct inode *ip, struct file *fp) { kdev_t dev = ip->i_rdev; - struct cdrom_device_info *cdi = cdrom_find_device (dev); + struct cdrom_device_info *cdi = cdrom_find_device(dev); struct cdrom_device_ops *cdo = cdi->ops; int opened_for_data; cdinfo(CD_CLOSE, "entering cdrom_release\n"); - if (cdi == NULL) - return 0; - if (cdi->use_count > 0) cdi->use_count--; + + if (cdi->use_count > 0) + cdi->use_count--; if (cdi->use_count == 0) cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name); - if (cdi->use_count == 0 && /* last process that closes dev*/ + if (cdi->use_count == 0 && cdo->capability & CDC_LOCK && !keeplocked) { cdinfo(CD_CLOSE, "Unlocking door!\n"); cdo->lock_door(cdi, 0); @@ -557,13 +666,140 @@ sb = get_super(dev); if (sb) invalidate_inodes(sb); invalidate_buffers(dev); - if (opened_for_data && (cdi->options & CDO_AUTO_EJECT) && - CDROM_CAN(CDC_OPEN_TRAY)) + if (opened_for_data && + cdi->options & CDO_AUTO_EJECT && CDROM_CAN(CDC_OPEN_TRAY)) cdo->tray_move(cdi, 1); } return 0; } +static int cdrom_read_mech_status(struct cdrom_device_info *cdi, + struct cdrom_changer_info *buf) +{ + struct cdrom_generic_command cgc; + struct cdrom_device_ops *cdo = cdi->ops; + int length; + + length = sizeof(struct cdrom_mechstat_header) + + cdi->capacity * sizeof(struct cdrom_slot); + + init_cdrom_command(&cgc, buf, length); + cgc.cmd[0] = GPCMD_MECHANISM_STATUS; + cgc.cmd[8] = (length >> 8) & 0xff; + cgc.cmd[9] = length & 0xff; + return cdo->generic_packet(cdi, &cgc); +} + +static int cdrom_slot_status(struct cdrom_device_info *cdi, int slot) +{ + struct cdrom_changer_info info; + int ret; + + cdinfo(CD_CHANGER, "entering cdrom_slot_status()\n"); + if (cdi->sanyo_slot) + return CDS_NO_INFO; + + if ((ret = cdrom_read_mech_status(cdi, &info))) + return ret; + + if (info.slots[slot].disc_present) + return CDS_DISC_OK; + else + return CDS_NO_DISC; + +} + +/* Return the number of slots for an ATAPI/SCSI cdrom, + * return 1 if not a changer. + */ +int cdrom_number_of_slots(struct cdrom_device_info *cdi) +{ + int status; + int nslots = 1; + struct cdrom_changer_info info; + + cdinfo(CD_CHANGER, "entering cdrom_number_of_slots()\n"); + /* cdrom_read_mech_status requires a valid value for capacity: */ + cdi->capacity = 0; + + if ((status = cdrom_read_mech_status(cdi, &info)) == 0) + nslots = info.hdr.nslots; + + return nslots; +} + + +/* If SLOT < 0, unload the current slot. Otherwise, try to load SLOT. */ +static int cdrom_load_unload(struct cdrom_device_info *cdi, int slot) +{ + struct cdrom_generic_command cgc; + + cdinfo(CD_CHANGER, "entering cdrom_load_unload()\n"); + if (cdi->sanyo_slot && slot < 0) + return 0; + + init_cdrom_command(&cgc, NULL, 0); + cgc.cmd[0] = GPCMD_LOAD_UNLOAD; + cgc.cmd[4] = 2 + (slot >= 0); + cgc.cmd[8] = slot; + + /* The Sanyo 3 CD changer uses byte 7 of the + GPCMD_TEST_UNIT_READY to command to switch CDs instead of + using the GPCMD_LOAD_UNLOAD opcode. */ + if (cdi->sanyo_slot && slot) { + cgc.cmd[0] = GPCMD_TEST_UNIT_READY; + cgc.cmd[7] = slot; + cdi->sanyo_slot = slot ? slot : 3; + } + + return cdi->ops->generic_packet(cdi, &cgc); +} + +int cdrom_select_disc(struct cdrom_device_info *cdi, int slot) +{ + struct cdrom_changer_info info; + int curslot; + int ret; + + cdinfo(CD_CHANGER, "entering cdrom_select_disc()\n"); + if (!CDROM_CAN(CDC_SELECT_DISC)) + return -EDRIVE_CANT_DO_THIS; + + if (slot == CDSL_NONE) { + /* set media changed bits, on both queues */ + cdi->mc_flags = 0x3; + return cdrom_load_unload(cdi, -1); + } + + if ((ret = cdrom_read_mech_status(cdi, &info))) + return ret; + + curslot = info.hdr.curslot; + + if (cdi->use_count > 1 || keeplocked) { + if (slot == CDSL_CURRENT) { + return curslot; + } else { + return -EBUSY; + } + } + + /* Specifying CDSL_CURRENT will attempt to load the currnet slot, + which is useful if it had been previously unloaded. + Whether it can or not, it returns the current slot. + Similarly, if slot happens to be the current one, we still + try and load it. */ + if (slot == CDSL_CURRENT) + slot = curslot; + + /* set media changed bits on both queues */ + cdi->mc_flags = 0x3; + if ((ret = cdrom_load_unload(cdi, slot))) + return ret; + + return slot; +} + /* We want to make media_changed accessible to the user through an * ioctl. The main problem now is that we must double-buffer the * low-level implementation, to assure that the VFS and the user both @@ -587,15 +823,12 @@ return ret; } -static -int cdrom_media_changed(kdev_t dev) +static int cdrom_media_changed(kdev_t dev) { - struct cdrom_device_info *cdi = cdrom_find_device (dev); + struct cdrom_device_info *cdi = cdrom_find_device(dev); /* This talks to the VFS, which doesn't like errors - just 1 or 0. * Returning "0" is always safe (media hasn't been changed). Do that * if the low-level cdrom driver dosn't support media changed. */ - if (cdi == NULL) - return 0; if (cdi->ops->media_changed == NULL) return 0; if (!CDROM_CAN(CDC_MEDIA_CHANGED)) @@ -603,6 +836,7 @@ return (media_changed(cdi, 0)); } +/* badly broken, I know. Is due for a fixup anytime. */ void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype* tracks) { struct cdrom_tochdr header; @@ -614,7 +848,7 @@ tracks->xa=0; tracks->error=0; cdinfo(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n"); - if (!(cdi->ops->capability & ~cdi->mask & CDC_PLAY_AUDIO)) { + if (!CDROM_CAN(CDC_PLAY_AUDIO)) { tracks->error=CDS_NO_INFO; return; } @@ -688,38 +922,496 @@ *curr = requested; } -/* Some of the cdrom ioctls are not implemented here, because these - * appear to be either too device-specific, or it is not clear to me - * what use they are. These are (number of drivers that support them - * in parenthesis): CDROMREADMODE1 (2+ide), CDROMREADMODE2 (2+ide), - * CDROMREADAUDIO (2+ide), CDROMREADRAW (2), CDROMREADCOOKED (2), - * CDROMSEEK (2), CDROMPLAYBLK (scsi), CDROMREADALL (1). Read-audio, - * OK (although i guess the record companies aren't too happy with - * this, most drives therefore refuse to transport audio data). But - * why are there 5 different READs defined? For now, these functions - * are left over to the device-specific ioctl routine, - * cdo->dev_ioctl. Note that as a result of this, no - * memory-verification is performed for these ioctls. +void init_cdrom_command(struct cdrom_generic_command *cgc, void *buf, int len) +{ + memset(cgc, 0, sizeof(struct cdrom_generic_command)); + if (buf) + memset(buf, 0, len); + cgc->buffer = (char *) buf; + cgc->buflen = len; +} + +/* DVD handling */ + +#define copy_key(dest,src) memcpy((dest), (src), sizeof(dvd_key)) +#define copy_chal(dest,src) memcpy((dest), (src), sizeof(dvd_challenge)) + +static void setup_report_key(struct cdrom_generic_command *cgc, unsigned agid, unsigned type) +{ + cgc->cmd[0] = GPCMD_REPORT_KEY; + cgc->cmd[10] = type | (agid << 6); + switch (type) { + case 0: case 8: case 5: { + cgc->buflen = 8; + break; + } + case 1: { + cgc->buflen = 16; + break; + } + case 2: case 4: { + cgc->buflen = 12; + break; + } + } + cgc->cmd[9] = cgc->buflen; +} + +static void setup_send_key(struct cdrom_generic_command *cgc, unsigned agid, unsigned type) +{ + cgc->cmd[0] = GPCMD_SEND_KEY; + cgc->cmd[10] = type | (agid << 6); + switch (type) { + case 1: { + cgc->buflen = 16; + break; + } + case 3: { + cgc->buflen = 12; + break; + } + case 6: { + cgc->buflen = 8; + break; + } + } + cgc->cmd[9] = cgc->buflen; +} + +static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) +{ + int ret; + u_char buf[20]; + struct cdrom_generic_command cgc; + struct cdrom_device_ops *cdo = cdi->ops; + rpc_state_t rpc_state; + + memset(buf, 0, sizeof(buf)); + init_cdrom_command(&cgc, buf, 0); + + switch (ai->type) { + /* LU data send */ + case DVD_LU_SEND_AGID: + cdinfo(CD_DVD, "entering DVD_LU_SEND_AGID\n"); + setup_report_key(&cgc, ai->lsa.agid, 0); + + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + ai->lsa.agid = buf[7] >> 6; + /* Returning data, let host change state */ + break; + + case DVD_LU_SEND_KEY1: + cdinfo(CD_DVD, "entering DVD_LU_SEND_KEY1\n"); + setup_report_key(&cgc, ai->lsk.agid, 2); + + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + copy_key(ai->lsk.key, &buf[4]); + /* Returning data, let host change state */ + break; + + case DVD_LU_SEND_CHALLENGE: + cdinfo(CD_DVD, "entering DVD_LU_SEND_CHALLENGE\n"); + setup_report_key(&cgc, ai->lsc.agid, 1); + + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + copy_chal(ai->lsc.chal, &buf[4]); + /* Returning data, let host change state */ + break; + + /* Post-auth key */ + case DVD_LU_SEND_TITLE_KEY: + cdinfo(CD_DVD, "entering DVD_LU_SEND_TITLE_KEY\n"); + setup_report_key(&cgc, ai->lstk.agid, 4); + cgc.cmd[5] = ai->lstk.lba; + cgc.cmd[4] = ai->lstk.lba >> 8; + cgc.cmd[3] = ai->lstk.lba >> 16; + cgc.cmd[2] = ai->lstk.lba >> 24; + + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + ai->lstk.cpm = (buf[4] >> 7) & 1; + ai->lstk.cp_sec = (buf[4] >> 6) & 1; + ai->lstk.cgms = (buf[4] >> 4) & 3; + copy_key(ai->lstk.title_key, &buf[5]); + /* Returning data, let host change state */ + break; + + case DVD_LU_SEND_ASF: + cdinfo(CD_DVD, "entering DVD_LU_SEND_ASF\n"); + setup_report_key(&cgc, ai->lsasf.agid, 5); + + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + ai->lsasf.asf = buf[7] & 1; + break; + + /* LU data receive (LU changes state) */ + case DVD_HOST_SEND_CHALLENGE: + cdinfo(CD_DVD, "entering DVD_HOST_SEND_CHALLENGE\n"); + setup_send_key(&cgc, ai->hsc.agid, 1); + buf[1] = 0xe; + copy_chal(&buf[4], ai->hsc.chal); + + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + ai->type = DVD_LU_SEND_KEY1; + break; + + case DVD_HOST_SEND_KEY2: + cdinfo(CD_DVD, "entering DVD_HOST_SEND_KEY2\n"); + setup_send_key(&cgc, ai->hsk.agid, 3); + buf[1] = 0xa; + copy_key(&buf[4], ai->hsk.key); + + if ((ret = cdo->generic_packet(cdi, &cgc))) { + ai->type = DVD_AUTH_FAILURE; + return ret; + } + ai->type = DVD_AUTH_ESTABLISHED; + break; + + /* Misc */ + case DVD_INVALIDATE_AGID: + cdinfo(CD_DVD, "entering DVD_INVALIDATE_AGID\n"); + setup_report_key(&cgc, ai->lsa.agid, 0x3f); + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + break; + + /* Get region settings */ + case DVD_LU_SEND_RPC_STATE: + cdinfo(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n"); + setup_report_key(&cgc, 0, 8); + + init_cdrom_command(&cgc, &rpc_state, 0); + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + ai->lrpcs.type = rpc_state.type_code; + ai->lrpcs.vra = rpc_state.vra; + ai->lrpcs.ucca = rpc_state.ucca; + ai->lrpcs.region_mask = rpc_state.region_mask; + ai->lrpcs.rpc_scheme = rpc_state.rpc_scheme; + break; + + /* Set region settings */ + case DVD_HOST_SEND_RPC_STATE: + cdinfo(CD_DVD, "entering DVD_HOST_SEND_RPC_STATE\n"); + setup_send_key(&cgc, 0, 6); + buf[1] = 6; + buf[4] = ai->hrpcs.pdrc; + + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + break; + + default: + cdinfo(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type); + return -ENOTTY; + } + + return 0; +} + +static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s) +{ + int ret, i; + u_char buf[4 + 4 * 20], *base; + struct dvd_layer *layer; + struct cdrom_generic_command cgc; + struct cdrom_device_ops *cdo = cdi->ops; + + init_cdrom_command(&cgc, buf, sizeof(buf)); + cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; + cgc.cmd[6] = s->physical.layer_num; + cgc.cmd[7] = s->type; + cgc.cmd[9] = cgc.buflen & 0xff; + + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + base = &buf[4]; + layer = &s->physical.layer[0]; + + /* place the data... really ugly, but at least we won't have to + worry about endianess in userspace or here. */ + for (i = 0; i < 4; ++i, base += 20, ++layer) { + memset(layer, 0, sizeof(*layer)); + layer->book_version = base[0] & 0xf; + layer->book_type = base[0] >> 4; + layer->min_rate = base[1] & 0xf; + layer->disc_size = base[1] >> 4; + layer->layer_type = base[2] & 0xf; + layer->track_path = (base[2] >> 4) & 1; + layer->nlayers = (base[2] >> 5) & 3; + layer->track_density = base[3] & 0xf; + layer->linear_density = base[3] >> 4; + layer->start_sector = base[5] << 16 | base[6] << 8 | base[7]; + layer->end_sector = base[9] << 16 | base[10] << 8 | base[11]; + layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15]; + layer->bca = base[16] >> 7; + } + + return 0; +} + +static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s) +{ + int ret; + u_char buf[8]; + struct cdrom_generic_command cgc; + struct cdrom_device_ops *cdo = cdi->ops; + + init_cdrom_command(&cgc, buf, sizeof(buf)); + cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; + cgc.cmd[6] = s->copyright.layer_num; + cgc.cmd[7] = s->type; + cgc.cmd[8] = cgc.buflen >> 8; + cgc.cmd[9] = cgc.buflen & 0xff; + + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + s->copyright.cpst = buf[4]; + s->copyright.rmi = buf[5]; + + return 0; +} + +static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s) +{ + int ret, size; + u_char *buf; + struct cdrom_generic_command cgc; + struct cdrom_device_ops *cdo = cdi->ops; + + size = sizeof(s->disckey.value) + 4; + + if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL) + return -ENOMEM; + + init_cdrom_command(&cgc, buf, size); + cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; + cgc.cmd[7] = s->type; + cgc.cmd[8] = size >> 8; + cgc.cmd[9] = size & 0xff; + cgc.cmd[10] = s->disckey.agid << 6; + + if (!(ret = cdo->generic_packet(cdi, &cgc))) + memcpy(s->disckey.value, &buf[4], sizeof(s->disckey.value)); + + kfree(buf); + return ret; +} + +static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s) +{ + int ret; + u_char buf[4 + 188]; + struct cdrom_generic_command cgc; + struct cdrom_device_ops *cdo = cdi->ops; + + init_cdrom_command(&cgc, buf, sizeof(buf)); + cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; + cgc.cmd[7] = s->type; + cgc.cmd[9] = cgc.buflen = 0xff; + + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + s->bca.len = buf[0] << 8 | buf[1]; + if (s->bca.len < 12 || s->bca.len > 188) { + cdinfo(CD_WARNING, "Received invalid BCA length (%d)\n", s->bca.len); + return -EIO; + } + memcpy(s->bca.value, &buf[4], s->bca.len); + + return 0; +} + +static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s) +{ + int ret = 0, size; + u_char *buf; + struct cdrom_generic_command cgc; + struct cdrom_device_ops *cdo = cdi->ops; + + size = sizeof(s->manufact.value) + 4; + + if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL) + return -ENOMEM; + + init_cdrom_command(&cgc, buf, size); + cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; + cgc.cmd[7] = s->type; + cgc.cmd[8] = size >> 8; + cgc.cmd[9] = size & 0xff; + + if ((ret = cdo->generic_packet(cdi, &cgc))) { + kfree(buf); + return ret; + } + + s->manufact.len = buf[0] << 8 | buf[1]; + if (s->manufact.len < 0 || s->manufact.len > 2048) { + cdinfo(CD_WARNING, "Received invalid manufacture info length" + " (%d)\n", s->bca.len); + ret = -EIO; + } else { + memcpy(s->manufact.value, &buf[4], s->manufact.len); + } + + kfree(buf); + return ret; +} + +static int dvd_read_struct(struct cdrom_device_info *cdi, dvd_struct *s) +{ + switch (s->type) { + case DVD_STRUCT_PHYSICAL: + return dvd_read_physical(cdi, s); + + case DVD_STRUCT_COPYRIGHT: + return dvd_read_copyright(cdi, s); + + case DVD_STRUCT_DISCKEY: + return dvd_read_disckey(cdi, s); + + case DVD_STRUCT_BCA: + return dvd_read_bca(cdi, s); + + case DVD_STRUCT_MANUFACT: + return dvd_read_manufact(cdi, s); + + default: + cdinfo(CD_WARNING, ": Invalid DVD structure read requested (%d)\n", + s->type); + return -EINVAL; + } +} + +int cdrom_mode_sense(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc, + int page_code, int page_control) +{ + struct cdrom_device_ops *cdo = cdi->ops; + + memset(cgc->cmd, 0, sizeof(cgc->cmd)); + + cgc->cmd[0] = GPCMD_MODE_SENSE_10; + cgc->cmd[2] = page_code | (page_control << 6); + cgc->cmd[7] = cgc->buflen >> 8; + cgc->cmd[8] = cgc->buflen & 0xff; + return cdo->generic_packet(cdi, cgc); +} + +int cdrom_mode_select(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc) +{ + struct cdrom_device_ops *cdo = cdi->ops; + + memset(cgc->cmd, 0, sizeof(cgc->cmd)); + memset(cgc->buffer, 0, 3); + + cgc->cmd[0] = GPCMD_MODE_SELECT_10; + cgc->cmd[1] = 0x10; /* PF */ + cgc->cmd[7] = cgc->buflen >> 8; + cgc->cmd[8] = cgc->buflen & 0xff; + return cdo->generic_packet(cdi, cgc); +} + +static int cdrom_read_subchannel(struct cdrom_device_info *cdi, + struct cdrom_subchnl *subchnl, int mcn) +{ + struct cdrom_device_ops *cdo = cdi->ops; + struct cdrom_generic_command cgc; + char buffer[32]; + int ret; + + init_cdrom_command(&cgc, buffer, 16); + cgc.cmd[0] = GPCMD_READ_SUBCHANNEL; + cgc.cmd[1] = 2; /* MSF addressing */ + cgc.cmd[2] = 0x40; /* request subQ data */ + cgc.cmd[3] = mcn ? 2 : 1; + cgc.cmd[8] = 16; + + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + subchnl->cdsc_audiostatus = cgc.buffer[1]; + subchnl->cdsc_format = CDROM_MSF; + subchnl->cdsc_ctrl = cgc.buffer[5] & 0xf; + subchnl->cdsc_trk = cgc.buffer[6]; + subchnl->cdsc_ind = cgc.buffer[7]; + + subchnl->cdsc_reladdr.msf.minute = cgc.buffer[13]; + subchnl->cdsc_reladdr.msf.second = cgc.buffer[14]; + subchnl->cdsc_reladdr.msf.frame = cgc.buffer[15]; + subchnl->cdsc_absaddr.msf.minute = cgc.buffer[9]; + subchnl->cdsc_absaddr.msf.second = cgc.buffer[10]; + subchnl->cdsc_absaddr.msf.frame = cgc.buffer[11]; + + return 0; +} + +/* very generic interface for reading the various types of blocks */ +static int cdrom_read_block(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc, + int lba, int nblocks, int format, int blksize) +{ + struct cdrom_device_ops *cdo = cdi->ops; + + memset(&cgc->cmd, 0, sizeof(cgc->cmd)); + cgc->cmd[0] = GPCMD_READ_CD; + /* expected sector size - cdda,mode1,etc. */ + cgc->cmd[1] = format << 2; + /* starting address */ + cgc->cmd[2] = (lba >> 24) & 0xff; + cgc->cmd[3] = (lba >> 16) & 0xff; + cgc->cmd[4] = (lba >> 8) & 0xff; + cgc->cmd[5] = lba & 0xff; + /* number of blocks */ + cgc->cmd[6] = (nblocks >> 16) & 0xff; + cgc->cmd[7] = (nblocks >> 8) & 0xff; + cgc->cmd[8] = nblocks & 0xff; + cgc->buflen = blksize * nblocks; + + /* set the header info returned */ + switch (blksize) { + case CD_FRAMESIZE_RAW0 : cgc->cmd[9] = 0x58; break; + case CD_FRAMESIZE_RAW1 : cgc->cmd[9] = 0x78; break; + case CD_FRAMESIZE_RAW : cgc->cmd[9] = 0xf8; break; + default : cgc->cmd[9] = 0x10; + } + + return cdo->generic_packet(cdi, cgc); +} + +/* Just about every imaginable ioctl is supported in the Uniform layer + * these days. ATAPI / SCSI specific code now mainly resides in + * mmc_ioct(). */ -static -int cdrom_ioctl(struct inode *ip, struct file *fp, - unsigned int cmd, unsigned long arg) +static int cdrom_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, + unsigned long arg) { kdev_t dev = ip->i_rdev; - struct cdrom_device_info *cdi = cdrom_find_device (dev); - struct cdrom_device_ops *cdo; - - if (cdi == NULL) - return -ENODEV; - cdo = cdi->ops; + struct cdrom_device_info *cdi = cdrom_find_device(dev); + struct cdrom_device_ops *cdo = cdi->ops; + int ret; /* the first few commands do not deal with audio drive_info, but only with routines in cdrom device operations. */ switch (cmd) { - /* maybe we should order cases after statistics of use? */ - case CDROMMULTISESSION: { - int ret; struct cdrom_multisession ms_info; u_char requested_format; cdinfo(CD_DO_IOCTL, "entering CDROMMULTISESSION\n"); @@ -741,7 +1433,6 @@ } case CDROMEJECT: { - int ret; cdinfo(CD_DO_IOCTL, "entering CDROMEJECT\n"); if (!CDROM_CAN(CDC_OPEN_TRAY)) return -ENOSYS; @@ -774,16 +1465,22 @@ } case CDROM_MEDIA_CHANGED: { + struct cdrom_changer_info info; + cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n"); if (!CDROM_CAN(CDC_MEDIA_CHANGED)) return -ENOSYS; - if (!CDROM_CAN(CDC_SELECT_DISC) - || arg == CDSL_CURRENT) + if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT) /* cannot select disc or select current disc */ return media_changed(cdi, 1); - if ((unsigned int)arg >= cdi->capacity) + if ((unsigned int)arg >= cdi->capacity) { return -EINVAL; - return cdo->media_changed (cdi, arg); + } + + if ((ret = cdrom_read_mech_status(cdi, &info))) + return ret; + + return info.slots[arg].change; } case CDROM_SET_OPTIONS: { @@ -824,16 +1521,29 @@ case CDROM_SELECT_DISC: { cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n"); - if (!(cdo->capability & ~cdi->mask & CDC_SELECT_DISC)) + if (!CDROM_CAN(CDC_SELECT_DISC)) return -ENOSYS; - if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE)) + + if ((arg != CDSL_CURRENT) && (arg != CDSL_NONE)) { + if ((int)arg >= cdi->capacity) + return -EINVAL; + } + /* cdo->select_disc is a hook to allow a driver-specific + * way of seleting disc. However, since there is no + * equiv hook for cdrom_slot_status this may not + * actually be useful... + */ + if (cdo->select_disc != NULL) return cdo->select_disc(cdi, arg); - if ((int)arg >= cdi->capacity) - return -EDRIVE_CANT_DO_THIS; - return cdo->select_disc(cdi, arg); + + /* no driver specific select_disc(), call our own */ + cdinfo(CD_CHANGER, "Using generic cdrom_select_disc()\n"); + return cdrom_select_disc(cdi, arg); } case CDROMRESET: { + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n"); if (!CDROM_CAN(CDC_RESET)) return -ENOSYS; @@ -841,7 +1551,7 @@ } case CDROM_LOCKDOOR: { - cdinfo(CD_DO_IOCTL, "%socking door.\n",arg?"L":"Unl"); + cdinfo(CD_DO_IOCTL, "%socking door.\n", arg ? "L" : "Unl"); if (!CDROM_CAN(CDC_LOCK)) return -EDRIVE_CANT_DO_THIS; keeplocked = arg ? 1 : 0; @@ -854,7 +1564,7 @@ case CDROM_DEBUG: { if (!capable(CAP_SYS_ADMIN)) return -EACCES; - cdinfo(CD_DO_IOCTL, "%sabling debug.\n",arg?"En":"Dis"); + cdinfo(CD_DO_IOCTL, "%sabling debug.\n", arg ? "En" : "Dis"); debug = arg ? 1 : 0; return debug; } @@ -870,10 +1580,9 @@ * is written on the CD is /not/ uniform across all discs! */ case CDROM_GET_MCN: { - int ret; struct cdrom_mcn mcn; cdinfo(CD_DO_IOCTL, "entering CDROM_GET_MCN\n"); - if (!CDROM_CAN(CDC_MCN)) + if (!(cdo->capability & CDC_MCN)) return -ENOSYS; if ((ret=cdo->get_mcn(cdi, &mcn))) return ret; @@ -884,13 +1593,15 @@ case CDROM_DRIVE_STATUS: { cdinfo(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n"); - if (!CDROM_CAN(CDC_DRIVE_STATUS)) + if (!(cdo->capability & CDC_DRIVE_STATUS)) return -ENOSYS; + if (!CDROM_CAN(CDC_SELECT_DISC)) + return cdo->drive_status(cdi, CDSL_CURRENT); if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE)) - return cdo->drive_status(cdi, arg); - if (((int)arg > cdi->capacity)) + return cdo->drive_status(cdi, CDSL_CURRENT); + if (((int)arg >= cdi->capacity)) return -EINVAL; - return cdo->drive_status(cdi, arg); + return cdrom_slot_status(cdi, arg); } /* Ok, this is where problems start. The current interface for the @@ -921,242 +1632,852 @@ if (tracks.audio > 0) { if (tracks.data==0 && tracks.cdi==0 && tracks.xa==0) return CDS_AUDIO; - else return CDS_MIXED; + else + return CDS_MIXED; } if (tracks.cdi > 0) return CDS_XA_2_2; if (tracks.xa > 0) return CDS_XA_2_1; if (tracks.data > 0) return CDS_DATA_1; /* Policy mode off */ - cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognise!\n"); + cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognize!\n"); return CDS_NO_INFO; } - case CDROM_CHANGER_NSLOTS: + case CDROM_CHANGER_NSLOTS: { cdinfo(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n"); - return cdi->capacity; + return cdi->capacity; + } + } -/* The following is not implemented, because there are too many - * different data types. We could support /1/ raw mode, that is large - * enough to hold everything. - */ + /* use the ioctls that are implemented through the generic_packet() + interface. this may look at bit funny, but if -ENOTTY is + returned that particular ioctl is not implemented and we + let it go through the device specific ones. */ + if (CDROM_CAN(CDC_GENERIC_PACKET)) { + ret = mmc_ioctl(cdi, cmd, arg); + if (ret != -ENOTTY) { + return ret; + } + } -#if 0 - case CDROMREADMODE1: { - int ret; + /* note: most of the cdinfo() calls are commented out here, + because they fill up the sys log when CD players poll + the drive. */ + switch (cmd) { + case CDROMSUBCHNL: { + struct cdrom_subchnl q; + u_char requested, back; + if (!CDROM_CAN(CDC_PLAY_AUDIO)) + return -ENOSYS; + /* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/ + IOCTL_IN(arg, struct cdrom_subchnl, q); + requested = q.cdsc_format; + if (!((requested == CDROM_MSF) || + (requested == CDROM_LBA))) + return -EINVAL; + q.cdsc_format = CDROM_MSF; + if ((ret=cdo->audio_ioctl(cdi, cmd, &q))) + return ret; + back = q.cdsc_format; /* local copy */ + sanitize_format(&q.cdsc_absaddr, &back, requested); + sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested); + IOCTL_OUT(arg, struct cdrom_subchnl, q); + /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ + return 0; + } + case CDROMREADTOCHDR: { + struct cdrom_tochdr header; + if (!CDROM_CAN(CDC_PLAY_AUDIO)) + return -ENOSYS; + /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */ + IOCTL_IN(arg, struct cdrom_tochdr, header); + if ((ret=cdo->audio_ioctl(cdi, cmd, &header))) + return ret; + IOCTL_OUT(arg, struct cdrom_tochdr, header); + /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */ + return 0; + } + case CDROMREADTOCENTRY: { + struct cdrom_tocentry entry; + u_char requested_format; + if (!CDROM_CAN(CDC_PLAY_AUDIO)) + return -ENOSYS; + /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */ + IOCTL_IN(arg, struct cdrom_tocentry, entry); + requested_format = entry.cdte_format; + if (!((requested_format == CDROM_MSF) || + (requested_format == CDROM_LBA))) + return -EINVAL; + /* make interface to low-level uniform */ + entry.cdte_format = CDROM_MSF; + if ((ret=cdo->audio_ioctl(cdi, cmd, &entry))) + return ret; + sanitize_format(&entry.cdte_addr, + &entry.cdte_format, requested_format); + IOCTL_OUT(arg, struct cdrom_tocentry, entry); + /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */ + return 0; + } + case CDROMPLAYMSF: { struct cdrom_msf msf; - char buf[CD_FRAMESIZE]; - cdinfo(CD_DO_IOCTL, "entering CDROMREADMODE1\n"); + if (!CDROM_CAN(CDC_PLAY_AUDIO)) + return -ENOSYS; + cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); IOCTL_IN(arg, struct cdrom_msf, msf); - if (ret=cdo->read_audio(dev, cmd, &msf, &buf, cdi)) + return cdo->audio_ioctl(cdi, cmd, &msf); + } + case CDROMPLAYTRKIND: { + struct cdrom_ti ti; + if (!CDROM_CAN(CDC_PLAY_AUDIO)) + return -ENOSYS; + cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); + IOCTL_IN(arg, struct cdrom_ti, ti); + CHECKAUDIO; + return cdo->audio_ioctl(cdi, cmd, &ti); + } + case CDROMVOLCTRL: { + struct cdrom_volctrl volume; + if (!CDROM_CAN(CDC_PLAY_AUDIO)) + return -ENOSYS; + cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n"); + IOCTL_IN(arg, struct cdrom_volctrl, volume); + return cdo->audio_ioctl(cdi, cmd, &volume); + } + case CDROMVOLREAD: { + struct cdrom_volctrl volume; + if (!CDROM_CAN(CDC_PLAY_AUDIO)) + return -ENOSYS; + cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n"); + if ((ret=cdo->audio_ioctl(cdi, cmd, &volume))) return ret; - IOCTL_OUT(arg, __typeof__(buf), buf); + IOCTL_OUT(arg, struct cdrom_volctrl, volume); return 0; } -#endif + case CDROMSTART: + case CDROMSTOP: + case CDROMPAUSE: + case CDROMRESUME: { + if (!CDROM_CAN(CDC_PLAY_AUDIO)) + return -ENOSYS; + cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n"); + CHECKAUDIO; + return cdo->audio_ioctl(cdi, cmd, NULL); + } } /* switch */ -/* Now all the audio-ioctls follow, they are all routed through the - same call audio_ioctl(). */ + /* do the device specific ioctls */ + if (CDROM_CAN(CDC_IOCTLS)) + return cdo->dev_ioctl(cdi, cmd, arg); + + return -ENOSYS; +} + +static inline +int msf_to_lba(char m, char s, char f) +{ + return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET; +} -#define CHECKAUDIO if ((ret=check_for_audio_disc(cdi, cdo))) return ret +static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, + unsigned long arg) +{ + struct cdrom_device_ops *cdo = cdi->ops; + struct cdrom_generic_command cgc; + kdev_t dev = cdi->dev; + char buffer[32]; + int ret = 0; + + memset(&cgc, 0, sizeof(cgc)); - if (!CDROM_CAN(CDC_PLAY_AUDIO)) - return -ENOSYS; - else { + /* build a unified command and queue it through + cdo->generic_packet() */ + switch (cmd) { + case CDROMREADRAW: + case CDROMREADMODE1: + case CDROMREADMODE2: { + struct cdrom_msf msf; + int blocksize = 0, format = 0, lba; + switch (cmd) { - case CDROMSUBCHNL: { - int ret; - struct cdrom_subchnl q; - u_char requested, back; - /* comment out the cdinfo calls here because they - fill up the sys logs when CD players poll the drive*/ - /* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/ - IOCTL_IN(arg, struct cdrom_subchnl, q); - requested = q.cdsc_format; - if (!((requested == CDROM_MSF) || - (requested == CDROM_LBA))) - return -EINVAL; - q.cdsc_format = CDROM_MSF; - if ((ret=cdo->audio_ioctl(cdi, cmd, &q))) - return ret; - back = q.cdsc_format; /* local copy */ - sanitize_format(&q.cdsc_absaddr, &back, requested); - sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested); - IOCTL_OUT(arg, struct cdrom_subchnl, q); - /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ - return 0; - } - case CDROMREADTOCHDR: { - int ret; - struct cdrom_tochdr header; - /* comment out the cdinfo calls here because they - fill up the sys logs when CD players poll the drive*/ - /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */ - IOCTL_IN(arg, struct cdrom_tochdr, header); - if ((ret=cdo->audio_ioctl(cdi, cmd, &header))) - return ret; - IOCTL_OUT(arg, struct cdrom_tochdr, header); - /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */ - return 0; - } - case CDROMREADTOCENTRY: { - int ret; - struct cdrom_tocentry entry; - u_char requested_format; - /* comment out the cdinfo calls here because they - fill up the sys logs when CD players poll the drive*/ - /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */ - IOCTL_IN(arg, struct cdrom_tocentry, entry); - requested_format = entry.cdte_format; - if (!((requested_format == CDROM_MSF) || - (requested_format == CDROM_LBA))) - return -EINVAL; - /* make interface to low-level uniform */ - entry.cdte_format = CDROM_MSF; - if ((ret=cdo->audio_ioctl(cdi, cmd, &entry))) - return ret; - sanitize_format(&entry.cdte_addr, - &entry.cdte_format, requested_format); - IOCTL_OUT(arg, struct cdrom_tocentry, entry); - /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */ - return 0; - } - case CDROMPLAYMSF: { - int ret; - struct cdrom_msf msf; - cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); - IOCTL_IN(arg, struct cdrom_msf, msf); - CHECKAUDIO; - return cdo->audio_ioctl(cdi, cmd, &msf); - } - case CDROMPLAYTRKIND: { - int ret; - struct cdrom_ti ti; - cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); - IOCTL_IN(arg, struct cdrom_ti, ti); - CHECKAUDIO; - return cdo->audio_ioctl(cdi, cmd, &ti); - } - case CDROMVOLCTRL: { - struct cdrom_volctrl volume; - cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n"); - IOCTL_IN(arg, struct cdrom_volctrl, volume); - return cdo->audio_ioctl(cdi, cmd, &volume); - } - case CDROMVOLREAD: { - int ret; - struct cdrom_volctrl volume; - cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n"); - if ((ret=cdo->audio_ioctl(cdi, cmd, &volume))) - return ret; - IOCTL_OUT(arg, struct cdrom_volctrl, volume); + case CDROMREADRAW: + blocksize = CD_FRAMESIZE_RAW; + break; + case CDROMREADMODE1: + blocksize = CD_FRAMESIZE; + format = 2; + break; + case CDROMREADMODE2: + blocksize = CD_FRAMESIZE_RAW0; + break; + } + IOCTL_IN(arg, struct cdrom_msf, msf); + lba = msf_to_lba(msf.cdmsf_min0,msf.cdmsf_sec0,msf.cdmsf_frame0); + /* FIXME: we need upper bound checking, too!! */ + if (lba < 0) + return -EINVAL; + cgc.buffer = (char *) kmalloc(blocksize, GFP_KERNEL); + if (cgc.buffer == NULL) + return -ENOMEM; + ret = cdrom_read_block(cdi, &cgc, lba, 1, format, blocksize); + if (!ret) + if (copy_to_user((char *)arg, cgc.buffer, blocksize)) + ret = -EFAULT; + kfree(cgc.buffer); + return ret; + } + case CDROMREADAUDIO: { + struct cdrom_read_audio ra; + int lba, frames; + + IOCTL_IN(arg, struct cdrom_read_audio, ra); + + 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; + + /* FIXME: we need upper bound checking, too!! */ + if (lba < 0) + return -EINVAL; + + /* do max 8 frames at the time */ + frames = ra.nframes > 8 ? 8 : ra.nframes; + + if ((cgc.buffer = (char *) kmalloc(CD_FRAMESIZE_RAW * frames, + GFP_KERNEL)) == NULL) + return -ENOMEM; + + if (!access_ok(VERIFY_WRITE, ra.buf, ra.nframes*CD_FRAMESIZE_RAW)) { + kfree(cgc.buffer); + return -EFAULT; + } + + while (ra.nframes > 0) { + ret = cdrom_read_block(cdi, &cgc, lba, frames, 1, + CD_FRAMESIZE_RAW); + if (ret) break; + __copy_to_user(ra.buf, cgc.buffer, + CD_FRAMESIZE_RAW * frames); + ra.buf += (CD_FRAMESIZE_RAW * frames); + ra.nframes -= frames; + lba += frames; + } + kfree(cgc.buffer); + return ret; + } + case CDROMSUBCHNL: { + struct cdrom_subchnl q; + u_char requested, back; + IOCTL_IN(arg, struct cdrom_subchnl, q); + requested = q.cdsc_format; + if (!((requested == CDROM_MSF) || + (requested == CDROM_LBA))) + return -EINVAL; + q.cdsc_format = CDROM_MSF; + if ((ret = cdrom_read_subchannel(cdi, &q, 0))) + return ret; + back = q.cdsc_format; /* local copy */ + sanitize_format(&q.cdsc_absaddr, &back, requested); + sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested); + IOCTL_OUT(arg, struct cdrom_subchnl, q); + /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ + return 0; + } + case CDROMPLAYTRKIND: { + struct cdrom_ti ti; + struct cdrom_tocentry entry; + struct cdrom_tochdr tochdr; + + cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); + IOCTL_IN(arg, struct cdrom_ti, ti); + entry.cdte_format = CDROM_MSF; + + /* get toc entry for start and end track */ + if (cdo->audio_ioctl(cdi, CDROMREADTOCHDR, &tochdr)) + return -EINVAL; + if ((entry.cdte_track = ti.cdti_trk0) > tochdr.cdth_trk1) + return -EINVAL; + if (cdo->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) + return -EINVAL; + + cgc.cmd[3] = entry.cdte_addr.msf.minute; + cgc.cmd[4] = entry.cdte_addr.msf.second; + cgc.cmd[5] = entry.cdte_addr.msf.frame; + + entry.cdte_track = ti.cdti_trk1 + 1; + if (entry.cdte_track > tochdr.cdth_trk1) + entry.cdte_track = CDROM_LEADOUT; + + if (cdo->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) + return -EINVAL; + + cgc.cmd[6] = entry.cdte_addr.msf.minute; + cgc.cmd[7] = entry.cdte_addr.msf.second; + cgc.cmd[8] = entry.cdte_addr.msf.frame; + cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF; + return cdo->generic_packet(cdi, &cgc); + } + case CDROMPLAYMSF: { + struct cdrom_msf msf; + cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); + IOCTL_IN(arg, struct cdrom_msf, msf); + cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF; + cgc.cmd[3] = msf.cdmsf_min0; + cgc.cmd[4] = msf.cdmsf_sec0; + cgc.cmd[5] = msf.cdmsf_frame0; + cgc.cmd[6] = msf.cdmsf_min1; + cgc.cmd[7] = msf.cdmsf_sec1; + cgc.cmd[8] = msf.cdmsf_frame1; + return cdo->generic_packet(cdi, &cgc); + } + case CDROMPLAYBLK: { + struct cdrom_blk blk; + cdinfo(CD_DO_IOCTL, "entering CDROMPLAYBLK\n"); + IOCTL_IN(arg, struct cdrom_blk, blk); + cgc.cmd[0] = GPCMD_PLAY_AUDIO_10; + cgc.cmd[2] = (blk.from >> 24) & 0xff; + cgc.cmd[3] = (blk.from >> 16) & 0xff; + cgc.cmd[4] = (blk.from >> 8) & 0xff; + cgc.cmd[5] = blk.from & 0xff; + cgc.cmd[7] = (blk.len >> 8) & 0xff; + cgc.cmd[8] = blk.len & 0xff; + return cdo->generic_packet(cdi, &cgc); + } + case CDROMVOLCTRL: + case CDROMVOLREAD: { + struct cdrom_volctrl volctrl; + char mask[32]; + unsigned short offset; + cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n"); + + IOCTL_IN(arg, struct cdrom_volctrl, volctrl); + + cgc.buffer = buffer; + cgc.buflen = 24; + if ((ret = cdrom_mode_sense(cdi, &cgc, GPMODE_AUDIO_CTL_PAGE, 0))) + return ret; + + /* some drives have longer pages, adjust and reread. */ + if (buffer[1] > cgc.buflen) { + cgc.buflen = buffer[1] + 2; + if ((ret = cdrom_mode_sense(cdi, &cgc, + GPMODE_AUDIO_CTL_PAGE, 0))) + return ret; + } + + /* get the offset from the length of the page. length + is measure from byte 2 an on, thus the 14. */ + offset = buffer[1] - 14; + + /* now we have the current volume settings. if it was only + a CDROMVOLREAD, return these values */ + if (cmd == CDROMVOLREAD) { + volctrl.channel0 = buffer[offset+9]; + volctrl.channel1 = buffer[offset+11]; + volctrl.channel2 = buffer[offset+13]; + volctrl.channel3 = buffer[offset+15]; + IOCTL_OUT(arg, struct cdrom_volctrl, volctrl); return 0; + } + + /* get the volume mask */ + cgc.buffer = mask; + if ((ret = cdrom_mode_sense(cdi, &cgc, + GPMODE_AUDIO_CTL_PAGE, 1))) + return ret; + + buffer[offset+9] = volctrl.channel0 & mask[offset+9]; + buffer[offset+11] = volctrl.channel1 & mask[offset+11]; + buffer[offset+13] = volctrl.channel2 & mask[offset+13]; + buffer[offset+15] = volctrl.channel3 & mask[offset+15]; + + /* set volume */ + cgc.buffer = buffer; + return cdrom_mode_select(cdi, &cgc); + } + + case CDROMSTART: + case CDROMSTOP: { + cdinfo(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n"); + cgc.cmd[0] = GPCMD_START_STOP_UNIT; + cgc.cmd[1] = 1; + cgc.cmd[4] = (cmd == CDROMSTART) ? 1 : 0; + return cdo->generic_packet(cdi, &cgc); + } + + case CDROMPAUSE: + case CDROMRESUME: { + cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); + cgc.cmd[0] = GPCMD_PAUSE_RESUME; + cgc.cmd[8] = (cmd == CDROMRESUME) ? 1 : 0; + return cdo->generic_packet(cdi, &cgc); + } + + case DVD_READ_STRUCT: { + dvd_struct *s; + int size = sizeof(dvd_struct); + if (!CDROM_CAN(CDC_DVD)) + return -ENOSYS; + if ((s = (dvd_struct *) kmalloc(size, GFP_KERNEL)) == NULL) + return -ENOMEM; + cdinfo(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n"); + if (copy_from_user(s, (dvd_struct *)arg, size)) { + kfree(s); + return -EFAULT; + } + if ((ret = dvd_read_struct(cdi, s))) { + kfree(s); + return ret; + } + if (copy_to_user((dvd_struct *)arg, s, size)) + ret = -EFAULT; + kfree(s); + return ret; + } + + case DVD_AUTH: { + dvd_authinfo ai; + if (!CDROM_CAN(CDC_DVD)) + return -ENOSYS; + cdinfo(CD_DO_IOCTL, "entering DVD_AUTH\n"); + IOCTL_IN(arg, dvd_authinfo, ai); + if ((ret = dvd_do_auth (cdi, &ai))) + return ret; + IOCTL_OUT(arg, dvd_authinfo, ai); + return 0; + } + + case CDROM_SEND_PACKET: { + __u8 *userbuf, copy = 0; + struct request_sense *sense; + if (!CDROM_CAN(CDC_GENERIC_PACKET)) + return -ENOSYS; + cdinfo(CD_DO_IOCTL, "entering CDROM_SEND_PACKET\n"); + IOCTL_IN(arg, struct cdrom_generic_command, cgc); + copy = !!cgc.buflen; + userbuf = cgc.buffer; + cgc.buffer = NULL; + sense = cgc.sense; + if (userbuf != NULL && copy) { + /* usually commands just copy data one way, i.e. + * we send a buffer to the drive and the command + * specifies whether the drive will read or + * write to that buffer. usually the buffers + * are very small, so we don't loose that much + * by doing a redundant copy each time. */ + if (!access_ok(VERIFY_WRITE, userbuf, cgc.buflen)) { + printk("can't get write perms\n"); + return -EFAULT; } - case CDROMSTART: - case CDROMSTOP: - case CDROMPAUSE: - case CDROMRESUME: { - int ret; - cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n"); - CHECKAUDIO; - return cdo->audio_ioctl(cdi, cmd, NULL); + if (!access_ok(VERIFY_READ, userbuf, cgc.buflen)) { + printk("can't get read perms\n"); + return -EFAULT; } - } /* switch */ + } + /* reasonable limits */ + if (cgc.buflen < 0 || cgc.buflen > 131072) { + printk("invalid size given\n"); + return -EINVAL; + } + if (copy) { + cgc.buffer = kmalloc(cgc.buflen, GFP_KERNEL); + if (cgc.buffer == NULL) + return -ENOMEM; + __copy_from_user(cgc.buffer, userbuf, cgc.buflen); + } + ret = cdo->generic_packet(cdi, &cgc); + if (copy && !ret) + __copy_to_user(userbuf, cgc.buffer, cgc.buflen); + /* copy back sense data */ + if (sense != NULL) + if (copy_to_user(sense, cgc.sense, sizeof(struct request_sense))) + ret = -EFAULT; + kfree(cgc.buffer); + return ret; + } + case CDROM_NEXT_WRITABLE: { + long next = 0; + cdinfo(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n"); + if ((ret = cdrom_get_next_writable(dev, &next))) + return ret; + IOCTL_OUT(arg, long, next); + return 0; + } + case CDROM_LAST_WRITTEN: { + long last = 0; + cdinfo(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n"); + if ((ret = cdrom_get_last_written(dev, &last))) + return ret; + IOCTL_OUT(arg, long, last); + return 0; + } + } /* switch */ + + return -ENOTTY; +} + +static int cdrom_get_track_info(kdev_t dev, __u16 track, __u8 type, + track_information *ti) +{ + struct cdrom_device_info *cdi = cdrom_find_device(dev); + struct cdrom_device_ops *cdo = cdi->ops; + struct cdrom_generic_command cgc; + int ret; + + init_cdrom_command(&cgc, ti, 8); + cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO; + cgc.cmd[1] = type & 3; + cgc.cmd[4] = (track & 0xff00) >> 8; + cgc.cmd[5] = track & 0xff; + cgc.cmd[8] = 8; + + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + cgc.cmd[8] = cgc.buflen = be16_to_cpu(ti->track_information_length) + + sizeof(ti->track_information_length); + return cdo->generic_packet(cdi, &cgc); +} + +static int cdrom_get_disc_info(kdev_t dev, disc_information *di) +{ + struct cdrom_device_info *cdi = cdrom_find_device(dev); + struct cdrom_device_ops *cdo = cdi->ops; + struct cdrom_generic_command cgc; + int ret; + + /* set up command and get the disc info */ + init_cdrom_command(&cgc, di, sizeof(*di)); + cgc.cmd[0] = GPCMD_READ_DISC_INFO; + cgc.cmd[8] = cgc.buflen = 2; + + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + /* not all drives have the same disc_info length, so requeue + * packet with the length the drive tells us it can supply + */ + cgc.buflen = be16_to_cpu(di->disc_information_length) + + sizeof(di->disc_information_length); + + if (cgc.buflen > sizeof(disc_information)) + cgc.buflen = sizeof(disc_information); + + cgc.cmd[8] = cgc.buflen; + + return cdo->generic_packet(cdi, &cgc); +} + + +/* return the last written block on the CD-R media. this is for the udf + file system. */ +int cdrom_get_last_written(kdev_t dev, long *last_written) +{ + struct cdrom_device_info *cdi = cdrom_find_device(dev); + struct cdrom_tocentry toc; + disc_information di; + track_information ti; + __u32 last_track; + int ret = -1; + + if (!CDROM_CAN(CDC_GENERIC_PACKET)) + goto use_toc; + + if ((ret = cdrom_get_disc_info(dev, &di))) + goto use_toc; + + last_track = (di.last_track_msb << 8) | di.last_track_lsb; + if ((ret = cdrom_get_track_info(dev, last_track, 1, &ti))) + goto use_toc; + + /* if this track is blank, try the previous. */ + if (ti.blank) { + last_track--; + if ((ret = cdrom_get_track_info(dev, last_track, 1, &ti))) + goto use_toc; } - /* device specific ioctls? */ - if (!(cdo->capability & CDC_IOCTLS)) - return -ENOSYS; - else - return cdo->dev_ioctl(cdi, cmd, arg); + /* if last recorded field is valid, return it. */ + if (ti.lra_v) { + *last_written = be32_to_cpu(ti.last_rec_address); + } else { + /* make it up instead */ + *last_written = be32_to_cpu(ti.track_start) + + be32_to_cpu(ti.track_size); + if (ti.free_blocks) + *last_written -= (be32_to_cpu(ti.free_blocks) + 7); + } + return 0; + + /* this is where we end up if the drive either can't do a + GPCMD_READ_DISC_INFO or GPCMD_READ_TRACK_RZONE_INFO or if + it fails. then we return the toc contents. */ +use_toc: + toc.cdte_format = CDROM_MSF; + toc.cdte_track = CDROM_LEADOUT; + if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &toc)) + return ret; + sanitize_format(&toc.cdte_addr, &toc.cdte_format, CDROM_LBA); + *last_written = toc.cdte_addr.lba; + return 0; } +/* return the next writable block. also for udf file system. */ +int cdrom_get_next_writable(kdev_t dev, long *next_writable) +{ + struct cdrom_device_info *cdi = cdrom_find_device(dev); + disc_information di; + track_information ti; + __u16 last_track; + int ret = -1; + + if (!CDROM_CAN(CDC_GENERIC_PACKET)) + goto use_last_written; + + if ((ret = cdrom_get_disc_info(dev, &di))) + goto use_last_written; + + last_track = (di.last_track_msb << 8) | di.last_track_lsb; + if ((ret = cdrom_get_track_info(dev, last_track, 1, &ti))) + goto use_last_written; + + /* if this track is blank, try the previous. */ + if (ti.blank) { + last_track--; + if ((ret = cdrom_get_track_info(dev, last_track, 1, &ti))) + goto use_last_written; + } + + /* if next recordable address field is valid, use it. */ + if (ti.nwa_v) + *next_writable = be32_to_cpu(ti.next_writable); + else + goto use_last_written; + + return 0; + +use_last_written: + if ((ret = cdrom_get_last_written(dev, next_writable))) { + *next_writable = 0; + return ret; + } else { + *next_writable += 7; + return 0; + } +} + +EXPORT_SYMBOL(cdrom_get_next_writable); +EXPORT_SYMBOL(cdrom_get_last_written); EXPORT_SYMBOL(cdrom_count_tracks); EXPORT_SYMBOL(register_cdrom); EXPORT_SYMBOL(unregister_cdrom); EXPORT_SYMBOL(cdrom_fops); +EXPORT_SYMBOL(cdrom_number_of_slots); +EXPORT_SYMBOL(cdrom_select_disc); +EXPORT_SYMBOL(cdrom_mode_select); +EXPORT_SYMBOL(cdrom_mode_sense); +EXPORT_SYMBOL(init_cdrom_command); #ifdef CONFIG_SYSCTL #define CDROM_STR_SIZE 1000 -static char cdrom_drive_info[CDROM_STR_SIZE]="info\n"; +struct cdrom_sysctl_settings { + char info[CDROM_STR_SIZE]; /* general info */ + int autoclose; /* close tray upon mount, etc */ + int autoeject; /* eject on umount */ + int debug; /* turn on debugging messages */ + int lock; /* lock the door on device open */ + int check; /* check media type */ +} cdrom_sysctl_settings; int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp) { int pos; struct cdrom_device_info *cdi; - char *info = cdrom_drive_info; + char *info = cdrom_sysctl_settings.info; if (!*lenp || (filp->f_pos && !write)) { *lenp = 0; return 0; } - pos = sprintf(cdrom_drive_info, "CD-ROM information, " VERSION "\n"); + pos = sprintf(info, "CD-ROM information, " VERSION "\n"); - pos += sprintf(cdrom_drive_info+pos, "\ndrive name:\t"); + pos += sprintf(info+pos, "\ndrive name:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(info+pos, "\t%s", cdi->name); - pos += sprintf(cdrom_drive_info+pos, "\ndrive speed:\t"); + pos += sprintf(info+pos, "\ndrive speed:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(info+pos, "\t%d", cdi->speed); - pos += sprintf(cdrom_drive_info+pos, "\ndrive # of slots:"); + pos += sprintf(info+pos, "\ndrive # of slots:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(info+pos, "\t%d", cdi->capacity); - pos += sprintf(cdrom_drive_info+pos, "\nCan close tray:\t"); + pos += sprintf(info+pos, "\nCan close tray:\t"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CLOSE_TRAY) != 0); + + pos += sprintf(info+pos, "\nCan open tray:\t"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_OPEN_TRAY) != 0); + + pos += sprintf(info+pos, "\nCan lock tray:\t"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_LOCK) != 0); + + pos += sprintf(info+pos, "\nCan change speed:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CLOSE_TRAY)!=0); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_SPEED) != 0); - pos += sprintf(cdrom_drive_info+pos, "\nCan open tray:\t"); + pos += sprintf(info+pos, "\nCan select disk:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_OPEN_TRAY)!=0); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_DISC) != 0); - pos += sprintf(cdrom_drive_info+pos, "\nCan lock tray:\t"); + pos += sprintf(info+pos, "\nCan read multisession:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_LOCK)!=0); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MULTI_SESSION) != 0); - pos += sprintf(cdrom_drive_info+pos, "\nCan change speed:"); + pos += sprintf(info+pos, "\nCan read MCN:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_SPEED)!=0); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MCN) != 0); - pos += sprintf(cdrom_drive_info+pos, "\nCan select disk:"); + pos += sprintf(info+pos, "\nReports media changed:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_DISC)!=0); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MEDIA_CHANGED) != 0); - pos += sprintf(cdrom_drive_info+pos, "\nCan read multisession:"); + pos += sprintf(info+pos, "\nCan play audio:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MULTI_SESSION)!=0); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_PLAY_AUDIO) != 0); - pos += sprintf(cdrom_drive_info+pos, "\nCan read MCN:\t"); + pos += sprintf(info+pos, "\nCan write CD-R:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MCN)!=0); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_R) != 0); - pos += sprintf(cdrom_drive_info+pos, "\nReports media changed:"); + pos += sprintf(info+pos, "\nCan write CD-RW:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MEDIA_CHANGED)!=0); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_RW) != 0); - pos += sprintf(cdrom_drive_info+pos, "\nCan play audio:\t"); + pos += sprintf(info+pos, "\nCan read DVD:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_PLAY_AUDIO)!=0); + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD) != 0); - strcpy(info+pos,"\n\n"); - pos += 3; - if (*lenp > pos) - *lenp = pos; + pos += sprintf(info+pos, "\nCan write DVD-R:"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_R) != 0); + + pos += sprintf(info+pos, "\nCan write DVD-RAM:"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_RAM) != 0); + + strcpy(info+pos,"\n\n"); return proc_dostring(ctl, write, filp, buffer, lenp); } +/* Unfortunately, per device settings are not implemented through + procfs/sysctl yet. When they are, this will naturally disappear. For now + just update all drives. Later this will become the template on which + new registered drives will be based. */ +void cdrom_update_settings(void) +{ + struct cdrom_device_info *cdi; + + for (cdi = topCdromPtr; cdi != NULL; cdi = cdi->next) { + if (autoclose && CDROM_CAN(CDC_CLOSE_TRAY)) + cdi->options |= CDO_AUTO_CLOSE; + else if (!autoclose) + cdi->options &= ~CDO_AUTO_CLOSE; + if (autoeject && CDROM_CAN(CDC_OPEN_TRAY)) + cdi->options |= CDO_AUTO_EJECT; + else if (!autoeject) + cdi->options &= ~CDO_AUTO_EJECT; + if (lockdoor && CDROM_CAN(CDC_LOCK)) + cdi->options |= CDO_LOCK; + else if (!lockdoor) + cdi->options &= ~CDO_LOCK; + if (check_media_type) + cdi->options |= CDO_CHECK_TYPE; + else + cdi->options &= ~CDO_CHECK_TYPE; + } +} + +static int cdrom_sysctl_handler(ctl_table *ctl, int write, struct file * filp, + void *buffer, size_t *lenp) +{ + int *valp = ctl->data; + int val = *valp; + int ret; + + ret = proc_dointvec(ctl, write, filp, buffer, lenp); + + if (write && *valp != val) { + + /* we only care for 1 or 0. */ + if (*valp) + *valp = 1; + else + *valp = 0; + + switch (ctl->ctl_name) { + case DEV_CDROM_AUTOCLOSE: { + if (valp == &cdrom_sysctl_settings.autoclose) + autoclose = cdrom_sysctl_settings.autoclose; + break; + } + case DEV_CDROM_AUTOEJECT: { + if (valp == &cdrom_sysctl_settings.autoeject) + autoeject = cdrom_sysctl_settings.autoeject; + break; + } + case DEV_CDROM_DEBUG: { + if (valp == &cdrom_sysctl_settings.debug) + debug = cdrom_sysctl_settings.debug; + break; + } + case DEV_CDROM_LOCK: { + if (valp == &cdrom_sysctl_settings.lock) + lockdoor = cdrom_sysctl_settings.lock; + break; + } + case DEV_CDROM_CHECK_MEDIA: { + if (valp == &cdrom_sysctl_settings.check) + check_media_type = cdrom_sysctl_settings.check; + break; + } + } + /* update the option flags according to the changes. we + don't have per device options through sysctl yet, + but we will have and then this will disappear. */ + cdrom_update_settings(); + } + + return ret; +} + /* Place files in /proc/sys/dev/cdrom */ ctl_table cdrom_table[] = { - {DEV_CDROM_INFO, "info", &cdrom_drive_info, + {DEV_CDROM_INFO, "info", &cdrom_sysctl_settings.info, CDROM_STR_SIZE, 0444, NULL, &cdrom_sysctl_info}, + {DEV_CDROM_AUTOCLOSE, "autoclose", &cdrom_sysctl_settings.autoclose, + sizeof(int), 0644, NULL, &cdrom_sysctl_handler }, + {DEV_CDROM_AUTOEJECT, "autoeject", &cdrom_sysctl_settings.autoeject, + sizeof(int), 0644, NULL, &cdrom_sysctl_handler }, + {DEV_CDROM_DEBUG, "debug", &cdrom_sysctl_settings.debug, + sizeof(int), 0644, NULL, &cdrom_sysctl_handler }, + {DEV_CDROM_LOCK, "lock", &cdrom_sysctl_settings.lock, + sizeof(int), 0644, NULL, &cdrom_sysctl_handler }, + {DEV_CDROM_CHECK_MEDIA, "check_media", &cdrom_sysctl_settings.check, + sizeof(int), 0644, NULL, &cdrom_sysctl_handler }, {0} }; @@ -1200,24 +2521,31 @@ cdrom_sysctl_header = register_sysctl_table(cdrom_root_table, 1); cdrom_root_table->child->de->fill_inode = &cdrom_procfs_modcount; + /* set the defaults */ + cdrom_sysctl_settings.autoclose = autoclose; + cdrom_sysctl_settings.autoeject = autoeject; + cdrom_sysctl_settings.debug = debug; + cdrom_sysctl_settings.lock = lockdoor; + cdrom_sysctl_settings.check = check_media_type; + initialized = 1; } +#endif /* endif CONFIG_SYSCTL */ + #ifdef MODULE static void cdrom_sysctl_unregister(void) { +#ifdef CONFIG_SYSCTL unregister_sysctl_table(cdrom_sysctl_header); +#endif } -#endif /* endif MODULE */ -#endif /* endif CONFIG_SYSCTL */ - -#ifdef MODULE int init_module(void) { #ifdef CONFIG_SYSCTL cdrom_sysctl_register(); -#endif /* CONFIG_SYSCTL */ +#endif return 0; } @@ -1228,14 +2556,5 @@ cdrom_sysctl_unregister(); #endif /* CONFIG_SYSCTL */ } - #endif /* endif MODULE */ - - -/* - * Local variables: - * comment-column: 40 - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DCPU=486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o cdrom.o cdrom.c" - * End: - */ diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c --- linux-2.2.15/drivers/scsi/ide-scsi.c Thu May 4 15:21:22 2000 +++ linux/drivers/scsi/ide-scsi.c Thu May 4 01:19:23 2000 @@ -364,7 +364,7 @@ pc->actually_transferred += temp; pc->current_position += temp; idescsi_discard_data (drive,bcount - temp); - ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc)); + ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL); return ide_started; } #if IDESCSI_DEBUG_LOG @@ -388,7 +388,7 @@ pc->actually_transferred+=bcount; /* Update the current position */ pc->current_position+=bcount; - ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc)); /* And set the interrupt handler again */ + ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL); /* And set the interrupt handler again */ return ide_started; } @@ -408,7 +408,7 @@ printk (KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while issuing a packet command\n"); return ide_do_reset (drive); } - ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc)); /* Set the interrupt routine */ + ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL); /* Set the interrupt routine */ atapi_output_bytes (drive, scsi->pc->c, 12); /* Send the actual packet */ return ide_started; } @@ -442,7 +442,7 @@ (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); } if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) { - ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc)); + ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc), NULL); OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */ return ide_started; } else { diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- linux-2.2.15/drivers/scsi/sr.c Thu May 4 15:21:22 2000 +++ linux/drivers/scsi/sr.c Thu May 4 01:19:23 2000 @@ -1,25 +1,28 @@ /* * sr.c Copyright (C) 1992 David Giller - * Copyright (C) 1993, 1994, 1995 Eric Youngdale + * Copyright (C) 1993, 1994, 1995 Eric Youngdale * * adapted from: - * sd.c Copyright (C) 1992 Drew Eckhardt - * Linux scsi disk driver by - * Drew Eckhardt + * sd.c Copyright (C) 1992 Drew Eckhardt + * Linux scsi disk driver by + * Drew Eckhardt * * Modified by Eric Youngdale ericy@cais.com to * add scatter-gather, multiple outstanding request, and other * enhancements. * - * Modified by Eric Youngdale eric@aib.com to support loadable - * low-level scsi drivers. + * Modified by Eric Youngdale eric@aib.com to support loadable + * low-level scsi drivers. * - * Modified by Thomas Quinot thomas@melchior.cuivre.fdn.fr to - * provide auto-eject. + * Modified by Thomas Quinot thomas@melchior.cuivre.fdn.fr to + * provide auto-eject. * * Modified by Gerd Knorr to support the * generic cdrom interface * + * Modified by Jens Axboe - Uniform sr_packet() + * interface, capabilities probe additions, ioctl cleanups, etc. + * */ #include @@ -34,19 +37,22 @@ #include #include #include +#include #define MAJOR_NR SCSI_CDROM_MAJOR #include #include "scsi.h" #include "hosts.h" #include "sr.h" -#include /* For the door lock/unlock commands */ +#include /* For the door lock/unlock commands */ #include "constants.h" -MODULE_PARM(xa_test,"i"); /* see sr_ioctl.c */ +#ifdef MODULE +MODULE_PARM(xa_test, "i"); /* see sr_ioctl.c */ +#endif -#define MAX_RETRIES 3 -#define SR_TIMEOUT (30 * HZ) +#define MAX_RETRIES 3 +#define SR_TIMEOUT (30 * HZ) static int sr_init(void); static void sr_finish(void); @@ -54,53 +60,60 @@ static int sr_detect(Scsi_Device *); static void sr_detach(Scsi_Device *); -struct Scsi_Device_Template sr_template = {NULL, "cdrom", "sr", NULL, TYPE_ROM, - SCSI_CDROM_MAJOR, 0, 0, 0, 1, - sr_detect, sr_init, - sr_finish, sr_attach, sr_detach}; +struct Scsi_Device_Template sr_template = { + NULL, "cdrom", "sr", NULL, TYPE_ROM, + SCSI_CDROM_MAJOR, 0, 0, 0, 1, + sr_detect, sr_init, + sr_finish, sr_attach, sr_detach +}; -Scsi_CD * scsi_CDs = NULL; -static int * sr_sizes = NULL; +Scsi_CD *scsi_CDs = NULL; +static int *sr_sizes = NULL; -static int * sr_blocksizes = NULL; +static int *sr_blocksizes = NULL; -static int sr_open(struct cdrom_device_info*, int); +static int sr_open(struct cdrom_device_info *, int); void get_sectorsize(int); void get_capabilities(int); -void requeue_sr_request (Scsi_Cmnd * SCpnt); -static int sr_media_change(struct cdrom_device_info*, int); +void requeue_sr_request(Scsi_Cmnd * SCpnt); +static int sr_media_change(struct cdrom_device_info *, int); +static int sr_packet(struct cdrom_device_info *, struct cdrom_generic_command *); static void sr_release(struct cdrom_device_info *cdi) { if (scsi_CDs[MINOR(cdi->dev)].sector_size > 2048) - sr_set_blocklength(MINOR(cdi->dev),2048); + sr_set_blocklength(MINOR(cdi->dev), 2048); sync_dev(cdi->dev); scsi_CDs[MINOR(cdi->dev)].device->access_count--; if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module) __MOD_DEC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module); - if(sr_template.module) - __MOD_DEC_USE_COUNT(sr_template.module); + if (sr_template.module) + __MOD_DEC_USE_COUNT(sr_template.module); } -static struct cdrom_device_ops sr_dops = { - sr_open, /* open */ - sr_release, /* release */ - sr_drive_status, /* drive status */ - sr_media_change, /* media changed */ - sr_tray_move, /* tray move */ - sr_lock_door, /* lock door */ - sr_select_speed, /* select speed */ - NULL, /* select disc */ - sr_get_last_session, /* get last session */ - sr_get_mcn, /* get universal product code */ - sr_reset, /* hard reset */ - sr_audio_ioctl, /* audio ioctl */ - sr_dev_ioctl, /* device-specific ioctl */ - CDC_CLOSE_TRAY | CDC_OPEN_TRAY| CDC_LOCK | CDC_SELECT_SPEED | - CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | - CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS, - 0 +static struct cdrom_device_ops sr_dops = +{ + sr_open, /* open */ + sr_release, /* release */ + sr_drive_status, /* drive status */ + sr_media_change, /* media changed */ + sr_tray_move, /* tray move */ + sr_lock_door, /* lock door */ + sr_select_speed, /* select speed */ + NULL, /* select disc */ + sr_get_last_session, /* get last session */ + sr_get_mcn, /* get universal product code */ + sr_reset, /* hard reset */ + sr_audio_ioctl, /* audio ioctl */ + sr_dev_ioctl, /* device-specific ioctl */ + CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | + CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | + CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS | + CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | + CDC_GENERIC_PACKET, + 0, + sr_packet }; /* @@ -113,48 +126,47 @@ * an inode for that to work, and we do not always have one. */ -int sr_media_change(struct cdrom_device_info *cdi, int slot){ +int sr_media_change(struct cdrom_device_info *cdi, int slot) +{ int retval; - if (CDSL_CURRENT != slot) { - /* no changer support */ - return -EINVAL; - } - + if (CDSL_CURRENT != slot) { + /* no changer support */ + return -EINVAL; + } retval = scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device, - SCSI_IOCTL_TEST_UNIT_READY, 0); + SCSI_IOCTL_TEST_UNIT_READY, 0); - if(retval) - { - /* Unable to test, unit probably not ready. This usually + if (retval) { + /* Unable to test, unit probably not ready. This usually * means there is no disc in the drive. Mark as changed, * and we will figure it out later once the drive is * available again. */ - scsi_CDs[MINOR(cdi->dev)].device->changed = 1; - return 1; /* This will force a flush, if called from - * check_disk_change */ + scsi_CDs[MINOR(cdi->dev)].device->changed = 1; + return 1; /* This will force a flush, if called from + * check_disk_change */ }; retval = scsi_CDs[MINOR(cdi->dev)].device->changed; - scsi_CDs[MINOR(cdi->dev)].device->changed = 0; - /* If the disk changed, the capacity will now be different, - * so we force a re-read of this information */ - if (retval) { + scsi_CDs[MINOR(cdi->dev)].device->changed = 0; + /* If the disk changed, the capacity will now be different, + * so we force a re-read of this information */ + if (retval) { /* check multisession offset etc */ - sr_cd_check(cdi); - - /* - * If the disk changed, the capacity will now be different, - * so we force a re-read of this information - * Force 2048 for the sector size so that filesystems won't - * be trying to use something that is too small if the disc - * has changed. - */ - scsi_CDs[MINOR(cdi->dev)].needs_sector_size = 1; + sr_cd_check(cdi); + + /* + * If the disk changed, the capacity will now be different, + * so we force a re-read of this information + * Force 2048 for the sector size so that filesystems won't + * be trying to use something that is too small if the disc + * has changed. + */ + scsi_CDs[MINOR(cdi->dev)].needs_sector_size = 1; - scsi_CDs[MINOR(cdi->dev)].sector_size = 2048; - } + scsi_CDs[MINOR(cdi->dev)].sector_size = 2048; + } return retval; } @@ -163,7 +175,7 @@ * end of a SCSI read / write, and will take on of several actions based on success or failure. */ -static void rw_intr (Scsi_Cmnd * SCpnt) +static void rw_intr(Scsi_Cmnd * SCpnt) { int result = SCpnt->result; int this_count = SCpnt->this_count; @@ -171,137 +183,130 @@ int block_sectors = 0; #ifdef DEBUG - printk("sr.c done: %x %x\n",result, SCpnt->request.bh->b_data); + printk("sr.c done: %x %x\n", result, SCpnt->request.bh->b_data); #endif - /* - Handle MEDIUM ERRORs or VOLUME OVERFLOWs that indicate partial success. - Since this is a relatively rare error condition, no care is taken to - avoid unnecessary additional work such as memcpy's that could be avoided. - */ + /* + Handle MEDIUM ERRORs or VOLUME OVERFLOWs that indicate partial success. + Since this is a relatively rare error condition, no care is taken to + avoid unnecessary additional work such as memcpy's that could be avoided. + */ - if (driver_byte(result) != 0 && /* An error occurred */ - SCpnt->sense_buffer[0] == 0xF0 && /* Sense data is valid */ + if (driver_byte(result) != 0 && /* An error occurred */ + SCpnt->sense_buffer[0] == 0xF0 && /* Sense data is valid */ (SCpnt->sense_buffer[2] == MEDIUM_ERROR || SCpnt->sense_buffer[2] == VOLUME_OVERFLOW || - SCpnt->sense_buffer[2] == ILLEGAL_REQUEST)) - { - long error_sector = (SCpnt->sense_buffer[3] << 24) | - (SCpnt->sense_buffer[4] << 16) | - (SCpnt->sense_buffer[5] << 8) | - SCpnt->sense_buffer[6]; - int device_nr = DEVICE_NR(SCpnt->request.rq_dev); - if (SCpnt->request.bh != NULL) - block_sectors = SCpnt->request.bh->b_size >> 9; - if (block_sectors < 4) block_sectors = 4; - if (scsi_CDs[device_nr].sector_size == 2048) - error_sector <<= 2; - error_sector &= ~ (block_sectors - 1); - good_sectors = error_sector - SCpnt->request.sector; - if (good_sectors < 0 || good_sectors >= this_count) - good_sectors = 0; - /* - The SCSI specification allows for the value returned by READ - CAPACITY to be up to 75 2K sectors past the last readable - block. Therefore, if we hit a medium error within the last - 75 2K sectors, we decrease the saved size value. - */ - if ((error_sector >> 1) < sr_sizes[device_nr] && - scsi_CDs[device_nr].capacity - error_sector < 4*75) - sr_sizes[device_nr] = error_sector >> 1; - } - - if (good_sectors > 0) - { /* Some sectors were read successfully. */ - if (SCpnt->use_sg == 0) { - if (SCpnt->buffer != SCpnt->request.buffer) - { - int offset; - offset = (SCpnt->request.sector % 4) << 9; - memcpy((char *)SCpnt->request.buffer, - (char *)SCpnt->buffer + offset, - good_sectors << 9); - /* Even though we are not using scatter-gather, we look - * ahead and see if there is a linked request for the - * other half of this buffer. If there is, then satisfy - * it. */ - if((offset == 0) && good_sectors == 2 && - SCpnt->request.nr_sectors > good_sectors && - SCpnt->request.bh && - SCpnt->request.bh->b_reqnext && - SCpnt->request.bh->b_reqnext->b_size == 1024) { - memcpy((char *)SCpnt->request.bh->b_reqnext->b_data, - (char *)SCpnt->buffer + 1024, - 1024); - good_sectors += 2; - }; + SCpnt->sense_buffer[2] == ILLEGAL_REQUEST)) { + long error_sector = (SCpnt->sense_buffer[3] << 24) | + (SCpnt->sense_buffer[4] << 16) | + (SCpnt->sense_buffer[5] << 8) | + SCpnt->sense_buffer[6]; + int device_nr = DEVICE_NR(SCpnt->request.rq_dev); + if (SCpnt->request.bh != NULL) + block_sectors = SCpnt->request.bh->b_size >> 9; + if (block_sectors < 4) + block_sectors = 4; + if (scsi_CDs[device_nr].sector_size == 2048) + error_sector <<= 2; + error_sector &= ~(block_sectors - 1); + good_sectors = error_sector - SCpnt->request.sector; + if (good_sectors < 0 || good_sectors >= this_count) + good_sectors = 0; + /* + The SCSI specification allows for the value returned by READ + CAPACITY to be up to 75 2K sectors past the last readable + block. Therefore, if we hit a medium error within the last + 75 2K sectors, we decrease the saved size value. + */ + if ((error_sector >> 1) < sr_sizes[device_nr] && + scsi_CDs[device_nr].capacity - error_sector < 4 * 75) + sr_sizes[device_nr] = error_sector >> 1; + } + if (good_sectors > 0) { /* Some sectors were read successfully. */ + if (SCpnt->use_sg == 0) { + if (SCpnt->buffer != SCpnt->request.buffer) { + int offset; + offset = (SCpnt->request.sector % 4) << 9; + memcpy((char *) SCpnt->request.buffer, + (char *) SCpnt->buffer + offset, + good_sectors << 9); + /* Even though we are not using scatter-gather, we look + * ahead and see if there is a linked request for the + * other half of this buffer. If there is, then satisfy + * it. */ + if ((offset == 0) && good_sectors == 2 && + SCpnt->request.nr_sectors > good_sectors && + SCpnt->request.bh && + SCpnt->request.bh->b_reqnext && + SCpnt->request.bh->b_reqnext->b_size == 1024) { + memcpy((char *) SCpnt->request.bh->b_reqnext->b_data, + (char *) SCpnt->buffer + 1024, + 1024); + good_sectors += 2; + }; - scsi_free(SCpnt->buffer, 2048); - } - } else { - struct scatterlist * sgpnt; - int i; - sgpnt = (struct scatterlist *) SCpnt->buffer; - for(i=0; iuse_sg; i++) { - if (sgpnt[i].alt_address) { - if (sgpnt[i].alt_address != sgpnt[i].address) { - memcpy(sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length); - }; - scsi_free(sgpnt[i].address, sgpnt[i].length); + scsi_free(SCpnt->buffer, 2048); + } + } else { + struct scatterlist *sgpnt; + int i; + sgpnt = (struct scatterlist *) SCpnt->buffer; + for (i = 0; i < SCpnt->use_sg; i++) { + if (sgpnt[i].alt_address) { + if (sgpnt[i].alt_address != sgpnt[i].address) { + memcpy(sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length); + }; + scsi_free(sgpnt[i].address, sgpnt[i].length); + }; + }; + scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */ + if (SCpnt->request.sector % 4) + good_sectors -= 2; + /* See if there is a padding record at the end that needs to be removed */ + if (good_sectors > SCpnt->request.nr_sectors) + good_sectors -= 2; }; - }; - scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */ - if(SCpnt->request.sector % 4) good_sectors -= 2; - /* See if there is a padding record at the end that needs to be removed */ - if(good_sectors > SCpnt->request.nr_sectors) - good_sectors -= 2; - }; #ifdef DEBUG - printk("(%x %x %x) ",SCpnt->request.bh, SCpnt->request.nr_sectors, + printk("(%x %x %x) ", SCpnt->request.bh, SCpnt->request.nr_sectors, good_sectors); #endif - if (SCpnt->request.nr_sectors > this_count) - { + if (SCpnt->request.nr_sectors > this_count) { SCpnt->request.errors = 0; if (!SCpnt->request.bh) - panic("sr.c: linked page request (%lx %x)", - SCpnt->request.sector, this_count); - } - - SCpnt = end_scsi_request(SCpnt, 1, good_sectors); /* All done */ - if (result == 0) - { - requeue_sr_request(SCpnt); - return; - } - } - - if (good_sectors == 0) { - /* We only come through here if no sectors were read successfully. */ - - /* Free up any indirection buffers we allocated for DMA purposes. */ - if (SCpnt->use_sg) { - struct scatterlist * sgpnt; - int i; - sgpnt = (struct scatterlist *) SCpnt->buffer; - for(i=0; iuse_sg; i++) { - if (sgpnt[i].alt_address) { - scsi_free(sgpnt[i].address, sgpnt[i].length); - } - } - scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */ - } else { - if (SCpnt->buffer != SCpnt->request.buffer) - scsi_free(SCpnt->buffer, SCpnt->bufflen); + panic("sr.c: linked page request (%lx %x)", + SCpnt->request.sector, this_count); + } + SCpnt = end_scsi_request(SCpnt, 1, good_sectors); /* All done */ + if (result == 0) { + requeue_sr_request(SCpnt); + return; + } } + if (good_sectors == 0) { + /* We only come through here if no sectors were read successfully. */ - } + /* Free up any indirection buffers we allocated for DMA purposes. */ + if (SCpnt->use_sg) { + struct scatterlist *sgpnt; + int i; + sgpnt = (struct scatterlist *) SCpnt->buffer; + for (i = 0; i < SCpnt->use_sg; i++) { + if (sgpnt[i].alt_address) { + scsi_free(sgpnt[i].address, sgpnt[i].length); + } + } + scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */ + } else { + if (SCpnt->buffer != SCpnt->request.buffer) + scsi_free(SCpnt->buffer, SCpnt->bufflen); + } + } if (driver_byte(result) != 0) { if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) { if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) { /* detected disc change. set a bit and quietly refuse - * further access. */ + * further access. */ scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->changed = 1; SCpnt = end_scsi_request(SCpnt, 0, this_count); @@ -309,10 +314,9 @@ return; } } - if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) { printk("sr%d: CD-ROM error: ", - DEVICE_NR(SCpnt->request.rq_dev)); + DEVICE_NR(SCpnt->request.rq_dev)); print_sense("sr", SCpnt); printk("command was: "); print_command(SCpnt->cmnd); @@ -323,95 +327,87 @@ return; } else { SCpnt = end_scsi_request(SCpnt, 0, this_count); - requeue_sr_request(SCpnt); /* Do next request */ + requeue_sr_request(SCpnt); /* Do next request */ return; } } - if (SCpnt->sense_buffer[2] == NOT_READY) { printk(KERN_INFO "sr%d: CD-ROM not ready. Make sure you have a disc in the drive.\n", - DEVICE_NR(SCpnt->request.rq_dev)); + DEVICE_NR(SCpnt->request.rq_dev)); SCpnt = end_scsi_request(SCpnt, 0, this_count); - requeue_sr_request(SCpnt); /* Do next request */ + requeue_sr_request(SCpnt); /* Do next request */ return; } - if (SCpnt->sense_buffer[2] == MEDIUM_ERROR) { - printk("scsi%d: MEDIUM ERROR on " - "channel %d, id %d, lun %d, CDB: ", - SCpnt->host->host_no, (int) SCpnt->channel, - (int) SCpnt->target, (int) SCpnt->lun); - print_command(SCpnt->cmnd); - print_sense("sr", SCpnt); - SCpnt = end_scsi_request(SCpnt, 0, block_sectors); - requeue_sr_request(SCpnt); - return; + printk("scsi%d: MEDIUM ERROR on " + "channel %d, id %d, lun %d, CDB: ", + SCpnt->host->host_no, (int) SCpnt->channel, + (int) SCpnt->target, (int) SCpnt->lun); + print_command(SCpnt->cmnd); + print_sense("sr", SCpnt); + SCpnt = end_scsi_request(SCpnt, 0, block_sectors); + requeue_sr_request(SCpnt); + return; } - if (SCpnt->sense_buffer[2] == VOLUME_OVERFLOW) { - printk("scsi%d: VOLUME OVERFLOW on " - "channel %d, id %d, lun %d, CDB: ", - SCpnt->host->host_no, (int) SCpnt->channel, - (int) SCpnt->target, (int) SCpnt->lun); - print_command(SCpnt->cmnd); - print_sense("sr", SCpnt); - SCpnt = end_scsi_request(SCpnt, 0, block_sectors); - requeue_sr_request(SCpnt); - return; + printk("scsi%d: VOLUME OVERFLOW on " + "channel %d, id %d, lun %d, CDB: ", + SCpnt->host->host_no, (int) SCpnt->channel, + (int) SCpnt->target, (int) SCpnt->lun); + print_command(SCpnt->cmnd); + print_sense("sr", SCpnt); + SCpnt = end_scsi_request(SCpnt, 0, block_sectors); + requeue_sr_request(SCpnt); + return; } - } - + } /* We only get this far if we have an error we have not recognized */ - if(result) { - printk("SCSI CD error : host %d id %d lun %d return code = %03x\n", - scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->host->host_no, - scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->id, - scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->lun, - result); - - if (status_byte(result) == CHECK_CONDITION) - print_sense("sr", SCpnt); - - SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors); - requeue_sr_request(SCpnt); - } + if (result) { + printk("SCSI CD error : host %d id %d lun %d return code = %03x\n", + scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->host->host_no, + scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->id, + scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->lun, + result); + + if (status_byte(result) == CHECK_CONDITION) + print_sense("sr", SCpnt); + + SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors); + requeue_sr_request(SCpnt); + } } static int sr_open(struct cdrom_device_info *cdi, int purpose) { - check_disk_change(cdi->dev); + check_disk_change(cdi->dev); - if( MINOR(cdi->dev) >= sr_template.dev_max - || !scsi_CDs[MINOR(cdi->dev)].device) - { - return -ENXIO; /* No such device */ - } - - /* - * If the device is in error recovery, wait until it is done. - * If the device is offline, then disallow any access to it. - */ - if( !scsi_block_when_processing_errors(scsi_CDs[MINOR(cdi->dev)].device) ) - { - return -ENXIO; - } - - scsi_CDs[MINOR(cdi->dev)].device->access_count++; - if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module) - __MOD_INC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module); - if(sr_template.module) - __MOD_INC_USE_COUNT(sr_template.module); - - /* If this device did not have media in the drive at boot time, then - * we would have been unable to get the sector size. Check to see if - * this is the case, and try again. - */ + if (MINOR(cdi->dev) >= sr_template.dev_max + || !scsi_CDs[MINOR(cdi->dev)].device) { + return -ENXIO; /* No such device */ + } + /* + * If the device is in error recovery, wait until it is done. + * If the device is offline, then disallow any access to it. + */ + if (!scsi_block_when_processing_errors(scsi_CDs[MINOR(cdi->dev)].device)) { + return -ENXIO; + } + scsi_CDs[MINOR(cdi->dev)].device->access_count++; + if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module) + __MOD_INC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module); + if (sr_template.module) + __MOD_INC_USE_COUNT(sr_template.module); + + /* If this device did not have media in the drive at boot time, then + * we would have been unable to get the sector size. Check to see if + * this is the case, and try again. + */ - if(scsi_CDs[MINOR(cdi->dev)].needs_sector_size) - get_sectorsize(MINOR(cdi->dev)); + if (scsi_CDs[MINOR(cdi->dev)].needs_sector_size) + get_sectorsize(MINOR(cdi->dev)); - return 0; + return 0; } /* @@ -420,111 +416,106 @@ * translate them to SCSI commands. */ -static void do_sr_request (void) +static void do_sr_request(void) { - Scsi_Cmnd * SCpnt = NULL; - struct request * req = NULL; - Scsi_Device * SDev; - int flag = 0; - - while (1==1){ - if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) { - return; - }; + Scsi_Cmnd *SCpnt = NULL; + struct request *req = NULL; + Scsi_Device *SDev; + int flag = 0; - INIT_SCSI_REQUEST; + while (1 == 1) { + if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) { + return; + }; - SDev = scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device; + INIT_SCSI_REQUEST; - /* - * If the host for this device is in error recovery mode, don't - * do anything at all here. When the host leaves error recovery - * mode, it will automatically restart things and start queueing - * commands again. - */ - if( SDev->host->in_recovery ) - { - return; - } + SDev = scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device; - /* - * I am not sure where the best place to do this is. We need - * to hook in a place where we are likely to come if in user - * space. - */ - if( SDev->was_reset ) - { - /* - * We need to relock the door, but we might - * be in an interrupt handler. Only do this - * from user space, since we do not want to - * sleep from an interrupt. - */ - if( SDev->removable && !in_interrupt() ) - { - spin_unlock_irq(&io_request_lock); /* FIXME!!!! */ - scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0); - spin_lock_irq(&io_request_lock); /* FIXME!!!! */ - /* scsi_ioctl may allow CURRENT to change, so start over. */ - SDev->was_reset = 0; - continue; - } - SDev->was_reset = 0; - } - - /* we do lazy blocksize switching (when reading XA sectors, - * see CDROMREADMODE2 ioctl) */ - if (scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].sector_size > 2048) { - if (!in_interrupt()) - sr_set_blocklength(DEVICE_NR(CURRENT->rq_dev),2048); + /* + * If the host for this device is in error recovery mode, don't + * do anything at all here. When the host leaves error recovery + * mode, it will automatically restart things and start queueing + * commands again. + */ + if (SDev->host->in_recovery) { + return; + } + /* + * I am not sure where the best place to do this is. We need + * to hook in a place where we are likely to come if in user + * space. + */ + if (SDev->was_reset) { + /* + * We need to relock the door, but we might + * be in an interrupt handler. Only do this + * from user space, since we do not want to + * sleep from an interrupt. + */ + if (SDev->removable && !in_interrupt()) { + spin_unlock_irq(&io_request_lock); /* FIXME!!!! */ + scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0); + spin_lock_irq(&io_request_lock); /* FIXME!!!! */ + /* scsi_ioctl may allow CURRENT to change, so start over. */ + SDev->was_reset = 0; + continue; + } + SDev->was_reset = 0; + } + /* we do lazy blocksize switching (when reading XA sectors, + * see CDROMREADMODE2 ioctl) */ + if (scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].sector_size > 2048) { + if (!in_interrupt()) + sr_set_blocklength(DEVICE_NR(CURRENT->rq_dev), 2048); #if 1 - else - printk("sr: can't switch blocksize: in interrupt\n"); + else + printk("sr: can't switch blocksize: in interrupt\n"); #endif - } - - if (flag++ == 0) - SCpnt = scsi_allocate_device(&CURRENT, - scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0); - else SCpnt = NULL; - - /* This is a performance enhancement. We dig down into the request list and - * try to find a queueable request (i.e. device not busy, and host able to - * accept another command. If we find one, then we queue it. This can - * make a big difference on systems with more than one disk drive. We want - * to have the interrupts off when monkeying with the request list, because - * otherwise the kernel might try to slip in a request in between somewhere. */ - - if (!SCpnt && sr_template.nr_dev > 1){ - struct request *req1; - req1 = NULL; - req = CURRENT; - while(req){ - SCpnt = scsi_request_queueable(req, - scsi_CDs[DEVICE_NR(req->rq_dev)].device); - if(SCpnt) break; - req1 = req; - req = req->next; - } - if (SCpnt && req->rq_status == RQ_INACTIVE) { - if (req == CURRENT) - CURRENT = CURRENT->next; + } + if (flag++ == 0) + SCpnt = scsi_allocate_device(&CURRENT, + scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0); else - req1->next = req->next; - } - } + SCpnt = NULL; - if (!SCpnt) - return; /* Could not find anything to do */ + /* This is a performance enhancement. We dig down into the request list and + * try to find a queueable request (i.e. device not busy, and host able to + * accept another command. If we find one, then we queue it. This can + * make a big difference on systems with more than one disk drive. We want + * to have the interrupts off when monkeying with the request list, because + * otherwise the kernel might try to slip in a request in between somewhere. */ + + if (!SCpnt && sr_template.nr_dev > 1) { + struct request *req1; + req1 = NULL; + req = CURRENT; + while (req) { + SCpnt = scsi_request_queueable(req, + scsi_CDs[DEVICE_NR(req->rq_dev)].device); + if (SCpnt) + break; + req1 = req; + req = req->next; + } + if (SCpnt && req->rq_status == RQ_INACTIVE) { + if (req == CURRENT) + CURRENT = CURRENT->next; + else + req1->next = req->next; + } + } + if (!SCpnt) + return; /* Could not find anything to do */ - wake_up(&wait_for_request); + wake_up(&wait_for_request); - /* Queue command */ - requeue_sr_request(SCpnt); - } /* While */ + /* Queue command */ + requeue_sr_request(SCpnt); + } /* While */ } -void requeue_sr_request (Scsi_Cmnd * SCpnt) +void requeue_sr_request(Scsi_Cmnd * SCpnt) { unsigned int dev, block, realcount; unsigned char cmd[10], *buffer, tries; @@ -532,244 +523,234 @@ tries = 2; - repeat: - if(!SCpnt || SCpnt->request.rq_status == RQ_INACTIVE) { +repeat: + if (!SCpnt || SCpnt->request.rq_status == RQ_INACTIVE) { do_sr_request(); return; } - - dev = MINOR(SCpnt->request.rq_dev); + dev = MINOR(SCpnt->request.rq_dev); block = SCpnt->request.sector; buffer = NULL; this_count = 0; if (dev >= sr_template.nr_dev) { - /* printk("CD-ROM request error: invalid device.\n"); */ + /* printk("CD-ROM request error: invalid device.\n"); */ SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); tries = 2; goto repeat; } - if (!scsi_CDs[dev].use) { - /* printk("CD-ROM request error: device marked not in use.\n"); */ + /* printk("CD-ROM request error: device marked not in use.\n"); */ + SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); + tries = 2; + goto repeat; + } + if (!scsi_CDs[dev].device->online) { SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); tries = 2; goto repeat; } - - if( !scsi_CDs[dev].device->online ) - { - SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); - tries = 2; - goto repeat; - } - if (scsi_CDs[dev].device->changed) { - /* - * quietly refuse to do anything to a changed disc - * until the changed bit has been reset - */ - /* printk("CD-ROM has been changed. Prohibiting further I/O.\n"); */ + /* + * quietly refuse to do anything to a changed disc + * until the changed bit has been reset + */ + /* printk("CD-ROM has been changed. Prohibiting further I/O.\n"); */ SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); tries = 2; goto repeat; } - - switch (SCpnt->request.cmd) - { - case WRITE: - SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); - goto repeat; - break; - case READ : - cmd[0] = READ_6; - break; - default : - panic ("Unknown sr command %d\n", SCpnt->request.cmd); - } + switch (SCpnt->request.cmd) { + case WRITE: + SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); + goto repeat; + break; + case READ: + cmd[0] = READ_6; + break; + default: + panic("Unknown sr command %d\n", SCpnt->request.cmd); + } cmd[1] = (SCpnt->lun << 5) & 0xe0; - /* - * Now do the grungy work of figuring out which sectors we need, and - * where in memory we are going to put them. - * - * The variables we need are: - * - * this_count= number of 512 byte sectors being read - * block = starting cdrom sector to read. - * realcount = # of cdrom sectors to read - * - * The major difference between a scsi disk and a scsi cdrom - * is that we will always use scatter-gather if we can, because we can - * work around the fact that the buffer cache has a block size of 1024, - * and we have 2048 byte sectors. This code should work for buffers that - * are any multiple of 512 bytes long. - */ + /* + * Now do the grungy work of figuring out which sectors we need, and + * where in memory we are going to put them. + * + * The variables we need are: + * + * this_count= number of 512 byte sectors being read + * block = starting cdrom sector to read. + * realcount = # of cdrom sectors to read + * + * The major difference between a scsi disk and a scsi cdrom + * is that we will always use scatter-gather if we can, because we can + * work around the fact that the buffer cache has a block size of 1024, + * and we have 2048 byte sectors. This code should work for buffers that + * are any multiple of 512 bytes long. + */ SCpnt->use_sg = 0; if (SCpnt->host->sg_tablesize > 0 && (!scsi_need_isa_buffer || - scsi_dma_free_sectors >= 10)) { - struct buffer_head * bh; - struct scatterlist * sgpnt; - int count, this_count_max; - bh = SCpnt->request.bh; - this_count = 0; - count = 0; - this_count_max = (scsi_CDs[dev].ten ? 0xffff : 0xff) << 4; - /* Calculate how many links we can use. First see if we need - * a padding record at the start */ - this_count = SCpnt->request.sector % 4; - if(this_count) count++; - while(bh && count < SCpnt->host->sg_tablesize) { - if ((this_count + (bh->b_size >> 9)) > this_count_max) break; - this_count += (bh->b_size >> 9); - count++; - bh = bh->b_reqnext; - }; - /* Fix up in case of an odd record at the end */ - end_rec = 0; - if(this_count % 4) { - if (count < SCpnt->host->sg_tablesize) { - count++; - end_rec = (4 - (this_count % 4)) << 9; - this_count += 4 - (this_count % 4); - } else { - count--; - this_count -= (this_count % 4); - }; - }; - SCpnt->use_sg = count; /* Number of chains */ - /* scsi_malloc can only allocate in chunks of 512 bytes */ - count = (SCpnt->use_sg * sizeof(struct scatterlist) + 511) & ~511; - - SCpnt->sglist_len = count; - sgpnt = (struct scatterlist * ) scsi_malloc(count); - if (!sgpnt) { - printk("Warning - running *really* short on DMA buffers\n"); - SCpnt->use_sg = 0; /* No memory left - bail out */ - } else { - buffer = (unsigned char *) sgpnt; - count = 0; - bh = SCpnt->request.bh; - if(SCpnt->request.sector % 4) { - sgpnt[count].length = (SCpnt->request.sector % 4) << 9; - sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length); - if(!sgpnt[count].address) panic("SCSI DMA pool exhausted."); - sgpnt[count].alt_address = sgpnt[count].address; /* Flag to delete - if needed */ - count++; - }; - for(bh = SCpnt->request.bh; count < SCpnt->use_sg; - count++, bh = bh->b_reqnext) { - if (bh) { /* Need a placeholder at the end of the record? */ - sgpnt[count].address = bh->b_data; - sgpnt[count].length = bh->b_size; - sgpnt[count].alt_address = NULL; - } else { - sgpnt[count].address = (char *) scsi_malloc(end_rec); - if(!sgpnt[count].address) panic("SCSI DMA pool exhausted."); - sgpnt[count].length = end_rec; - sgpnt[count].alt_address = sgpnt[count].address; - if (count+1 != SCpnt->use_sg) panic("Bad sr request list"); - break; + scsi_dma_free_sectors >= 10)) { + struct buffer_head *bh; + struct scatterlist *sgpnt; + int count, this_count_max; + bh = SCpnt->request.bh; + this_count = 0; + count = 0; + this_count_max = (scsi_CDs[dev].ten ? 0xffff : 0xff) << 4; + /* Calculate how many links we can use. First see if we need + * a padding record at the start */ + this_count = SCpnt->request.sector % 4; + if (this_count) + count++; + while (bh && count < SCpnt->host->sg_tablesize) { + if ((this_count + (bh->b_size >> 9)) > this_count_max) + break; + this_count += (bh->b_size >> 9); + count++; + bh = bh->b_reqnext; }; - if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length - 1 > - ISA_DMA_THRESHOLD && SCpnt->host->unchecked_isa_dma) { - sgpnt[count].alt_address = sgpnt[count].address; - /* We try to avoid exhausting the DMA pool, since it is easier - * to control usage here. In other places we might have a more - * pressing need, and we would be screwed if we ran out */ - if(scsi_dma_free_sectors < (sgpnt[count].length >> 9) + 5) { - sgpnt[count].address = NULL; - } else { - sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length); - }; - /* If we start running low on DMA buffers, we abort the scatter-gather - * operation, and free all of the memory we have allocated. We want to - * ensure that all scsi operations are able to do at least a non-scatter/gather - * operation */ - if(sgpnt[count].address == NULL){ /* Out of dma memory */ - printk("Warning: Running low on SCSI DMA buffers\n"); - /* Try switching back to a non scatter-gather operation. */ - while(--count >= 0){ - if(sgpnt[count].alt_address) - scsi_free(sgpnt[count].address, sgpnt[count].length); + /* Fix up in case of an odd record at the end */ + end_rec = 0; + if (this_count % 4) { + if (count < SCpnt->host->sg_tablesize) { + count++; + end_rec = (4 - (this_count % 4)) << 9; + this_count += 4 - (this_count % 4); + } else { + count--; + this_count -= (this_count % 4); }; - SCpnt->use_sg = 0; - scsi_free(buffer, SCpnt->sglist_len); - break; - }; /* if address == NULL */ - }; /* if need DMA fixup */ - }; /* for loop to fill list */ + }; + SCpnt->use_sg = count; /* Number of chains */ + /* scsi_malloc can only allocate in chunks of 512 bytes */ + count = (SCpnt->use_sg * sizeof(struct scatterlist) + 511) & ~511; + + SCpnt->sglist_len = count; + sgpnt = (struct scatterlist *) scsi_malloc(count); + if (!sgpnt) { + printk("Warning - running *really* short on DMA buffers\n"); + SCpnt->use_sg = 0; /* No memory left - bail out */ + } else { + buffer = (unsigned char *) sgpnt; + count = 0; + bh = SCpnt->request.bh; + if (SCpnt->request.sector % 4) { + sgpnt[count].length = (SCpnt->request.sector % 4) << 9; + sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length); + if (!sgpnt[count].address) + panic("SCSI DMA pool exhausted."); + sgpnt[count].alt_address = sgpnt[count].address; /* Flag to delete + if needed */ + count++; + }; + for (bh = SCpnt->request.bh; count < SCpnt->use_sg; + count++, bh = bh->b_reqnext) { + if (bh) { /* Need a placeholder at the end of the record? */ + sgpnt[count].address = bh->b_data; + sgpnt[count].length = bh->b_size; + sgpnt[count].alt_address = NULL; + } else { + sgpnt[count].address = (char *) scsi_malloc(end_rec); + if (!sgpnt[count].address) + panic("SCSI DMA pool exhausted."); + sgpnt[count].length = end_rec; + sgpnt[count].alt_address = sgpnt[count].address; + if (count + 1 != SCpnt->use_sg) + panic("Bad sr request list"); + break; + }; + if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length - 1 > + ISA_DMA_THRESHOLD && SCpnt->host->unchecked_isa_dma) { + sgpnt[count].alt_address = sgpnt[count].address; + /* We try to avoid exhausting the DMA pool, since it is easier + * to control usage here. In other places we might have a more + * pressing need, and we would be screwed if we ran out */ + if (scsi_dma_free_sectors < (sgpnt[count].length >> 9) + 5) { + sgpnt[count].address = NULL; + } else { + sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length); + }; + /* If we start running low on DMA buffers, we abort the scatter-gather + * operation, and free all of the memory we have allocated. We want to + * ensure that all scsi operations are able to do at least a non-scatter/gather + * operation */ + if (sgpnt[count].address == NULL) { /* Out of dma memory */ + printk("Warning: Running low on SCSI DMA buffers\n"); + /* Try switching back to a non scatter-gather operation. */ + while (--count >= 0) { + if (sgpnt[count].alt_address) + scsi_free(sgpnt[count].address, sgpnt[count].length); + }; + SCpnt->use_sg = 0; + scsi_free(buffer, SCpnt->sglist_len); + break; + }; /* if address == NULL */ + }; /* if need DMA fixup */ + }; /* for loop to fill list */ #ifdef DEBUG - printk("SR: %d %d %d %d %d *** ",SCpnt->use_sg, SCpnt->request.sector, - this_count, - SCpnt->request.current_nr_sectors, - SCpnt->request.nr_sectors); - for(count=0; countuse_sg; count++) - printk("SGlist: %d %x %x %x\n", count, - sgpnt[count].address, - sgpnt[count].alt_address, - sgpnt[count].length); + printk("SR: %d %d %d %d %d *** ", SCpnt->use_sg, SCpnt->request.sector, + this_count, + SCpnt->request.current_nr_sectors, + SCpnt->request.nr_sectors); + for (count = 0; count < SCpnt->use_sg; count++) + printk("SGlist: %d %x %x %x\n", count, + sgpnt[count].address, + sgpnt[count].alt_address, + sgpnt[count].length); #endif - }; /* Able to allocate scatter-gather list */ + }; /* Able to allocate scatter-gather list */ }; - if (SCpnt->use_sg == 0){ - /* We cannot use scatter-gather. Do this the old fashion way */ - if (!SCpnt->request.bh) - this_count = SCpnt->request.nr_sectors; - else - this_count = (SCpnt->request.bh->b_size >> 9); + if (SCpnt->use_sg == 0) { + /* We cannot use scatter-gather. Do this the old fashion way */ + if (!SCpnt->request.bh) + this_count = SCpnt->request.nr_sectors; + else + this_count = (SCpnt->request.bh->b_size >> 9); - start = block % 4; - if (start) - { - this_count = ((this_count > 4 - start) ? - (4 - start) : (this_count)); - buffer = (unsigned char *) scsi_malloc(2048); - } - else if (this_count < 4) - { - buffer = (unsigned char *) scsi_malloc(2048); - } - else - { - this_count -= this_count % 4; - buffer = (unsigned char *) SCpnt->request.buffer; - if (virt_to_phys(buffer) + (this_count << 9) > ISA_DMA_THRESHOLD && - SCpnt->host->unchecked_isa_dma) - buffer = (unsigned char *) scsi_malloc(this_count << 9); - } + start = block % 4; + if (start) { + this_count = ((this_count > 4 - start) ? + (4 - start) : (this_count)); + buffer = (unsigned char *) scsi_malloc(2048); + } else if (this_count < 4) { + buffer = (unsigned char *) scsi_malloc(2048); + } else { + this_count -= this_count % 4; + buffer = (unsigned char *) SCpnt->request.buffer; + if (virt_to_phys(buffer) + (this_count << 9) > ISA_DMA_THRESHOLD && + SCpnt->host->unchecked_isa_dma) + buffer = (unsigned char *) scsi_malloc(this_count << 9); + } }; if (scsi_CDs[dev].sector_size == 2048) - block = block >> 2; /* These are the sectors that the cdrom uses */ + block = block >> 2; /* These are the sectors that the cdrom uses */ else - block = block & 0xfffffffc; + block = block & 0xfffffffc; realcount = (this_count + 3) / 4; - if (scsi_CDs[dev].sector_size == 512) realcount = realcount << 2; + if (scsi_CDs[dev].sector_size == 512) + realcount = realcount << 2; - /* - * Note: The scsi standard says that READ_6 is *optional*, while - * READ_10 is mandatory. Thus there is no point in using - * READ_6. - */ - if (scsi_CDs[dev].ten) - - { - if (realcount > 0xffff) - { + /* + * Note: The scsi standard says that READ_6 is *optional*, while + * READ_10 is mandatory. Thus there is no point in using + * READ_6. + */ + if (scsi_CDs[dev].ten) { + if (realcount > 0xffff) { realcount = 0xffff; this_count = realcount * (scsi_CDs[dev].sector_size >> 9); - } - - cmd[0] += READ_10 - READ_6 ; + } + cmd[0] += READ_10 - READ_6; cmd[2] = (unsigned char) (block >> 24) & 0xff; cmd[3] = (unsigned char) (block >> 16) & 0xff; cmd[4] = (unsigned char) (block >> 8) & 0xff; @@ -777,164 +758,174 @@ cmd[6] = cmd[9] = 0; cmd[7] = (unsigned char) (realcount >> 8) & 0xff; cmd[8] = (unsigned char) realcount & 0xff; - } - else - { - if (realcount > 0xff) - { - realcount = 0xff; - this_count = realcount * (scsi_CDs[dev].sector_size >> 9); + } else { + if (realcount > 0xff) { + realcount = 0xff; + this_count = realcount * (scsi_CDs[dev].sector_size >> 9); + } + cmd[1] |= (unsigned char) ((block >> 16) & 0x1f); + cmd[2] = (unsigned char) ((block >> 8) & 0xff); + cmd[3] = (unsigned char) block & 0xff; + cmd[4] = (unsigned char) realcount; + cmd[5] = 0; } - cmd[1] |= (unsigned char) ((block >> 16) & 0x1f); - cmd[2] = (unsigned char) ((block >> 8) & 0xff); - cmd[3] = (unsigned char) block & 0xff; - cmd[4] = (unsigned char) realcount; - cmd[5] = 0; - } - #ifdef DEBUG - { - int i; - printk("ReadCD: %d %d %d %d\n",block, realcount, buffer, this_count); - printk("Use sg: %d\n", SCpnt->use_sg); - printk("Dumping command: "); - for(i=0; i<12; i++) printk("%2.2x ", cmd[i]); - printk("\n"); - }; + { + int i; + printk("ReadCD: %d %d %d %d\n", block, realcount, buffer, this_count); + printk("Use sg: %d\n", SCpnt->use_sg); + printk("Dumping command: "); + for (i = 0; i < 12; i++) + printk("%2.2x ", cmd[i]); + printk("\n"); + }; #endif - /* Some dumb host adapters can speed transfers by knowing the - * minimum transfersize in advance. - * - * We shouldn't disconnect in the middle of a sector, but the cdrom - * sector size can be larger than the size of a buffer and the - * transfer may be split to the size of a buffer. So it's safe to - * assume that we can at least transfer the minimum of the buffer - * size (1024) and the sector size between each connect / disconnect. - */ + /* Some dumb host adapters can speed transfers by knowing the + * minimum transfersize in advance. + * + * We shouldn't disconnect in the middle of a sector, but the cdrom + * sector size can be larger than the size of a buffer and the + * transfer may be split to the size of a buffer. So it's safe to + * assume that we can at least transfer the minimum of the buffer + * size (1024) and the sector size between each connect / disconnect. + */ - SCpnt->transfersize = (scsi_CDs[dev].sector_size > 1024) ? - 1024 : scsi_CDs[dev].sector_size; + SCpnt->transfersize = (scsi_CDs[dev].sector_size > 1024) ? + 1024 : scsi_CDs[dev].sector_size; SCpnt->this_count = this_count; - scsi_do_cmd (SCpnt, (void *) cmd, buffer, - realcount * scsi_CDs[dev].sector_size, - rw_intr, SR_TIMEOUT, MAX_RETRIES); + scsi_do_cmd(SCpnt, (void *) cmd, buffer, + realcount * scsi_CDs[dev].sector_size, + rw_intr, SR_TIMEOUT, MAX_RETRIES); } -static int sr_detect(Scsi_Device * SDp){ +static int sr_detect(Scsi_Device * SDp) +{ - if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 0; + if (SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) + return 0; - printk("Detected scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n", - sr_template.dev_noticed++, - SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); + printk("Detected scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n", + sr_template.dev_noticed++, + SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); - return 1; + return 1; } -static int sr_attach(Scsi_Device * SDp){ - Scsi_CD * cpnt; - int i; - - if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 1; - - if (sr_template.nr_dev >= sr_template.dev_max) - { - SDp->attached--; - return 1; - } +static int sr_attach(Scsi_Device * SDp) +{ + Scsi_CD *cpnt; + int i; - for(cpnt = scsi_CDs, i=0; idevice) break; + if (SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) + return 1; - if(i >= sr_template.dev_max) panic ("scsi_devices corrupt (sr)"); + if (sr_template.nr_dev >= sr_template.dev_max) { + SDp->attached--; + return 1; + } + for (cpnt = scsi_CDs, i = 0; i < sr_template.dev_max; i++, cpnt++) + if (!cpnt->device) + break; + + if (i >= sr_template.dev_max) + panic("scsi_devices corrupt (sr)"); - SDp->scsi_request_fn = do_sr_request; - scsi_CDs[i].device = SDp; + SDp->scsi_request_fn = do_sr_request; + scsi_CDs[i].device = SDp; - sr_template.nr_dev++; - if(sr_template.nr_dev > sr_template.dev_max) - panic ("scsi_devices corrupt (sr)"); - return 0; + sr_template.nr_dev++; + if (sr_template.nr_dev > sr_template.dev_max) + panic("scsi_devices corrupt (sr)"); + return 0; } -static void sr_init_done (Scsi_Cmnd * SCpnt) +static void sr_init_done(Scsi_Cmnd * SCpnt) { - struct request * req; + struct request *req; - req = &SCpnt->request; - req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ + req = &SCpnt->request; + req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ - if (req->sem != NULL) { - up(req->sem); - } + if (req->sem != NULL) { + up(req->sem); + } } -void get_sectorsize(int i){ - unsigned char cmd[10]; - unsigned char *buffer; - int the_result, retries; - Scsi_Cmnd * SCpnt; - unsigned long flags; - - buffer = (unsigned char *) scsi_malloc(512); - SCpnt = scsi_allocate_device(NULL, scsi_CDs[i].device, 1); - - retries = 3; - do { - cmd[0] = READ_CAPACITY; - cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0; - memset ((void *) &cmd[2], 0, 8); - SCpnt->request.rq_status = RQ_SCSI_BUSY; /* Mark as really busy */ - SCpnt->cmd_len = 0; +void get_sectorsize(int i) +{ + unsigned char cmd[10]; + unsigned char *buffer; + int the_result, retries; + Scsi_Cmnd *SCpnt; + unsigned long flags; + + spin_lock_irq(&io_request_lock); + buffer = (unsigned char *) scsi_malloc(512); + SCpnt = scsi_allocate_device(NULL, scsi_CDs[i].device, 1); + spin_unlock_irq(&io_request_lock); + + retries = 3; + do { + cmd[0] = READ_CAPACITY; + cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0; + memset((void *) &cmd[2], 0, 8); + SCpnt->request.rq_status = RQ_SCSI_BUSY; /* Mark as really busy */ + SCpnt->cmd_len = 0; + + memset(buffer, 0, 8); + + /* Do the command and wait.. */ + { + struct semaphore sem = MUTEX_LOCKED; + SCpnt->request.sem = &sem; + spin_lock_irqsave(&io_request_lock, flags); + scsi_do_cmd (SCpnt, + (void *) cmd, (void *) buffer, + 512, sr_init_done, SR_TIMEOUT, + MAX_RETRIES); + spin_unlock_irqrestore(&io_request_lock, flags); + down(&sem); + } - memset(buffer, 0, 8); + the_result = SCpnt->result; + retries--; - /* Do the command and wait.. */ - { - struct semaphore sem = MUTEX_LOCKED; - SCpnt->request.sem = &sem; - spin_lock_irqsave(&io_request_lock, flags); - scsi_do_cmd (SCpnt, - (void *) cmd, (void *) buffer, - 512, sr_init_done, SR_TIMEOUT, - MAX_RETRIES); - spin_unlock_irqrestore(&io_request_lock, flags); - down(&sem); - } - - the_result = SCpnt->result; - retries--; - - } while(the_result && retries); - - - wake_up(&SCpnt->device->device_wait); - scsi_release_command(SCpnt); - SCpnt = NULL; - - if (the_result) { - scsi_CDs[i].capacity = 0x1fffff; - scsi_CDs[i].sector_size = 2048; /* A guess, just in case */ - scsi_CDs[i].needs_sector_size = 1; - } else { - scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) | - (buffer[1] << 16) | - (buffer[2] << 8) | - buffer[3]); - scsi_CDs[i].sector_size = (buffer[4] << 24) | - (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; - switch (scsi_CDs[i].sector_size) { - /* - * HP 4020i CD-Recorder reports 2340 byte sectors - * Philips CD-Writers report 2352 byte sectors - * - * Use 2k sectors for them.. - */ - case 0: case 2340: case 2352: + } while (the_result && retries); + + + wake_up(&SCpnt->device->device_wait); + scsi_release_command(SCpnt); + SCpnt = NULL; + + if (the_result) { + scsi_CDs[i].capacity = 0x1fffff; + scsi_CDs[i].sector_size = 2048; /* A guess, just in case */ + scsi_CDs[i].needs_sector_size = 1; + } else { +#if 0 + if (cdrom_get_last_written(MKDEV(MAJOR_NR, i), + (long *) &scsi_CDs[i].capacity)) +#endif + scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) | + (buffer[1] << 16) | + (buffer[2] << 8) | + buffer[3]); + scsi_CDs[i].sector_size = (buffer[4] << 24) | + (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; + switch (scsi_CDs[i].sector_size) { + /* + * HP 4020i CD-Recorder reports 2340 byte sectors + * Philips CD-Writers report 2352 byte sectors + * + * Use 2k sectors for them.. + */ + case 0: + case 2340: + case 2352: scsi_CDs[i].sector_size = 2048; /* fall through */ case 2048: @@ -943,229 +934,334 @@ case 512: break; default: - printk ("sr%d: unsupported sector size %d.\n", - i, scsi_CDs[i].sector_size); + printk("sr%d: unsupported sector size %d.\n", + i, scsi_CDs[i].sector_size); scsi_CDs[i].capacity = 0; scsi_CDs[i].needs_sector_size = 1; - } + } - /* - * Add this so that we have the ability to correctly gauge - * what the device is capable of. - */ - scsi_CDs[i].needs_sector_size = 0; - sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9); - }; - scsi_free(buffer, 512); + /* + * Add this so that we have the ability to correctly gauge + * what the device is capable of. + */ + scsi_CDs[i].needs_sector_size = 0; + sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9); + }; + scsi_free(buffer, 512); } -void get_capabilities(int i){ - unsigned char cmd[6]; - unsigned char *buffer; - int rc,n; - - static char *loadmech[] = { - "caddy", - "tray", - "pop-up", - "", - "changer", - "changer", - "", - "" - }; - - buffer = (unsigned char *) scsi_malloc(512); - cmd[0] = MODE_SENSE; - cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0; - cmd[2] = 0x2a; - cmd[4] = 128; - cmd[3] = cmd[5] = 0; - rc = sr_do_ioctl(i, cmd, buffer, 128, 1); - - if (-EINVAL == rc) { - /* failed, drive has'nt this mode page */ - scsi_CDs[i].cdi.speed = 1; - /* disable speed select, drive probably can't do this either */ - scsi_CDs[i].cdi.mask |= CDC_SELECT_SPEED; - } else { - n = buffer[3]+4; - scsi_CDs[i].cdi.speed = ((buffer[n+8] << 8) + buffer[n+9])/176; - scsi_CDs[i].readcd_known = 1; - scsi_CDs[i].readcd_cdda = buffer[n+5] & 0x01; - /* print some capability bits */ - printk("sr%i: scsi3-mmc drive: %dx/%dx %s%s%s%s%s\n",i, - ((buffer[n+14] << 8) + buffer[n+15])/176, - scsi_CDs[i].cdi.speed, - buffer[n+3]&0x01 ? "writer " : "", /* CD Writer */ - buffer[n+2]&0x02 ? "cd/rw " : "", /* can read rewriteable */ - buffer[n+4]&0x20 ? "xa/form2 " : "", /* can read xa/from2 */ - buffer[n+5]&0x01 ? "cdda " : "", /* can read audio data */ - loadmech[buffer[n+6]>>5]); - if ((buffer[n+6] >> 5) == 0) +void get_capabilities(int i) +{ + unsigned char cmd[6]; + unsigned char *buffer; + int rc, n; + + static char *loadmech[] = + { + "caddy", + "tray", + "pop-up", + "", + "changer", + "cartridge changer", + "", + "" + }; + + spin_lock_irq(&io_request_lock); + buffer = (unsigned char *) scsi_malloc(512); + spin_unlock_irq(&io_request_lock); + cmd[0] = MODE_SENSE; + cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0; + cmd[2] = 0x2a; + cmd[4] = 128; + cmd[3] = cmd[5] = 0; + rc = sr_do_ioctl(i, cmd, buffer, 128, 1); + + if (-EINVAL == rc) { + /* failed, drive has'nt this mode page */ + scsi_CDs[i].cdi.speed = 1; + /* disable speed select, drive probably can't do this either */ + scsi_CDs[i].cdi.mask |= CDC_SELECT_SPEED; + scsi_free(buffer, 512); + return; + } + n = buffer[3] + 4; + scsi_CDs[i].cdi.speed = ((buffer[n + 8] << 8) + buffer[n + 9]) / 176; + scsi_CDs[i].readcd_known = 1; + scsi_CDs[i].readcd_cdda = buffer[n + 5] & 0x01; + /* print some capability bits */ + printk("sr%i: scsi3-mmc drive: %dx/%dx %s%s%s%s%s\n", i, + ((buffer[n + 14] << 8) + buffer[n + 15]) / 176, + scsi_CDs[i].cdi.speed, + buffer[n + 3] & 0x01 ? "writer " : "", /* CD Writer */ + buffer[n + 2] & 0x02 ? "cd/rw " : "", /* can read rewriteable */ + buffer[n + 4] & 0x20 ? "xa/form2 " : "", /* can read xa/from2 */ + buffer[n + 5] & 0x01 ? "cdda " : "", /* can read audio data */ + loadmech[buffer[n + 6] >> 5]); + if ((buffer[n + 6] >> 5) == 0) /* caddy drives can't close tray... */ - scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY; - } - scsi_free(buffer, 512); + scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY; + if ((buffer[n + 2] & 0x8) == 0) + /* not a DVD drive */ + scsi_CDs[i].cdi.mask |= CDC_DVD; + if ((buffer[n + 3] & 0x20) == 0) + /* can't write DVD-RAM media */ + scsi_CDs[i].cdi.mask |= CDC_DVD_RAM; + if ((buffer[n + 3] & 0x10) == 0) + /* can't write DVD-R media */ + scsi_CDs[i].cdi.mask |= CDC_DVD_R; + if ((buffer[n + 3] & 0x2) == 0) + /* can't write CD-RW media */ + scsi_CDs[i].cdi.mask |= CDC_CD_RW; + if ((buffer[n + 3] & 0x1) == 0) + /* can't write CD-R media */ + scsi_CDs[i].cdi.mask |= CDC_CD_R; + if ((buffer[n+6] & 0x8) == 0) + /* can't eject */ + scsi_CDs[i].cdi.mask |= CDC_OPEN_TRAY; + + if ((buffer[n+6] >> 5) == mechtype_individual_changer || + (buffer[n+6] >> 5) == mechtype_cartridge_changer) + scsi_CDs[i].cdi.capacity = + cdrom_number_of_slots(&(scsi_CDs[i].cdi)); + if (scsi_CDs[i].cdi.capacity <= 1) + /* not a changer */ + scsi_CDs[i].cdi.mask |= CDC_SELECT_DISC; + /*else I don't think it can close its tray + scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY; */ + + + scsi_free(buffer, 512); +} + +/* + * sr_packet() is the entry point for the generic commands generated + * by the Uniform CD-ROM layer. + */ +static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc) +{ + Scsi_Cmnd *SCpnt; + Scsi_Device *device = scsi_CDs[MINOR(cdi->dev)].device; + unsigned char *buffer = cgc->buffer; + unsigned long flags; + int buflen; + int stat; + + /* get the device */ + SCpnt = scsi_allocate_device(NULL, device, 1); + if (SCpnt == NULL) + return -ENODEV; /* this just doesn't seem right /axboe */ + + /* use buffer for ISA DMA */ + buflen = (cgc->buflen + 511) & ~511; + if (cgc->buffer && SCpnt->host->unchecked_isa_dma && + (virt_to_phys(cgc->buffer) + cgc->buflen - 1 > ISA_DMA_THRESHOLD)) { + spin_lock_irq(&io_request_lock); + buffer = scsi_malloc(buflen); + spin_unlock_irq(&io_request_lock); + if (buffer == NULL) { + printk("sr: SCSI DMA pool exhausted."); + return -ENOMEM; + } + memcpy(buffer, cgc->buffer, cgc->buflen); + } + + /* set the LUN */ + cgc->cmd[1] |= device->lun << 5; + + /* do the locking and issue the command */ + SCpnt->request.rq_dev = cdi->dev; + /* scsi_do_cmd sets the command length */ + SCpnt->cmd_len = 0; + + { + struct semaphore sem = MUTEX_LOCKED; + SCpnt->request.sem = &sem; + spin_lock_irqsave(&io_request_lock, flags); + scsi_do_cmd(SCpnt, (void *)cgc->cmd, (void *) buffer, + cgc->buflen, sr_init_done, SR_TIMEOUT, + MAX_RETRIES); + spin_unlock_irqrestore(&io_request_lock, flags); + down(&sem); + } + + stat = SCpnt->result; + + /* release */ + SCpnt->request.rq_dev = MKDEV(0, 0); + scsi_release_command(SCpnt); + SCpnt = NULL; + + /* write DMA buffer back if used */ + if (buffer && (buffer != cgc->buffer)) { + memcpy(cgc->buffer, buffer, cgc->buflen); + scsi_free(buffer, buflen); + } + + return stat; } static int sr_registered = 0; static int sr_init() { - int i; + int i; - if(sr_template.dev_noticed == 0) return 0; + if (sr_template.dev_noticed == 0) + return 0; - if(!sr_registered) { - if (register_blkdev(MAJOR_NR,"sr",&cdrom_fops)) { - printk("Unable to get major %d for SCSI-CD\n",MAJOR_NR); - return 1; + if (!sr_registered) { + if (register_blkdev(MAJOR_NR, "sr", &cdrom_fops)) { + printk("Unable to get major %d for SCSI-CD\n", MAJOR_NR); + return 1; + } + sr_registered++; } - sr_registered++; - } + if (scsi_CDs) + return 0; + sr_template.dev_max = + sr_template.dev_noticed + SR_EXTRA_DEVS; + scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC); + memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD)); + sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC); + memset(sr_sizes, 0, sr_template.dev_max * sizeof(int)); - if (scsi_CDs) return 0; - sr_template.dev_max = - sr_template.dev_noticed + SR_EXTRA_DEVS; - scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC); - memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD)); + sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max * + sizeof(int), GFP_ATOMIC); - sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC); - memset(sr_sizes, 0, sr_template.dev_max * sizeof(int)); - - sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max * - sizeof(int), GFP_ATOMIC); - - /* - * These are good guesses for the time being. - */ - for(i=0;ichanged = 1; /* force recheck CD type */ + for (i = 0; i < sr_template.nr_dev; ++i) { + /* If we have already seen this, then skip it. Comes up + * with loadable modules. */ + if (scsi_CDs[i].capacity) + continue; + scsi_CDs[i].capacity = 0x1fffff; + scsi_CDs[i].sector_size = 2048; /* A guess, just in case */ + scsi_CDs[i].needs_sector_size = 1; + scsi_CDs[i].device->changed = 1; /* force recheck CD type */ #if 0 - /* seems better to leave this for later */ - get_sectorsize(i); - printk("Scd sectorsize = %d bytes.\n", scsi_CDs[i].sector_size); + /* seems better to leave this for later */ + get_sectorsize(i); + printk("Scd sectorsize = %d bytes.\n", scsi_CDs[i].sector_size); #endif - scsi_CDs[i].use = 1; - scsi_CDs[i].ten = 1; - scsi_CDs[i].remap = 1; - scsi_CDs[i].readcd_known = 0; - scsi_CDs[i].readcd_cdda = 0; - sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9); - - scsi_CDs[i].cdi.ops = &sr_dops; - scsi_CDs[i].cdi.handle = &scsi_CDs[i]; - scsi_CDs[i].cdi.dev = MKDEV(MAJOR_NR,i); - scsi_CDs[i].cdi.mask = 0; - scsi_CDs[i].cdi.capacity = 1; - get_capabilities(i); - sr_vendor_init(i); - - sprintf(name, "sr%d", i); - strcpy(scsi_CDs[i].cdi.name, name); - register_cdrom(&scsi_CDs[i].cdi); - } - - - /* If our host adapter is capable of scatter-gather, then we increase - * the read-ahead to 16 blocks (32 sectors). If not, we use - * a two block (4 sector) read ahead. */ - if(scsi_CDs[0].device && scsi_CDs[0].device->host->sg_tablesize) - read_ahead[MAJOR_NR] = 32; /* 32 sector read-ahead. Always removable. */ - else - read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */ + scsi_CDs[i].use = 1; + scsi_CDs[i].ten = 1; + scsi_CDs[i].remap = 1; + scsi_CDs[i].readcd_known = 0; + scsi_CDs[i].readcd_cdda = 0; + sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9); + + scsi_CDs[i].cdi.ops = &sr_dops; + scsi_CDs[i].cdi.handle = &scsi_CDs[i]; + scsi_CDs[i].cdi.dev = MKDEV(MAJOR_NR, i); + scsi_CDs[i].cdi.mask = 0; + scsi_CDs[i].cdi.capacity = 1; + get_capabilities(i); + sr_vendor_init(i); + + sprintf(name, "sr%d", i); + strcpy(scsi_CDs[i].cdi.name, name); + register_cdrom(&scsi_CDs[i].cdi); + } - return; + + /* If our host adapter is capable of scatter-gather, then we increase + * the read-ahead to 16 blocks (32 sectors). If not, we use + * a two block (4 sector) read ahead. */ + if (scsi_CDs[0].device && scsi_CDs[0].device->host->sg_tablesize) + read_ahead[MAJOR_NR] = 32; /* 32 sector read-ahead. Always removable. */ + else + read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */ + + return; } static void sr_detach(Scsi_Device * SDp) { - Scsi_CD * cpnt; - int i; + Scsi_CD *cpnt; + int i; - for(cpnt = scsi_CDs, i=0; idevice == SDp) { - kdev_t devi = MKDEV(MAJOR_NR, i); - struct super_block * sb = get_super(devi); - - /* - * Since the cdrom is read-only, no need to sync the device. - * We should be kind to our buffer cache, however. - */ - if (sb) invalidate_inodes(sb); - invalidate_buffers(devi); - - /* - * Reset things back to a sane state so that one can re-load a new - * driver (perhaps the same one). - */ - unregister_cdrom(&(cpnt->cdi)); - cpnt->device = NULL; - cpnt->capacity = 0; - SDp->attached--; - sr_template.nr_dev--; - sr_template.dev_noticed--; - sr_sizes[i] = 0; - return; - } - return; + for (cpnt = scsi_CDs, i = 0; i < sr_template.dev_max; i++, cpnt++) + if (cpnt->device == SDp) { + kdev_t devi = MKDEV(MAJOR_NR, i); + struct super_block *sb = get_super(devi); + + /* + * Since the cdrom is read-only, no need to sync the device. + * We should be kind to our buffer cache, however. + */ + if (sb) + invalidate_inodes(sb); + invalidate_buffers(devi); + + /* + * Reset things back to a sane state so that one can re-load a new + * driver (perhaps the same one). + */ + unregister_cdrom(&(cpnt->cdi)); + cpnt->device = NULL; + cpnt->capacity = 0; + SDp->attached--; + sr_template.nr_dev--; + sr_template.dev_noticed--; + sr_sizes[i] = 0; + return; + } + return; } #ifdef MODULE -int init_module(void) { - sr_template.module = &__this_module; - return scsi_register_module(MODULE_SCSI_DEV, &sr_template); +int init_module(void) +{ + sr_template.module = &__this_module; + return scsi_register_module(MODULE_SCSI_DEV, &sr_template); } -void cleanup_module( void) +void cleanup_module(void) { - scsi_unregister_module(MODULE_SCSI_DEV, &sr_template); - unregister_blkdev(MAJOR_NR, "sr"); - sr_registered--; - if(scsi_CDs != NULL) { - scsi_init_free((char *) scsi_CDs, - (sr_template.dev_noticed + SR_EXTRA_DEVS) - * sizeof(Scsi_CD)); - - scsi_init_free((char *) sr_sizes, sr_template.dev_max * sizeof(int)); - sr_sizes = NULL; - - scsi_init_free((char *) sr_blocksizes, sr_template.dev_max * sizeof(int)); - sr_blocksizes = NULL; - } - - blksize_size[MAJOR_NR] = NULL; - blk_dev[MAJOR_NR].request_fn = NULL; - blk_size[MAJOR_NR] = NULL; - read_ahead[MAJOR_NR] = 0; + scsi_unregister_module(MODULE_SCSI_DEV, &sr_template); + unregister_blkdev(MAJOR_NR, "sr"); + sr_registered--; + if (scsi_CDs != NULL) { + scsi_init_free((char *) scsi_CDs, + (sr_template.dev_noticed + SR_EXTRA_DEVS) + * sizeof(Scsi_CD)); + + scsi_init_free((char *) sr_sizes, sr_template.dev_max * sizeof(int)); + sr_sizes = NULL; - sr_template.dev_max = 0; + scsi_init_free((char *) sr_blocksizes, sr_template.dev_max * sizeof(int)); + sr_blocksizes = NULL; + } + blksize_size[MAJOR_NR] = NULL; + blk_dev[MAJOR_NR].request_fn = NULL; + blk_size[MAJOR_NR] = NULL; + read_ahead[MAJOR_NR] = 0; + + sr_template.dev_max = 0; } -#endif /* MODULE */ + +#endif /* MODULE */ /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c --- linux-2.2.15/drivers/scsi/sr_ioctl.c Thu May 4 15:21:22 2000 +++ linux/drivers/scsi/sr_ioctl.c Thu May 4 01:19:23 2000 @@ -18,9 +18,6 @@ # define DEBUG #endif -/* for now we borrow the "operation not supported" from the network folks */ -#define EDRIVE_CANT_DO_THIS EOPNOTSUPP - /* The sr_is_xa() seems to trigger firmware bugs with some drives :-( * It is off by default and can be turned on with this module parameter */ static int xa_test = 0; @@ -38,6 +35,12 @@ req = &SCpnt->request; req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ + + if (SCpnt->buffer && req->buffer && SCpnt->buffer != req->buffer) { + memcpy(req->buffer, SCpnt->buffer, SCpnt->bufflen); + scsi_free(SCpnt->buffer, (SCpnt->bufflen + 511) & ~511); + SCpnt->buffer = req->buffer; + } if (req->sem != NULL) { up(req->sem); @@ -54,12 +57,26 @@ Scsi_Device * SDev; int result, err = 0, retries = 0; unsigned long flags; + char * bounce_buffer; spin_lock_irqsave(&io_request_lock, flags); SDev = scsi_CDs[target].device; SCpnt = scsi_allocate_device(NULL, scsi_CDs[target].device, 1); spin_unlock_irqrestore(&io_request_lock, flags); + /* use ISA DMA buffer if necessary */ + SCpnt->request.buffer=buffer; + if (buffer && SCpnt->host->unchecked_isa_dma && + (virt_to_phys(buffer) + buflength - 1 > ISA_DMA_THRESHOLD)) { + bounce_buffer = (char *)scsi_malloc((buflength + 511) & ~511); + if (bounce_buffer == NULL) { + printk("SCSI DMA pool exhausted."); + return -ENOMEM; + } + memcpy(bounce_buffer, (char *)buffer, buflength); + buffer = bounce_buffer; + } + retry: if( !scsi_block_when_processing_errors(SDev) ) return -ENODEV; @@ -74,7 +91,7 @@ down(&sem); SCpnt->request.sem = NULL; } - + result = SCpnt->result; /* Minimal error checking. Ignore cases we know about, and report the rest. */ @@ -159,7 +176,7 @@ { u_char sr_cmd[10]; - sr_cmd[0] = TEST_UNIT_READY; + sr_cmd[0] = GPCMD_TEST_UNIT_READY; sr_cmd[1] = ((scsi_CDs[minor].device -> lun) << 5); sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; return sr_do_ioctl(minor, sr_cmd, NULL, 255, 1); @@ -169,7 +186,7 @@ { u_char sr_cmd[10]; - sr_cmd[0] = START_STOP; + sr_cmd[0] = GPCMD_START_STOP_UNIT; sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device -> lun) << 5); sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */; @@ -239,10 +256,10 @@ int sr_get_mcn(struct cdrom_device_info *cdi,struct cdrom_mcn *mcn) { u_char sr_cmd[10]; - char * buffer; + char buffer[32]; int result; - sr_cmd[0] = SCMD_READ_SUBCHANNEL; + sr_cmd[0] = GPCMD_READ_SUBCHANNEL; sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5); sr_cmd[2] = 0x40; /* I do want the subchannel info */ sr_cmd[3] = 0x02; /* Give me medium catalog number info */ @@ -252,15 +269,11 @@ sr_cmd[8] = 24; sr_cmd[9] = 0; - if ((buffer = (unsigned char*) scsi_malloc(512)) == NULL) - return -ENOMEM; - result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0); memcpy (mcn->medium_catalog_number, buffer + 9, 13); mcn->medium_catalog_number[13] = 0; - scsi_free(buffer, 512); return result; } @@ -280,7 +293,7 @@ speed *= 177; /* Nx to kbyte/s */ memset(sr_cmd,0,12); - sr_cmd[0] = 0xbb; /* SET CD SPEED */ + sr_cmd[0] = GPCMD_SET_SPEED; /* SET CD SPEED */ sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->lun) << 5; sr_cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */ sr_cmd[3] = speed & 0xff; /* LSB */ @@ -293,104 +306,22 @@ /* ----------------------------------------------------------------------- */ /* this is called by the generic cdrom driver. arg is a _kernel_ pointer, */ /* becauce the generic cdrom driver does the user access stuff for us. */ +/* only cdromreadtochdr and cdromreadtocentry are left - for use with the */ +/* sr_disk_status interface for the generic cdrom driver. */ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg) { u_char sr_cmd[10]; - int result, target; - - target = MINOR(cdi->dev); + int result, target = MINOR(cdi->dev); + unsigned char buffer[32]; switch (cmd) { - /* Sun-compatible */ - case CDROMPAUSE: - - sr_cmd[0] = SCMD_PAUSE_RESUME; - sr_cmd[1] = scsi_CDs[target].device->lun << 5; - sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = 0; - sr_cmd[5] = sr_cmd[6] = sr_cmd[7] = 0; - sr_cmd[8] = 0; - sr_cmd[9] = 0; - - result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0); - break; - - case CDROMRESUME: - - sr_cmd[0] = SCMD_PAUSE_RESUME; - sr_cmd[1] = scsi_CDs[target].device->lun << 5; - sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = 0; - sr_cmd[5] = sr_cmd[6] = sr_cmd[7] = 0; - sr_cmd[8] = 1; - sr_cmd[9] = 0; - - result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0); - break; - - case CDROMPLAYMSF: - { - struct cdrom_msf* msf = (struct cdrom_msf*)arg; - - sr_cmd[0] = SCMD_PLAYAUDIO_MSF; - sr_cmd[1] = scsi_CDs[target].device->lun << 5; - sr_cmd[2] = 0; - sr_cmd[3] = msf->cdmsf_min0; - sr_cmd[4] = msf->cdmsf_sec0; - sr_cmd[5] = msf->cdmsf_frame0; - sr_cmd[6] = msf->cdmsf_min1; - sr_cmd[7] = msf->cdmsf_sec1; - sr_cmd[8] = msf->cdmsf_frame1; - sr_cmd[9] = 0; - - result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0); - break; - } - - case CDROMPLAYBLK: - { - struct cdrom_blk* blk = (struct cdrom_blk*)arg; - - sr_cmd[0] = SCMD_PLAYAUDIO10; - sr_cmd[1] = scsi_CDs[target].device->lun << 5; - sr_cmd[2] = blk->from >> 24; - sr_cmd[3] = blk->from >> 16; - sr_cmd[4] = blk->from >> 8; - sr_cmd[5] = blk->from; - sr_cmd[6] = 0; - sr_cmd[7] = blk->len >> 8; - sr_cmd[8] = blk->len; - sr_cmd[9] = 0; - - result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0); - break; - } - - case CDROMPLAYTRKIND: - { - struct cdrom_ti* ti = (struct cdrom_ti*)arg; - - sr_cmd[0] = SCMD_PLAYAUDIO_TI; - sr_cmd[1] = scsi_CDs[target].device->lun << 5; - sr_cmd[2] = 0; - sr_cmd[3] = 0; - sr_cmd[4] = ti->cdti_trk0; - sr_cmd[5] = ti->cdti_ind0; - sr_cmd[6] = 0; - sr_cmd[7] = ti->cdti_trk1; - sr_cmd[8] = ti->cdti_ind1; - sr_cmd[9] = 0; - - result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0); - break; - } - case CDROMREADTOCHDR: { struct cdrom_tochdr* tochdr = (struct cdrom_tochdr*)arg; - char * buffer; - sr_cmd[0] = SCMD_READ_TOC; + sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP; sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5); sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; sr_cmd[6] = 0; @@ -398,24 +329,19 @@ sr_cmd[8] = 12; /* LSB of length */ sr_cmd[9] = 0; - if ((buffer = (unsigned char *) scsi_malloc(512)) == NULL) - return -ENOMEM; - result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1); tochdr->cdth_trk0 = buffer[2]; tochdr->cdth_trk1 = buffer[3]; - scsi_free(buffer, 512); break; } case CDROMREADTOCENTRY: { struct cdrom_tocentry* tocentry = (struct cdrom_tocentry*)arg; - unsigned char * buffer; - sr_cmd[0] = SCMD_READ_TOC; + sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP; sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0); sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; @@ -424,9 +350,6 @@ sr_cmd[8] = 12; /* LSB of length */ sr_cmd[9] = 0; - if ((buffer = (unsigned char *) scsi_malloc(512)) == NULL) - return -ENOMEM; - result = sr_do_ioctl (target, sr_cmd, buffer, 12, 0); tocentry->cdte_ctrl = buffer[5] & 0xf; @@ -440,160 +363,9 @@ tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8) + buffer[10]) << 8) + buffer[11]; - scsi_free(buffer, 512); break; } - - case CDROMSTOP: - sr_cmd[0] = START_STOP; - sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1; - sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; - sr_cmd[4] = 0; - - result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0); - break; - - case CDROMSTART: - sr_cmd[0] = START_STOP; - sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1; - sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; - sr_cmd[4] = 1; - - result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0); - break; - - case CDROMVOLCTRL: - { - char * buffer, * mask; - struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg; - - /* First we get the current params so we can just twiddle the volume */ - - sr_cmd[0] = MODE_SENSE; - sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5; - sr_cmd[2] = 0xe; /* Want mode page 0xe, CDROM audio params */ - sr_cmd[3] = 0; - sr_cmd[4] = 28; - sr_cmd[5] = 0; - - if ((buffer = (unsigned char *) scsi_malloc(512)) == NULL) - return -ENOMEM; - - if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0))) { - printk ("Hosed while obtaining audio mode page\n"); - scsi_free(buffer, 512); - break; - } - - sr_cmd[0] = MODE_SENSE; - sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5; - sr_cmd[2] = 0x4e; /* Want the mask for mode page 0xe */ - sr_cmd[3] = 0; - sr_cmd[4] = 28; - sr_cmd[5] = 0; - - mask = (unsigned char *) scsi_malloc(512); - if(!mask) { - scsi_free(buffer, 512); - result = -ENOMEM; - break; - }; - - if ((result = sr_do_ioctl (target, sr_cmd, mask, 28, 0))) { - printk ("Hosed while obtaining mask for audio mode page\n"); - scsi_free(buffer, 512); - scsi_free(mask, 512); - break; - } - - /* Now mask and substitute our own volume and reuse the rest */ - buffer[0] = 0; /* Clear reserved field */ - - buffer[21] = volctrl->channel0 & mask[21]; - buffer[23] = volctrl->channel1 & mask[23]; - buffer[25] = volctrl->channel2 & mask[25]; - buffer[27] = volctrl->channel3 & mask[27]; - - sr_cmd[0] = MODE_SELECT; - sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 0x10; /* Params are SCSI-2 */ - sr_cmd[2] = sr_cmd[3] = 0; - sr_cmd[4] = 28; - sr_cmd[5] = 0; - - result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0); - scsi_free(buffer, 512); - scsi_free(mask, 512); - break; - } - - case CDROMVOLREAD: - { - char * buffer; - struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg; - - /* Get the current params */ - - sr_cmd[0] = MODE_SENSE; - sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5; - sr_cmd[2] = 0xe; /* Want mode page 0xe, CDROM audio params */ - sr_cmd[3] = 0; - sr_cmd[4] = 28; - sr_cmd[5] = 0; - - if ((buffer = (unsigned char *) scsi_malloc(512)) == NULL) - return -ENOMEM; - - if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0))) { - printk ("(CDROMVOLREAD) Hosed while obtaining audio mode page\n"); - scsi_free(buffer, 512); - break; - } - - volctrl->channel0 = buffer[21]; - volctrl->channel1 = buffer[23]; - volctrl->channel2 = buffer[25]; - volctrl->channel3 = buffer[27]; - scsi_free(buffer, 512); - break; - } - - case CDROMSUBCHNL: - { - struct cdrom_subchnl* subchnl = (struct cdrom_subchnl*)arg; - char * buffer; - - sr_cmd[0] = SCMD_READ_SUBCHANNEL; - sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02; /* MSF format */ - sr_cmd[2] = 0x40; /* I do want the subchannel info */ - sr_cmd[3] = 0x01; /* Give me current position info */ - sr_cmd[4] = sr_cmd[5] = 0; - sr_cmd[6] = 0; - sr_cmd[7] = 0; - sr_cmd[8] = 16; - sr_cmd[9] = 0; - - if ((buffer = (unsigned char *) scsi_malloc(512)) == NULL) - return -ENOMEM; - - result = sr_do_ioctl(target, sr_cmd, buffer, 16, 0); - - subchnl->cdsc_audiostatus = buffer[1]; - subchnl->cdsc_format = CDROM_MSF; - subchnl->cdsc_ctrl = buffer[5] & 0xf; - subchnl->cdsc_trk = buffer[6]; - subchnl->cdsc_ind = buffer[7]; - - subchnl->cdsc_reladdr.msf.minute = buffer[13]; - subchnl->cdsc_reladdr.msf.second = buffer[14]; - subchnl->cdsc_reladdr.msf.frame = buffer[15]; - subchnl->cdsc_absaddr.msf.minute = buffer[9]; - subchnl->cdsc_absaddr.msf.second = buffer[10]; - subchnl->cdsc_absaddr.msf.frame = buffer[11]; - - scsi_free(buffer, 512); - break; - } default: return -EINVAL; } @@ -631,7 +403,7 @@ #endif memset(cmd,0,12); - cmd[0] = 0xbe /* READ_CD */; + cmd[0] = GPCMD_READ_CD; /* READ_CD */ cmd[1] = (scsi_CDs[minor].device->lun << 5) | ((format & 7) << 2); cmd[2] = (unsigned char)(lba >> 24) & 0xff; cmd[3] = (unsigned char)(lba >> 16) & 0xff; @@ -677,7 +449,7 @@ #endif memset(cmd,0,12); - cmd[0] = READ_10; + cmd[0] = GPCMD_READ_10; cmd[1] = (scsi_CDs[minor].device->lun << 5); cmd[2] = (unsigned char)(lba >> 24) & 0xff; cmd[3] = (unsigned char)(lba >> 16) & 0xff; @@ -723,123 +495,7 @@ int sr_dev_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, unsigned long arg) { - int target, err; - - target = MINOR(cdi->dev); - - switch (cmd) { - case CDROMREADMODE1: - case CDROMREADMODE2: - case CDROMREADRAW: - { - unsigned char *raw; - struct cdrom_msf msf; - int lba, rc; - int blocksize = 2048; - - switch (cmd) { - case CDROMREADMODE2: blocksize = CD_FRAMESIZE_RAW0; break; /* 2336 */ - case CDROMREADRAW: blocksize = CD_FRAMESIZE_RAW; break; /* 2352 */ - } - - if (copy_from_user(&msf,(void*)arg,sizeof(msf))) - return -EFAULT; - - if ((raw = scsi_malloc(2048+512)) == NULL) - return -ENOMEM; - - lba = (((msf.cdmsf_min0 * CD_SECS) + msf.cdmsf_sec0) - * CD_FRAMES + msf.cdmsf_frame0) - CD_MSF_OFFSET; - if (lba < 0 || lba >= scsi_CDs[target].capacity) - { - scsi_free(raw, 2048+512); - return -EINVAL; - } - - rc = sr_read_sector(target, lba, blocksize, raw); - if (!rc) - if (copy_to_user((void*)arg, raw, blocksize)) - rc = -EFAULT; - - scsi_free(raw,2048+512); - return rc; - } - case CDROMREADAUDIO: - { - unsigned char *raw; - int lba, rc=0; - struct cdrom_read_audio ra; - - if (!scsi_CDs[target].readcd_known || !scsi_CDs[target].readcd_cdda) - return -EINVAL; /* -EDRIVE_DOES_NOT_SUPPORT_THIS ? */ - - if (copy_from_user(&ra,(void*)arg,sizeof(ra))) - return -EFAULT; - - if (ra.addr_format == CDROM_LBA) - lba = ra.addr.lba; - else - lba = (((ra.addr.msf.minute * CD_SECS) + ra.addr.msf.second) - * CD_FRAMES + ra.addr.msf.frame) - CD_MSF_OFFSET; - - if (lba < 0 || lba >= scsi_CDs[target].capacity) - return -EINVAL; - if ((raw = scsi_malloc(2048+512)) == NULL) - return -ENOMEM; - - while (ra.nframes > 0) { - rc = sr_read_cd(target, raw, lba, 1, CD_FRAMESIZE_RAW); - if (!rc) - if (copy_to_user(ra.buf, raw, CD_FRAMESIZE_RAW)) - rc = -EFAULT; - if (rc) - break; - - ra.buf += CD_FRAMESIZE_RAW; - ra.nframes -= 1; - lba++; - } - scsi_free(raw,2048+512); - return rc; - } - case BLKRAGET: - if (!arg) - return -EINVAL; - err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); - if (err) - return err; - put_user(read_ahead[MAJOR(cdi->dev)], (long *) arg); - return 0; - - case BLKRASET: - if(!capable(CAP_SYS_ADMIN)) - return -EACCES; - if(!(cdi->dev)) - return -EINVAL; - if(arg > 0xff) - return -EINVAL; - read_ahead[MAJOR(cdi->dev)] = arg; - return 0; - - case BLKSSZGET: - /* Block size of media */ - return put_user(blksize_size[MAJOR(cdi->dev)][MINOR(cdi->dev)], - (int *)arg); - - RO_IOCTLS(cdi->dev,arg); - - case BLKFLSBUF: - if(!capable(CAP_SYS_ADMIN)) - return -EACCES; - if(!(cdi->dev)) - return -EINVAL; - fsync_dev(cdi->dev); - invalidate_buffers(cdi->dev); - return 0; - - default: - return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) arg); - } + return scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device,cmd,(void *) arg); } /* diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c --- linux-2.2.15/drivers/scsi/sr_vendor.c Thu May 4 15:21:22 2000 +++ linux/drivers/scsi/sr_vendor.c Thu May 4 01:19:23 2000 @@ -60,8 +60,7 @@ #define VENDOR_ID (scsi_CDs[minor].vendor) -void -sr_vendor_init(int minor) +void sr_vendor_init(int minor) { #ifndef CONFIG_BLK_DEV_SR_VENDOR VENDOR_ID = VENDOR_SCSI3; @@ -104,8 +103,7 @@ /* small handy function for switching block length using MODE SELECT, * used by sr_read_sector() */ -int -sr_set_blocklength(int minor, int blocklength) +int sr_set_blocklength(int minor, int blocklength) { unsigned char *buffer; /* the buffer for the ioctl */ unsigned char cmd[12]; /* the scsi-command */ diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/fs/isofs/inode.c linux/fs/isofs/inode.c --- linux-2.2.15/fs/isofs/inode.c Thu May 4 15:21:22 2000 +++ linux/fs/isofs/inode.c Thu May 4 01:19:23 2000 @@ -411,7 +411,7 @@ struct inode inode_fake; struct file_operations *fops; extern struct file_operations * get_blkfops(unsigned int); - int i; + int i, session = 0; vol_desc_start=0; fops = get_blkfops(MAJOR(dev)); @@ -424,6 +424,27 @@ mm_segment_t old_fs=get_fs(); inode_fake.i_rdev=dev; ms_info.addr_format=CDROM_LBA; + /* If a minor device was explicitly opened, set session to the + * minor number. For instance, if /dev/hdc1 is mounted, session + * 1 on the CD-ROM is selected. CD_PART_MAX gives access to + * a max of 64 sessions on IDE. SCSI drives must still use + * the session option to mount. + */ + if ((MINOR(dev) % CD_PART_MAX) && (MAJOR(dev) != SCSI_CDROM_MAJOR)) + session = MINOR(dev) % CD_PART_MAX; + if (session > 0 && session <= CD_PART_MAX) { + struct cdrom_tocentry entry; + entry.cdte_track=session; + entry.cdte_format=CDROM_LBA; + set_fs(KERNEL_DS); + i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake, + NULL, CDROMREADTOCENTRY, (unsigned long) &entry); + set_fs(old_fs); + if(!i) printk(KERN_ERR"Session %d start %d type %d\n",session,entry.cdte_addr.lba,entry.cdte_ctrl&CDROM_DATA_TRACK); + if(i || (entry.cdte_ctrl & CDROM_DATA_TRACK) != 4) + printk(KERN_ERR"Invalid session number or type of track\n"); + else return entry.cdte_addr.lba; + } set_fs(KERNEL_DS); i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake, NULL, diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/include/linux/cdrom.h linux/include/linux/cdrom.h --- linux-2.2.15/include/linux/cdrom.h Thu May 4 15:21:22 2000 +++ linux/include/linux/cdrom.h Thu May 4 01:52:02 2000 @@ -5,12 +5,14 @@ * 1994, 1995 Eberhard Moenkeberg, emoenke@gwdg.de * 1996 David van Leeuwen, david@tm.tno.nl * 1997, 1998 Erik Andersen, andersee@debian.org - * 1998, 1999 Jens Axboe, axboe@image.dk + * 1998-2000 Jens Axboe, axboe@suse.de */ #ifndef _LINUX_CDROM_H #define _LINUX_CDROM_H +#include + /******************************************************* * As of Linux 2.1.x, all Linux CD-ROM application programs will use this * (and only this) include file. It is my hope to provide Linux with @@ -94,16 +96,26 @@ #define CDROMPLAYBLK 0x5317 /* (struct cdrom_blk) */ /* - * These ioctls are used only used in optcd.c + * These ioctls are only used in optcd.c */ #define CDROMREADALL 0x5318 /* read all 2646 bytes */ -#define CDROMCLOSETRAY 0x5319 /* pendant of CDROMEJECT */ + +/* + * These ioctls are (now) only in ide-cd.c for controlling + * drive spindown time. They should be implemented in the + * Uniform driver, via generic packet commands, GPCMD_MODE_SELECT_10, + * GPCMD_MODE_SENSE_10 and the GPMODE_POWER_PAGE... + * -Erik + */ +#define CDROMGETSPINDOWN 0x531d +#define CDROMSETSPINDOWN 0x531e /* * These ioctls are implemented through the uniform CD-ROM driver * They _will_ be adopted by all CD-ROM drivers, when all the CD-ROM * drivers are eventually ported to the uniform CD-ROM driver interface. */ +#define CDROMCLOSETRAY 0x5319 /* pendant of CDROMEJECT */ #define CDROM_SET_OPTIONS 0x5320 /* Set behavior options */ #define CDROM_CLEAR_OPTIONS 0x5321 /* Clear behavior options */ #define CDROM_SELECT_SPEED 0x5322 /* Set the CD-ROM speed */ @@ -119,6 +131,15 @@ /* This ioctl is only used by sbpcd at the moment */ #define CDROMAUDIOBUFSIZ 0x5382 /* set the audio buffer size */ +/* DVD-ROM Specific ioctls */ +#define DVD_READ_STRUCT 0x5390 /* Read structure */ +#define DVD_WRITE_STRUCT 0x5391 /* Write structure */ +#define DVD_AUTH 0x5392 /* Authentication */ + +#define CDROM_SEND_PACKET 0x5393 /* send a packet to the drive */ +#define CDROM_NEXT_WRITABLE 0x5394 /* get next writable block */ +#define CDROM_LAST_WRITTEN 0x5395 /* get last block written on disc */ + /******************************************************* * CDROM IOCTL structures *******************************************************/ @@ -126,9 +147,9 @@ /* Address in MSF format */ struct cdrom_msf0 { - u_char minute; - u_char second; - u_char frame; + __u8 minute; + __u8 second; + __u8 frame; }; /* Address in either MSF or logical format */ @@ -141,48 +162,48 @@ /* This struct is used by the CDROMPLAYMSF ioctl */ struct cdrom_msf { - u_char cdmsf_min0; /* start minute */ - u_char cdmsf_sec0; /* start second */ - u_char cdmsf_frame0; /* start frame */ - u_char cdmsf_min1; /* end minute */ - u_char cdmsf_sec1; /* end second */ - u_char cdmsf_frame1; /* end frame */ + __u8 cdmsf_min0; /* start minute */ + __u8 cdmsf_sec0; /* start second */ + __u8 cdmsf_frame0; /* start frame */ + __u8 cdmsf_min1; /* end minute */ + __u8 cdmsf_sec1; /* end second */ + __u8 cdmsf_frame1; /* end frame */ }; /* This struct is used by the CDROMPLAYTRKIND ioctl */ struct cdrom_ti { - u_char cdti_trk0; /* start track */ - u_char cdti_ind0; /* start index */ - u_char cdti_trk1; /* end track */ - u_char cdti_ind1; /* end index */ + __u8 cdti_trk0; /* start track */ + __u8 cdti_ind0; /* start index */ + __u8 cdti_trk1; /* end track */ + __u8 cdti_ind1; /* end index */ }; /* This struct is used by the CDROMREADTOCHDR ioctl */ struct cdrom_tochdr { - u_char cdth_trk0; /* start track */ - u_char cdth_trk1; /* end track */ + __u8 cdth_trk0; /* start track */ + __u8 cdth_trk1; /* end track */ }; /* This struct is used by the CDROMVOLCTRL and CDROMVOLREAD ioctls */ struct cdrom_volctrl { - u_char channel0; - u_char channel1; - u_char channel2; - u_char channel3; + __u8 channel0; + __u8 channel1; + __u8 channel2; + __u8 channel3; }; /* This struct is used by the CDROMSUBCHNL ioctl */ struct cdrom_subchnl { - u_char cdsc_format; - u_char cdsc_audiostatus; - u_char cdsc_adr: 4; - u_char cdsc_ctrl: 4; - u_char cdsc_trk; - u_char cdsc_ind; + __u8 cdsc_format; + __u8 cdsc_audiostatus; + __u8 cdsc_adr: 4; + __u8 cdsc_ctrl: 4; + __u8 cdsc_trk; + __u8 cdsc_ind; union cdrom_addr cdsc_absaddr; union cdrom_addr cdsc_reladdr; }; @@ -191,12 +212,12 @@ /* This struct is used by the CDROMREADTOCENTRY ioctl */ struct cdrom_tocentry { - u_char cdte_track; - u_char cdte_adr :4; - u_char cdte_ctrl :4; - u_char cdte_format; + __u8 cdte_track; + __u8 cdte_adr :4; + __u8 cdte_ctrl :4; + __u8 cdte_format; union cdrom_addr cdte_addr; - u_char cdte_datamode; + __u8 cdte_datamode; }; /* This struct is used by the CDROMREADMODE1, and CDROMREADMODE2 ioctls */ @@ -211,9 +232,9 @@ struct cdrom_read_audio { union cdrom_addr addr; /* frame address */ - u_char addr_format; /* CDROM_LBA or CDROM_MSF */ + __u8 addr_format; /* CDROM_LBA or CDROM_MSF */ int nframes; /* number of 2352-byte-frames to read at once */ - u_char *buf; /* frame buffer (size: nframes*2352 bytes) */ + __u8 *buf; /* frame buffer (size: nframes*2352 bytes) */ }; /* This struct is used with the CDROMMULTISESSION ioctl */ @@ -222,8 +243,8 @@ union cdrom_addr addr; /* frame address: start-of-last-session (not the new "frame 16"!). Only valid if the "xa_flag" is true. */ - u_char xa_flag; /* 1: "is XA disk" */ - u_char addr_format; /* CDROM_LBA or CDROM_MSF */ + __u8 xa_flag; /* 1: "is XA disk" */ + __u8 addr_format; /* CDROM_LBA or CDROM_MSF */ }; /* This struct is used with the CDROM_GET_MCN ioctl. @@ -233,7 +254,7 @@ */ struct cdrom_mcn { - u_char medium_catalog_number[14]; /* 13 ASCII digits, null-terminated */ + __u8 medium_catalog_number[14]; /* 13 ASCII digits, null-terminated */ }; /* This is used by the CDROMPLAYBLK ioctl */ @@ -243,6 +264,19 @@ unsigned short len; }; +#define CDROM_PACKET_SIZE 12 + +/* for CDROM_PACKET_COMMAND ioctl */ +struct cdrom_generic_command +{ + unsigned char cmd[CDROM_PACKET_SIZE]; + unsigned char *buffer; + unsigned int buflen; + int stat; + struct request_sense *sense; + void *reserved[3]; +}; + /* * A CD-ROM physical sector size is 2048, 2052, 2056, 2324, 2332, 2336, @@ -321,14 +355,6 @@ #define CDROM_AUDIO_ERROR 0x14 /* audio play stopped due to error */ #define CDROM_AUDIO_NO_STATUS 0x15 /* no current audio status to return */ -/* CD-ROM-specific SCSI command opcodes */ -#define SCMD_READ_TOC 0x43 /* read table of contents */ -#define SCMD_PLAYAUDIO_MSF 0x47 /* play data at time offset */ -#define SCMD_PLAYAUDIO_TI 0x48 /* play data at track/index */ -#define SCMD_PAUSE_RESUME 0x4B /* pause/resume audio */ -#define SCMD_READ_SUBCHANNEL 0x42 /* read SC info on playing disc */ -#define SCMD_PLAYAUDIO10 0x45 /* play data at logical block */ - /* capability flags used with the uniform CD-ROM driver */ #define CDC_CLOSE_TRAY 0x1 /* caddy systems _can't_ close */ #define CDC_OPEN_TRAY 0x2 /* but _can_ eject. */ @@ -342,6 +368,12 @@ #define CDC_RESET 0x200 /* hard reset device */ #define CDC_IOCTLS 0x400 /* driver has non-standard ioctls */ #define CDC_DRIVE_STATUS 0x800 /* driver implements drive status */ +#define CDC_GENERIC_PACKET 0x1000 /* driver implements generic packets */ +#define CDC_CD_R 0x2000 /* drive is a CD-R */ +#define CDC_CD_RW 0x4000 /* drive is a CD-RW */ +#define CDC_DVD 0x8000 /* drive is a DVD */ +#define CDC_DVD_R 0x10000 /* drive can write DVD-R */ +#define CDC_DVD_RAM 0x20000 /* drive can write DVD-RAM */ /* drive status possibilities returned by CDROM_DRIVE_STATUS ioctl */ #define CDS_NO_INFO 0 /* if not implemented */ @@ -370,7 +402,316 @@ #define CDSL_NONE ((int) (~0U>>1)-1) #define CDSL_CURRENT ((int) (~0U>>1)) +/* For partition based multisession access. IDE can handle 64 partitions + * per drive - SCSI CD-ROM's use minors to differentiate between the + * various drives, so we can't do multisessions the same way there. + * Use the -o session=x option to mount on them. + */ +#define CD_PART_MAX 64 +#define CD_PART_MASK (CD_PART_MAX - 1) + +/********************************************************************* + * Generic Packet commands, MMC commands, and such + *********************************************************************/ + + /* The generic packet command opcodes for CD/DVD Logical Units, + * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ +#define GPCMD_BLANK 0xa1 +#define GPCMD_CLOSE_TRACK 0x5b +#define GPCMD_FLUSH_CACHE 0x35 +#define GPCMD_FORMAT_UNIT 0x04 +#define GPCMD_GET_CONFIGURATION 0x46 +#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a +#define GPCMD_GET_PERFORMANCE 0xac +#define GPCMD_INQUIRY 0x12 +#define GPCMD_LOAD_UNLOAD 0xa6 +#define GPCMD_MECHANISM_STATUS 0xbd +#define GPCMD_MODE_SELECT_10 0x55 +#define GPCMD_MODE_SENSE_10 0x5a +#define GPCMD_PAUSE_RESUME 0x4b +#define GPCMD_PLAY_AUDIO_10 0x45 +#define GPCMD_PLAY_AUDIO_MSF 0x47 +#define GPCMD_PLAY_CD 0xbc +#define GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e +#define GPCMD_READ_10 0x28 +#define GPCMD_READ_12 0xa8 +#define GPCMD_READ_CDVD_CAPACITY 0x25 +#define GPCMD_READ_CD 0xbe +#define GPCMD_READ_CD_MSF 0xb9 +#define GPCMD_READ_DISC_INFO 0x51 +#define GPCMD_READ_DVD_STRUCTURE 0xad +#define GPCMD_READ_FORMAT_CAPACITIES 0x23 +#define GPCMD_READ_HEADER 0x44 +#define GPCMD_READ_TRACK_RZONE_INFO 0x52 +#define GPCMD_READ_SUBCHANNEL 0x42 +#define GPCMD_READ_TOC_PMA_ATIP 0x43 +#define GPCMD_REPAIR_RZONE_TRACK 0x58 +#define GPCMD_REPORT_KEY 0xa4 +#define GPCMD_REQUEST_SENSE 0x03 +#define GPCMD_RESERVE_RZONE_TRACK 0x53 +#define GPCMD_SCAN 0xba +#define GPCMD_SEEK 0x2b +#define GPCMD_SEND_DVD_STRUCTURE 0xad +#define GPCMD_SEND_EVENT 0xa2 +#define GPCMD_SEND_KEY 0xa3 +#define GPCMD_SEND_OPC 0x54 +#define GPCMD_SET_READ_AHEAD 0xa7 +#define GPCMD_SET_STREAMING 0xb6 +#define GPCMD_START_STOP_UNIT 0x1b +#define GPCMD_STOP_PLAY_SCAN 0x4e +#define GPCMD_TEST_UNIT_READY 0x00 +#define GPCMD_VERIFY_10 0x2f +#define GPCMD_WRITE_10 0x2a +#define GPCMD_WRITE_AND_VERIFY_10 0x2e +/* This is listed as optional in ATAPI 2.6, but is (curiously) + * missing from Mt. Fuji, Table 57. It _is_ mentioned in Mt. Fuji + * Table 377 as an MMC command for SCSi devices though... Most ATAPI + * drives support it. */ +#define GPCMD_SET_SPEED 0xbb +/* This seems to be a SCSI specific CD-ROM opcode + * to play data at track/index */ +#define GPCMD_PLAYAUDIO_TI 0x48 + +/* Is this really used by anything? I couldn't find these...*/ +#if 0 +/* MMC2/MTFuji Opcodes */ +#define ERASE 0x2c +#define READ_BUFFER 0x3c +#endif + + + + +/* Mode page codes for mode sense/set */ +#define GPMODE_R_W_ERROR_PAGE 0x01 +#define GPMODE_WRITE_PARMS_PAGE 0x05 +#define GPMODE_AUDIO_CTL_PAGE 0x0e +#define GPMODE_POWER_PAGE 0x1a +#define GPMODE_FAULT_FAIL_PAGE 0x1c +#define GPMODE_TO_PROTECT_PAGE 0x1d +#define GPMODE_CAPABILITIES_PAGE 0x2a +#define GPMODE_ALL_PAGES 0x3f +/* Not in Mt. Fuji, but in ATAPI 2.6 -- depricated now in favor + * of MODE_SENSE_POWER_PAGE */ +#define GPMODE_CDROM_PAGE 0x0d + + + +/* DVD struct types */ +#define DVD_STRUCT_PHYSICAL 0x00 +#define DVD_STRUCT_COPYRIGHT 0x01 +#define DVD_STRUCT_DISCKEY 0x02 +#define DVD_STRUCT_BCA 0x03 +#define DVD_STRUCT_MANUFACT 0x04 + +struct dvd_layer { + __u8 book_version : 4; + __u8 book_type : 4; + __u8 min_rate : 4; + __u8 disc_size : 4; + __u8 layer_type : 4; + __u8 track_path : 1; + __u8 nlayers : 2; + __u8 track_density : 4; + __u8 linear_density : 4; + __u8 bca : 1; + __u32 start_sector; + __u32 end_sector; + __u32 end_sector_l0; +}; + +struct dvd_physical { + __u8 type; + __u8 layer_num; + struct dvd_layer layer[4]; +}; + +struct dvd_copyright { + __u8 type; + + __u8 layer_num; + __u8 cpst; + __u8 rmi; +}; + +struct dvd_disckey { + __u8 type; + + unsigned agid : 2; + __u8 value[2048]; +}; + +struct dvd_bca { + __u8 type; + + int len; + __u8 value[188]; +}; + +struct dvd_manufact { + __u8 type; + + __u8 layer_num; + int len; + __u8 value[2048]; +}; + +typedef union { + __u8 type; + + struct dvd_physical physical; + struct dvd_copyright copyright; + struct dvd_disckey disckey; + struct dvd_bca bca; + struct dvd_manufact manufact; +} dvd_struct; + +/* + * DVD authentication ioctl + */ + +/* Authentication states */ +#define DVD_LU_SEND_AGID 0 +#define DVD_HOST_SEND_CHALLENGE 1 +#define DVD_LU_SEND_KEY1 2 +#define DVD_LU_SEND_CHALLENGE 3 +#define DVD_HOST_SEND_KEY2 4 + +/* Termination states */ +#define DVD_AUTH_ESTABLISHED 5 +#define DVD_AUTH_FAILURE 6 + +/* Other functions */ +#define DVD_LU_SEND_TITLE_KEY 7 +#define DVD_LU_SEND_ASF 8 +#define DVD_INVALIDATE_AGID 9 +#define DVD_LU_SEND_RPC_STATE 10 +#define DVD_HOST_SEND_RPC_STATE 11 + +/* State data */ +typedef __u8 dvd_key[5]; /* 40-bit value, MSB is first elem. */ +typedef __u8 dvd_challenge[10]; /* 80-bit value, MSB is first elem. */ + +struct dvd_lu_send_agid { + __u8 type; + unsigned agid : 2; +}; + +struct dvd_host_send_challenge { + __u8 type; + unsigned agid : 2; + + dvd_challenge chal; +}; + +struct dvd_send_key { + __u8 type; + unsigned agid : 2; + + dvd_key key; +}; + +struct dvd_lu_send_challenge { + __u8 type; + unsigned agid : 2; + + dvd_challenge chal; +}; + +#define DVD_CPM_NO_COPYRIGHT 0 +#define DVD_CPM_COPYRIGHTED 1 + +#define DVD_CP_SEC_NONE 0 +#define DVD_CP_SEC_EXIST 1 + +#define DVD_CGMS_UNRESTRICTED 0 +#define DVD_CGMS_SINGLE 2 +#define DVD_CGMS_RESTRICTED 3 + +struct dvd_lu_send_title_key { + __u8 type; + unsigned agid : 2; + + dvd_key title_key; + int lba; + unsigned cpm : 1; + unsigned cp_sec : 1; + unsigned cgms : 2; +}; + +struct dvd_lu_send_asf { + __u8 type; + unsigned agid : 2; + + unsigned asf : 1; +}; + +struct dvd_host_send_rpcstate { + __u8 type; + __u8 pdrc; +}; + +struct dvd_lu_send_rpcstate { + __u8 type : 2; + __u8 vra : 3; + __u8 ucca : 3; + __u8 region_mask; + __u8 rpc_scheme; +}; + +typedef union { + __u8 type; + + struct dvd_lu_send_agid lsa; + struct dvd_host_send_challenge hsc; + struct dvd_send_key lsk; + struct dvd_lu_send_challenge lsc; + struct dvd_send_key hsk; + struct dvd_lu_send_title_key lstk; + struct dvd_lu_send_asf lsasf; + struct dvd_host_send_rpcstate hrpcs; + struct dvd_lu_send_rpcstate lrpcs; +} dvd_authinfo; + +struct request_sense { +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 valid : 1; + __u8 error_code : 7; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 error_code : 7; + __u8 valid : 1; +#endif + __u8 segment_number; +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 reserved1 : 2; + __u8 ili : 1; + __u8 reserved2 : 1; + __u8 sense_key : 4; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 sense_key : 4; + __u8 reserved2 : 1; + __u8 ili : 1; + __u8 reserved1 : 2; +#endif + __u8 information[4]; + __u8 add_sense_len; + __u8 command_info[4]; + __u8 asc; + __u8 ascq; + __u8 fruc; + __u8 sks[3]; + __u8 asb[46]; +}; + #ifdef __KERNEL__ + +struct cdrom_write_settings { + unsigned char fpacket; /* fixed/variable packets */ + unsigned long packet_size; /* write out this number of packets */ + unsigned long nwa; /* next writeable address */ + unsigned char writeable; /* cdrom is writeable */ +}; + /* Uniform cdrom data structures for cdrom.c */ struct cdrom_device_info { struct cdrom_device_ops *ops; /* link to device_ops */ @@ -382,11 +723,14 @@ int speed; /* maximum speed for reading data */ int capacity; /* number of discs in jukebox */ /* device-related storage */ - int options : 30; /* options flags */ - unsigned mc_flags : 2; /* media change buffer flags */ + int options : 30; /* options flags */ + unsigned mc_flags : 2; /* media change buffer flags */ int use_count; /* number of times device opened */ char name[20]; /* name of the device type */ - +/* per-device flags */ + __u8 sanyo_slot : 2; /* Sanyo 3 CD changer support */ + __u8 reserved : 6; /* not used yet */ + struct cdrom_write_settings write; }; struct cdrom_device_ops { @@ -413,6 +757,9 @@ /* driver specifications */ const int capability; /* capability flags */ int n_minors; /* number of active minor devices */ + /* handle uniform packets for scsi type devices (scsi,atapi) */ + int (*generic_packet) (struct cdrom_device_info *, + struct cdrom_generic_command *); }; /* the general file operations structure: */ @@ -420,6 +767,7 @@ extern int register_cdrom(struct cdrom_device_info *cdi); extern int unregister_cdrom(struct cdrom_device_info *cdi); + typedef struct { int data; int audio; @@ -427,7 +775,236 @@ int xa; long error; } tracktype; + extern void cdrom_count_tracks(struct cdrom_device_info *cdi,tracktype* tracks); +extern int cdrom_get_next_writable(kdev_t dev, long *next_writable); +extern int cdrom_get_last_written(kdev_t dev, long *last_written); +extern int cdrom_number_of_slots(struct cdrom_device_info *cdi); +extern int cdrom_select_disc(struct cdrom_device_info *cdi, int slot); +extern int cdrom_mode_select(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc); +extern int cdrom_mode_sense(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc, + int page_code, int page_control); +extern void init_cdrom_command(struct cdrom_generic_command *cgc, + void *buffer, int len); + + +typedef struct { + __u16 disc_information_length; +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 reserved1 : 3; + __u8 erasable : 1; + __u8 border_status : 2; + __u8 disc_border : 2; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 disc_border : 2; + __u8 border_status : 2; + __u8 erasable : 1; + __u8 reserved1 : 3; +#else +#error "Please fix " +#endif + __u8 n_first_track; + __u8 n_sessions_lsb; + __u8 first_track_lsb; + __u8 last_track_lsb; +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 did_v : 1; + __u8 dbc_v : 1; + __u8 uru : 1; + __u8 reserved2 : 5; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 reserved2 : 5; + __u8 uru : 1; + __u8 dbc_v : 1; + __u8 did_v : 1; +#endif + __u8 disc_type; + __u8 n_sessions_msb; + __u8 first_track_msb; + __u8 last_track_msb; + __u32 disc_id; + __u32 lead_in; + __u32 lead_out; + __u8 disc_bar_code[8]; + __u8 reserved3; + __u8 n_opc; +} disc_information; + +typedef struct { + __u16 track_information_length; + __u8 track_lsb; + __u8 session_lsb; + __u8 reserved1; +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 reserved2 : 2; + __u8 damage : 1; + __u8 copy : 1; + __u8 track_mode : 4; + __u8 rt : 1; + __u8 blank : 1; + __u8 packet : 1; + __u8 fp : 1; + __u8 data_mode : 4; + __u8 reserved3 : 6; + __u8 lra_v : 1; + __u8 nwa_v : 1; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 track_mode : 4; + __u8 copy : 1; + __u8 damage : 1; + __u8 reserved2 : 2; + __u8 data_mode : 4; + __u8 fp : 1; + __u8 packet : 1; + __u8 blank : 1; + __u8 rt : 1; + __u8 nwa_v : 1; + __u8 lra_v : 1; + __u8 reserved3 : 6; +#endif + __u32 track_start; + __u32 next_writable; + __u32 free_blocks; + __u32 fixed_packet_size; + __u32 track_size; + __u32 last_rec_address; +} track_information; + +/* The SCSI spec says there could be 256 slots. */ +#define CDROM_MAX_SLOTS 256 + +struct cdrom_mechstat_header { +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 fault : 1; + __u8 changer_state : 2; + __u8 curslot : 5; + __u8 mech_state : 3; + __u8 door_open : 1; + __u8 reserved1 : 4; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 curslot : 5; + __u8 changer_state : 2; + __u8 fault : 1; + __u8 reserved1 : 4; + __u8 door_open : 1; + __u8 mech_state : 3; +#endif + __u8 curlba[3]; + __u8 nslots; + __u16 slot_tablelen; +}; + +struct cdrom_slot { +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 disc_present : 1; + __u8 reserved1 : 6; + __u8 change : 1; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 change : 1; + __u8 reserved1 : 6; + __u8 disc_present : 1; +#endif + __u8 reserved2[3]; +}; + +struct cdrom_changer_info { + struct cdrom_mechstat_header hdr; + struct cdrom_slot slots[CDROM_MAX_SLOTS]; +}; + +typedef enum { + mechtype_caddy = 0, + mechtype_tray = 1, + mechtype_popup = 2, + mechtype_individual_changer = 4, + mechtype_cartridge_changer = 5 +} mechtype_t; + +struct mode_page_header { + __u16 mode_data_length; + __u8 medium_type; + __u8 reserved1; + __u8 reserved2; + __u8 reserved3; + __u16 desc_length; +}; + +typedef struct { + struct mode_page_header header; +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 ps : 1; + __u8 reserved1 : 1; + __u8 page_code : 6; + __u8 page_length; + __u8 reserved2 : 1; + __u8 bufe : 1; + __u8 ls_v : 1; + __u8 test_write : 1; + __u8 write_type : 4; + __u8 multi_session : 2; /* or border, DVD */ + __u8 fp : 1; + __u8 copy : 1; + __u8 track_mode : 4; + __u8 reserved3 : 4; + __u8 data_block_type : 4; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 page_code : 6; + __u8 reserved1 : 1; + __u8 ps : 1; + __u8 page_length; + __u8 write_type : 4; + __u8 test_write : 1; + __u8 ls_v : 1; + __u8 bufe : 1; + __u8 reserved2 : 1; + __u8 track_mode : 4; + __u8 copy : 1; + __u8 fp : 1; + __u8 multi_session : 2; /* or border, DVD */ + __u8 data_block_type : 4; + __u8 reserved3 : 4; +#endif + __u8 link_size; + __u8 reserved4; +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 reserved5 : 2; + __u8 app_code : 6; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 app_code : 6; + __u8 reserved5 : 2; +#endif + __u8 session_format; + __u8 reserved6; + __u32 packet_size; + __u16 audio_pause; + __u8 mcn[16]; + __u8 isrc[16]; + __u8 subhdr0; + __u8 subhdr1; + __u8 subhdr2; + __u8 subhdr3; +} __attribute__((packed)) write_param_page; + +typedef struct { + __u16 report_key_length; + __u8 reserved1; + __u8 reserved2; +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 type_code : 2; + __u8 vra : 3; + __u8 ucca : 3; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 ucca : 3; + __u8 vra : 3; + __u8 type_code : 2; +#endif + __u8 region_mask; + __u8 rpc_scheme; + __u8 reserved3; +} rpc_state_t; + #endif /* End of kernel only stuff */ #endif /* _LINUX_CDROM_H */ diff -ur --exclude-from /home/axboe/cdrom/exclude linux-2.2.15/include/linux/sysctl.h linux/include/linux/sysctl.h --- linux-2.2.15/include/linux/sysctl.h Thu May 4 15:21:22 2000 +++ linux/include/linux/sysctl.h Thu May 4 01:19:23 2000 @@ -435,7 +435,12 @@ /* /proc/sys/dev/cdrom */ enum { - DEV_CDROM_INFO=1 + DEV_CDROM_INFO=1, + DEV_CDROM_AUTOCLOSE=2, + DEV_CDROM_AUTOEJECT=3, + DEV_CDROM_DEBUG=4, + DEV_CDROM_LOCK=5, + DEV_CDROM_CHECK_MEDIA=6 }; #ifdef __KERNEL__