patch-2.4.0-prerelease linux/drivers/cdrom/cdrom.c
Next file: linux/drivers/char/Config.in
Previous file: linux/drivers/cdrom/Makefile
Back to the patch index
Back to the overall index
- Lines: 267
- Date:
Sat Dec 30 18:16:13 2000
- Orig file:
v2.4.0-test12/linux/drivers/cdrom/cdrom.c
- Orig date:
Tue Oct 31 12:42:26 2000
diff -u --recursive --new-file v2.4.0-test12/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
@@ -224,11 +224,14 @@
3.11 Jun 12, 2000 - Jens Axboe <axboe@suse.de>
-- Fix bug in getting rpc phase 2 region info.
-- Reinstate "correct" CDROMPLAYTRKIND
-
+
+ 3.12 Oct 18, 2000 - Jens Axboe <axboe@suse.de>
+ -- Use quiet bit on packet commands not known to work
+
-------------------------------------------------------------------------*/
-#define REVISION "Revision: 3.11"
-#define VERSION "Id: cdrom.c 3.11 2000/06/12"
+#define REVISION "Revision: 3.12"
+#define VERSION "Id: cdrom.c 3.12 2000/10/18"
/* 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: */
@@ -701,6 +704,21 @@
struct cdrom_device_ops *cdo = cdi->ops;
int length;
+ /*
+ * Sanyo changer isn't spec compliant (doesn't use regular change
+ * LOAD_UNLOAD command, and it doesn't implement the mech status
+ * command below
+ */
+ if (cdi->sanyo_slot) {
+ buf->hdr.nslots = 3;
+ buf->hdr.curslot = cdi->sanyo_slot == 3 ? 0 : cdi->sanyo_slot;
+ for (length = 0; length < 3; length++) {
+ buf->slots[length].disc_present = 1;
+ buf->slots[length].change = 0;
+ }
+ return 0;
+ }
+
length = sizeof(struct cdrom_mechstat_header) +
cdi->capacity * sizeof(struct cdrom_slot);
@@ -767,9 +785,10 @@
/* 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) {
+ if (cdi->sanyo_slot && -1 < slot) {
cgc.cmd[0] = GPCMD_TEST_UNIT_READY;
cgc.cmd[7] = slot;
+ cgc.cmd[4] = cgc.cmd[8] = 0;
cdi->sanyo_slot = slot ? slot : 3;
}
@@ -953,6 +972,7 @@
cgc->buffer = (char *) buf;
cgc->buflen = len;
cgc->data_direction = type;
+ cgc->timeout = 5*HZ;
}
/* DVD handling */
@@ -1860,6 +1880,48 @@
return cdo->generic_packet(cdi, &cgc);
}
+static int cdrom_do_cmd(struct cdrom_device_info *cdi,
+ struct cdrom_generic_command *cgc)
+{
+ struct request_sense *usense, sense;
+ unsigned char *ubuf;
+ int ret;
+
+ if (cgc->data_direction == CGC_DATA_UNKNOWN)
+ return -EINVAL;
+
+ if (cgc->buflen < 0 || cgc->buflen >= 131072)
+ return -EINVAL;
+
+ if ((ubuf = cgc->buffer)) {
+ cgc->buffer = kmalloc(cgc->buflen, GFP_KERNEL);
+ if (cgc->buffer == NULL)
+ return -ENOMEM;
+ }
+
+ usense = cgc->sense;
+ cgc->sense = &sense;
+ if (usense && !access_ok(VERIFY_WRITE, usense, sizeof(*usense)))
+ return -EFAULT;
+
+ if (cgc->data_direction == CGC_DATA_READ) {
+ if (!access_ok(VERIFY_READ, ubuf, cgc->buflen))
+ return -EFAULT;
+ } else if (cgc->data_direction == CGC_DATA_WRITE) {
+ if (copy_from_user(cgc->buffer, ubuf, cgc->buflen)) {
+ kfree(cgc->buffer);
+ return -EFAULT;
+ }
+ }
+
+ ret = cdi->ops->generic_packet(cdi, cgc);
+ __copy_to_user(usense, cgc->sense, sizeof(*usense));
+ if (!ret && cgc->data_direction == CGC_DATA_READ)
+ __copy_to_user(ubuf, cgc->buffer, cgc->buflen);
+ kfree(cgc->buffer);
+ return ret;
+}
+
static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
unsigned long arg)
{
@@ -1923,7 +1985,7 @@
}
case CDROMREADAUDIO: {
struct cdrom_read_audio ra;
- int lba, frames;
+ int lba;
IOCTL_IN(arg, struct cdrom_read_audio, ra);
@@ -1937,14 +1999,10 @@
return -EINVAL;
/* FIXME: we need upper bound checking, too!! */
- if (lba < 0)
+ if (lba < 0 || ra.nframes <= 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)
+ if ((cgc.buffer = (char *) kmalloc(CD_FRAMESIZE_RAW, GFP_KERNEL)) == NULL)
return -ENOMEM;
if (!access_ok(VERIFY_WRITE, ra.buf, ra.nframes*CD_FRAMESIZE_RAW)) {
@@ -1953,13 +2011,12 @@
}
cgc.data_direction = CGC_DATA_READ;
while (ra.nframes > 0) {
- ret = cdrom_read_block(cdi, &cgc, lba, frames, 1, CD_FRAMESIZE_RAW);
+ ret = cdrom_read_block(cdi, &cgc, lba, 1, 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;
+ __copy_to_user(ra.buf, cgc.buffer, CD_FRAMESIZE_RAW);
+ ra.buf += CD_FRAMESIZE_RAW;
+ ra.nframes--;
+ lba++;
}
kfree(cgc.buffer);
return ret;
@@ -2051,7 +2108,7 @@
cgc.buffer = mask;
if ((ret = cdrom_mode_sense(cdi, &cgc,
GPMODE_AUDIO_CTL_PAGE, 1)))
- return ret;
+ return ret;
buffer[offset+9] = volctrl.channel0 & mask[offset+9];
buffer[offset+11] = volctrl.channel1 & mask[offset+11];
@@ -2117,52 +2174,11 @@
}
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;
- }
- if (!access_ok(VERIFY_READ, userbuf, cgc.buflen)) {
- printk("can't get read perms\n");
- return -EFAULT;
- }
- }
- /* 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;
+ return cdrom_do_cmd(cdi, &cgc);
}
case CDROM_NEXT_WRITABLE: {
long next = 0;
@@ -2199,6 +2215,7 @@
cgc.cmd[4] = (track & 0xff00) >> 8;
cgc.cmd[5] = track & 0xff;
cgc.cmd[8] = 8;
+ cgc.quiet = 1;
if ((ret = cdo->generic_packet(cdi, &cgc)))
return ret;
@@ -2220,6 +2237,7 @@
init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ);
cgc.cmd[0] = GPCMD_READ_DISC_INFO;
cgc.cmd[8] = cgc.buflen = 2;
+ cgc.quiet = 1;
if ((ret = cdo->generic_packet(cdi, &cgc)))
return ret;
@@ -2252,9 +2270,6 @@
if (!CDROM_CAN(CDC_GENERIC_PACKET))
goto use_toc;
- if (!CDROM_CAN(CDC_CD_R | CDC_CD_RW | CDC_DVD_R | CDC_DVD_RAM))
- goto use_toc;
-
if ((ret = cdrom_get_disc_info(dev, &di)))
goto use_toc;
@@ -2558,10 +2573,11 @@
/* Make sure that /proc/sys/dev is there */
ctl_table cdrom_root_table[] = {
+#ifdef CONFIG_PROC_FS
{CTL_DEV, "dev", NULL, 0, 0555, cdrom_cdrom_table},
+#endif /* CONFIG_PROC_FS */
{0}
};
-
static struct ctl_table_header *cdrom_sysctl_header;
static void cdrom_sysctl_register(void)
@@ -2572,9 +2588,8 @@
return;
cdrom_sysctl_header = register_sysctl_table(cdrom_root_table, 1);
-#ifdef CONFIG_PROC_FS
cdrom_root_table->child->de->owner = THIS_MODULE;
-#endif /* CONFIG_PROC_FS */
+
/* set the defaults */
cdrom_sysctl_settings.autoclose = autoclose;
cdrom_sysctl_settings.autoeject = autoeject;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)