patch-2.1.34 linux/drivers/scsi/sr_vendor.c
Next file: linux/fs/binfmt_em86.c
Previous file: linux/drivers/scsi/sr_ioctl.c
Back to the patch index
Back to the overall index
- Lines: 299
- Date:
Mon Apr 14 09:26:00 1997
- Orig file:
v2.1.33/linux/drivers/scsi/sr_vendor.c
- Orig date:
Tue Nov 12 22:11:17 1996
diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c
@@ -7,6 +7,23 @@
* be exact: there is'nt anything in my draft copy).
*
* Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * --------------------------------------------------------------------------
+ *
+ * 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, TEAC: known to work with SONY code.
+ *
+ * - HP: Much like SONY, but a little different... (Thomas)
+ * HP-Writers only ??? Maybe other CD-Writers work with this too ?
*/
#include <linux/errno.h>
@@ -27,9 +44,11 @@
#define VENDOR_NEC 2
#define VENDOR_TOSHIBA 3
#define VENDOR_SONY_LIKE 4 /* much drives are Sony compatible */
-#define VENDOR_HP 5
+#define VENDOR_HP 5 /* HP Writers, others too ?? */
+#if 0
#define DEBUG
+#endif
void
sr_vendor_init(int minor)
@@ -37,9 +56,13 @@
char *vendor = scsi_CDs[minor].device->vendor;
char *model = scsi_CDs[minor].device->model;
- if (!strncmp (vendor, "NEC", 3)) {
+ if ((!strncmp(vendor,"HP",2) || !strncmp(vendor,"PHILIPS",7)) &&
+ scsi_CDs[minor].device->type == TYPE_WORM) {
+ scsi_CDs[minor].vendor = VENDOR_HP;
+
+ } else if (!strncmp (vendor, "NEC", 3)) {
scsi_CDs[minor].vendor = VENDOR_NEC;
- if (!strncmp (model,"CD-ROM DRIVE:25", 15) ||
+ 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))
@@ -49,45 +72,102 @@
} 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;
+#ifdef DEBUG
+ printk(KERN_DEBUG
+ "sr: using \"Sony group\" multisession code\n");
+#endif
}
}
+/* small handy function for switching block length using MODE SELECT,
+ * used by sr_read_sector() */
-/*
- * 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.
+static int
+set_density_and_blocklength(int minor, unsigned char *buffer,
+ int density, int blocklength)
+{
+ unsigned char cmd[12]; /* the scsi-command */
+ struct ccs_modesel_head *modesel;
+ int rc;
+
+ memset(cmd,0,12);
+ cmd[0] = MODE_SELECT;
+ cmd[1] = (scsi_CDs[minor].device->lun << 5) | (1 << 4);
+ cmd[4] = 12;
+ modesel = (struct ccs_modesel_head*)buffer;
+ memset(modesel,0,sizeof(*modesel));
+ modesel->block_desc_length = 0x08;
+ modesel->density = density;
+ modesel->block_length_med = (blocklength >> 8 ) & 0xff;
+ modesel->block_length_lo = blocklength & 0xff;
+ rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel));
+#ifdef DEBUG
+ if (rc)
+ printk("sr: switching blocklength to %d bytes failed\n",
+ blocklength);
+#endif
+ return rc;
+}
+
+
+/* read a sector with other than 2048 bytes length
+ * dest is assumed to be allocated with scsi_malloc
*
- * - HP: Much like SONY, but a little different... (Thomas)
- * HP-Writers only ???
+ * XXX maybe we have to do some locking here.
*/
+int
+sr_read_sector(int minor, int lba, int blksize, unsigned char *dest)
+{
+ unsigned char *buffer; /* the buffer for the ioctl */
+ unsigned char cmd[12]; /* the scsi-command */
+ int rc, density;
+
+ density = (scsi_CDs[minor].vendor == VENDOR_TOSHIBA) ? 0x83 : 0;
+
+ buffer = (unsigned char *) scsi_malloc(512);
+ if (!buffer) return -ENOMEM;
+
+ rc = set_density_and_blocklength(minor, buffer, density, blksize);
+ if (!rc) {
+ memset(cmd,0,12);
+ cmd[0] = READ_10;
+ cmd[1] = (scsi_CDs[minor].device->lun << 5);
+ cmd[2] = (unsigned char)(lba >> 24) & 0xff;
+ cmd[3] = (unsigned char)(lba >> 16) & 0xff;
+ cmd[4] = (unsigned char)(lba >> 8) & 0xff;
+ cmd[5] = (unsigned char) lba & 0xff;
+ cmd[8] = 1;
+ rc = sr_do_ioctl(minor, cmd, dest, blksize);
+ set_density_and_blocklength(minor, buffer, density, 2048);
+ }
+
+ scsi_free(buffer, 512);
+ return rc;
+}
+
+
+/* This function gets called after a media change. Checks if the CD is
+ multisession, asks for offset etc. */
+
#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 */
+ unsigned char *buffer; /* the buffer for the ioctl */
+ unsigned char *raw_sector;
+ unsigned char cmd[12]; /* the scsi-command */
int rc,is_xa,no_multi,minor;
minor = MINOR(cdi->dev);
+ if (scsi_CDs[minor].cdi.mask & CDC_MULTI_SESSION)
+ return 0;
buffer = (unsigned char *) scsi_malloc(512);
if(!buffer) return -ENOMEM;
@@ -116,7 +196,6 @@
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:
@@ -141,36 +220,6 @@
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:
@@ -209,15 +258,10 @@
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);
@@ -227,7 +271,7 @@
if (rc != 0) {
break;
}
- if ((buffer[0] << 8) + buffer[1] != 0x0a) {
+ 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;
@@ -238,7 +282,6 @@
/* ignore sector offsets from first track */
sector = 0;
}
- is_xa = !!sector;
break;
case VENDOR_CAN_NOT_HANDLE:
@@ -255,19 +298,39 @@
no_multi = 1;
break;
}
-
+
+ scsi_CDs[minor].xa_flag = 0;
+ if (CDS_AUDIO != sr_disk_status(cdi)) {
+ /* read a sector in raw mode to check the sector format */
+ raw_sector = (unsigned char *) scsi_malloc(2048+512);
+ if (!buffer) return -ENOMEM;
+ if (0 == sr_read_sector(minor,sector+16,CD_FRAMESIZE_RAW1,
+ raw_sector)){
+ is_xa = (raw_sector[3] == 0x02);
+ if (sector > 0 && !is_xa)
+ printk(KERN_INFO "sr: broken CD found: It is "
+ "multisession, but has'nt XA sectors\n");
+ } else {
+ /* read a raw sector failed for some reason. */
+ is_xa = (sector > 0);
+ }
+ scsi_free(raw_sector, 2048+512);
+ }
#ifdef DEBUG
- if (sector)
- printk(KERN_DEBUG
- "sr: multisession CD detected, offset: %lu\n",sector);
+ else printk("sr: audio CD found\n");
#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);
+#ifdef DEBUG
+ printk(KERN_DEBUG
+ "sr: multisession offset=%lu, XA=%s\n",
+ sector,is_xa ? "yes" : "no");
+#endif
+
+ scsi_free(buffer, 512);
return rc;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov