patch-2.1.70 linux/drivers/cdrom/cdu31a.c
Next file: linux/drivers/cdrom/cdu31a.h
Previous file: linux/drivers/cdrom/cdrom.c
Back to the patch index
Back to the overall index
- Lines: 1815
- Date:
Tue Dec 2 11:41:44 1997
- Orig file:
v2.1.69/linux/drivers/cdrom/cdu31a.c
- Orig date:
Wed Sep 24 20:05:46 1997
diff -u --recursive --new-file v2.1.69/linux/drivers/cdrom/cdu31a.c linux/drivers/cdrom/cdu31a.c
@@ -111,6 +111,13 @@
* Heiko Eissfeldt <heiko@colossus.escape.de>
* For finding abug in the return of the track numbers.
*/
+/* conversion to Uniform cdrom layer.
+ TOC processing redone for proper multisession support.
+
+ TODO:
+ CDs with form1 and form2 sectors cause problems
+ with current read-ahead strategy.
+ Heiko Eissfeldt Sep 97 */
/*
*
@@ -173,7 +180,13 @@
* status and be reset. It recovers, though.
*
* 03/07/97 - Fixed a problem with timers.
- */
+ *
+ *
+ * 18 Spetember 1997 -- Ported to Uniform CD-ROM driver by
+ * Heiko Eissfeldt <heiko@colossus.escape.de> with additional
+ * changes by Erik Andersen <andersee@debian.org>
+ *
+*/
#include <linux/major.h>
@@ -198,16 +211,16 @@
#include <asm/dma.h>
#include <linux/cdrom.h>
-#include <linux/cdu31a.h>
+#include "cdu31a.h"
#define MAJOR_NR CDU31A_CDROM_MAJOR
#include <linux/blk.h>
-#define DEBUG 0
-
-#define CDU31A_READAHEAD 128 /* 128 sector, 64kB, 32 reads read-ahead */
+#define CDU31A_READAHEAD 4 /* 128 sector, 64kB, 32 reads read-ahead */
#define CDU31A_MAX_CONSECUTIVE_ATTENTIONS 10
+#define DEBUG 0
+
/* Define the following if you have data corruption problems. */
#undef SONY_POLL_EACH_BYTE
@@ -240,7 +253,8 @@
static int handle_sony_cd_attention(void);
static int read_subcode(void);
static void sony_get_toc(void);
-static int scd_open(struct inode *inode, struct file *filp);
+/*static int scd_open(struct inode *inode, struct file *filp);*/
+static int scd_open(struct cdrom_device_info *, int);
static void do_sony_cd_cmd(unsigned char cmd,
unsigned char *params,
unsigned int num_params,
@@ -276,6 +290,8 @@
static int sony_spun_up = 0; /* Has the drive been spun up? */
+static int sony_speed = 0; /* Last wanted speed */
+
static int sony_xa_mode = 0; /* Is an XA disk in the drive
and the drive a CDU31A? */
@@ -288,9 +304,12 @@
static int sony_pas_init = 0; /* Initialize the Pro-Audio
Spectrum card? */
-static struct s_sony_session_toc sony_toc; /* Holds the
- table of
- contents. */
+static struct s_sony_session_toc single_toc; /* Holds the
+ table of
+ contents. */
+
+static struct s_all_sessions_toc sony_toc; /* entries gathered from all
+ sessions */
static int sony_toc_read = 0; /* Has the TOC been read for
the drive? */
@@ -307,7 +326,8 @@
using the CDROM drive, or
NULL if none. */
-static int is_double_speed = 0; /* Is the drive a CDU33A? */
+static int is_double_speed = 0; /* does the drive support double speed ? */
+static int is_a_cdu31a = 1; /* Is the drive a CDU31A? */
static int is_auto_eject = 1; /* Door has been locked? 1=No/0=Yes */
@@ -375,6 +395,30 @@
return retval;
}
+/*
+ * Uniform cdrom interface function
+ * report back, if disc has changed from time of last request.
+ */
+static int
+scd_media_changed(struct cdrom_device_info *cdi, int disc_nr)
+{
+ return scd_disk_change(cdi->dev);
+}
+
+/*
+ * Uniform cdrom interface function
+ * report back, if drive is ready
+ */
+static int scd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
+{
+ if (CDSL_CURRENT != slot_nr) {
+ /* we have no changer support */
+ return -EINVAL;
+ }
+
+ return sony_spun_up ? CDS_DISC_OK : CDS_DRIVE_NOT_READY;
+}
+
static inline void
enable_interrupts(void)
{
@@ -474,6 +518,25 @@
outb(SONY_DRIVE_RESET_BIT, sony_cd_control_reg);
}
+/*
+ * Uniform cdrom interface function
+ * reset drive and return when it is ready
+ */
+static int scd_reset(struct cdrom_device_info * cdi)
+{
+ int retry_count;
+
+ reset_drive();
+
+ retry_count = jiffies + SONY_RESET_TIMEOUT;
+ while ((retry_count > jiffies) && (!is_attention()))
+ {
+ sony_sleep();
+ }
+
+ return 0;
+}
+
static inline void
clear_attention(void)
{
@@ -574,11 +637,65 @@
}
/*
+ * give more verbose error messages
+ */
+static unsigned char *translate_error( unsigned char err_code )
+{
+ static unsigned char errbuf[80];
+
+ switch (err_code) {
+ case 0x10: return "illegal command ";
+ case 0x11: return "illegal parameter ";
+
+ case 0x20: return "not loaded ";
+ case 0x21: return "no disc ";
+ case 0x22: return "not spinning ";
+ case 0x23: return "spinning ";
+ case 0x25: return "spindle servo ";
+ case 0x26: return "focus servo ";
+ case 0x29: return "eject mechanism ";
+ case 0x2a: return "audio playing ";
+ case 0x2c: return "emergency eject ";
+
+ case 0x30: return "focus ";
+ case 0x31: return "frame sync ";
+ case 0x32: return "subcode address ";
+ case 0x33: return "block sync ";
+ case 0x34: return "header address ";
+
+ case 0x40: return "illegal track read ";
+ case 0x41: return "mode 0 read ";
+ case 0x42: return "illegal mode read ";
+ case 0x43: return "illegal block size read ";
+ case 0x44: return "mode read ";
+ case 0x45: return "form read ";
+ case 0x46: return "leadout read ";
+ case 0x47: return "buffer overrun ";
+
+ case 0x53: return "unrecoverable CIRC ";
+ case 0x57: return "unrecoverable LECC ";
+
+ case 0x60: return "no TOC ";
+ case 0x61: return "invalid subcode data ";
+ case 0x63: return "focus on TOC read ";
+ case 0x64: return "frame sync on TOC read ";
+ case 0x65: return "TOC data ";
+
+ case 0x70: return "hardware failure ";
+ case 0x91: return "leadin ";
+ case 0x92: return "leadout ";
+ case 0x93: return "data track ";
+ }
+ sprintf(errbuf, "unknown 0x%02x ", err_code);
+ return errbuf;
+}
+
+/*
* Set the drive parameters so the drive will auto-spin-up when a
* disk is inserted.
*/
static void
-set_drive_params(void)
+set_drive_params(int want_doublespeed)
{
unsigned char res_reg[12];
unsigned int res_size;
@@ -602,7 +719,7 @@
if (is_auto_eject) params[1] |= SONY_AUTO_EJECT_BIT;
- if (is_double_speed)
+ if (is_double_speed && want_doublespeed)
{
params[1] |= SONY_DOUBLE_SPEED_BIT; /* Set the drive to double speed if
possible */
@@ -619,6 +736,38 @@
}
/*
+ * Uniform cdrom interface function
+ * select reading speed for data access
+ */
+static int scd_select_speed(struct cdrom_device_info *cdi, int speed)
+{
+ if (speed == 0)
+ sony_speed = 1;
+ else
+ sony_speed = speed - 1;
+
+ set_drive_params(sony_speed);
+ return 0;
+}
+
+/*
+ * Uniform cdrom interface function
+ * lock or unlock eject button
+ */
+static int scd_lock_door(struct cdrom_device_info *cdi, int lock)
+{
+ if (lock == 0 && sony_usage == 1)
+ {
+ /* Unlock the door, only if nobody is using the drive */
+ is_auto_eject = 1;
+ } else {
+ is_auto_eject = 0;
+ }
+ set_drive_params(sony_speed);
+ return 0;
+}
+
+/*
* This code will reset the drive and attempt to restore sane parameters.
*/
static void
@@ -636,7 +785,7 @@
{
sony_sleep();
}
- set_drive_params();
+ set_drive_params(sony_speed);
do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20))
{
@@ -1069,9 +1218,9 @@
unsigned int log;
- log = bcd_to_int(msf[2]);
- log += bcd_to_int(msf[1]) * 75;
- log += bcd_to_int(msf[0]) * 4500;
+ log = msf[2];
+ log += msf[1] * 75;
+ log += msf[0] * 4500;
log = log - LOG_START_OFFSET;
return log;
@@ -1092,10 +1241,37 @@
buf[2] = size % 256;
}
+/* Uniform cdrom interface function.
+ Return the status of the current disc:
+ If it is recognized as CD-I -> return XA Mode 2 Form 2
+ If it is recognized as XA -> return XA Mode 2 Form 1
+ If there is at least one data track return Mode 1
+ else return type AUDIO
+ */
+static int scd_disc_status(struct cdrom_device_info *cdi)
+{
+ if (sony_spun_up)
+ {
+ int i;
+
+ sony_get_toc();
+ /* look into the TOC */
+ if (sony_toc.disk_type == 0x10) /* this is a CD-I disc */
+ return CDS_XA_2_2;
+ if (sony_toc.disk_type == 0x20) /* this is a XA disc */
+ return CDS_XA_2_1;
+ for (i = 0; i < sony_toc.track_entries; i++)
+ if (sony_toc.tracks[i].control & CDROM_DATA_TRACK)
+ return CDS_DATA_1;
+ return CDS_AUDIO;
+ } else
+ return CDS_NO_INFO;
+}
+
/* Starts a read operation. Returns 0 on success and 1 on failure.
The read operation used here allows multiple sequential sectors
to be read and status returned for each sector. The driver will
- read the out one at a time as the requests come and abort the
+ read the output one at a time as the requests come and abort the
operation if the requested sector is not the next one from the
drive. */
static int
@@ -1128,7 +1304,7 @@
/* Read the full readahead amount. */
else
{
- read_size = CDU31A_READAHEAD;
+ read_size = CDU31A_READAHEAD / 4;
}
size_to_buf(read_size, ¶ms[3]);
@@ -1192,8 +1368,9 @@
do_sony_cd_cmd(SONY_ABORT_CMD, NULL, 0, result_reg, &result_size);
if ((result_reg[0] & 0xf0) == 0x20)
{
- printk("CDU31A: Error aborting read, error = 0x%2.2x\n",
- result_reg[1]);
+ printk("CDU31A: Error aborting read, %s error\n",
+ translate_error(
+ result_reg[1]));
}
while (is_result_reg_not_empty())
@@ -1525,6 +1702,8 @@
#endif
}
+static int scd_spinup(void);
+
/*
* The OS calls this to perform a read or write operation to the drive.
* Write obviously fail. Reads to a read ahead of sony_buffer_size
@@ -1599,13 +1778,7 @@
if (!sony_spun_up)
{
- struct inode in;
-
- /* This is a kludge to get a valid dev in an inode that
- scd_open can take. That's the only thing scd_open()
- uses the inode for. */
- in.i_rdev = CURRENT->rq_dev;
- scd_open(&in,NULL);
+ scd_spinup();
}
/* I don't use INIT_REQUEST because it calls return, which would
@@ -1633,16 +1806,6 @@
goto cdu31a_request_startover;
}
- /* Check for base read of multi-session disk. This will still work
- for single session disks, so just do it. Blocks less than 80
- are for the volume info, so offset them by the start track (which
- should be zero for a single-session disk). */
- if (block < 80)
- {
- /* Offset the request into the session. */
- block += (sony_toc.start_track_lba * 4);
- }
-
switch(CURRENT->cmd)
{
case READ:
@@ -1735,7 +1898,7 @@
}
else
{
- printk("CDU31A: Read error: 0x%2.2x\n", res_reg[1]);
+ printk("CDU31A: %s error for block %d, nblock %d\n", translate_error(res_reg[1]), block, nblock);
}
goto try_read_again;
}
@@ -1775,23 +1938,6 @@
#endif
}
-/* Copy overlapping buffers. */
-static void
-mcovlp(char *dst,
- char *src,
- int size)
-{
- src += (size - 1);
- dst += (size - 1);
- while (size > 0)
- {
- *dst = *src;
- size--;
- dst--;
- src--;
- }
-}
-
/*
* Read the table of contents from the drive and set up TOC if
@@ -1805,7 +1951,9 @@
unsigned char parms[1];
int session;
int num_spin_ups;
-
+ int totaltracks = 0;
+ int mint = 99;
+ int maxt = 0;
#if DEBUG
printk("Entering sony_get_toc\n");
@@ -1839,9 +1987,8 @@
goto respinup_on_gettoc;
}
- printk("cdu31a: Error reading TOC: %x %x\n",
- sony_toc.exec_status[0],
- sony_toc.exec_status[1]);
+ printk("cdu31a: Error reading TOC: %x %s\n",
+ res_reg[0], translate_error(res_reg[1]));
return;
}
@@ -1851,9 +1998,12 @@
fails. Then we know what the last valid session on the disk is.
No need to check session 0, since session 0 is the same as session
1; the command returns different information if you give it 0.
- Don't check session 1 because that is the first session, it must
- be there. */
- session = 2;
+ */
+#if DEBUG
+ memset(&sony_toc, 0x0e, sizeof(sony_toc));
+ memset(&single_toc, 0x0f, sizeof(single_toc));
+#endif
+ session = 1;
while (1)
{
#if DEBUG
@@ -1875,95 +2025,265 @@
/* An error reading the TOC, this must be past the last session. */
break;
}
-
- session++;
-
- /* Let's not get carried away... */
- if (session > 20)
- {
- printk("cdu31a: too many sessions: %d\n", session);
- return;
- }
- }
-
- session--;
-
#if DEBUG
- printk("Reading session %d\n", session);
+ printk("Reading session %d\n", session);
#endif
- parms[0] = session;
- do_sony_cd_cmd(SONY_REQ_TOC_DATA_SPEC_CMD,
+ parms[0] = session;
+ do_sony_cd_cmd(SONY_REQ_TOC_DATA_SPEC_CMD,
parms,
1,
- (unsigned char *) &sony_toc,
+ (unsigned char *) &single_toc,
&res_size);
- if ((res_size < 2) || ((sony_toc.exec_status[0] & 0xf0) == 0x20))
- {
- printk("cdu31a: Error reading session %d: %x %x\n",
+ if ((res_size < 2) || ((single_toc.exec_status[0] & 0xf0) == 0x20))
+ {
+ printk("cdu31a: Error reading session %d: %x %s\n",
session,
- sony_toc.exec_status[0],
- sony_toc.exec_status[1]);
- /* An error reading the TOC. Return without sony_toc_read
- set. */
- return;
- }
-
- sony_toc_read = 1;
+ single_toc.exec_status[0],
+ translate_error(single_toc.exec_status[1]));
+ /* An error reading the TOC. Return without sony_toc_read
+ set. */
+ return;
+ }
+#if DEBUG
+ printk("add0 %01x, con0 %01x, poi0 %02x, 1st trk %d, dsktyp %x, dum0 %x\n",
+ single_toc.address0, single_toc.control0, single_toc.point0,
+ bcd_to_int(single_toc.first_track_num), single_toc.disk_type, single_toc.dummy0);
+ printk("add1 %01x, con1 %01x, poi1 %02x, lst trk %d, dummy1 %x, dum2 %x\n",
+ single_toc.address1, single_toc.control1, single_toc.point1,
+ bcd_to_int(single_toc.last_track_num), single_toc.dummy1, single_toc.dummy2);
+ printk("add2 %01x, con2 %01x, poi2 %02x leadout start min %d, sec %d, frame %d\n",
+ single_toc.address2, single_toc.control2, single_toc.point2,
+ bcd_to_int(single_toc.lead_out_start_msf[0]),
+ bcd_to_int(single_toc.lead_out_start_msf[1]),
+ bcd_to_int(single_toc.lead_out_start_msf[2]));
+ if (res_size > 18 && single_toc.pointb0 > 0xaf)
+ printk("addb0 %01x, conb0 %01x, poib0 %02x, nextsession min %d, sec %d, frame %d\n"
+ "#mode5_ptrs %02d, max_start_outer_leadout_msf min %d, sec %d, frame %d\n",
+ single_toc.addressb0, single_toc.controlb0, single_toc.pointb0,
+ bcd_to_int(single_toc.next_poss_prog_area_msf[0]),
+ bcd_to_int(single_toc.next_poss_prog_area_msf[1]),
+ bcd_to_int(single_toc.next_poss_prog_area_msf[2]),
+ single_toc.num_mode_5_pointers,
+ bcd_to_int(single_toc.max_start_outer_leadout_msf[0]),
+ bcd_to_int(single_toc.max_start_outer_leadout_msf[1]),
+ bcd_to_int(single_toc.max_start_outer_leadout_msf[2]));
+ if (res_size > 27 && single_toc.pointb1 > 0xaf)
+ printk("addb1 %01x, conb1 %01x, poib1 %02x, %x %x %x %x #skipint_ptrs %d, #skiptrkassign %d %x\n",
+ single_toc.addressb1, single_toc.controlb1, single_toc.pointb1,
+ single_toc.dummyb0_1[0],
+ single_toc.dummyb0_1[1],
+ single_toc.dummyb0_1[2],
+ single_toc.dummyb0_1[3],
+ single_toc.num_skip_interval_pointers,
+ single_toc.num_skip_track_assignments,
+ single_toc.dummyb0_2);
+ if (res_size > 36 && single_toc.pointb2 > 0xaf)
+ printk("addb2 %01x, conb2 %01x, poib2 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
+ single_toc.addressb2, single_toc.controlb2, single_toc.pointb2,
+ single_toc.tracksb2[0],
+ single_toc.tracksb2[1],
+ single_toc.tracksb2[2],
+ single_toc.tracksb2[3],
+ single_toc.tracksb2[4],
+ single_toc.tracksb2[5],
+ single_toc.tracksb2[6]);
+ if (res_size > 45 && single_toc.pointb3 > 0xaf)
+ printk("addb3 %01x, conb3 %01x, poib3 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
+ single_toc.addressb3, single_toc.controlb3, single_toc.pointb3,
+ single_toc.tracksb3[0],
+ single_toc.tracksb3[1],
+ single_toc.tracksb3[2],
+ single_toc.tracksb3[3],
+ single_toc.tracksb3[4],
+ single_toc.tracksb3[5],
+ single_toc.tracksb3[6]);
+ if (res_size > 54 && single_toc.pointb4 > 0xaf)
+ printk("addb4 %01x, conb4 %01x, poib4 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
+ single_toc.addressb4, single_toc.controlb4, single_toc.pointb4,
+ single_toc.tracksb4[0],
+ single_toc.tracksb4[1],
+ single_toc.tracksb4[2],
+ single_toc.tracksb4[3],
+ single_toc.tracksb4[4],
+ single_toc.tracksb4[5],
+ single_toc.tracksb4[6]);
+ if (res_size > 63 && single_toc.pointc0 > 0xaf)
+ printk("addc0 %01x, conc0 %01x, poic0 %02x, %02x %02x %02x %02x %02x %02x %02x\n",
+ single_toc.addressc0, single_toc.controlc0, single_toc.pointc0,
+ single_toc.dummyc0[0],
+ single_toc.dummyc0[1],
+ single_toc.dummyc0[2],
+ single_toc.dummyc0[3],
+ single_toc.dummyc0[4],
+ single_toc.dummyc0[5],
+ single_toc.dummyc0[6]);
+#endif
+#undef DEBUG
+#define DEBUG 0
+
+ sony_toc.lead_out_start_msf[0] = bcd_to_int(single_toc.lead_out_start_msf[0]);
+ sony_toc.lead_out_start_msf[1] = bcd_to_int(single_toc.lead_out_start_msf[1]);
+ sony_toc.lead_out_start_msf[2] = bcd_to_int(single_toc.lead_out_start_msf[2]);
+ sony_toc.lead_out_start_lba = single_toc.lead_out_start_lba =
+ msf_to_log(sony_toc.lead_out_start_msf);
/* For points that do not exist, move the data over them
to the right location. */
- if (sony_toc.pointb0 != 0xb0)
+ if (single_toc.pointb0 != 0xb0)
{
- mcovlp(((char *) &sony_toc) + 27,
- ((char *) &sony_toc) + 18,
- res_size - 18);
+ memmove(((char *) &single_toc) + 27,
+ ((char *) &single_toc) + 18,
+ res_size - 18);
res_size += 9;
}
- if (sony_toc.pointb1 != 0xb1)
+ else if (res_size > 18) {
+ sony_toc.lead_out_start_msf[0] = bcd_to_int(single_toc.max_start_outer_leadout_msf[0]);
+ sony_toc.lead_out_start_msf[1] = bcd_to_int(single_toc.max_start_outer_leadout_msf[1]);
+ sony_toc.lead_out_start_msf[2] = bcd_to_int(single_toc.max_start_outer_leadout_msf[2]);
+ sony_toc.lead_out_start_lba = msf_to_log(sony_toc.lead_out_start_msf);
+ }
+ if (single_toc.pointb1 != 0xb1)
{
- mcovlp(((char *) &sony_toc) + 36,
- ((char *) &sony_toc) + 27,
+ memmove(((char *) &single_toc) + 36,
+ ((char *) &single_toc) + 27,
res_size - 27);
res_size += 9;
}
- if (sony_toc.pointb2 != 0xb2)
+ if (single_toc.pointb2 != 0xb2)
{
- mcovlp(((char *) &sony_toc) + 45,
- ((char *) &sony_toc) + 36,
+ memmove(((char *) &single_toc) + 45,
+ ((char *) &single_toc) + 36,
res_size - 36);
res_size += 9;
}
- if (sony_toc.pointb3 != 0xb3)
+ if (single_toc.pointb3 != 0xb3)
{
- mcovlp(((char *) &sony_toc) + 54,
- ((char *) &sony_toc) + 45,
+ memmove(((char *) &single_toc) + 54,
+ ((char *) &single_toc) + 45,
res_size - 45);
res_size += 9;
}
- if (sony_toc.pointb4 != 0xb4)
+ if (single_toc.pointb4 != 0xb4)
{
- mcovlp(((char *) &sony_toc) + 63,
- ((char *) &sony_toc) + 54,
+ memmove(((char *) &single_toc) + 63,
+ ((char *) &single_toc) + 54,
res_size - 54);
res_size += 9;
}
- if (sony_toc.pointc0 != 0xc0)
+ if (single_toc.pointc0 != 0xc0)
{
- mcovlp(((char *) &sony_toc) + 72,
- ((char *) &sony_toc) + 63,
+ memmove(((char *) &single_toc) + 72,
+ ((char *) &single_toc) + 63,
res_size - 63);
res_size += 9;
}
- sony_toc.start_track_lba = msf_to_log(sony_toc.tracks[0].track_start_msf);
- sony_toc.lead_out_start_lba = msf_to_log(sony_toc.lead_out_start_msf);
+#if DEBUG
+ printk("start track lba %u, leadout start lba %u\n",
+ single_toc.start_track_lba, single_toc.lead_out_start_lba);
+ { int i;
+ for (i = 0; i < 1 + bcd_to_int(single_toc.last_track_num)
+ - bcd_to_int(single_toc.first_track_num); i++) {
+ printk("trk %02d: add 0x%01x, con 0x%01x, track %02d, start min %02d, sec %02d, frame %02d\n",
+ i, single_toc.tracks[i].address, single_toc.tracks[i].control,
+ bcd_to_int(single_toc.tracks[i].track),
+ bcd_to_int(single_toc.tracks[i].track_start_msf[0]),
+ bcd_to_int(single_toc.tracks[i].track_start_msf[1]),
+ bcd_to_int(single_toc.tracks[i].track_start_msf[2]));
+ if (mint > bcd_to_int(single_toc.tracks[i].track))
+ mint = bcd_to_int(single_toc.tracks[i].track);
+ if (maxt < bcd_to_int(single_toc.tracks[i].track))
+ maxt = bcd_to_int(single_toc.tracks[i].track);
+ }
+ printk("min track number %d, max track number %d\n", mint, maxt);
+ }
+#endif
+
+ /* prepare a special table of contents for a CD-I disc. They don't have one. */
+ if (single_toc.disk_type == 0x10 &&
+ single_toc.first_track_num == 2 &&
+ single_toc.last_track_num == 2 /* CD-I */)
+ {
+ sony_toc.tracks[totaltracks].address = 1;
+ sony_toc.tracks[totaltracks].control = 4; /* force data tracks */
+ sony_toc.tracks[totaltracks].track = 1;
+ sony_toc.tracks[totaltracks].track_start_msf[0] = 0;
+ sony_toc.tracks[totaltracks].track_start_msf[1] = 2;
+ sony_toc.tracks[totaltracks].track_start_msf[2] = 0;
+ mint = maxt = 1;
+ totaltracks++;
+ } else
+ /* gather track entries from this session */
+ { int i;
+ for (i = 0; i < 1 + bcd_to_int(single_toc.last_track_num)
+ - bcd_to_int(single_toc.first_track_num); i++, totaltracks++) {
+ sony_toc.tracks[totaltracks].address = single_toc.tracks[i].address;
+ sony_toc.tracks[totaltracks].control = single_toc.tracks[i].control;
+ sony_toc.tracks[totaltracks].track = bcd_to_int(single_toc.tracks[i].track);
+ sony_toc.tracks[totaltracks].track_start_msf[0] =
+ bcd_to_int(single_toc.tracks[i].track_start_msf[0]);
+ sony_toc.tracks[totaltracks].track_start_msf[1] =
+ bcd_to_int(single_toc.tracks[i].track_start_msf[1]);
+ sony_toc.tracks[totaltracks].track_start_msf[2] =
+ bcd_to_int(single_toc.tracks[i].track_start_msf[2]);
+ if (i == 0)
+ single_toc.start_track_lba = msf_to_log(sony_toc.tracks[totaltracks].track_start_msf);
+ if (mint > sony_toc.tracks[totaltracks].track)
+ mint = sony_toc.tracks[totaltracks].track;
+ if (maxt < sony_toc.tracks[totaltracks].track)
+ maxt = sony_toc.tracks[totaltracks].track;
+ }
+ }
+ sony_toc.first_track_num = mint;
+ sony_toc.last_track_num = maxt;
+ /* Disk type of last session wins. For example:
+ CD-Extra has disk type 0 for the first session, so
+ a dumb HiFi CD player thinks it is a plain audio CD.
+ We are interested in the disk type of the last session,
+ which is 0x20 (XA) for CD-Extra, so we can access the
+ data track ... */
+ sony_toc.disk_type = single_toc.disk_type;
+ sony_toc.sessions = session;
+
+ /* don't believe everything :-) */
+ if (session == 1)
+ single_toc.start_track_lba = 0;
+ sony_toc.start_track_lba = single_toc.start_track_lba;
+ if (session > 1 && single_toc.pointb0 == 0xb0 &&
+ sony_toc.lead_out_start_lba == single_toc.lead_out_start_lba)
+ {
+ break;
+ }
+
+ /* Let's not get carried away... */
+ if (session > 40)
+ {
+ printk("cdu31a: too many sessions: %d\n", session);
+ break;
+ }
+ session++;
+ }
+ sony_toc.track_entries = totaltracks;
+ /* add one entry for the LAST track with track number CDROM_LEADOUT */
+ sony_toc.tracks[totaltracks].address = single_toc.address2;
+ sony_toc.tracks[totaltracks].control = single_toc.control2;
+ sony_toc.tracks[totaltracks].track = CDROM_LEADOUT;
+ sony_toc.tracks[totaltracks].track_start_msf[0] =
+ sony_toc.lead_out_start_msf[0];
+ sony_toc.tracks[totaltracks].track_start_msf[1] =
+ sony_toc.lead_out_start_msf[1];
+ sony_toc.tracks[totaltracks].track_start_msf[2] =
+ sony_toc.lead_out_start_msf[2];
+
+ sony_toc_read = 1;
+#undef DEBUG
#if DEBUG
printk("Disk session %d, start track: %d, stop track: %d\n",
session,
- sony_toc.start_track_lba,
- sony_toc.lead_out_start_lba);
+ single_toc.start_track_lba,
+ single_toc.lead_out_start_lba);
#endif
}
#if DEBUG
@@ -1973,19 +2293,35 @@
/*
+ * Uniform cdrom interface function
+ * return multisession offset and sector information
+ */
+static int scd_get_last_session(struct cdrom_device_info *cdi,
+ struct cdrom_multisession *ms_info)
+{
+ if (ms_info == NULL)
+ return 1;
+
+ if (!sony_toc_read)
+ sony_get_toc();
+
+ ms_info->addr_format = CDROM_LBA;
+ ms_info->addr.lba = sony_toc.start_track_lba;
+ ms_info->xa_flag = sony_toc.disk_type == SONY_XA_DISK_TYPE ||
+ sony_toc.disk_type == 0x10 /* CDI */;
+
+ return 0;
+}
+
+/*
* Search for a specific track in the table of contents.
*/
static int
find_track(int track)
{
int i;
- int num_tracks;
-
- num_tracks = ( bcd_to_int(sony_toc.last_track_num)
- - bcd_to_int(sony_toc.first_track_num)
- + 1);
- for (i = 0; i < num_tracks; i++)
+ for (i = 0; i <= sony_toc.track_entries; i++)
{
if (sony_toc.tracks[i].track == track)
{
@@ -1998,7 +2334,7 @@
/*
- * Read the subcode and put it int last_sony_subcode for future use.
+ * Read the subcode and put it in last_sony_subcode for future use.
*/
static int
read_subcode(void)
@@ -2013,11 +2349,60 @@
&res_size);
if ((res_size < 2) || ((last_sony_subcode.exec_status[0] & 0xf0) == 0x20))
{
- printk("Sony CDROM error 0x%2.2x (read_subcode)\n",
- last_sony_subcode.exec_status[1]);
+ printk("Sony CDROM error %s (read_subcode)\n",
+ translate_error(last_sony_subcode.exec_status[1]));
return -EIO;
}
+ last_sony_subcode.track_num = bcd_to_int(last_sony_subcode.track_num);
+ last_sony_subcode.index_num = bcd_to_int(last_sony_subcode.index_num);
+ last_sony_subcode.abs_msf[0] = bcd_to_int(last_sony_subcode.abs_msf[0]);
+ last_sony_subcode.abs_msf[1] = bcd_to_int(last_sony_subcode.abs_msf[1]);
+ last_sony_subcode.abs_msf[2] = bcd_to_int(last_sony_subcode.abs_msf[2]);
+
+ last_sony_subcode.rel_msf[0] = bcd_to_int(last_sony_subcode.rel_msf[0]);
+ last_sony_subcode.rel_msf[1] = bcd_to_int(last_sony_subcode.rel_msf[1]);
+ last_sony_subcode.rel_msf[2] = bcd_to_int(last_sony_subcode.rel_msf[2]);
+ return 0;
+}
+
+/*
+ * Uniform cdrom interface function
+ * return the media catalog number found on some older audio cds
+ */
+static int
+scd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
+{
+ unsigned char resbuffer[2 + 14];
+ unsigned char *mcnp = mcn->medium_catalog_number;
+ unsigned char *resp = resbuffer + 3;
+ unsigned int res_size;
+
+ memset(mcn->medium_catalog_number, 0, 14);
+ do_sony_cd_cmd(SONY_REQ_UPC_EAN_CMD,
+ NULL,
+ 0,
+ resbuffer,
+ &res_size);
+ if ((res_size < 2) || ((resbuffer[0] & 0xf0) == 0x20))
+ ;
+ else {
+ /* packed bcd to single ASCII digits */
+ *mcnp++ = (*resp >> 4) + '0';
+ *mcnp++ = (*resp++ & 0x0f) + '0';
+ *mcnp++ = (*resp >> 4) + '0';
+ *mcnp++ = (*resp++ & 0x0f) + '0';
+ *mcnp++ = (*resp >> 4) + '0';
+ *mcnp++ = (*resp++ & 0x0f) + '0';
+ *mcnp++ = (*resp >> 4) + '0';
+ *mcnp++ = (*resp++ & 0x0f) + '0';
+ *mcnp++ = (*resp >> 4) + '0';
+ *mcnp++ = (*resp++ & 0x0f) + '0';
+ *mcnp++ = (*resp >> 4) + '0';
+ *mcnp++ = (*resp++ & 0x0f) + '0';
+ *mcnp++ = (*resp >> 4) + '0';
+ }
+ *mcnp = '\0';
return 0;
}
@@ -2030,12 +2415,8 @@
* (not BCD), so all the conversions are done.
*/
static int
-sony_get_subchnl_info(long arg)
+sony_get_subchnl_info(struct cdrom_subchnl *schi)
{
- int err;
- struct cdrom_subchnl schi;
-
-
/* Get attention stuff */
while (handle_sony_cd_attention())
;
@@ -2046,13 +2427,9 @@
return -EIO;
}
- err = verify_area(VERIFY_WRITE, (char *) arg, sizeof(schi));
- if (err) return err;
-
- copy_from_user(&schi, (char *) arg, sizeof(schi));
-
switch (sony_audio_status)
{
+ case CDROM_AUDIO_NO_STATUS:
case CDROM_AUDIO_PLAY:
if (read_subcode() < 0)
{
@@ -2064,40 +2441,39 @@
case CDROM_AUDIO_COMPLETED:
break;
+#if 0
case CDROM_AUDIO_NO_STATUS:
- schi.cdsc_audiostatus = sony_audio_status;
- copy_to_user((char *) arg, &schi, sizeof(schi));
+ schi->cdsc_audiostatus = sony_audio_status;
return 0;
break;
-
+#endif
case CDROM_AUDIO_INVALID:
case CDROM_AUDIO_ERROR:
default:
return -EIO;
}
- schi.cdsc_audiostatus = sony_audio_status;
- schi.cdsc_adr = last_sony_subcode.address;
- schi.cdsc_ctrl = last_sony_subcode.control;
- schi.cdsc_trk = bcd_to_int(last_sony_subcode.track_num);
- schi.cdsc_ind = bcd_to_int(last_sony_subcode.index_num);
- if (schi.cdsc_format == CDROM_MSF)
- {
- schi.cdsc_absaddr.msf.minute = bcd_to_int(last_sony_subcode.abs_msf[0]);
- schi.cdsc_absaddr.msf.second = bcd_to_int(last_sony_subcode.abs_msf[1]);
- schi.cdsc_absaddr.msf.frame = bcd_to_int(last_sony_subcode.abs_msf[2]);
-
- schi.cdsc_reladdr.msf.minute = bcd_to_int(last_sony_subcode.rel_msf[0]);
- schi.cdsc_reladdr.msf.second = bcd_to_int(last_sony_subcode.rel_msf[1]);
- schi.cdsc_reladdr.msf.frame = bcd_to_int(last_sony_subcode.rel_msf[2]);
+ schi->cdsc_audiostatus = sony_audio_status;
+ schi->cdsc_adr = last_sony_subcode.address;
+ schi->cdsc_ctrl = last_sony_subcode.control;
+ schi->cdsc_trk = last_sony_subcode.track_num;
+ schi->cdsc_ind = last_sony_subcode.index_num;
+ if (schi->cdsc_format == CDROM_MSF)
+ {
+ schi->cdsc_absaddr.msf.minute = last_sony_subcode.abs_msf[0];
+ schi->cdsc_absaddr.msf.second = last_sony_subcode.abs_msf[1];
+ schi->cdsc_absaddr.msf.frame = last_sony_subcode.abs_msf[2];
+
+ schi->cdsc_reladdr.msf.minute = last_sony_subcode.rel_msf[0];
+ schi->cdsc_reladdr.msf.second = last_sony_subcode.rel_msf[1];
+ schi->cdsc_reladdr.msf.frame = last_sony_subcode.rel_msf[2];
}
- else if (schi.cdsc_format == CDROM_LBA)
+ else if (schi->cdsc_format == CDROM_LBA)
{
- schi.cdsc_absaddr.lba = msf_to_log(last_sony_subcode.abs_msf);
- schi.cdsc_reladdr.lba = msf_to_log(last_sony_subcode.rel_msf);
+ schi->cdsc_absaddr.lba = msf_to_log(last_sony_subcode.abs_msf);
+ schi->cdsc_reladdr.lba = msf_to_log(last_sony_subcode.rel_msf);
}
- copy_to_user((char *) arg, &schi, sizeof(schi));
return 0;
}
@@ -2172,7 +2548,7 @@
/* If data block, then get 2340 bytes offset by 12. */
if (sony_raw_data_mode)
{
- insb(sony_cd_read_reg, buffer + CD_XA_HEAD, CD_FRAMESIZE_XA);
+ insb(sony_cd_read_reg, buffer + CD_XA_HEAD, CD_FRAMESIZE_RAW1);
}
else
{
@@ -2243,8 +2619,7 @@
/* Perform a raw data read. This will automatically detect the
track type and read the proper data (audio or data). */
static int
-read_audio(struct cdrom_read_audio *ra,
- struct inode *inode)
+read_audio(struct cdrom_read_audio *ra)
{
int retval;
unsigned char params[2];
@@ -2274,7 +2649,7 @@
if (!sony_spun_up)
{
- scd_open (inode, NULL);
+ scd_spinup();
}
/* Set the drive to do raw operations. */
@@ -2355,9 +2730,9 @@
}
else
{
- printk("CDU31A: Error reading audio data on sector %d: 0x%x\n",
+ printk("CDU31A: Error reading audio data on sector %d: %s\n",
ra->addr.lba + cframe,
- res_reg[1]);
+ translate_error(res_reg[1]));
retval = -EIO;
goto exit_read_audio;
}
@@ -2371,9 +2746,9 @@
}
else
{
- printk("CDU31A: Error reading audio data on sector %d: 0x%x\n",
+ printk("CDU31A: Error reading audio data on sector %d: %s\n",
ra->addr.lba + cframe,
- res_reg[1]);
+ translate_error(res_reg[1]));
retval = -EIO;
goto exit_read_audio;
}
@@ -2391,8 +2766,8 @@
get_result(res_reg, &res_size);
if ((res_reg[0] & 0xf0) == 0x20)
{
- printk("CDU31A: Error return from audio read: 0x%x\n",
- res_reg[1]);
+ printk("CDU31A: Error return from audio read: %s\n",
+ translate_error(res_reg[1]));
retval = -EIO;
goto exit_read_audio;
}
@@ -2438,19 +2813,38 @@
do_sony_cd_cmd(cmd, params, num_params, result_buffer, result_size);
if ((*result_size < 2) || ((result_buffer[0] & 0xf0) == 0x20))
{
- printk("Sony CDROM error 0x%2.2x (CDROM%s)\n", result_buffer[1], name);
+ printk("Sony CDROM error %s (CDROM%s)\n", translate_error(result_buffer[1]), name);
return -EIO;
}
return 0;
}
/*
+ * Uniform cdrom interface function
+ * open the tray
+ */
+static int scd_tray_move(struct cdrom_device_info *cdi, int position)
+{
+ if (position == 1 /* open tray */)
+ {
+ unsigned char res_reg[12];
+ unsigned int res_size;
+
+ do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, &res_size);
+ do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size);
+
+ sony_audio_status = CDROM_AUDIO_INVALID;
+ return do_sony_cd_cmd_chk("EJECT",SONY_EJECT_CMD, NULL, 0, res_reg, &res_size);
+ } else
+ return 0;
+}
+
+/*
* The big ugly ioctl handler.
*/
-static int scd_ioctl(struct inode *inode,
- struct file *file,
+static int scd_audio_ioctl(struct cdrom_device_info *cdi,
unsigned int cmd,
- unsigned long arg)
+ void * arg)
{
unsigned char res_reg[12];
unsigned int res_size;
@@ -2458,16 +2852,10 @@
int i;
- if (!inode)
- {
- return -EINVAL;
- }
-
switch (cmd)
{
case CDROMSTART: /* Spin up the drive */
return do_sony_cd_cmd_chk("START",SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
- return 0;
break;
case CDROMSTOP: /* Spin down the drive */
@@ -2504,12 +2892,12 @@
do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
/* Start the drive at the saved position. */
- params[1] = cur_pos_msf[0];
- params[2] = cur_pos_msf[1];
- params[3] = cur_pos_msf[2];
- params[4] = final_pos_msf[0];
- params[5] = final_pos_msf[1];
- params[6] = final_pos_msf[2];
+ params[1] = int_to_bcd(cur_pos_msf[0]);
+ params[2] = int_to_bcd(cur_pos_msf[1]);
+ params[3] = int_to_bcd(cur_pos_msf[2]);
+ params[4] = int_to_bcd(final_pos_msf[0]);
+ params[5] = int_to_bcd(final_pos_msf[1]);
+ params[6] = int_to_bcd(final_pos_msf[2]);
params[0] = 0x03;
if(do_sony_cd_cmd_chk("RESUME",SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg, &res_size)<0)
return -EIO;
@@ -2517,32 +2905,27 @@
return 0;
case CDROMPLAYMSF: /* Play starting at the given MSF address. */
- i=verify_area(VERIFY_READ, (char *) arg, 6);
- if(i)
- return i;
do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
- copy_from_user(&(params[1]), (void *) arg, 6);
/* The parameters are given in int, must be converted */
for (i=1; i<7; i++)
{
- params[i] = int_to_bcd(params[i]);
+ params[i] = int_to_bcd(((unsigned char *)arg)[i-1]);
}
params[0] = 0x03;
if(do_sony_cd_cmd_chk("PLAYMSF",SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg, &res_size)<0)
return -EIO;
/* Save the final position for pauses and resumes */
- final_pos_msf[0] = params[4];
- final_pos_msf[1] = params[5];
- final_pos_msf[2] = params[6];
+ final_pos_msf[0] = bcd_to_int(params[4]);
+ final_pos_msf[1] = bcd_to_int(params[5]);
+ final_pos_msf[2] = bcd_to_int(params[6]);
sony_audio_status = CDROM_AUDIO_PLAY;
return 0;
case CDROMREADTOCHDR: /* Read the table of contents header */
{
struct cdrom_tochdr *hdr;
- struct cdrom_tochdr loc_hdr;
sony_get_toc();
if (!sony_toc_read)
@@ -2551,19 +2934,14 @@
}
hdr = (struct cdrom_tochdr *) arg;
- i=verify_area(VERIFY_WRITE, hdr, sizeof(*hdr));
- if(i<0)
- return i;
- loc_hdr.cdth_trk0 = bcd_to_int(sony_toc.first_track_num);
- loc_hdr.cdth_trk1 = bcd_to_int(sony_toc.last_track_num);
- copy_to_user(hdr, &loc_hdr, sizeof(*hdr));
+ hdr->cdth_trk0 = sony_toc.first_track_num;
+ hdr->cdth_trk1 = sony_toc.last_track_num;
}
return 0;
case CDROMREADTOCENTRY: /* Read a given table of contents entry */
{
struct cdrom_tocentry *entry;
- struct cdrom_tocentry loc_entry;
int track_idx;
unsigned char *msf_val = NULL;
@@ -2574,54 +2952,35 @@
}
entry = (struct cdrom_tocentry *) arg;
- i=verify_area(VERIFY_READ, entry, sizeof(*entry));
- if(i<0)
- return i;
- i=verify_area(VERIFY_WRITE, entry, sizeof(*entry));
- if(i<0)
- return i;
- copy_from_user(&loc_entry, entry, sizeof(loc_entry));
-
- /* Lead out is handled separately since it is special. */
- if (loc_entry.cdte_track == CDROM_LEADOUT)
+ track_idx = find_track(entry->cdte_track);
+ if (track_idx < 0)
{
- loc_entry.cdte_adr = sony_toc.address2;
- loc_entry.cdte_ctrl = sony_toc.control2;
- msf_val = sony_toc.lead_out_start_msf;
+ return -EINVAL;
}
- else
- {
- track_idx = find_track(int_to_bcd(loc_entry.cdte_track));
- if (track_idx < 0)
- {
- return -EINVAL;
- }
- loc_entry.cdte_adr = sony_toc.tracks[track_idx].address;
- loc_entry.cdte_ctrl = sony_toc.tracks[track_idx].control;
- msf_val = sony_toc.tracks[track_idx].track_start_msf;
- }
+ entry->cdte_adr = sony_toc.tracks[track_idx].address;
+ entry->cdte_ctrl = sony_toc.tracks[track_idx].control;
+ msf_val = sony_toc.tracks[track_idx].track_start_msf;
/* Logical buffer address or MSF format requested? */
- if (loc_entry.cdte_format == CDROM_LBA)
+ if (entry->cdte_format == CDROM_LBA)
{
- loc_entry.cdte_addr.lba = msf_to_log(msf_val);
+ entry->cdte_addr.lba = msf_to_log(msf_val);
}
- else if (loc_entry.cdte_format == CDROM_MSF)
+ else if (entry->cdte_format == CDROM_MSF)
{
- loc_entry.cdte_addr.msf.minute = bcd_to_int(*msf_val);
- loc_entry.cdte_addr.msf.second = bcd_to_int(*(msf_val+1));
- loc_entry.cdte_addr.msf.frame = bcd_to_int(*(msf_val+2));
+ entry->cdte_addr.msf.minute = *msf_val;
+ entry->cdte_addr.msf.second = *(msf_val+1);
+ entry->cdte_addr.msf.frame = *(msf_val+2);
}
- copy_to_user(entry, &loc_entry, sizeof(*entry));
}
return 0;
break;
case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */
{
- struct cdrom_ti ti;
+ struct cdrom_ti *ti = (struct cdrom_ti *) arg;
int track_idx;
sony_get_toc();
@@ -2630,46 +2989,41 @@
return -EIO;
}
- i=verify_area(VERIFY_READ, (char *) arg, sizeof(ti));
- if(i<0)
- return i;
-
- copy_from_user(&ti, (char *) arg, sizeof(ti));
- if ( (ti.cdti_trk0 < bcd_to_int(sony_toc.first_track_num))
- || (ti.cdti_trk0 > bcd_to_int(sony_toc.last_track_num))
- || (ti.cdti_trk1 < ti.cdti_trk0))
+ if ( (ti->cdti_trk0 < sony_toc.first_track_num)
+ || (ti->cdti_trk0 > sony_toc.last_track_num)
+ || (ti->cdti_trk1 < ti->cdti_trk0))
{
return -EINVAL;
}
- track_idx = find_track(int_to_bcd(ti.cdti_trk0));
+ track_idx = find_track(ti->cdti_trk0);
if (track_idx < 0)
{
return -EINVAL;
}
- params[1] = sony_toc.tracks[track_idx].track_start_msf[0];
- params[2] = sony_toc.tracks[track_idx].track_start_msf[1];
- params[3] = sony_toc.tracks[track_idx].track_start_msf[2];
+ params[1] = int_to_bcd(sony_toc.tracks[track_idx].track_start_msf[0]);
+ params[2] = int_to_bcd(sony_toc.tracks[track_idx].track_start_msf[1]);
+ params[3] = int_to_bcd(sony_toc.tracks[track_idx].track_start_msf[2]);
/*
* If we want to stop after the last track, use the lead-out
* MSF to do that.
*/
- if (ti.cdti_trk1 >= bcd_to_int(sony_toc.last_track_num))
+ if (ti->cdti_trk1 >= sony_toc.last_track_num)
{
- log_to_msf(msf_to_log(sony_toc.lead_out_start_msf)-1,
- &(params[4]));
+ track_idx = find_track(CDROM_LEADOUT);
}
else
{
- track_idx = find_track(int_to_bcd(ti.cdti_trk1+1));
- if (track_idx < 0)
- {
- return -EINVAL;
- }
- log_to_msf(msf_to_log(sony_toc.tracks[track_idx].track_start_msf)-1,
- &(params[4]));
+ track_idx = find_track(ti->cdti_trk1+1);
+ }
+ if (track_idx < 0)
+ {
+ return -EINVAL;
}
+ params[4] = int_to_bcd(sony_toc.tracks[track_idx].track_start_msf[0]);
+ params[5] = int_to_bcd(sony_toc.tracks[track_idx].track_start_msf[1]);
+ params[6] = int_to_bcd(sony_toc.tracks[track_idx].track_start_msf[2]);
params[0] = 0x03;
do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
@@ -2680,43 +3034,44 @@
{
printk("Params: %x %x %x %x %x %x %x\n", params[0], params[1],
params[2], params[3], params[4], params[5], params[6]);
- printk("Sony CDROM error 0x%2.2x (CDROMPLAYTRKIND\n", res_reg[1]);
+ printk("Sony CDROM error %s (CDROMPLAYTRKIND)\n", translate_error(res_reg[1]));
return -EIO;
}
/* Save the final position for pauses and resumes */
- final_pos_msf[0] = params[4];
- final_pos_msf[1] = params[5];
- final_pos_msf[2] = params[6];
+ final_pos_msf[0] = bcd_to_int(params[4]);
+ final_pos_msf[1] = bcd_to_int(params[5]);
+ final_pos_msf[2] = bcd_to_int(params[6]);
sony_audio_status = CDROM_AUDIO_PLAY;
return 0;
}
- case CDROMSUBCHNL: /* Get subchannel info */
- return sony_get_subchnl_info(arg);
-
case CDROMVOLCTRL: /* Volume control. What volume does this change, anyway? */
{
- struct cdrom_volctrl volctrl;
-
- i=verify_area(VERIFY_READ, (char *) arg, sizeof(volctrl));
- if(i<0)
- return i;
+ struct cdrom_volctrl *volctrl = (struct cdrom_volctrl *) arg;
- copy_from_user(&volctrl, (char *) arg, sizeof(volctrl));
params[0] = SONY_SD_AUDIO_VOLUME;
- params[1] = volctrl.channel0;
- params[2] = volctrl.channel1;
+ params[1] = volctrl->channel0;
+ params[2] = volctrl->channel1;
return do_sony_cd_cmd_chk("VOLCTRL",SONY_SET_DRIVE_PARAM_CMD, params, 3, res_reg, &res_size);
}
- case CDROMEJECT: /* Eject the drive */
- do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, &res_size);
- do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size);
+ case CDROMSUBCHNL: /* Get subchannel info */
+ return sony_get_subchnl_info((struct cdrom_subchnl *)arg);
- sony_audio_status = CDROM_AUDIO_INVALID;
- return do_sony_cd_cmd_chk("EJECT",SONY_EJECT_CMD, NULL, 0, res_reg, &res_size);
-
- case CDROMREADAUDIO: /* Read 2352 byte audio tracks and 2340 byte
+ default:
+ return -EINVAL;
+ }
+}
+
+static int scd_dev_ioctl(struct cdrom_device_info *cdi,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ int i;
+
+ switch (cmd)
+ {
+ case CDROMREADAUDIO: /* Read 2352 byte audio tracks and 2340 byte
raw data tracks. */
{
struct cdrom_read_audio ra;
@@ -2728,14 +3083,15 @@
return -EIO;
}
- i=verify_area(VERIFY_READ, (char *) arg, sizeof(ra));
- if(i<0)
- return i;
- copy_from_user(&ra, (char *) arg, sizeof(ra));
+ if (ra.nframes == 0)
+ {
+ return 0;
+ }
i=verify_area(VERIFY_WRITE, ra.buf, CD_FRAMESIZE_RAW * ra.nframes);
if(i<0)
return i;
+ copy_from_user(&ra, (char *) arg, sizeof(ra));
if (ra.addr_format == CDROM_LBA)
{
@@ -2773,92 +3129,93 @@
return -EINVAL;
}
- return(read_audio(&ra, inode));
+ return(read_audio(&ra));
}
return 0;
break;
- case CDROMEJECT_SW:
- is_auto_eject = arg;
- set_drive_params();
- return 0;
- break;
-
default:
return -EINVAL;
}
}
-
-/*
- * Open the drive for operations. Spin the drive up and read the table of
- * contents if these have not already been done.
- */
-static int
-scd_open(struct inode *inode,
- struct file *filp)
+static int scd_spinup(void)
{
unsigned char res_reg[12];
unsigned int res_size;
int num_spin_ups;
- unsigned char params[2];
+ num_spin_ups = 0;
- if ((filp) && filp->f_mode & 2)
- return -EROFS;
+respinup_on_open:
+ do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
- if (!sony_spun_up)
+ /* The drive sometimes returns error 0. I don't know why, but ignore
+ it. It seems to mean the drive has already done the operation. */
+ if ((res_size < 2) || ((res_reg[0] != 0) && (res_reg[1] != 0)))
{
- num_spin_ups = 0;
-
-respinup_on_open:
- do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
+ printk("Sony CDROM %s error (scd_open, spin up)\n", translate_error(res_reg[1]));
+ return 1;
+ }
+
+ do_sony_cd_cmd(SONY_READ_TOC_CMD, NULL, 0, res_reg, &res_size);
- /* The drive sometimes returns error 0. I don't know why, but ignore
- it. It seems to mean the drive has already done the operation. */
- if ((res_size < 2) || ((res_reg[0] != 0) && (res_reg[1] != 0)))
+ /* The drive sometimes returns error 0. I don't know why, but ignore
+ it. It seems to mean the drive has already done the operation. */
+ if ((res_size < 2) || ((res_reg[0] != 0) && (res_reg[1] != 0)))
+ {
+ /* If the drive is already playing, it's ok. */
+ if ((res_reg[1] == SONY_AUDIO_PLAYING_ERR) || (res_reg[1] == 0))
{
- printk("Sony CDROM error 0x%2.2x (scd_open, spin up)\n", res_reg[1]);
- return -EIO;
+ return 0;
}
-
- do_sony_cd_cmd(SONY_READ_TOC_CMD, NULL, 0, res_reg, &res_size);
- /* The drive sometimes returns error 0. I don't know why, but ignore
- it. It seems to mean the drive has already done the operation. */
- if ((res_size < 2) || ((res_reg[0] != 0) && (res_reg[1] != 0)))
+ /* If the drive says it is not spun up (even though we just did it!)
+ then retry the operation at least a few times. */
+ if ( (res_reg[1] == SONY_NOT_SPIN_ERR)
+ && (num_spin_ups < MAX_CDU31A_RETRIES))
{
- /* If the drive is already playing, it's ok. */
- if ((res_reg[1] == SONY_AUDIO_PLAYING_ERR) || (res_reg[1] == 0))
- {
- goto drive_spinning;
- }
+ num_spin_ups++;
+ goto respinup_on_open;
+ }
- /* If the drive says it is not spun up (even though we just did it!)
- then retry the operation at least a few times. */
- if ( (res_reg[1] == SONY_NOT_SPIN_ERR)
- && (num_spin_ups < MAX_CDU31A_RETRIES))
- {
- num_spin_ups++;
- goto respinup_on_open;
- }
+ printk("Sony CDROM error %s (scd_open, read toc)\n", translate_error(res_reg[1]));
+ do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size);
+ return 1;
+ }
+ return 0;
+}
- printk("Sony CDROM error 0x%2.2x (scd_open, read toc)\n", res_reg[1]);
- do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size);
-
+/*
+ * Open the drive for operations. Spin the drive up and read the table of
+ * contents if these have not already been done.
+ */
+static int
+scd_open(struct cdrom_device_info *cdi, int openmode)
+{
+ unsigned char res_reg[12];
+ unsigned int res_size;
+ unsigned char params[2];
+
+ MOD_INC_USE_COUNT;
+ if (sony_usage == 0)
+ {
+ if (scd_spinup() != 0) {
+ MOD_DEC_USE_COUNT;
return -EIO;
}
-
sony_get_toc();
if (!sony_toc_read)
{
do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size);
+ MOD_DEC_USE_COUNT;
return -EIO;
}
/* For XA on the CDU31A only, we have to do special reads.
The CDU33A handles XA automagically. */
- if ( (sony_toc.disk_type == SONY_XA_DISK_TYPE)
+ /* if ( (sony_toc.disk_type == SONY_XA_DISK_TYPE) */
+ if ( (sony_toc.disk_type != 0x00)
&& (!is_double_speed))
{
params[0] = SONY_SD_DECODE_PARAM;
@@ -2873,6 +3230,7 @@
printk("CDU31A: Unable to set XA params: 0x%2.2x\n", res_reg[1]);
}
sony_xa_mode = 1;
+printk("sony_xa_mode is set\n");
}
/* A non-XA disk. Set the parms back if necessary. */
else if (sony_xa_mode)
@@ -2889,25 +3247,13 @@
printk("CDU31A: Unable to reset XA params: 0x%2.2x\n", res_reg[1]);
}
sony_xa_mode = 0;
+printk("sony_xa_mode is reset\n");
}
sony_spun_up = 1;
}
-drive_spinning:
-
- /* If filp is not NULL (standard open), try a disk change. */
- if (filp)
- {
- check_disk_change(inode->i_rdev);
- }
-
sony_usage++;
- MOD_INC_USE_COUNT;
-
- /* If all is OK (until now...), then lock the door */
- is_auto_eject = 0;
- set_drive_params();
return 0;
}
@@ -2917,51 +3263,54 @@
* Close the drive. Spin it down if no task is using it. The spin
* down will fail if playing audio, so audio play is OK.
*/
-static int
-scd_release(struct inode *inode,
- struct file *filp)
+static void
+scd_release(struct cdrom_device_info *cdi)
{
- unsigned char res_reg[12];
- unsigned int res_size;
-
-
- if (sony_usage > 0)
+ if (sony_usage == 1)
{
- sony_usage--;
- MOD_DEC_USE_COUNT;
- }
- if (sony_usage == 0)
- {
- sync_dev(inode->i_rdev);
-
- /* Unlock the door, only if nobody is using the drive */
- is_auto_eject = 1;
- set_drive_params();
+ unsigned char res_reg[12];
+ unsigned int res_size;
do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size);
sony_spun_up = 0;
}
- return 0;
+ sony_usage--;
+ MOD_DEC_USE_COUNT;
}
-
-static struct file_operations scd_fops = {
- NULL, /* lseek - default */
- block_read, /* read - general block-dev read */
- block_write, /* write - general block-dev write */
- NULL, /* readdir - bad */
- NULL, /* poll */
- scd_ioctl, /* ioctl */
- NULL, /* mmap */
- scd_open, /* open */
- scd_release, /* release */
- NULL, /* fsync */
- NULL, /* fasync */
- scd_disk_change, /* media_change */
- NULL /* revalidate */
+static struct cdrom_device_ops scd_dops = {
+ scd_open, /* open */
+ scd_release, /* release */
+ scd_drive_status, /* drive status */
+ scd_media_changed, /* media changed */
+ scd_tray_move, /* tray move */
+ scd_lock_door, /* lock door */
+ scd_select_speed, /* select speed */
+ NULL, /* select disc */
+ scd_get_last_session, /* get last session */
+ scd_get_mcn, /* get universal product code */
+ scd_reset, /* hard reset */
+ scd_audio_ioctl, /* audio ioctl */
+ scd_dev_ioctl, /* device-specific ioctl */
+ CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_MULTI_SESSION |
+ CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO |
+ CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS, /* capability */
+ 1, /* number of minor devices */
};
+static struct cdrom_device_info scd_info = {
+ &scd_dops, /* device operations */
+ NULL, /* link */
+ NULL, /* handle */
+ MKDEV(MAJOR_NR,0), /* dev */
+ 0, /* mask */
+ 2, /* maximum speed */
+ 1, /* number of discs */
+ 0, /* options, not owned */
+ 0, /* mc_flags, not owned */
+ 0 /* use count, not owned */
+};
/* The different types of disc loading mechanisms supported */
static const char *load_mech[] __initdata = { "caddy", "tray", "pop-up", "unknown" };
@@ -3069,6 +3418,8 @@
{
struct s_sony_drive_config drive_config;
unsigned int res_size;
+ char msg[255];
+ char buf[40];
int i;
int drive_found;
int tmp_irq;
@@ -3136,12 +3487,14 @@
if (drive_found)
{
+ int deficiency=0;
+
request_region(cdu31a_port, 4,"cdu31a");
- if (register_blkdev(MAJOR_NR,"cdu31a",&scd_fops))
+ if (register_blkdev(MAJOR_NR,"cdu31a",&cdrom_fops))
{
printk("Unable to get major %d for CDU-31a\n", MAJOR_NR);
- return -EIO;
+ goto errout2;
}
if (SONY_HWC_DOUBLE_SPEED(drive_config))
@@ -3152,7 +3505,7 @@
tmp_irq = cdu31a_irq; /* Need IRQ 0 because we can't sleep here. */
cdu31a_irq = 0;
- set_drive_params();
+ set_drive_params(sony_speed);
cdu31a_irq = tmp_irq;
@@ -3165,41 +3518,48 @@
}
}
- printk(KERN_INFO "Sony I/F CDROM : %8.8s %16.16s %8.8s\n",
+ sprintf(msg, "Sony I/F CDROM : %8.8s %16.16s %8.8s\n",
drive_config.vendor_id,
drive_config.product_id,
drive_config.product_rev_level);
- printk(KERN_INFO " Capabilities: %s",
+ sprintf(buf, " Capabilities: %s",
load_mech[SONY_HWC_GET_LOAD_MECH(drive_config)]);
+ strcat(msg, buf);
if (SONY_HWC_AUDIO_PLAYBACK(drive_config))
{
- printk(", audio");
- }
+ strcat(msg, ", audio");
+ } else
+ deficiency |= CDC_PLAY_AUDIO;
if (SONY_HWC_EJECT(drive_config))
{
- printk(", eject");
- }
+ strcat(msg, ", eject");
+ } else
+ deficiency |= CDC_OPEN_TRAY;
if (SONY_HWC_LED_SUPPORT(drive_config))
{
- printk(", LED");
+ strcat(msg, ", LED");
}
if (SONY_HWC_ELECTRIC_VOLUME(drive_config))
{
- printk(", elec. Vol");
+ strcat(msg, ", elec. Vol");
}
if (SONY_HWC_ELECTRIC_VOLUME_CTL(drive_config))
{
- printk(", sep. Vol");
+ strcat(msg, ", sep. Vol");
}
if (is_double_speed)
{
- printk(", double speed");
- }
+ strcat(msg, ", double speed");
+ } else
+ deficiency |= CDC_SELECT_SPEED;
if (cdu31a_irq > 0)
{
- printk(", irq %d", cdu31a_irq);
+ sprintf(buf, ", irq %d", cdu31a_irq);
+ strcat(msg, buf);
}
- printk("\n");
+ strcat(msg, "\n");
+
+ is_a_cdu31a = strcmp("CD-ROM CDU31A", drive_config.product_id) == 0;
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
read_ahead[MAJOR_NR] = CDU31A_READAHEAD;
@@ -3209,6 +3569,13 @@
init_timer(&cdu31a_abort_timer);
cdu31a_abort_timer.function = handle_abort_timeout;
+
+ scd_info.mask = deficiency;
+
+ if (register_cdrom(&scd_info))
+ {
+ goto errout0;
+ }
}
@@ -3220,8 +3587,18 @@
}
else
{
- return -EIO;
+ goto errout3;
}
+errout0:
+ printk("Unable to register CDU-31a with Uniform cdrom driver\n");
+ if (unregister_blkdev(MAJOR_NR, "cdu31a"))
+ {
+ printk("Can't unregister block device for cdu31a\n");
+ }
+errout2:
+ release_region(cdu31a_port,4);
+errout3:
+ return -EIO;
}
#ifdef MODULE
@@ -3235,6 +3612,11 @@
void
cleanup_module(void)
{
+ if (unregister_cdrom(&scd_info))
+ {
+ printk("Can't unregister cdu31a from Uniform cdrom driver\n");
+ return;
+ }
if ((unregister_blkdev(MAJOR_NR, "cdu31a") == -EINVAL))
{
printk("Can't unregister cdu31a\n");
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov