patch-2.2.16 linux/drivers/block/ide-cd.c
Next file: linux/drivers/block/ide-cd.h
Previous file: linux/drivers/block/genhd.c
Back to the patch index
Back to the overall index
- Lines: 3023
- Date:
Wed Jun 7 14:26:42 2000
- Orig file:
v2.2.15/linux/drivers/block/ide-cd.c
- Orig date:
Wed May 3 17:16:33 2000
diff -urN v2.2.15/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
@@ -2,7 +2,7 @@
* linux/drivers/block/ide-cd.c
* Copyright (C) 1994, 1995, 1996 scott snyder <snyder@fnald0.fnal.gov>
* Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org>
- * Copyright (C) 1998, 1999 Jens Axboe
+ * Copyright (C) 1998-2000 Jens Axboe <axboe@suse.de>
*
* 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 <heiko@colossus.escape.de> supplied
+ * some fixes for CDI.
+ * - CD-ROM leaving door locked fix from Andries
+ * Brouwer <Andries.Brouwer@cwi.nl>
+ * - Erik Andersen <andersen@xmission.com> 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 <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -266,6 +295,7 @@
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/cdrom.h>
+
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/byteorder.h>
@@ -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; i<sizeof (failed_command->c); 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,148 @@
struct cdrom_device_info *devinfo = &info->devinfo;
int minor = (drive->select.b.unit)<<PARTN_BITS;
- devinfo->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) {
+ if (!(!strcmp(drive->id->model, "ATAPI CD ROM DRIVE 50X MAX") ||
+ !strcmp(drive->id->model, "WPI CDS-32X")))
+ size -= sizeof(cap->pad);
+ }
+
+ /* 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;
+ }
+
+ /* 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_rw)
+ 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 +2330,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 +2350,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 (dev, 1);
- blksize_size[HWIF(drive)->major][drive->select.b.unit << PARTN_BITS] =
- CD_FRAMESIZE;
+ set_device_ro(MKDEV(HWIF(drive)->major, minor), 1);
+ set_blocksize(MKDEV(HWIF(drive)->major, minor), 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 +2382,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 +2456,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 +2494,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 +2524,6 @@
(drive->select.b.unit)<<PARTN_BITS));
}
-
static
int ide_cdrom_cleanup(ide_drive_t *drive)
{
@@ -3187,15 +2532,15 @@
if (ide_unregister_subdriver (drive))
return 1;
- if (info->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 +2580,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 +2592,11 @@
}
ide_unregister_module (&ide_cdrom_module);
}
+
+int init_module(void)
+{
+ return ide_cdrom_init();
+}
#endif /* MODULE */
int ide_cdrom_init (void)
@@ -3263,11 +2608,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 +2640,3 @@
MOD_DEC_USE_COUNT;
return 0;
}
-
-
-/*==========================================================================*/
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)