patch-2.1.10 linux/drivers/scsi/sr_vendor.c
Next file: linux/fs/binfmt_elf.c
Previous file: linux/drivers/scsi/sr_ioctl.c
Back to the patch index
Back to the overall index
- Lines: 274
- Date:
Wed Nov 13 08:11:17 1996
- Orig file:
v2.1.9/linux/drivers/scsi/sr_vendor.c
- Orig date:
Thu Jan 1 02:00:00 1970
diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c
@@ -0,0 +1,273 @@
+/* -*-linux-c-*-
+ *
+ * vendor-specific code for SCSI CD-ROM's goes here.
+ *
+ * This is needed becauce most of the new features (multisession and
+ * the like) are to new to be included into the SCSI-II standard (to
+ * be exact: there is'nt anything in my draft copy).
+ *
+ * Gerd Knorr <kraxel@cs.tu-berlin.de>
+ */
+
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#include <linux/blk.h>
+#include "scsi.h"
+#include "hosts.h"
+#include <scsi/scsi_ioctl.h>
+
+#include <linux/cdrom.h>
+#include <linux/ucdrom.h>
+#include "sr.h"
+
+/* here are some constants to sort the vendors into groups */
+
+#define VENDOR_CAN_NOT_HANDLE 1 /* don't know how to handle */
+#define VENDOR_NEC 2
+#define VENDOR_TOSHIBA 3
+#define VENDOR_SONY_LIKE 4 /* much drives are Sony compatible */
+#define VENDOR_HP 5
+
+#define DEBUG
+
+void
+sr_vendor_init(int minor)
+{
+ char *vendor = scsi_CDs[minor].device->vendor;
+ char *model = scsi_CDs[minor].device->model;
+
+ if (!strncmp (vendor, "NEC", 3)) {
+ scsi_CDs[minor].vendor = VENDOR_NEC;
+ if (!strncmp (model,"CD-ROM DRIVE:25", 15) ||
+ !strncmp (model,"CD-ROM DRIVE:36", 15) ||
+ !strncmp (model,"CD-ROM DRIVE:83", 15) ||
+ !strncmp (model,"CD-ROM DRIVE:84 ",16))
+ /* these can't handle multisession, may hang */
+ scsi_CDs[minor].cdi.mask |= CDC_MULTI_SESSION;
+
+ } else if (!strncmp (vendor, "TOSHIBA", 7)) {
+ scsi_CDs[minor].vendor = VENDOR_TOSHIBA;
+
+ } else if (!strncmp (vendor, "HP", 2)) {
+ scsi_CDs[minor].vendor = VENDOR_HP;
+
+ } else {
+ /* most drives can handled like sony ones, so we take
+ * it as default */
+ scsi_CDs[minor].vendor = VENDOR_SONY_LIKE;
+ }
+}
+
+
+
+/*
+ * support for XA/multisession-CD's
+ *
+ * - NEC: Detection and support of multisession CD's.
+ *
+ * - TOSHIBA: Detection and support of multisession CD's.
+ * Some XA-Sector tweaking, required for older drives.
+ *
+ * - SONY: Detection and support of multisession CD's.
+ * added by Thomas Quinot <operator@melchior.cuivre.fdn.fr>
+ *
+ * - PIONEER, HITACHI, PLEXTOR, MATSHITA: known to work with SONY code.
+ *
+ * - HP: Much like SONY, but a little different... (Thomas)
+ * HP-Writers only ???
+ */
+
+#define BCD_TO_BIN(x) ((((int)x & 0xf0) >> 4)*10 + ((int)x & 0x0f))
+
+int sr_cd_check(struct cdrom_device_info *cdi)
+{
+ unsigned long sector,min,sec,frame;
+ unsigned char *buffer; /* the buffer for the ioctl */
+ unsigned char cmd[12]; /* the scsi-command */
+ int rc,is_xa,no_multi,minor;
+
+ minor = MINOR(cdi->dev);
+
+ buffer = (unsigned char *) scsi_malloc(512);
+ if(!buffer) return -ENOMEM;
+
+ sector = 0; /* the multisession sector offset goes here */
+ is_xa = 0; /* flag: the CD uses XA-Sectors */
+ no_multi = 0; /* flag: the drive can't handle multisession */
+ rc = 0;
+
+ switch(scsi_CDs[minor].vendor) {
+
+ case VENDOR_NEC:
+ memset(cmd,0,12);
+ cmd[0] = 0xde;
+ cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03;
+ cmd[2] = 0xb0;
+ rc = sr_do_ioctl(minor, cmd, buffer, 0x16);
+ if (rc != 0)
+ break;
+ if (buffer[14] != 0 && buffer[14] != 0xb0) {
+ printk(KERN_INFO "sr (nec): Hmm, seems the cdrom doesn't support multisession CD's\n");
+ no_multi = 1;
+ break;
+ }
+ min = BCD_TO_BIN(buffer[15]);
+ sec = BCD_TO_BIN(buffer[16]);
+ frame = BCD_TO_BIN(buffer[17]);
+ sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
+ is_xa = (buffer[14] == 0xb0);
+ break;
+
+ case VENDOR_TOSHIBA:
+ /* we request some disc information (is it a XA-CD ?,
+ * where starts the last session ?) */
+ memset(cmd,0,12);
+ cmd[0] = 0xc7;
+ cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3;
+ rc = sr_do_ioctl(minor, cmd, buffer, 4);
+ if (rc == 0x28000002 &&
+ !scsi_ioctl(scsi_CDs[minor].device,
+ SCSI_IOCTL_TEST_UNIT_READY, NULL)) {
+ printk(KERN_INFO "sr (toshiba): Hmm, seems the drive doesn't support multisession CD's\n");
+ no_multi = 1;
+ break;
+ }
+ if (rc != 0)
+ break;
+ min = BCD_TO_BIN(buffer[1]);
+ sec = BCD_TO_BIN(buffer[2]);
+ frame = BCD_TO_BIN(buffer[3]);
+ sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
+ if (sector)
+ sector -= CD_BLOCK_OFFSET;
+ is_xa = (buffer[0] == 0x20);
+#if 0
+ /* this is required for some CD's:
+ * - Enhanced-CD (Hardware tells wrong XA-flag)
+ * - these broken non-XA multisession CD's
+ */
+ if (is_xa == 0 && sector != 0) {
+ printk(KERN_WARNING "Warning: multisession offset "
+ "found, setting XA-flag\n");
+ is_xa = 1;
+ }
+#endif
+ /* now the XA-Sector tweaking: set_density... */
+ memset(cmd,0,12);
+ cmd[0] = MODE_SELECT;
+ cmd[1] = (scsi_CDs[minor].device->lun << 5)
+ | (1 << 4);
+ cmd[4] = 12;
+ memset(buffer,0,12);
+ buffer[ 3] = 0x08;
+ buffer[ 4] = 0x83;
+ buffer[10] = 0x08;
+ rc = sr_do_ioctl(minor, cmd, buffer, 12);
+ if (rc != 0) {
+ break;
+ }
+#if 0
+ /* shoult'nt be required any more */
+ scsi_CDs[minor].needs_sector_size = 1;
+#endif
+ break;
+
+ case VENDOR_HP:
+ cmd[0] = READ_TOC;
+ cmd[1] = (scsi_CDs[minor].device->lun << 5);
+ cmd[8] = 0x04;
+ cmd[9] = 0x40;
+ rc = sr_do_ioctl(minor, cmd, buffer, 12);
+ if (rc != 0) {
+ break;
+ }
+ if ((rc = buffer[2]) == 0) {
+ printk (KERN_WARNING
+ "sr (hp): No finished session\n");
+ break;
+ }
+
+ cmd[0] = READ_TOC; /* Read TOC */
+ cmd[1] = (scsi_CDs[minor].device->lun << 5);
+ cmd[6] = rc & 0x7f; /* number of last session */
+ cmd[8] = 0x0c;
+ cmd[9] = 0x40;
+ rc = sr_do_ioctl(minor, cmd, buffer, 12);
+ if (rc != 0) {
+ break;
+ }
+
+#undef STRICT_HP
+#ifdef STRICT_HP
+ sector = buffer[11] + (buffer[10] << 8) + (buffer[9] << 16);
+ /* HP documentation states that Logical Start Address is
+ returned as three (!) bytes, and that buffer[8] is
+ reserved. This is strange, because a LBA usually is
+ 4 bytes long. */
+#else
+ sector = buffer[11] + (buffer[10] << 8) +
+ (buffer[9] << 16) + (buffer[8] << 24);
+#endif
+ is_xa = !!sector;
+ break;
+
+ case VENDOR_SONY_LIKE:
+ /* Thomas QUINOT <thomas@melchior.cuivre.fdn.fr> */
+#ifdef DEBUG
+ printk(KERN_DEBUG
+ "sr: use \"Sony group\" multisession code\n");
+#endif
+ memset(cmd,0,12);
+ cmd[0] = READ_TOC;
+ cmd[1] = (scsi_CDs[minor].device->lun << 5);
+ cmd[8] = 12;
+ cmd[9] = 0x40;
+ rc = sr_do_ioctl(minor, cmd, buffer, 12);
+ if (rc != 0) {
+ break;
+ }
+ if ((buffer[0] << 8) + buffer[1] != 0x0a) {
+ printk(KERN_INFO "sr (sony): Hmm, seems the drive doesn't support multisession CD's\n");
+ no_multi = 1;
+ break;
+ }
+ sector = buffer[11] + (buffer[10] << 8) +
+ (buffer[9] << 16) + (buffer[8] << 24);
+ if (buffer[6] <= 1) {
+ /* ignore sector offsets from first track */
+ sector = 0;
+ }
+ is_xa = !!sector;
+ break;
+
+ case VENDOR_CAN_NOT_HANDLE:
+ sector = 0;
+ no_multi = 1;
+ break;
+
+ default:
+ /* should not happen */
+ printk(KERN_WARNING
+ "sr: unknown vendor code (%i), not initialized ?\n",
+ scsi_CDs[minor].vendor);
+ sector = 0;
+ no_multi = 1;
+ break;
+ }
+
+#ifdef DEBUG
+ if (sector)
+ printk(KERN_DEBUG
+ "sr: multisession CD detected, offset: %lu\n",sector);
+#endif
+
+ scsi_CDs[minor].ms_offset = sector;
+ scsi_CDs[minor].xa_flag = is_xa;
+ if (no_multi)
+ cdi->mask |= CDC_MULTI_SESSION;
+
+ scsi_free(buffer, 512);
+
+ return rc;
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov