diff options
Diffstat (limited to 'drivers/cdrom')
-rw-r--r-- | drivers/cdrom/.cvsignore | 1 | ||||
-rw-r--r-- | drivers/cdrom/Config.in | 1 | ||||
-rw-r--r-- | drivers/cdrom/Makefile | 8 | ||||
-rw-r--r-- | drivers/cdrom/bpcd.c | 793 | ||||
-rw-r--r-- | drivers/cdrom/cdrom.c | 120 | ||||
-rw-r--r-- | drivers/cdrom/cdu31a.c | 53 | ||||
-rw-r--r-- | drivers/cdrom/cm206.c | 325 | ||||
-rw-r--r-- | drivers/cdrom/mcd.c | 34 | ||||
-rw-r--r-- | drivers/cdrom/mcdx.c | 285 | ||||
-rw-r--r-- | drivers/cdrom/sbpcd.c | 238 | ||||
-rw-r--r-- | drivers/cdrom/sbpcd.h | 12 |
11 files changed, 611 insertions, 1259 deletions
diff --git a/drivers/cdrom/.cvsignore b/drivers/cdrom/.cvsignore index 4671378ae..857dd22e9 100644 --- a/drivers/cdrom/.cvsignore +++ b/drivers/cdrom/.cvsignore @@ -1 +1,2 @@ .depend +.*.flags diff --git a/drivers/cdrom/Config.in b/drivers/cdrom/Config.in index f07e65539..bc69156a4 100644 --- a/drivers/cdrom/Config.in +++ b/drivers/cdrom/Config.in @@ -13,7 +13,6 @@ if [ "$CONFIG_SBPCD" = "y" ]; then fi fi fi -tristate 'MicroSolutions backpack CDROM support' CONFIG_BPCD tristate 'Mitsumi (standard) [no XA/Multisession] CDROM support' CONFIG_MCD tristate 'Mitsumi [XA/MultiSession] CDROM support' CONFIG_MCDX tristate 'Optics Storage DOLPHIN 8000AT CDROM support' CONFIG_OPTCD diff --git a/drivers/cdrom/Makefile b/drivers/cdrom/Makefile index 0f54a6e2d..5681e2fe5 100644 --- a/drivers/cdrom/Makefile +++ b/drivers/cdrom/Makefile @@ -112,14 +112,6 @@ else endif endif #CONFIG_SJCD -ifeq ($(CONFIG_BPCD),y) -L_OBJS += bpcd.o -else - ifeq ($(CONFIG_BPCD),m) - M_OBJS += bpcd.o - endif -endif #CONFIG_BPCD - ifeq ($(CONFIG_ISP16_CDI),y) L_OBJS += isp16.o else diff --git a/drivers/cdrom/bpcd.c b/drivers/cdrom/bpcd.c deleted file mode 100644 index 4ea0f66bc..000000000 --- a/drivers/cdrom/bpcd.c +++ /dev/null @@ -1,793 +0,0 @@ -/* - bpcd.c (c) 1996 Grant R. Guenther <grant@torque.net> - Under the terms of the GNU public license. - - bpcd.c is a driver for the MicroSolutions "backpack" CDrom, - an external parallel port device. - - There are apparently two versions of the backpack protocol. This - driver knows about the version 2 protocol - as is used in the 4x - and 6x products. There is no support for the sound hardware that - is included in some models. It should not be difficult to add - support for the ATAPI audio play functions and the corresponding - ioctls. - - The driver was developed by reverse engineering the protocol - and testing it on the backpack model 164550. This model - is actually a stock ATAPI drive packaged with a custom - ASIC that implements the IDE over parallel protocol. - I tested with a backpack that happened to contain a Goldstar - drive, but I've seen reports of Sony and Mitsumi drives as well. - - bpcd.c can be compiled for version 1.2.13 of the Linux kernel - and for the 2.0 series. (It should also work with most of the - later 1.3 kernels.) - - If you have a copy of the driver that has not been integrated into - the kernel source tree, you can compile the driver manually, as a - module. Ensure that /usr/include/linux and /usr/include/asm are - links to the correct include files for the target system. Compile - the driver with - - cc -D__KERNEL__ -DMODULE -O2 -c bpcd.c - - You must then load it with insmod. If you are using - MODVERSIONS, add the following to the cc command: - - -DMODVERSIONS -I /usr/include/linux/modversions.h - - Before attempting to access the new driver, you will need to - create a new device special file. The following commands will - do that for you: - - mknod /dev/bpcd b 41 0 - chown root:disk /dev/bpcd - chmod 660 /dev/bpcd - - Afterward, you can mount a disk in the usual way: - - mount -t iso9660 /dev/bpcd /cdrom - - (assuming you have made a directory /cdrom to use as a - mount point). - - The driver will attempt to detect which parallel port your - backpack is connected to. If this fails for any reason, you - can override it by specifying a port on the LILO command line - (for built in drivers) or the insmod command (for drivers built - as modules). If your drive is on the port at 0x3bc, you would - use one of these commands: - - LILO: bpcd=0x3bc - - insmod: insmod bpcd bp_base=0x3bc - - The driver can detect if the parallel port supports 8-bit - transfers. If so, it will use them. You can force it to use - 4-bit (nybble) mode by setting the variable bp_nybble to 1 on - an insmod command, or using the following LILO parameters: - - bpcd=0x3bc,1 - - (you must specify the correct port address if you use this method.) - - There is currently no support for EPP or ECP modes. Also, - as far as I can tell, the MicroSolutions protocol does not - support interrupts in the 4-bit and 8-bit modes. - - MicroSolutions' protocol allows for several drives to be - chained together off the same parallel port. Currently, this - driver will recognise only one of them. If you do have more - than one drive, it will choose the one with the lowest id number, - where the id number is the last two digits of the product's - serial number. - - It is not currently possible to connect a printer to the chained - port on the BackPack and expect Linux to use both devices at once. - - If you need to use this driver together with a printer on the - same port, build both the bpcd and lp drivers are modules. - - Keep an eye on http://www.torque.net/bpcd.html for news and - other information about the driver. If you have any problems - with this driver, please send me, grant@torque.net, some mail - directly before posting into the newsgroups or mailing lists. - -*/ - -#define BP_VERSION "0.14" - -#define BP_BASE 0 /* set to 0 for autoprobe */ -#define BP_REP 4 - -#include <linux/version.h> -#include <linux/module.h> - -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/fs.h> -#include <linux/major.h> -#include <linux/kernel.h> -#include <linux/tqueue.h> -#include <linux/delay.h> -#include <linux/cdrom.h> -#include <linux/ioport.h> -#include <linux/init.h> - -#include <asm/system.h> -#include <asm/io.h> -#include <asm/uaccess.h> - -#ifndef BPCD_MAJOR -#define BPCD_MAJOR 41 -#endif - -#define MAJOR_NR BPCD_MAJOR - -/* set up defines for blk.h, why don't all drivers do it this way ? */ - -#define DEVICE_NAME "BackPack" -#define DEVICE_REQUEST do_bp_request -#define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) - -#include <linux/blk.h> - -#define BP_TMO 300 /* timeout in jiffies */ -#define BP_DELAY 50 /* spin delay in uS */ - -#define BP_SPIN (10000/BP_DELAY)*BP_TMO - -int bpcd_init(void); -void bpcd_setup(char * str, int * ints); -void cleanup_module( void ); - -static int bp_open(struct inode *inode, struct file *file); -static void do_bp_request(void); -static void do_bp_read(void); -static int bp_ioctl(struct inode *inode,struct file *file, - unsigned int cmd, unsigned long arg); -static int bp_release (struct inode *inode, struct file *file); - -static int bp_detect(void); -static int bp_lock(void); -static void bp_unlock(void); -static void bp_eject(void); -static void bp_interrupt(void *data); - -static int bp_base = BP_BASE; -static int bp_rep = BP_REP; -static int bp_nybble = 0; /* force 4-bit mode ? */ - -static int bp_unit_id; - -static int bp_access = 0; /* count of active opens ... */ -static int bp_mode = 1; /* 4- or 8-bit mode */ -static int bp_busy = 0; /* request being processed ? */ -static int bp_timeout; /* "interrupt" loop limiter */ -static int bp_sector; /* address of next requested sector */ -static int bp_count; /* number of blocks still to do */ -static char * bp_buf; /* buffer for request in progress */ -static char bp_buffer[2048]; /* raw block buffer */ -static int bp_bufblk = -1; /* block in buffer, in CD units, - -1 for nothing there */ -static int nyb_map[256]; /* decodes a nybble */ -static int PortCache = 0; /* cache of the control port */ - -static struct tq_struct bp_tq = {0,0,bp_interrupt,NULL}; - -/* kernel glue structures */ - -static struct file_operations bp_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - bp_ioctl, /* ioctl */ - NULL, /* mmap */ - bp_open, /* open */ - bp_release, /* release */ - block_fsync, /* fsync */ - NULL, /* fasync */ - NULL, /* media change ? */ - NULL /* revalidate new media */ -}; - - -/* the MicroSolutions protocol uses bits 3,4,5 & 7 of the status port to - deliver a nybble in 4 bit mode. We use a table lookup to extract the - nybble value. The following function initialises the table. -*/ - -__initfunc(static void init_nyb_map( void )) - -{ int i, j; - - for(i=0;i<256;i++) { - j = (i >> 3) & 0x7; - if (i & 0x80) j |= 8; - nyb_map[i] = j; - } -} - -__initfunc(int bpcd_init (void)) /* preliminary initialisation */ - -{ init_nyb_map(); - - if (bp_detect()) return -1; - - if (register_blkdev(MAJOR_NR,"bpcd",&bp_fops)) { - printk("bpcd: unable to get major number %d\n",MAJOR_NR); - return -1; - } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; - read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */ - - return 0; -} - -static int bp_open (struct inode *inode, struct file *file) - -{ - if (file->f_mode & 2) return -EROFS; /* wants to write ? */ - - MOD_INC_USE_COUNT; - - if (!bp_access) - if (bp_lock()) { - MOD_DEC_USE_COUNT; - return -ENXIO; - } - bp_access++; - return 0; -} - -static void do_bp_request (void) - -{ if (bp_busy) return; - while (1) { - if ((!CURRENT) || (CURRENT->rq_status == RQ_INACTIVE)) return; - INIT_REQUEST; - if (CURRENT->cmd == READ) { - bp_sector = CURRENT->sector; - bp_count = CURRENT->nr_sectors; - bp_buf = CURRENT->buffer; - do_bp_read(); - if (bp_busy) return; - } - else end_request(0); - } -} - -static int bp_ioctl(struct inode *inode,struct file *file, - unsigned int cmd, unsigned long arg) - -/* we currently support only the EJECT ioctl. */ - -{ switch (cmd) { - case CDROMEJECT: if (bp_access == 1) { - bp_eject(); - return 0; - } - default: - return -EINVAL; - } -} - -static int bp_release (struct inode *inode, struct file *file) - -{ kdev_t devp; - - bp_access--; - if (!bp_access) { - devp = inode->i_rdev; - fsync_dev(devp); - invalidate_inodes(devp); - invalidate_buffers(devp); - bp_unlock(); - } - MOD_DEC_USE_COUNT; - return 0; -} - -#ifdef MODULE - -/* Glue for modules ... */ - -int init_module(void) - -{ int err; - long flags; - - save_flags(flags); - cli(); - - err = bpcd_init(); - - restore_flags(flags); - return err; -} - -void cleanup_module(void) - -{ long flags; - - save_flags(flags); - cli(); - unregister_blkdev(MAJOR_NR,"bpcd"); - release_region(bp_base,3); - restore_flags(flags); -} - -#else - -/* bpcd_setup: process lilo command parameters ... - - syntax: bpcd=base[,nybble[,rep]] -*/ - -__initfunc(void bpcd_setup(char *str, int *ints)) - -{ if (ints[0] > 0) bp_base = ints[1]; - if (ints[0] > 1) bp_nybble = ints[2]; - if (ints[0] > 2) bp_rep = ints[3]; -} - -#endif - -static void out_p( short port, char byte) - -{ int i; - - for(i=0;i<bp_rep;i++) outb(byte,bp_base+port); -} - -static int in_p( short port) - -{ int i; - char c; - - for(i=0;i<bp_rep;i++) c=inb(bp_base+port); - c=inb(bp_base+port); - return c & 0xff; -} - -/* Unlike other PP devices I've worked on, the backpack protocol seems - to be driven by *changes* in the values of certain bits on the control - port, rather than their absolute value. Hence the unusual macros ... -*/ - -#define w0(byte) out_p(0,byte) -#define r0() (in_p(0) & 0xff) -#define w1(byte) out_p(1,byte) -#define r1() (in_p(1) & 0xff) -#define w2(byte) out_p(2,byte) ; PortCache = byte -#define t2(pat) PortCache ^= pat; out_p(2,PortCache) -#define e2() PortCache &= 0xfe; out_p(2,PortCache) -#define o2() PortCache |= 1; out_p(2,PortCache) - -static int read_byte( void ) - -{ int l, h; - - t2(4); - if (bp_mode == 2) return r0(); - l = nyb_map[r1()]; - t2(4); - h = nyb_map[r1()]; - return (h << 4) + l; -} - -static int read_regr( char regr ) - -{ int r; - - w0(regr & 0xf); w0(regr); t2(2); - if (bp_mode == 2) { e2(); t2(0x20); } - r = read_byte(); - if (bp_mode == 2) { t2(1); t2(0x20); } - return r; -} - -static void write_regr( char regr, char val ) - -{ w0(regr); - t2(2); - w0(val); - o2(); t2(4); t2(1); -} - -static void write_cmd( char * cmd, int len ) - -{ int i, f; - - if (bp_mode == 2) f = 0x10; else f = 0; - write_regr(4,0x40|f); - w0(0x40); t2(2); t2(1); - i = 0; - while (i < len) { - w0(cmd[i++]); - t2(4); - } - write_regr(4,f); -} - -static void read_data( char * buf, int len ) - -{ int i, f; - - if (bp_mode == 2) f = 0x50; else f = 0x40; - write_regr(4,f); - w0(0x40); t2(2); - if (bp_mode == 2) t2(0x20); - for(i=0;i<len;i++) buf[i] = read_byte(); - if (bp_mode == 2) { t2(1); t2(0x20); } -} - -__initfunc(static int probe( int id )) - -{ int l, h, t; - int r = -1; - - w2(4); w2(0xe); w2(0xec); w1(0x7f); - if ((r1() & 0xf8) != 0x78) return -1; - w0(255-id); w2(4); w0(id); - t2(8); t2(8); t2(8); - t2(2); t = (r1() & 0xf8); - if (t != 0x78) { - l = nyb_map[t]; - t2(2); h = nyb_map[r1()]; - t2(8); - r = 0; - } - w0(0); t2(2); w2(0x4c); w0(0x13); - return r; -} - -static void connect ( void ) - -{ int f; - - w0(0xff-bp_unit_id); w2(4); w0(bp_unit_id); - t2(8); t2(8); t2(8); - t2(2); t2(2); t2(8); - if (bp_mode == 2) f = 0x10; else f = 0; - write_regr(4,f); - write_regr(5,8); - write_regr(0x46,0x10); - write_regr(0x4c,0x38); - write_regr(0x4d,0x88); - write_regr(0x46,0xa0); - write_regr(0x41,0); - write_regr(0x4e,8); -} - -static void disconnect ( void ) - -{ w0(0); t2(2); w2(0x4c); - if (bp_mode == 2) w0(0xff); else w0(0x13); -} - -static int bp_wait_drq( char * lab, char * fun ) - -{ int j, r, e; - - j = 0; - - while (1) { - r = read_regr(0x47); - e = read_regr(0x41); - if ((r & 9) || (j++ >= BP_SPIN)) break; - udelay(BP_DELAY); - } - - if ((j >= BP_SPIN) || (r & 1)) { - if (lab && fun) - printk("bpcd: %s (%s): %s status: %x error: %x\n", - lab,fun,(j >= BP_SPIN)?"timeout, ":"",r,e); - return -1; - } - return 0; -} - -static int bp_wait( char * lab, char * fun ) - -{ int j, r, e; - - j = 0; - while ((!(read_regr(0xb) & 0x80)) && (j++ < BP_SPIN)) udelay(BP_DELAY); - r = read_regr(0x47); - e = read_regr(0x41); - if ((j >= BP_SPIN) || (r & 1)) { - if (lab && fun) - printk("bpcd: %s (%s): %s status: %x error: %x\n", - lab,fun,(j >= BP_SPIN)?"timeout, ":"",r,e); - return -1; - } - return 0; -} - -static int bp_command( char * cmd, int dlen, char * fun ) - -{ int r; - - connect(); - write_regr(0x44,dlen % 256); - write_regr(0x45,dlen / 256); - write_regr(0x46,0xa0); /* drive 0 */ - write_regr(0x47,0xa0); /* ATAPI packet command */ - if ((r=bp_wait_drq("bp_command",fun))) { - disconnect(); - return r; - } - write_cmd(cmd,12); - return 0; -} - -static int bp_completion( char * fun ) - -{ int r, n; - - if (!(r=bp_wait("bp_completion",fun))) { - if (read_regr(0x42) == 2) { - n = (read_regr(0x44) + 256*read_regr(0x45)); - read_data(bp_buffer,n); - r=bp_wait("transfer done",fun); - } - } - disconnect(); - return r; -} - -static int bp_atapi( char * cmd, int dlen, char * fun ) - -{ int r; - - if (!(r=bp_command(cmd,dlen,fun))) - r = bp_completion(fun); - return r; -} - -static int bp_req_sense( char * msg ) - -{ char rs_cmd[12] = { 0x03,0,0,0,18,0,0,0,0,0,0,0 }; - int r; - - r = bp_atapi(rs_cmd,18,"request sense"); - if (msg) printk("bpcd: %s: sense key: %x, ASC: %x, ASQ: %x\n",msg, - bp_buffer[2]&0xf, bp_buffer[12], bp_buffer[13]); - return r; -} - -static int bp_lock(void) - -{ char lo_cmd[12] = { 0x1e,0,0,0,1,0,0,0,0,0,0,0 }; - char cl_cmd[12] = { 0x1b,0,0,0,3,0,0,0,0,0,0,0 }; - - bp_atapi(cl_cmd,0,"close door"); - if (bp_req_sense(NULL)) return -1; /* check for disk */ - bp_atapi(lo_cmd,0,NULL); - bp_req_sense(NULL); /* in case there was a media change */ - bp_atapi(lo_cmd,0,"lock door"); - return 0; -} - -static void bp_unlock( void) - -{ char un_cmd[12] = { 0x1e,0,0,0,0,0,0,0,0,0,0,0 }; - - bp_atapi(un_cmd,0,"unlock door"); -} - -static void bp_eject( void) - -{ char ej_cmd[12] = { 0x1b,0,0,0,2,0,0,0,0,0,0,0 }; - - bp_unlock(); - bp_atapi(ej_cmd,0,"eject"); -} - -__initfunc(static int bp_reset( void )) - -/* the ATAPI standard actually specifies the contents of all 7 registers - after a reset, but the specification is ambiguous concerning the last - two bytes, and different drives interpret the standard differently. -*/ - -{ int i, flg; - int expect[5] = {1,1,1,0x14,0xeb}; - long flags; - - connect(); - write_regr(0x46,0xa0); - write_regr(0x47,8); - - save_flags(flags); - sti(); - udelay(500000); /* delay 0.5 seconds */ - restore_flags(flags); - - flg = 1; - for(i=0;i<5;i++) flg &= (read_regr(i+0x41) == expect[i]); - - disconnect(); - return flg-1; -} - -__initfunc(static int bp_identify( char * id )) - -{ int k; - char id_cmd[12] = {0x12,0,0,0,36,0,0,0,0,0,0,0}; - - bp_bufblk = -1; - if (bp_atapi(id_cmd,36,"identify")) return -1; - for (k=0;k<16;k++) id[k] = bp_buffer[16+k]; - id[16] = 0; - return 0; -} - -__initfunc(static int bp_port_check( void )) /* check for 8-bit port */ - -{ int r; - - w2(0); - w0(0x55); if (r0() != 0x55) return 0; - w0(0xaa); if (r0() != 0xaa) return 0; - w2(0x20); w0(0x55); r = r0(); w0(0xaa); - if (r0() == r) return 2; - if (r0() == 0xaa) return 1; - return 0; -} - -__initfunc(static int bp_locate( void )) - -{ int k; - - for(k=0;k<100;k++) - if (!probe(k)) { - bp_unit_id = k; - return 0; - } - return -1; -} - -__initfunc(static int bp_do_detect( int autop )) - -{ char id[18]; - - if (autop) bp_base = autop; - - if (check_region(bp_base,3)) { - if (!autop) - printk("bpcd: Ports at 0x%x are not available\n",bp_base); - return -1; - } - - bp_mode = bp_port_check(); - - if (!bp_mode) { - if (!autop) - printk("bpcd: No parallel port at 0x%x\n",bp_base); - return -1; - } - - if (bp_nybble) bp_mode = 1; - - if (bp_locate()) { - if (!autop) - printk("bpcd: Couldn't find a backpack adapter at 0x%x\n", - bp_base); - return -1; - } - - if (bp_reset()) { - if (!autop) - printk("bpcd: Failed to reset CD drive\n"); - return -1; - } - - if (bp_identify(id)) { - if (!autop) - printk("bpcd: ATAPI inquiry failed\n"); - return -1; - } - - request_region(bp_base,3,"bpcd"); - - printk("bpcd: Found %s, ID %d, using port 0x%x in %d-bit mode\n", - id,bp_unit_id,bp_base,4*bp_mode); - - return 0; -} - -/* If you know about some other weird parallel port base address, - add it here .... -*/ - -__initfunc(static int bp_detect( void )) - -{ if (bp_base) return bp_do_detect(0); - if (!bp_do_detect(0x378)) return 0; - if (!bp_do_detect(0x278)) return 0; - if (!bp_do_detect(0x3bc)) return 0; - printk("bpcd: Autoprobe failed\n"); - return -1; -} - - -static void bp_transfer( void ) - -{ int k, o; - - while (bp_count && (bp_sector/4 == bp_bufblk)) { - o = (bp_sector % 4) * 512; - for(k=0;k<512;k++) bp_buf[k] = bp_buffer[o+k]; - bp_count--; - bp_buf += 512; - bp_sector++; - } -} - -static void do_bp_read( void ) - -{ int b, i; - char rd_cmd[12] = {0xa8,0,0,0,0,0,0,0,0,1,0,0}; - - bp_busy = 1; - bp_transfer(); - if (!bp_count) { - end_request(1); - bp_busy = 0; - return; - } - sti(); - - bp_bufblk = bp_sector / 4; - b = bp_bufblk; - for(i=0;i<4;i++) { - rd_cmd[5-i] = b & 0xff; - b = b >> 8; - } - - if (bp_command(rd_cmd,2048,"read block")) { - bp_bufblk = -1; - bp_busy = 0; - cli(); - bp_req_sense("send read command"); - end_request(0); - return; - } - bp_timeout = jiffies + BP_TMO; - queue_task(&bp_tq,&tq_scheduler); -} - -static void bp_interrupt( void *data) - -{ if (!(read_regr(0xb) & 0x80)) { - if (jiffies > bp_timeout) { - bp_bufblk = -1; - bp_busy = 0; - bp_req_sense("interrupt timeout"); - end_request(0); - do_bp_request(); - } - queue_task(&bp_tq,&tq_scheduler); - return; - } - sti(); - if (bp_completion("read completion")) { - cli(); - bp_busy = 0; - bp_bufblk = -1; - bp_req_sense("read completion"); - end_request(0); - do_bp_request(); - } - do_bp_read(); - do_bp_request(); -} - -/* end of bpcd.c */ diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 4f1a2e877..48a3ae427 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -1,6 +1,6 @@ /* linux/drivers/cdrom/cdrom.c. Copyright (c) 1996, 1997 David A. van Leeuwen. - Copyright (c) 1997 Erik Andersen (andersee@debian.org) + Copyright (c) 1997, 1998 Erik Andersen <andersee@debian.org> May be copied or modified under the terms of the GNU General Public License. See linux/COPYING for more information. @@ -10,46 +10,71 @@ The routines in the file provide a uniform interface between the software that uses CD-ROMs and the various low-level drivers that - actually talk to actual hardware devices. Suggestions are welcome. + actually talk to the hardware. Suggestions are welcome. Patches that work are more welcome though. ;-) + To Do List: + ---------------------------------- - Recent Changes: - ---------------------------------- + -- Modify sysctl/proc interface. I plan on having one directory per + drive, with entries for outputing general drive information, and sysctl + based tunable parameters such as whether the tray should auto-close for + that drive. Suggestions (or patches) for this welcome! - New maintainer! As David A. van Leeuwen has been too busy to activly + -- Change the CDROMREADMODE1, CDROMREADMODE2, CDROMREADAUDIO, and + CDROMREADRAW ioctls so they go through the Uniform CD-ROM driver. + + + + + Revision History + ---------------------------------- + 1.00 Date Unknown -- David van Leeuwen <david@tm.tno.nl> + -- Initial version by David A. van Leeuwen. I don't have a detailed + changelog for the 1.x series, David? + +2.00 Dec 2, 1997 -- Erik Andersen <andersee@debian.org> + -- New maintainer! As David A. van Leeuwen has been too busy to activly maintain and improve this driver, I am now carrying on the torch. If you have a problem with this driver, please feel free to contact me. - Added (rudimentary) sysctl interface. I realize this is really weak - right now, and is _very_ badly implemented. It will be improved... I - plan on having one directory per drive, with entries for outputing - general drive information, and sysctl based tunable parameters such - as whether the tray should auto-close for that drive. Suggestions (or - patches) for improvements are very welcome. + -- Added (rudimentary) sysctl interface. I realize this is really weak + right now, and is _very_ badly implemented. It will be improved... - Modified CDROM_DISC_STATUS so that it is now incorporated into + -- Modified CDROM_DISC_STATUS so that it is now incorporated into the Uniform CD-ROM driver via the cdrom_count_tracks function. The cdrom_count_tracks function helps resolve some of the false assumptions of the CDROM_DISC_STATUS ioctl, and is also used to check for the correct media type when mounting or playing audio from a CD. - Remove the calls to verify_area and only use the copy_from_user and + -- Remove the calls to verify_area and only use the copy_from_user and copy_to_user stuff, since these calls now provide their own memory checking with the 2.1.x kernels. - Major update to return codes so that errors from low-level drivers + -- Major update to return codes so that errors from low-level drivers are passed on through (thanks to Gerd Knorr for pointing out this problem). - Made it so if a function isn't implemented in a low-level driver, + -- Made it so if a function isn't implemented in a low-level driver, ENOSYS is now returned instead of EINVAL. - Simplified some complex logic so that the source code is easier to read. + -- Simplified some complex logic so that the source code is easier to read. - Other stuff I probably forgot to mention (lots of changes). + -- Other stuff I probably forgot to mention (lots of changes). - */ +2.01 to 2.11 Dec 1997-Jan 1998 + -- TO-DO! Write changelogs for 2.01 to 2.12. + +2.12 Jan 24, 1998 -- Erik Andersen <andersee@debian.org> + -- Fixed a bug in the IOCTL_IN and IOCTL_OUT macros. It turns out that + copy_*_user does not return EFAULT on error, but instead return the number + of bytes not copied. I was returning whatever non-zero stuff came back from + the copy_*_user functions directly, which would result in strange errors. + +-------------------------------------------------------------------------*/ + +#define REVISION "Revision: 2.12" +#define VERSION "Id: cdrom.c 2.12 1998/01/24 22:15:45 erik Exp" #include <linux/config.h> @@ -68,14 +93,6 @@ #include <asm/uaccess.h> -#define VERSION "$Id: cdrom.c,v 2.0 1997/11/20 01:58:03 erik Exp $" -#define REVISION "revision 2.0" -#define FM_WRITE 0x2 /* file mode write bit */ - -/* When VERBOSE_STATUS_INFO is not defined, the debugging printks don't - get compiled in */ -#define VERBOSE_STATUS_INFO - /* I use an error-log mask to give fine grain control over the type of error messages dumped to the system logs. The available masks include: */ #define CD_WARNING 0x1 @@ -83,9 +100,14 @@ #define CD_DO_IOCTL 0x4 #define CD_OPEN 0x8 #define CD_CLOSE 0x10 +#define CD_COUNT_TRACKS 0x20 + +/* When VERBOSE_STATUS_INFO is not defined, the debugging printks don't + get compiled in at all */ +#define VERBOSE_STATUS_INFO #define ERRLOGMASK (CD_WARNING) -/* #define ERRLOGMASK (CD_WARNING|CD_OPEN|CD_CLOSE) */ +/* #define ERRLOGMASK (CD_WARNING|CD_OPEN|CD_COUNT_TRACKS|CD_CLOSE) */ /* #define ERRLOGMASK (CD_WARNING|CD_REG_UNREG|CD_DO_IOCTL|CD_OPEN|CD_CLOSE) */ #ifdef VERBOSE_STATUS_INFO @@ -95,15 +117,17 @@ #define cdinfo(type, fmt, args...) #endif - /* These are used to simplify getting data in from and back to user land */ #define IOCTL_IN(arg, type, in) { \ - int ret=copy_from_user(&in, (type *) arg, sizeof in); \ - if (ret) return ret; } + if ( copy_from_user(&in, (type *) arg, sizeof in) ) \ + return -EFAULT; } #define IOCTL_OUT(arg, type, out) { \ - int ret=copy_to_user((type *) arg, &out, sizeof out); \ - if (ret) return ret; } + if ( copy_to_user((type *) arg, &out, sizeof out) ) \ + return -EFAULT; } + + +#define FM_WRITE 0x2 /* file mode write bit */ /* Not-exported routines. */ static int cdrom_open(struct inode *ip, struct file *fp); @@ -177,7 +201,8 @@ int register_cdrom(struct cdrom_device_info *cdi) ENSURE(reset, CDC_RESET); ENSURE(audio_ioctl, CDC_PLAY_AUDIO); ENSURE(dev_ioctl, CDC_IOCTLS); - cdi->options = CDO_AUTO_CLOSE | CDO_USE_FFLAGS | CDO_LOCK | CDO_CHECK_TYPE; + cdi->options = CDO_AUTO_CLOSE | CDO_USE_FFLAGS | CDO_LOCK; + /* default compatibility mode */ cdi->mc_flags = 0; cdo->n_minors = 0; cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); @@ -305,15 +330,13 @@ int open_for_data(struct cdrom_device_info * cdi) ret=-ENOMEDIUM; goto clean_up_and_return; } -#if 0 - /* this breaks CD-Players which don't use O_NONBLOCK, workman - * for example, probably others too */ + /* CD-Players which don't use O_NONBLOCK, workman + * for example, need bit CDO_CHECK_TYPE cleared! */ if (cdi->options & CDO_CHECK_TYPE && tracks.data==0) { cdinfo(CD_OPEN, "bummer. wrong media type...\n"); ret=-EMEDIUMTYPE; goto clean_up_and_return; } -#endif cdinfo(CD_OPEN, "all seems well, opening the device...\n"); @@ -481,7 +504,7 @@ void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype* tracks) tracks->cdi=0; tracks->xa=0; tracks->error=0; - cdinfo(CD_OPEN, "entering cdrom_count_tracks\n"); + cdinfo(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n"); if (!(cdi->ops->capability & CDC_PLAY_AUDIO)) { tracks->error=CDS_NO_INFO; return; @@ -509,10 +532,10 @@ void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype* tracks) tracks->data++; } else tracks->audio++; - cdinfo(CD_OPEN, "track %d: format=%d, ctrl=%d\n", + cdinfo(CD_COUNT_TRACKS, "track %d: format=%d, ctrl=%d\n", i, entry.cdte_format, entry.cdte_ctrl); } - cdinfo(CD_OPEN, "disc has %d tracks: %d=audio %d=data %d=Cd-I %d=XA\n", + cdinfo(CD_COUNT_TRACKS, "disc has %d tracks: %d=audio %d=data %d=Cd-I %d=XA\n", header.cdth_trk1, tracks->audio, tracks->data, tracks->cdi, tracks->xa); } @@ -716,6 +739,10 @@ int cdrom_ioctl(struct inode *ip, struct file *fp, returns with the above, but this more clearly demonstrates the problem with the current interface. Too bad this wasn't designed to use bitmasks... -Erik + + Well, now we have the option CDS_MIXED: a mixed-type CD. + User level programmers might feel the ioctl is not very useful. + ---david */ case CDROM_DISC_STATUS: { tracktype tracks; @@ -725,11 +752,14 @@ int cdrom_ioctl(struct inode *ip, struct file *fp, return(tracks.error); /* Policy mode on */ - if (tracks.audio>0 && tracks.data==0 && tracks.cdi==0 && tracks.xa==0) - return CDS_AUDIO; - if (tracks.cdi>0) return CDS_XA_2_2; - if (tracks.xa>0) return CDS_XA_2_1; - if (tracks.data>0) return CDS_DATA_1; + if (tracks.audio > 0) { + if (tracks.data==0 && tracks.cdi==0 && tracks.xa==0) + return CDS_AUDIO; + else return CDS_MIXED; + } + if (tracks.cdi > 0) return CDS_XA_2_2; + if (tracks.xa > 0) return CDS_XA_2_1; + if (tracks.data > 0) return CDS_DATA_1; /* Policy mode off */ cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognise!\n"); diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c index 231e00548..15481c9a8 100644 --- a/drivers/cdrom/cdu31a.c +++ b/drivers/cdrom/cdu31a.c @@ -186,6 +186,10 @@ * Heiko Eissfeldt <heiko@colossus.escape.de> with additional * changes by Erik Andersen <andersee@debian.org> * + * 24 January 1998 -- Removed the scd_disc_status() function, which was now + * just dead code left over from the port. + * Erik Andersen <andersee@debian.org> + * */ #include <linux/major.h> @@ -416,7 +420,8 @@ static int scd_drive_status(struct cdrom_device_info *cdi, int slot_nr) return -EINVAL; } - return sony_spun_up ? CDS_DISC_OK : CDS_DRIVE_NOT_READY; + /*return sony_spun_up ? CDS_DISC_OK : CDS_DRIVE_NOT_READY;*/ + return sony_spun_up ? CDS_DISC_OK : CDS_TRAY_OPEN; } static inline void @@ -1085,7 +1090,7 @@ handle_sony_cd_attention(void) volatile int val; -#if DEBUG +#if 0*DEBUG printk("Entering handle_sony_cd_attention\n"); #endif if (is_attention()) @@ -1166,7 +1171,7 @@ handle_sony_cd_attention(void) } num_consecutive_attentions = 0; -#if DEBUG +#if 0*DEBUG printk("Leaving handle_sony_cd_attention at %d\n", __LINE__); #endif return(0); @@ -1241,33 +1246,6 @@ size_to_buf(unsigned int size, 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 @@ -2835,8 +2813,11 @@ static int scd_tray_move(struct cdrom_device_info *cdi, int position) 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; + } else { + if (0 == scd_spinup()) + sony_spun_up = 1; + return 0; + } } /* @@ -3230,7 +3211,6 @@ scd_open(struct cdrom_device_info *cdi, int openmode) 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) @@ -3247,7 +3227,6 @@ printk("sony_xa_mode is set\n"); 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; @@ -3293,7 +3272,7 @@ static struct cdrom_device_ops scd_dops = { 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_OPEN_TRAY | CDC_CLOSE_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 */ @@ -3303,7 +3282,7 @@ static struct cdrom_device_info scd_info = { &scd_dops, /* device operations */ NULL, /* link */ NULL, /* handle */ - MKDEV(MAJOR_NR,0), /* dev */ + 0, /* dev */ 0, /* mask */ 2, /* maximum speed */ 1, /* number of discs */ @@ -3570,7 +3549,9 @@ cdu31a_init(void)) init_timer(&cdu31a_abort_timer); cdu31a_abort_timer.function = handle_abort_timeout; + scd_info.dev = MKDEV(MAJOR_NR,0); scd_info.mask = deficiency; + strncpy(scd_info.name, "cdu31a", sizeof(scd_info.name)); if (register_cdrom(&scd_info)) { diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c index e699cfa8e..c0bcc7bf4 100644 --- a/drivers/cdrom/cm206.c +++ b/drivers/cdrom/cm206.c @@ -1,5 +1,6 @@ /* cm206.c. A linux-driver for the cm206 cdrom player with cm260 adapter card. - Copyright (c) 1995, 1996 David van Leeuwen. + Copyright (c) 1995--1997 David A. van Leeuwen. + $Id: cm206.c,v 1.5 1997/12/26 11:02:51 david Exp $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -70,40 +71,86 @@ History: open only for ioctl operation, e.g., for operation of tray etc. 4 apr 1996: 0.97 First implementation of layer between VFS and cdrom - driver, a Uniform interface. Much of the functionality + driver, a generic interface. Much of the functionality of cm206_open() and cm206_ioctl() is transferred to a - new file cdrom.c and its header cdrom.h. + new file cdrom.c and its header ucdrom.h. Upgrade to Linux kernel 1.3.78. 11 apr 1996 0.98 Upgrade to Linux kernel 1.3.85 More code moved to cdrom.c + + 0.99 Some more small changes to decrease number + of oopses at module load; + + 27 jul 1996 0.100 Many hours of debugging, kernel change from 1.2.13 + to 2.0.7 seems to have introduced some weird behavior + in (interruptible_)sleep_on(&cd->data): the process + seems to be woken without any explicit wake_up in my own + code. Patch to try 100x in case such untriggered wake_up's + occur. - 0.99 Some more small changes to decrease number - of oopses at module load; - - Branch from here: - - 0.99.1.0 Update to kernel release 2.0.10 dev_t -> kdev_t - (emoenke) various typos found by others. extra - module-load oops protection. - - 0.99.1.1 Initialization constant cdrom_dops.speed - changed from float (2.0) to int (2); Cli()-sti() pair - around cm260_reset() in module initialization code. + 28 jul 1996 0.101 Rewriting of the code that receives the command echo, + using a fifo to store echoed bytes. - 0.99.1.2 Changes literally as proposed by Scott Snyder - <snyder@d0sgif.fnal.gov>, which have to do mainly with - the poor minor support i had. The major new concept is - to change a cdrom driver's operations struct from the - capabilities struct. This reflects the fact that there - is one major for a driver, whilst there can be many - minors whith completely different capabilities. + Branch from 0.99: + + 0.99.1.0 Update to kernel release 2.0.10 dev_t -> kdev_t + (emoenke) various typos found by others. extra + module-load oops protection. + + 0.99.1.1 Initialization constant cdrom_dops.speed + changed from float (2.0) to int (2); Cli()-sti() pair + around cm260_reset() in module initialization code. + + 0.99.1.2 Changes literally as proposed by Scott Snyder + <snyder@d0sgif.fnal.gov> for the 2.1 kernel line, which + have to do mainly with the poor minor support i had. The + major new concept is to change a cdrom driver's + operations struct from the capabilities struct. This + reflects the fact that there is one major for a driver, + whilst there can be many minors whith completely + different capabilities. 0.99.1.3 More changes for operations/info separation. 0.99.1.4 Added speed selection (someone had to do this first). + + 23 jan 1997 0.99.1.5 MODULE_PARMS call added. + + 23 jan 1997 0.100.1.2--0.100.1.5 following similar lines as + 0.99.1.1--0.99.1.5. I get too many complaints about the + drive making read errors. What't wrong with the 2.0+ + kernel line? Why get i (and othe cm206 owners) weird + results? Why were things good in the good old 1.1--1.2 + era? Why don't i throw away the drive? + + 2 feb 1997 0.102 Added `volatile' to values in cm206_struct. Seems to + reduce many of the problems. Rewrote polling routines + to use fixed delays between polls. + 0.103 Changed printk behavior. + 0.104 Added a 0.100 -> 0.100.1.1 change + +11 feb 1997 0.105 Allow auto_probe during module load, disable + with module option "auto_probe=0". Moved some debugging + statements to lower priority. Implemented select_speed() + function. + +13 feb 1997 1.0 Final version for 2.0 kernel line. + + All following changes will be for the 2.1 kernel line. + +15 feb 1997 1.1 Keep up with kernel 2.1.26, merge in changes from + cdrom.c 0.100.1.1--1.0. Add some more MODULE_PARMS. + +14 sep 1997 1.2 Upgrade to Linux 2.1.55. Added blksize_size[], patch + sent by James Bottomley <James.Bottomley@columbiasc.ncr.com>. + +21 dec 1997 1.4 Upgrade to Linux 2.1.72. + +24 jan 1998 Removed the cm206_disc_status() function, as it was now dead + code. The Uniform CDROM driver now provides this functionality. * * Parts of the code are based upon lmscd.c written by Kai Petzke, * sbpcd.c written by Eberhard Moenkeberg, and mcd.c by Martin @@ -123,8 +170,8 @@ History: * - Philips/LMS cm206 and cm226 product specification * - Philips/LMS cm260 product specification * - * David van Leeuwen, david@tm.tno.nl. */ -#define VERSION "$Id: cm206.c,v 0.99.1.4 1996/12/23 21:46:13 david Exp $" + * David van Leeuwen, david@tm.tno.nl. */ +#define REVISION "$Revision: 1.5 $" #include <linux/module.h> @@ -140,6 +187,8 @@ History: #include <linux/malloc.h> #include <linux/init.h> +/* #include <linux/ucdrom.h> */ + #include <asm/io.h> #define MAJOR_NR CM206_CDROM_MAJOR @@ -147,7 +196,7 @@ History: #undef DEBUG #define STATISTICS /* record times and frequencies of events */ -#undef AUTO_PROBE_MODULE +#define AUTO_PROBE_MODULE #define USE_INSW #include "cm206.h" @@ -160,15 +209,18 @@ static int auto_probe=1; /* Yes, why not? */ static int cm206_base = CM206_BASE; static int cm206_irq = CM206_IRQ; -MODULE_PARM(cm206_base, "i"); -MODULE_PARM(cm206_irq, "i"); +MODULE_PARM(cm206_base, "i"); /* base */ +MODULE_PARM(cm206_irq, "i"); /* irq */ +MODULE_PARM(cm206, "1-2i"); /* base,irq or irq,base */ +MODULE_PARM(auto_probe, "i"); /* auto probe base and irq */ -#define POLLOOP 10000 +#define POLLOOP 100 /* milliseconds */ #define READ_AHEAD 1 /* defines private buffer, waste! */ #define BACK_AHEAD 1 /* defines adapter-read ahead */ #define DATA_TIMEOUT (3*HZ) /* measured in jiffies (10 ms) */ #define UART_TIMEOUT (5*HZ/100) #define DSB_TIMEOUT (7*HZ) /* time for the slowest command to finish */ +#define UR_SIZE 4 /* uart receive buffer fifo size */ #define LINUX_BLOCK_SIZE 512 /* WHERE is this defined? */ #define RAW_SECTOR_SIZE 2352 /* ok, is also defined in cdrom.h */ @@ -181,13 +233,14 @@ MODULE_PARM(cm206_irq, "i"); cd->last_stat[st_ ## i] = cd->stat_counter++; \ } #else -#define stats(i) (void) 0 +#define stats(i) (void) 0; #endif -#ifdef DEBUG /* from lmscd.c */ -#define debug(a) printk a +#define Debug(a) {printk (KERN_DEBUG); printk a;} +#ifdef DEBUG +#define debug(a) Debug(a) #else -#define debug(a) (void) 0 +#define debug(a) (void) 0; #endif typedef unsigned char uch; /* 8-bits */ @@ -197,21 +250,23 @@ struct toc_struct{ /* private copy of Table of Contents */ uch track, fsm[3], q0; }; +static int cm206_blocksizes[1] = { 2048 }; + struct cm206_struct { - ush intr_ds; /* data status read on last interrupt */ - ush intr_ls; /* uart line status read on last interrupt*/ - uch intr_ur; /* uart receive buffer */ - uch dsb, cc; /* drive status byte and condition (error) code */ - uch fool; + volatile ush intr_ds; /* data status read on last interrupt */ + volatile ush intr_ls; /* uart line status read on last interrupt*/ + volatile uch ur[UR_SIZE]; /* uart receive buffer fifo */ + volatile uch ur_w, ur_r; /* write/read buffer index */ + volatile uch dsb, cc; /* drive status byte and condition (error) code */ int command; /* command to be written to the uart */ int openfiles; ush sector[READ_AHEAD*RAW_SECTOR_SIZE/2]; /* buffered cd-sector */ - int sector_first, sector_last; /* range of these sector */ - struct wait_queue * uart; /* wait for interrupt */ + int sector_first, sector_last; /* range of these sectors */ + struct wait_queue * uart; /* wait queues for interrupt */ struct wait_queue * data; struct timer_list timer; /* time-out */ char timed_out; - signed char max_sectors; + signed char max_sectors; /* number of sectors that fit in adapter mem */ char wait_back; /* we're waiting for a background-read */ char background; /* is a read going on in the background? */ int adapter_first; /* if so, that's the starting sector */ @@ -243,15 +298,20 @@ static struct cm206_struct * cd; /* the main memory structure */ void send_command_polled(int command) { int loop=POLLOOP; - while (!(inw(r_line_status) & ls_transmitter_buffer_empty) && loop>0) + while (!(inw(r_line_status) & ls_transmitter_buffer_empty) && loop>0) { + udelay(1000); /* one millisec delay */ --loop; + } outw(command, r_uart_transmit); } uch receive_echo_polled(void) { int loop=POLLOOP; - while (!(inw(r_line_status) & ls_receive_buffer_full) && loop>0) --loop; + while (!(inw(r_line_status) & ls_receive_buffer_full) && loop>0) { + udelay(1000); + --loop; + } return ((uch) inw(r_uart_receive)); } @@ -261,6 +321,15 @@ uch send_receive_polled(int command) return receive_echo_polled(); } +inline void clear_ur(void) { + if (cd->ur_r != cd->ur_w) { + debug(("Deleting bytes from fifo:")); + for(;cd->ur_r != cd->ur_w; cd->ur_r++, cd->ur_r %= UR_SIZE) + debug((" 0x%x", cd->ur[cd->ur_r])); + debug(("\n")); + } +} + /* The interrupt handler. When the cm260 generates an interrupt, very much care has to be taken in reading out the registers in the right order; in case of a receive_buffer_full interrupt, first the @@ -282,18 +351,27 @@ static void cm206_interrupt(int sig, void *dev_id, struct pt_regs * regs) crc_error, sync_error, toc_ready interrupts */ cd->intr_ls = inw(r_line_status); /* resets overrun bit */ + debug(("Intr, 0x%x 0x%x, %d\n", cd->intr_ds, cd->intr_ls, cd->background)); if (cd->intr_ls & ls_attention) stats(attention); /* receive buffer full? */ if (cd->intr_ls & ls_receive_buffer_full) { - cd->intr_ur = inb(r_uart_receive); /* get order right! */ + cd->ur[cd->ur_w] = inb(r_uart_receive); /* get order right! */ cd->intr_ls = inw(r_line_status); /* resets rbf interrupt */ - if (!cd->background && cd->uart) wake_up_interruptible(&cd->uart); + debug(("receiving #%d: 0x%x\n", cd->ur_w, cd->ur[cd->ur_w])); + cd->ur_w++; cd->ur_w %= UR_SIZE; + if (cd->ur_w == cd->ur_r) debug(("cd->ur overflow!\n")); + if (cd->uart && cd->background < 2) { + del_timer(&cd->timer); + wake_up_interruptible(&cd->uart); + } } /* data ready in fifo? */ else if (cd->intr_ds & ds_data_ready) { if (cd->background) ++cd->adapter_last; - if ((cd->wait_back || !cd->background) && cd->data) + if (cd->data && (cd->wait_back || !cd->background)) { + del_timer(&cd->timer); wake_up_interruptible(&cd->data); + } stats(data_ready); } /* ready to issue a write command? */ @@ -340,6 +418,7 @@ static void cm206_interrupt(int sig, void *dev_id, struct pt_regs * regs) void cm206_timeout(unsigned long who) { cd->timed_out = 1; + debug(("Timing out\n")); wake_up_interruptible((struct wait_queue **) who); } @@ -347,9 +426,11 @@ void cm206_timeout(unsigned long who) happened */ int sleep_or_timeout(struct wait_queue ** wait, int timeout) { + cd->timed_out=0; cd->timer.data=(unsigned long) wait; cd->timer.expires = jiffies + timeout; add_timer(&cd->timer); + debug(("going to sleep\n")); interruptible_sleep_on(wait); del_timer(&cd->timer); if (cd->timed_out) { @@ -359,14 +440,15 @@ int sleep_or_timeout(struct wait_queue ** wait, int timeout) else return 0; } -void cm206_delay(int jiffies) +void cm206_delay(int nr_jiffies) { struct wait_queue * wait = NULL; - sleep_or_timeout(&wait, jiffies); + sleep_or_timeout(&wait, nr_jiffies); } void send_command(int command) { + debug(("Sending 0x%x\n", command)); if (!(inw(r_line_status) & ls_transmitter_buffer_empty)) { cd->command = command; cli(); /* don't interrupt before sleep */ @@ -378,19 +460,40 @@ void send_command(int command) stats(write_timeout); outw(command, r_uart_transmit); } + debug(("Write commmand delayed\n")); } else outw(command, r_uart_transmit); } -uch receive_echo(void) +uch receive_byte(int timeout) { - if (!(inw(r_line_status) & ls_receive_buffer_full) && - sleep_or_timeout(&cd->uart, UART_TIMEOUT)) { + uch ret; + cli(); + debug(("cli\n")); + ret = cd->ur[cd->ur_r]; + if (cd->ur_r != cd->ur_w) { + sti(); + debug(("returning #%d: 0x%x\n", cd->ur_r, cd->ur[cd->ur_r])); + cd->ur_r++; cd->ur_r %= UR_SIZE; + return ret; + } + else if (sleep_or_timeout(&cd->uart, timeout)) { /* does sti() */ debug(("Time out on receive-buffer\n")); - stats(receive_timeout); - return ((uch) inw(r_uart_receive)); +#ifdef STATISTICS + if (timeout==UART_TIMEOUT) stats(receive_timeout) /* no `;'! */ + else stats(dsb_timeout); +#endif + return 0xda; } - return cd->intr_ur; + ret = cd->ur[cd->ur_r]; + debug(("slept; returning #%d: 0x%x\n", cd->ur_r, cd->ur[cd->ur_r])); + cd->ur_r++; cd->ur_r %= UR_SIZE; + return ret; +} + +inline uch receive_echo(void) +{ + return receive_byte(UART_TIMEOUT); } inline uch send_receive(int command) @@ -399,20 +502,15 @@ inline uch send_receive(int command) return receive_echo(); } -uch wait_dsb(void) +inline uch wait_dsb(void) { - if (!(inw(r_line_status) & ls_receive_buffer_full) && - sleep_or_timeout(&cd->uart, DSB_TIMEOUT)) { - debug(("Time out on Drive Status Byte\n")); - stats(dsb_timeout); - return ((uch) inw(r_uart_receive)); - } - return cd->intr_ur; + return receive_byte(DSB_TIMEOUT); } int type_0_command(int command, int expect_dsb) { int e; + clear_ur(); if (command != (e=send_receive(command))) { debug(("command 0x%x echoed as 0x%x\n", command, e)); stats(echo); @@ -433,8 +531,8 @@ int type_1_command(int command, int bytes, uch * status) /* returns info */ return 0; } -/* This function resets the adapter card. We'd better not do this too */ -/* often, because it tends to generate `lost interrupts.' */ +/* This function resets the adapter card. We'd better not do this too + * often, because it tends to generate `lost interrupts.' */ void reset_cm260(void) { outw(dc_normal | dc_initialize | READ_AHEAD, r_data_control); @@ -442,7 +540,7 @@ void reset_cm260(void) outw(dc_normal | READ_AHEAD, r_data_control); } -/* fsm: frame-sec-min from linear address */ +/* fsm: frame-sec-min from linear address; one of many */ void fsm(int lba, uch * fsm) { fsm[0] = lba % 75; @@ -466,20 +564,26 @@ int start_read(int start) int i, e; fsm(start, &read_sector[1]); + clear_ur(); for (i=0; i<4; i++) if (read_sector[i] != (e=send_receive(read_sector[i]))) { debug(("read_sector: %x echoes %x\n", read_sector[i], e)); stats(echo); - return -1; + if (e==0xff) { /* this seems to happen often */ + e = receive_echo(); + debug(("Second try %x\n", e)); + if (e!=read_sector[i]) return -1; + } } return 0; } int stop_read(void) { + int e; type_0_command(c_stop,0); - if(receive_echo() != 0xff) { - debug(("c_stop didn't send 0xff\n")); + if((e=receive_echo()) != 0xff) { + debug(("c_stop didn't send 0xff, but 0x%x\n", e)); stats(stop_0xff); return -1; } @@ -515,8 +619,11 @@ void transport_data(int port, ush * dest, int count) } #endif + +#define MAX_TRIES 100 int read_sector(int start) { + int tries=0; if (cd->background) { cd->background=0; cd->adapter_last = -1; /* invalidate adapter memory */ @@ -525,12 +632,18 @@ int read_sector(int start) cd->fifo_overflowed=0; reset_cm260(); /* empty fifo etc. */ if (start_read(start)) return -1; - if (sleep_or_timeout(&cd->data, DATA_TIMEOUT)) { - debug(("Read timed out sector 0x%x\n", start)); - stats(read_timeout); - stop_read(); - return -3; - } + do { + if (sleep_or_timeout(&cd->data, DATA_TIMEOUT)) { + debug(("Read timed out sector 0x%x\n", start)); + stats(read_timeout); + stop_read(); + return -3; + } + tries++; + } while (cd->intr_ds & ds_fifo_empty && tries < MAX_TRIES); + if (tries>1) debug(("Took me some tries\n")) + else if (tries == MAX_TRIES) + debug(("MAX_TRIES tries for read sector\n")); transport_data(r_fifo_output_buffer, cd->sector, READ_AHEAD*RAW_SECTOR_SIZE/2); if (read_background(start+READ_AHEAD,1)) stats(read_background); @@ -569,16 +682,22 @@ void cm206_bh(void) cd->background=3; break; case 3: - if (cd->intr_ur != c_stop) { - debug(("cm206_bh: c_stop echoed 0x%x\n", cd->intr_ur)); - stats(echo); + if (cd->ur_r != cd->ur_w) { + if (cd->ur[cd->ur_r] != c_stop) { + debug(("cm206_bh: c_stop echoed 0x%x\n", cd->ur[cd->ur_r])); + stats(echo); + } + cd->ur_r++; cd->ur_r %= UR_SIZE; } cd->background++; break; case 4: - if (cd->intr_ur != 0xff) { - debug(("cm206_bh: c_stop reacted with 0x%x\n", cd->intr_ur)); - stats(stop_0xff); + if (cd->ur_r != cd->ur_w) { + if (cd->ur[cd->ur_r] != 0xff) { + debug(("cm206_bh: c_stop reacted with 0x%x\n", cd->ur[cd->ur_r])); + stats(stop_0xff); + } + cd->ur_r++; cd->ur_r %= UR_SIZE; } cd->background=0; } @@ -699,6 +818,7 @@ static void do_cm206_request(void) } error=0; for (i=0; i<CURRENT->nr_sectors; i++) { + int e1, e2; cd_sec_no = (CURRENT->sector+i)/BLOCKS_ISO; /* 4 times 512 bytes */ quarter = (CURRENT->sector+i) % BLOCKS_ISO; dest = CURRENT->buffer + i*LINUX_BLOCK_SIZE; @@ -708,12 +828,14 @@ static void do_cm206_request(void) + (cd_sec_no-cd->sector_first)*RAW_SECTOR_SIZE; memcpy(dest, source, LINUX_BLOCK_SIZE); } - else if (!try_adapter(cd_sec_no) || !read_sector(cd_sec_no)) { + else if (!(e1=try_adapter(cd_sec_no)) || + !(e2=read_sector(cd_sec_no))) { source = ((uch *) cd->sector)+16+quarter*LINUX_BLOCK_SIZE; memcpy(dest, source, LINUX_BLOCK_SIZE); } else { error=1; + debug(("cm206_request: %d %d\n", e1, e2)); } } end_request(!error); @@ -758,21 +880,22 @@ inline uch normalize_track(uch track) /* This function does a binary search for track start. It records all * tracks seen in the process. Input $track$ must be between 1 and - * #-of-tracks+1 */ + * #-of-tracks+1. Note that the start of the disc must be in toc[1].fsm. + */ int get_toc_lba(uch track) { - int max=74*60*75-150, min=0; + int max=74*60*75-150, min=fsm2lba(cd->toc[1].fsm); int i, lba, l, old_lba=0; uch * q = cd->q; uch ct; /* current track */ int binary=0; - const skip = 3*60*75; + const int skip = 3*60*75; /* 3 minutes */ for (i=track; i>0; i--) if (cd->toc[i].track) { min = fsm2lba(cd->toc[i].fsm); break; } - lba = min + skip; /* 3 minutes */ + lba = min + skip; do { seek(lba); type_1_command(c_read_current_q, 10, q); @@ -811,11 +934,11 @@ void update_toc_entry(uch track) int read_toc_header(struct cdrom_tochdr * hp) { if (!FIRST_TRACK) get_disc_status(); - if (hp && DISC_STATUS & cds_all_audio) { /* all audio */ + if (hp) { int i; hp->cdth_trk0 = FIRST_TRACK; - hp->cdth_trk1 = LAST_TRACK; - cd->toc[1].track=1; /* fill in first track position */ + hp->cdth_trk1 = LAST_TRACK; + /* fill in first track position */ for (i=0; i<3; i++) cd->toc[1].fsm[i] = cd->disc_status[3+i]; update_toc_entry(LAST_TRACK+1); /* find most entries */ return 0; @@ -988,7 +1111,7 @@ int cm206_media_changed(struct cdrom_device_info * cdi, int disc_nr) else return -EIO; } -/* The new Uniform cdrom support. Routines should be concise, most of +/* The new generic cdrom support. Routines should be concise, most of the logic should be in cdrom.c */ /* returns number of times device is in use */ @@ -1029,7 +1152,7 @@ int cm206_lock_door(struct cdrom_device_info * cdi, int lock) } /* Although a session start should be in LBA format, we return it in - MSF format because it is slightly easier, and the new Uniform ioctl + MSF format because it is slightly easier, and the new generic ioctl will take care of the necessary conversion. */ int cm206_get_last_session(struct cdrom_device_info * cdi, struct cdrom_multisession * mssp) @@ -1114,7 +1237,9 @@ static struct cdrom_device_ops cm206_dops = { cm206_audio_ioctl, /* audio ioctl */ cm206_ioctl, /* device-specific ioctl */ CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_MULTI_SESSION | - CDC_MEDIA_CHANGED | CDC_MCN | CDC_PLAY_AUDIO, /* capability */ + CDC_MEDIA_CHANGED | CDC_MCN | CDC_PLAY_AUDIO | CDC_SELECT_SPEED | + CDC_IOCTLS | CDC_DRIVE_STATUS, + /* capability */ 1, /* number of minor devices */ }; @@ -1123,7 +1248,7 @@ static struct cdrom_device_info cm206_info = { &cm206_dops, /* device operations */ NULL, /* link */ NULL, /* handle (not used by cm206) */ - MKDEV(MAJOR_NR,0), /* dev */ + 0, /* dev */ 0, /* mask */ 2, /* maximum speed */ 1, /* number of discs */ @@ -1133,9 +1258,9 @@ static struct cdrom_device_info cm206_info = { "cm206" /* name of the device type */ }; -/* This routine gets called during initialization if thing go wrong, +/* This routine gets called during initialization if things go wrong, * can be used in cleanup_module as well. */ -void cleanup(int level) +static void cleanup(int level) { switch (level) { case 4: @@ -1206,7 +1331,7 @@ __initfunc(int cm206_init(void)) uch e=0; long int size=sizeof(struct cm206_struct); - printk(KERN_INFO VERSION); + printk(KERN_INFO "cm206 cdrom driver " REVISION); cm206_base = probe_base_port(auto_probe ? 0 : cm206_base); if (!cm206_base) { printk(" can't find adapter!\n"); @@ -1233,14 +1358,14 @@ __initfunc(int cm206_init(void)) /* Now, the problem here is that reset_cm260 can generate an interrupt. It seems that this can cause a kernel oops some time later. So we wait a while and `service' this interrupt. */ - udelay(10); + udelay(1000); outw(dc_normal | READ_AHEAD, r_data_control); sti(); printk(" using IRQ %d\n", cm206_irq); #endif if (send_receive_polled(c_drive_configuration) != c_drive_configuration) { - printk(" drive not there\n"); + printk(KERN_INFO " drive not there\n"); cleanup(1); return -EIO; } @@ -1257,16 +1382,18 @@ __initfunc(int cm206_init(void)) } printk(".\n"); if (register_blkdev(MAJOR_NR, "cm206", &cdrom_fops) != 0) { - printk("Cannot register for major %d!\n", MAJOR_NR); + printk(KERN_INFO "Cannot register for major %d!\n", MAJOR_NR); cleanup(3); return -EIO; } + cm206_info.dev = MKDEV(MAJOR_NR,0); if (register_cdrom(&cm206_info) != 0) { - printk("Cannot register for cdrom %d!\n", MAJOR_NR); + printk(KERN_INFO "Cannot register for cdrom %d!\n", MAJOR_NR); cleanup(3); return -EIO; } blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blksize_size[MAJOR_NR] = cm206_blocksizes; read_ahead[MAJOR_NR] = 16; /* reads ahead what? */ init_bh(CM206_BH, cm206_bh); @@ -1336,6 +1463,6 @@ __initfunc(void cm206_setup(char *s, int *p)) #endif /* MODULE */ /* * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -I. -I/usr/src/linux/include/linux -Wall -Wstrict-prototypes -O2 -m486 -c cm206.c -o cm206.o" + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -D__SMP__ -pipe -fno-strength-reduce -m486 -DCPU=486 -D__SMP__ -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o cm206.o cm206.c" * End: */ diff --git a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c index 090d58498..1de0f7ba7 100644 --- a/drivers/cdrom/mcd.c +++ b/drivers/cdrom/mcd.c @@ -216,7 +216,7 @@ static struct cdrom_device_info mcd_info = { &mcd_dops, /* device operations */ NULL, /* link */ NULL, /* handle */ - MKDEV(MAJOR_NR,0), /* dev */ + 0, /* dev */ 0, /* mask */ 2, /* maximum speed */ 1, /* number of discs */ @@ -243,15 +243,14 @@ __initfunc(void mcd_setup(char *str, int *ints)) static int mcd_media_changed(struct cdrom_device_info * cdi, int disc_nr) { - int retval, target; + int retval; #if 1 /* the below is not reliable */ return 0; #endif - target = cdi->dev; - if (target > 0) { + if (cdi->dev) { printk("mcd: Mitsumi CD-ROM request error: invalid device.\n"); return 0; } @@ -1126,9 +1125,9 @@ static void mcd_release(struct cdrom_device_info * cdi) -/* This routine gets called during initialization if thing go wrong, +/* This routine gets called during initialization if things go wrong, * and is used in cleanup_module as well. */ -void cleanup(int level) +static void cleanup(int level) { switch (level) { case 3: @@ -1231,17 +1230,20 @@ __initfunc(int mcd_init(void)) if (result[1] == 'D') { - sprintf(msg, " mcd: Mitsumi Double Speed CD-ROM at port=0x%x, irq=%d\n", mcd_port, mcd_irq); - MCMD_DATA_READ = MCMD_2X_READ; - mcd_info.speed = 2; - mcdDouble = 1; /* Added flag to drop to 1x speed if too many errors */ - } - else { - sprintf(msg, " mcd: Mitsumi Single Speed CD-ROM at port=0x%x, irq=%d\n", mcd_port, mcd_irq); - mcd_info.speed = 2; + sprintf(msg, " mcd: Mitsumi Double Speed CD-ROM at port=0x%x," + " irq=%d\n", mcd_port, mcd_irq); + MCMD_DATA_READ = MCMD_2X_READ; + + mcd_info.speed = 2; + /* Added flag to drop to 1x speed if too many errors */ + mcdDouble = 1; + } else { + sprintf(msg, " mcd: Mitsumi Single Speed CD-ROM at port=0x%x," + " irq=%d\n", mcd_port, mcd_irq); + mcd_info.speed = 2; } - request_region(mcd_port, 4,"mcd"); + request_region(mcd_port, 4, "mcd"); outb(MCMD_CONFIG_DRIVE, MCDPORT(0)); outb(0x02,MCDPORT(0)); @@ -1256,6 +1258,8 @@ __initfunc(int mcd_init(void)) mcd_invalidate_buffers(); mcdPresent = 1; + mcd_info.dev = MKDEV(MAJOR_NR,0); + if (register_cdrom(&mcd_info) != 0) { printk("Cannot register Mitsumi CD-ROM!\n"); cleanup(3); diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c index f46388d06..d27417be6 100644 --- a/drivers/cdrom/mcdx.c +++ b/drivers/cdrom/mcdx.c @@ -75,9 +75,6 @@ static const char *mcdx_c_version #define mcdx_drive_map mcdx #include "mcdx.h" -#define MCDX_QUIET 0 - - #ifndef HZ #error HZ not defined #endif @@ -288,7 +285,7 @@ static struct cdrom_device_ops mcdx_dops = { NULL, /* hard reset */ mcdx_audio_ioctl, /* audio ioctl */ NULL, /* device-specific ioctl */ - CDC_OPEN_TRAY | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO + CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_DRIVE_STATUS, /* capability */ 0, /* number of minor devices */ }; @@ -297,7 +294,7 @@ static struct cdrom_device_info mcdx_info = { &mcdx_dops, /* device operations */ NULL, /* link */ NULL, /* handle */ - MKDEV(MAJOR_NR,0), /* dev */ + 0, /* dev */ 0, /* mask */ 2, /* maximum speed */ 1, /* number of discs */ @@ -1027,174 +1024,186 @@ void cleanup_module(void) /* Support functions ************************************************/ -__initfunc(int mcdx_init(void)) +__initfunc(int mcdx_init_drive(int drive)) { - int drive; + struct s_version version; + struct s_drive_stuff* stuffp; + int size = sizeof(*stuffp); char msg[80]; -#ifdef MODULE - xwarn("Version 2.14(hs) for " UTS_RELEASE "\n"); -#else - xwarn("Version 2.14(hs) \n"); -#endif - - xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n"); - - /* zero the pointer array */ - for (drive = 0; drive < MCDX_NDRIVES; drive++) - mcdx_stuffp[drive] = NULL; - - /* do the initialisation */ - for (drive = 0; drive < MCDX_NDRIVES; drive++) { - struct s_version version; - struct s_drive_stuff* stuffp; - int size; - - mcdx_blocksizes[drive] = 0; - size = sizeof(*stuffp); + mcdx_blocksizes[drive] = 0; - xtrace(INIT, "init() try drive %d\n", drive); + xtrace(INIT, "init() try drive %d\n", drive); - xtrace(INIT, "kmalloc space for stuffpt's\n"); - xtrace(MALLOC, "init() malloc %d bytes\n", size); - if (!(stuffp = kmalloc(size, GFP_KERNEL))) { - xwarn("init() malloc failed\n"); - break; - } + xtrace(INIT, "kmalloc space for stuffpt's\n"); + xtrace(MALLOC, "init() malloc %d bytes\n", size); + if (!(stuffp = kmalloc(size, GFP_KERNEL))) { + xwarn("init() malloc failed\n"); + return 1; + } - xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n", sizeof(*stuffp), stuffp); - - /* set default values */ - memset(stuffp, 0, sizeof(*stuffp)); - - stuffp->present = 0; /* this should be 0 already */ - stuffp->toc = NULL; /* this should be NULL already */ - - /* setup our irq and i/o addresses */ - stuffp->irq = irq(mcdx_drive_map[drive]); - stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]); - stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1; - stuffp->wreg_hcon = stuffp->wreg_reset + 1; - stuffp->wreg_chn = stuffp->wreg_hcon + 1; - - /* check if i/o addresses are available */ - if (0 != check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) { - xwarn("0x%3p,%d: " - "Init failed. I/O ports (0x%3p..0x%3p) already in use.\n", - stuffp->wreg_data, stuffp->irq, - stuffp->wreg_data, - stuffp->wreg_data + MCDX_IO_SIZE - 1); - xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); - kfree(stuffp); - xtrace(INIT, "init() continue at next drive\n"); - continue; /* next drive */ - } + xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n", + sizeof(*stuffp), stuffp); + + /* set default values */ + memset(stuffp, 0, sizeof(*stuffp)); + + stuffp->present = 0; /* this should be 0 already */ + stuffp->toc = NULL; /* this should be NULL already */ + + /* setup our irq and i/o addresses */ + stuffp->irq = irq(mcdx_drive_map[drive]); + stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]); + stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1; + stuffp->wreg_hcon = stuffp->wreg_reset + 1; + stuffp->wreg_chn = stuffp->wreg_hcon + 1; + + /* check if i/o addresses are available */ + if (check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) { + xwarn("0x%3p,%d: Init failed. " + "I/O ports (0x%3p..0x%3p) already in use.\n", + stuffp->wreg_data, stuffp->irq, + stuffp->wreg_data, + stuffp->wreg_data + MCDX_IO_SIZE - 1); + xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); + kfree(stuffp); + xtrace(INIT, "init() continue at next drive\n"); + return 0; /* next drive */ + } - xtrace(INIT, "init() i/o port is available at 0x%3p\n", stuffp->wreg_data); - - xtrace(INIT, "init() hardware reset\n"); - mcdx_reset(stuffp, HARD, 1); - - xtrace(INIT, "init() get version\n"); - if (-1 == mcdx_requestversion(stuffp, &version, 4)) { - /* failed, next drive */ - xwarn("%s=0x%3p,%d: Init failed. Can't get version.\n", - MCDX, - stuffp->wreg_data, stuffp->irq); - xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); - kfree(stuffp); - xtrace(INIT, "init() continue at next drive\n"); - continue; - } + xtrace(INIT, "init() i/o port is available at 0x%3p\n", + stuffp->wreg_data); + xtrace(INIT, "init() hardware reset\n"); + mcdx_reset(stuffp, HARD, 1); + + xtrace(INIT, "init() get version\n"); + if (-1 == mcdx_requestversion(stuffp, &version, 4)) { + /* failed, next drive */ + xwarn("%s=0x%3p,%d: Init failed. Can't get version.\n", + MCDX, + stuffp->wreg_data, stuffp->irq); + xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); + kfree(stuffp); + xtrace(INIT, "init() continue at next drive\n"); + return 0; + } - switch (version.code) { - case 'D': + switch (version.code) { + case 'D': stuffp->readcmd = READ2X; stuffp->present = DOUBLE | DOOR | MULTI; break; - case 'F': + case 'F': stuffp->readcmd = READ1X; stuffp->present = SINGLE | DOOR | MULTI; break; - case 'M': + case 'M': stuffp->readcmd = READ1X; stuffp->present = SINGLE; break; - default: + default: stuffp->present = 0; break; - } + } stuffp->playcmd = READ1X; + if (!stuffp->present) { + xwarn("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n", + MCDX, stuffp->wreg_data, stuffp->irq); + kfree(stuffp); + return 0; /* next drive */ + } - if (!stuffp->present) { - xwarn("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n", - MCDX, stuffp->wreg_data, stuffp->irq); - kfree(stuffp); - continue; /* next drive */ - } - - xtrace(INIT, "init() register blkdev\n"); - if (register_blkdev(MAJOR_NR, "mcdx", &cdrom_fops) != 0) { - xwarn("%s=0x%3p,%d: Init failed. Can't get major %d.\n", - MCDX, - stuffp->wreg_data, stuffp->irq, MAJOR_NR); - kfree(stuffp); - continue; /* next drive */ - } - - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; - read_ahead[MAJOR_NR] = READ_AHEAD; - - blksize_size[MAJOR_NR] = mcdx_blocksizes; + xtrace(INIT, "init() register blkdev\n"); + if (register_blkdev(MAJOR_NR, "mcdx", &cdrom_fops) != 0) { + xwarn("%s=0x%3p,%d: Init failed. Can't get major %d.\n", + MCDX, + stuffp->wreg_data, stuffp->irq, MAJOR_NR); + kfree(stuffp); + return 1; + } - xtrace(INIT, "init() subscribe irq and i/o\n"); - mcdx_irq_map[stuffp->irq] = stuffp; - if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, "mcdx", NULL)) { - xwarn("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n", - MCDX, - stuffp->wreg_data, stuffp->irq, stuffp->irq); - stuffp->irq = 0; - kfree(stuffp); - continue; - } - request_region((unsigned int) stuffp->wreg_data, - MCDX_IO_SIZE, - "mcdx"); + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + read_ahead[MAJOR_NR] = READ_AHEAD; + blksize_size[MAJOR_NR] = mcdx_blocksizes; + + xtrace(INIT, "init() subscribe irq and i/o\n"); + mcdx_irq_map[stuffp->irq] = stuffp; + if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, "mcdx", NULL)) { + xwarn("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n", + MCDX, + stuffp->wreg_data, stuffp->irq, stuffp->irq); + stuffp->irq = 0; + kfree(stuffp); + return 0; + } + request_region((unsigned int) stuffp->wreg_data, + MCDX_IO_SIZE, + "mcdx"); - xtrace(INIT, "init() get garbage\n"); - { - int i; - mcdx_delay(stuffp, HZ/2); - for (i = 100; i; i--) (void) inb((unsigned int) stuffp->rreg_status); - } + xtrace(INIT, "init() get garbage\n"); + { + int i; + mcdx_delay(stuffp, HZ/2); + for (i = 100; i; i--) + (void) inb((unsigned int) stuffp->rreg_status); + } #if WE_KNOW_WHY - outb(0x50, (unsigned int) stuffp->wreg_chn); /* irq 11 -> channel register */ + /* irq 11 -> channel register */ + outb(0x50, (unsigned int) stuffp->wreg_chn); #endif - xtrace(INIT, "init() set non dma but irq mode\n"); - mcdx_config(stuffp, 1); + xtrace(INIT, "init() set non dma but irq mode\n"); + mcdx_config(stuffp, 1); - stuffp->minor = drive; + stuffp->minor = drive; - sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%3p, irq %d." - " (Firmware version %c %x)\n", - stuffp->wreg_data, stuffp->irq, version.code, - version.ver); - mcdx_stuffp[drive] = stuffp; - xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp); + sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%3p, irq %d." + " (Firmware version %c %x)\n", + stuffp->wreg_data, stuffp->irq, version.code, + version.ver); + mcdx_stuffp[drive] = stuffp; + xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp); + mcdx_info.dev = MKDEV(MAJOR_NR,0); if (register_cdrom(&mcdx_info) != 0) { - printk("Cannot register Mitsumi CD-ROM!\n"); - release_region((unsigned long) stuffp->wreg_data, MCDX_IO_SIZE); - free_irq(stuffp->irq, NULL); - kfree(stuffp); - if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) + printk("Cannot register Mitsumi CD-ROM!\n"); + release_region((unsigned long) stuffp->wreg_data, + MCDX_IO_SIZE); + free_irq(stuffp->irq, NULL); + kfree(stuffp); + if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) xwarn("cleanup() unregister_blkdev() failed\n"); - return -EIO; + return 2; } printk(msg); + return 0; +} + +__initfunc(int mcdx_init(void)) +{ + int drive; +#ifdef MODULE + xwarn("Version 2.14(hs) for " UTS_RELEASE "\n"); +#else + xwarn("Version 2.14(hs) \n"); +#endif + + xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n"); + + /* zero the pointer array */ + for (drive = 0; drive < MCDX_NDRIVES; drive++) + mcdx_stuffp[drive] = NULL; + + /* do the initialisation */ + for (drive = 0; drive < MCDX_NDRIVES; drive++) { + switch(mcdx_init_drive(drive)) { + case 2: + return -EIO; + case 1: + break; + } } return 0; } diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c index 08de5a794..a3b3e2989 100644 --- a/drivers/cdrom/sbpcd.c +++ b/drivers/cdrom/sbpcd.c @@ -304,6 +304,9 @@ * Heiko Eissfeldt <heiko@colossus.escape.de> with additional * changes by Erik Andersen <andersee@debian.org> * + * 4.62 Fix a bug where playing audio left the drive in an unusable state. + * Heiko Eissfeldt <heiko@colossus.escape.de> + * * * TODO * implement "read all subchannel data" (96 bytes per frame) @@ -550,7 +553,6 @@ static struct cdrom_tocentry tocentry; static struct cdrom_subchnl SC; static struct cdrom_volctrl volctrl; static struct cdrom_read_audio read_audio; -static struct cdrom_multisession ms_info; static unsigned char msgnum=0; static char msgbuf[80]; @@ -1047,7 +1049,7 @@ static int CDi_stat_loop(void) sbp_sleep(1); i = 1; } - msg(DBG_LCS,"CDi_stat_loop failed\n"); + msg(DBG_LCS,"CDi_stat_loop failed in line %d\n", __LINE__); return (-1); } /*==========================================================================*/ @@ -2297,12 +2299,52 @@ static int cc_CloseTray(void) } i=cmd_out(); msg(DBG_LCS,"p_door_closed bit %d after\n", st_door_closed); + + i=cc_ReadError(); + flags_cmd_out |= f_respo2; + cc_ReadStatus(); /* command: give 1-byte status */ + i=ResponseStatus(); + if (famT_drive&&(i<0)) + { + cc_DriveReset(); + i=ResponseStatus(); +#if 0 + sbp_sleep(HZ); +#endif 0 + i=ResponseStatus(); + } + if (i<0) + { + msg(DBG_INF,"sbpcd cc_CloseTray: ResponseStatus timed out (%d).\n",i); + } + if (!(famT_drive)) + { + if (!st_spinning) + { + cc_SpinUp(); + if (st_check) i=cc_ReadError(); + flags_cmd_out |= f_respo2; + cc_ReadStatus(); + i=ResponseStatus(); + } else { + } + } + i=DiskInfo(); return (i); } static int sbpcd_tray_move(struct cdrom_device_info *cdi, int position) { - return position ? cc_CloseTray() : 0; + int i; + i = MINOR(cdi->dev); + + switch_drive(i); + if (position == 1) { + cc_SpinDown(); + } else { + return cc_CloseTray(); + } + return 0; } /*==========================================================================*/ @@ -2768,11 +2810,13 @@ static int cc_ReadTocDescr(void) if (famLV_drive) D_S[d].CDsize_frm=D_S[d].size_blk+1; } D_S[d].diskstate_flags |= toc_bit; - msg(DBG_TOC,"TocDesc: %02X %02X %02X %08X\n", + msg(DBG_TOC,"TocDesc: xa %02X firstt %02X lastt %02X size %08X firstses %02X lastsess %02X\n", D_S[d].xa_byte, D_S[d].n_first_track, D_S[d].n_last_track, - D_S[d].size_msf); + D_S[d].size_msf, + D_S[d].first_session, + D_S[d].last_session); return (0); } /*==========================================================================*/ @@ -3886,6 +3930,7 @@ static int DiskInfo(void) msg(DBG_000,"DiskInfo entered.\n"); for (j=1;j<LOOP_COUNT;j++) { +#if 0 i=SetSpeed(); if (i<0) { @@ -3898,10 +3943,14 @@ static int DiskInfo(void) msg(DBG_INF,"DiskInfo: cc_ModeSense returns %d\n", i); continue; } +#endif i=cc_ReadCapacity(); if (i>=0) break; msg(DBG_INF,"DiskInfo: ReadCapacity #%d returns %d\n", j, i); +#if 0 i=cc_DriveReset(); +#endif + if (!fam0_drive && j == 2) break; } if (j==LOOP_COUNT) return (-33); /* give up */ @@ -3946,12 +3995,36 @@ static int DiskInfo(void) static int sbpcd_drive_status(struct cdrom_device_info *cdi, int slot_nr) { - if (CDSL_CURRENT != slot_nr) { - /* we have no changer support */ - return -EINVAL; - } + int st; - return D_S[d].status_bits & p1_disk_ok ? CDS_DISC_OK : CDS_DRIVE_NOT_READY; + if (CDSL_CURRENT != slot_nr) { + /* we have no changer support */ + return -EINVAL; + } + + cc_ReadStatus(); + st=ResponseStatus(); + if (st<0) + { + msg(DBG_INF,"sbpcd_drive_status: timeout.\n"); + return (0); + } + msg(DBG_000,"Drive Status: door_locked =%d.\n", st_door_locked); + msg(DBG_000,"Drive Status: door_closed =%d.\n", st_door_closed); + msg(DBG_000,"Drive Status: caddy_in =%d.\n", st_caddy_in); + msg(DBG_000,"Drive Status: disk_ok =%d.\n", st_diskok); + msg(DBG_000,"Drive Status: spinning =%d.\n", st_spinning); + msg(DBG_000,"Drive Status: busy =%d.\n", st_busy); +#if 0 + if (!(D_S[MINOR(cdi->dev)].status_bits & p_door_closed)) return CDS_TRAY_OPEN; + if (D_S[MINOR(cdi->dev)].status_bits & p_disk_ok) return CDS_DISC_OK; + if (D_S[MINOR(cdi->dev)].status_bits & p_disk_in) return CDS_DRIVE_NOT_READY; + + return CDS_NO_DISC; +#else + if (D_S[MINOR(cdi->dev)].status_bits & p_spinning) return CDS_DISC_OK; + return CDS_TRAY_OPEN; +#endif } @@ -4082,13 +4155,13 @@ static int sbp_status(void) static int sbpcd_get_last_session(struct cdrom_device_info *cdi, struct cdrom_multisession *ms_infp) { ms_infp->addr_format = CDROM_LBA; - ms_infp->addr.lba = D_S[d].lba_multi; - if (D_S[d].f_multisession) + ms_infp->addr.lba = D_S[MINOR(cdi->dev)].lba_multi; + if (D_S[MINOR(cdi->dev)].f_multisession) ms_infp->xa_flag=1; /* valid redirection address */ else ms_infp->xa_flag=0; /* invalid redirection address */ - return 1; + return 0; } /*==========================================================================*/ @@ -4225,7 +4298,7 @@ static int sbpcd_dev_ioctl(struct cdrom_device_info *cdi, u_int cmd, } if (status_tries == 0) { - msg(DBG_AUD,"read_audio: sbp_status: failed after 3 tries.\n"); + msg(DBG_AUD,"read_audio: sbp_status: failed after 3 tries in line %d.\n", __LINE__); continue; } msg(DBG_AUD,"read_audio: sbp_status: ok.\n"); @@ -4304,8 +4377,30 @@ static int sbpcd_dev_ioctl(struct cdrom_device_info *cdi, u_int cmd, error_flag=0; p = D_S[d].aud_buf; if (sbpro_type==1) OUT(CDo_sel_i_d,1); - if (do_16bit) insw(CDi_data, p, read_audio.nframes*(CD_FRAMESIZE_RAW>>1)); - else insb(CDi_data, p, read_audio.nframes*CD_FRAMESIZE_RAW); + if (do_16bit) + { + u_short *p2 = (u_short *) p; + + for (; (u_char *) p2 < D_S[d].aud_buf + read_audio.nframes*CD_FRAMESIZE_RAW;) + { + if ((inb_p(CDi_status)&s_not_data_ready)) continue; + + /* get one sample */ + *p2++ = inw_p(CDi_data); + *p2++ = inw_p(CDi_data); + } + } else { + for (; p < D_S[d].aud_buf + read_audio.nframes*CD_FRAMESIZE_RAW;) + { + if ((inb_p(CDi_status)&s_not_data_ready)) continue; + + /* get one sample */ + *p++ = inb_p(CDi_data); + *p++ = inb_p(CDi_data); + *p++ = inb_p(CDi_data); + *p++ = inb_p(CDi_data); + } + } if (sbpro_type==1) OUT(CDo_sel_i_d,0); data_retrying = 0; } @@ -4375,7 +4470,7 @@ static int sbpcd_dev_ioctl(struct cdrom_device_info *cdi, u_int cmd, #endif OLD_BUSY if (data_tries == 0) { - msg(DBG_AUD,"read_audio: failed after 5 tries.\n"); + msg(DBG_AUD,"read_audio: failed after 5 tries in line %d.\n", __LINE__); RETURN_UP(-EIO); } msg(DBG_AUD,"read_audio: successful return.\n"); @@ -4388,28 +4483,6 @@ static int sbpcd_dev_ioctl(struct cdrom_device_info *cdi, u_int cmd, if(arg > 0xff) RETURN_UP(-EINVAL); read_ahead[MAJOR(cdi->dev)] = arg; RETURN_UP(0); -#if 0 - case CDROMEJECT: - msg(DBG_IOC,"ioctl: CDROMEJECT entered.\n"); - if (fam0_drive) return (0); - if (D_S[d].open_count>1) RETURN_UP(-EBUSY); - i=UnLockDoor(); - D_S[d].open_count=-9; /* to get it locked next time again */ - i=cc_SpinDown(); - msg(DBG_IOX,"ioctl: cc_SpinDown returned %d.\n", i); - msg(DBG_TEA,"ioctl: cc_SpinDown returned %d.\n", i); - if (i<0) RETURN_UP(-EIO); - D_S[d].CD_changed=0xFF; - D_S[d].diskstate_flags=0; - D_S[d].audio_state=0; - RETURN_UP(0); - - case CDROMEJECT_SW: - msg(DBG_IOC,"ioctl: CDROMEJECT_SW entered.\n"); - if (fam0_drive) RETURN_UP(0); - D_S[d].f_eject=arg; - RETURN_UP(0); -#endif default: msg(DBG_IOC,"ioctl: unknown function request %04X\n", cmd); RETURN_UP(-EINVAL); @@ -4581,6 +4654,7 @@ static int sbpcd_audio_ioctl(struct cdrom_device_info *cdi, u_int cmd, #endif SAFE_MIXED i=cc_Pause_Resume(1); D_S[d].audio_state=0; + cc_DriveReset(); RETURN_UP(i); case CDROMSTART: /* Spin up the drive */ @@ -4816,7 +4890,7 @@ static void DO_SBPCD_REQUEST(void) } if (status_tries == 0) { - msg(DBG_INF,"sbp_status: failed after 3 tries\n"); + msg(DBG_INF,"sbp_status: failed after 3 tries in line %d\n", __LINE__); break; } @@ -5242,54 +5316,13 @@ static int sbp_data(struct request *req) static int sbpcd_open(struct cdrom_device_info *cdi, int purpose) { int i; - + i = MINOR(cdi->dev); - if ((i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1)) - { - msg(DBG_INF, "open: bad device: %04X\n", cdi->dev); - return (-ENXIO); /* no such drive */ - } - + MOD_INC_USE_COUNT; down(&ioctl_read_sem); switch_drive(i); - - i=cc_ReadError(); - flags_cmd_out |= f_respo2; - cc_ReadStatus(); /* command: give 1-byte status */ - i=ResponseStatus(); - if (famT_drive&&(i<0)) - { - cc_DriveReset(); - i=ResponseStatus(); -#if 0 - sbp_sleep(HZ); -#endif 0 - i=ResponseStatus(); - } - if (i<0) - { - msg(DBG_INF,"sbpcd_open: ResponseStatus timed out (%d).\n",i); - MOD_DEC_USE_COUNT; - RETURN_UP(-EIO); /* drive doesn't respond */ - } - if (famT_drive) msg(DBG_TEA,"sbpcd_open: ResponseStatus=%02X\n", i); - if (!(famT_drive)) - if (!st_spinning) - { - cc_SpinUp(); - flags_cmd_out |= f_respo2; - cc_ReadStatus(); - i=ResponseStatus(); - } - if (famT_drive) msg(DBG_TEA,"sbpcd_open: status %02X\n", D_S[d].status_bits); - if (!st_door_closed||!st_caddy_in) - { - msg(DBG_INF, "sbpcd_open: no disk in drive.\n"); - D_S[d].open_count=0; - MOD_DEC_USE_COUNT; - RETURN_UP(-ENXIO); - } + /* * try to keep an "open" counter here and lock the door if 0->1. */ @@ -5360,24 +5393,6 @@ static void sbpcd_release(struct cdrom_device_info * cdi) /* * */ -#if 0 -static struct file_operations sbpcd_fops = -{ - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - sbpcd_ioctl, /* ioctl */ - NULL, /* mmap */ - sbpcd_open, /* open */ - sbpcd_release, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ - sbpcd_chk_disk_change, /* media_change */ - NULL /* revalidate */ -}; -#endif static int sbpcd_media_changed( struct cdrom_device_info *cdi, int disc_nr); static struct cdrom_device_ops sbpcd_dops = { sbpcd_open, /* open */ @@ -5394,7 +5409,7 @@ static struct cdrom_device_ops sbpcd_dops = { sbpcd_audio_ioctl, /* audio ioctl */ sbpcd_dev_ioctl, /* device-specific ioctl */ CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_MULTI_SESSION | - CDC_MEDIA_CHANGED | CDC_MCN | CDC_PLAY_AUDIO, /* capability */ + CDC_MEDIA_CHANGED | CDC_MCN | CDC_PLAY_AUDIO | CDC_IOCTLS, /* capability */ 1, /* number of minor devices */ }; @@ -5402,7 +5417,7 @@ static struct cdrom_device_info sbpcd_info = { &sbpcd_dops, /* device operations */ NULL, /* link */ NULL, /* handle */ - MKDEV(MAJOR_NR,0), /* dev */ + 0, /* dev */ 0, /* mask */ 2, /* maximum speed */ 1, /* number of discs */ @@ -5556,7 +5571,7 @@ __initfunc(int SBPCD_INIT(void)) int i=0, j=0; int addr[2]={1, CDROM_PORT}; int port_index; - + sti(); msg(DBG_INF,"sbpcd.c %s\n", VERSION); @@ -5630,14 +5645,6 @@ __initfunc(int SBPCD_INIT(void)) check_datarate(); msg(DBG_INI,"check_datarate done.\n"); -#if 0 - if (!famL_drive) - { - OUT(CDo_reset,0); - sbp_sleep(HZ); - } -#endif 0 - for (j=0;j<NR_SBPCD;j++) { if (D_S[j].drv_id==-1) continue; @@ -5830,11 +5837,6 @@ static int sbpcd_chk_disk_change(kdev_t full_dev) msg(DBG_CHK,"media_check (%d) called\n", MINOR(full_dev)); i=MINOR(full_dev); - if ( (i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1) ) - { - msg(DBG_INF, "media_check: invalid device %04X.\n", full_dev); - return (-1); - } if (D_S[i].CD_changed==0xFF) { diff --git a/drivers/cdrom/sbpcd.h b/drivers/cdrom/sbpcd.h index e9021316d..805e98a82 100644 --- a/drivers/cdrom/sbpcd.h +++ b/drivers/cdrom/sbpcd.h @@ -119,14 +119,14 @@ #define JUKEBOX 0 #else #define JUKEBOX 1 -#endif DISTRIBUTION +#endif /* DISTRIBUTION */ /* tray control: eject tray after last use */ #if DISTRIBUTION #define EJECT 0 #else #define EJECT 1 -#endif DISTRIBUTION +#endif /* DISTRIBUTION */ /* max. number of audio frames to read with one */ /* request (allocates n* 2352 bytes kernel memory!) */ @@ -570,7 +570,7 @@ pause: 8d pr 00 00 00 00 00. (0) pause (pr=00) resume (pr=80) audio playing Mode Select: - 84 00 nn-nn ??-?? 00 (0) nn-nn: 2048 or 2340 + 84 00 nn-nn ??.?? 00 (0) nn-nn: 2048 or 2340 possibly defines transfer size set_vol: 84 83 00 00 sw le 00. (0) sw(itch): lrxxxxxx (off=1) @@ -604,12 +604,12 @@ seek: 01 00 ll-bb-aa 00 00. (0) seek: 01 02 mm-ss-ff 00 00. (0) Read Data: -read: 02 xx-xx-xx nn-nn fl. (??) read nn-nn blocks of 2048 bytes, +read: 02 xx-xx-xx nn-nn fl. (?) read nn-nn blocks of 2048 bytes, starting at block xx-xx-xx fl=0: "lba"-, =2:"msf-bcd"-coded xx-xx-xx Read XA-Data: -read: 03 xx-xx-xx nn-nn fl. (??) read nn-nn blocks of 2340 bytes, +read: 03 xx-xx-xx nn-nn fl. (?) read nn-nn blocks of 2340 bytes, starting at block xx-xx-xx fl=0: "lba"-, =2:"msf-bcd"-coded xx-xx-xx @@ -838,7 +838,7 @@ Read XA Parameter: /*==========================================================================*/ /*==========================================================================*/ -#endif _LINUX_SBPCD_H +#endif /* _LINUX_SBPCD_H */ /*==========================================================================*/ /* * Overrides for Emacs so that we follow Linus's tabbing style. |