patch-2.1.77 linux/drivers/cdrom/cm206.c

Next file: linux/drivers/char/Config.in
Previous file: linux/drivers/cdrom/cdrom.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.76/linux/drivers/cdrom/cm206.c linux/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,84 @@
 	      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:
+ 28 jul 1996  0.101 Rewriting of the code that receives the command echo,
+	      using a fifo to store echoed bytes. 
 
-	      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>, 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.  
+
  * 
  * 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 +168,8 @@
  * - 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 +185,8 @@
 #include <linux/malloc.h>
 #include <linux/init.h>
 
+/* #include <linux/ucdrom.h> */
+
 #include <asm/io.h>
 
 #define MAJOR_NR CM206_CDROM_MAJOR
@@ -147,7 +194,7 @@
 
 #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 +207,18 @@
 
 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 +231,14 @@
 		     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 +248,23 @@
   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 +296,20 @@
 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 +319,15 @@
   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 +349,27 @@
 				       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 +416,7 @@
 void cm206_timeout(unsigned long who)
 {
   cd->timed_out = 1;
+  debug(("Timing out\n"));
   wake_up_interruptible((struct wait_queue **) who);
 }
 
@@ -347,9 +424,11 @@
    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 +438,15 @@
   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 +458,40 @@
       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 +500,15 @@
   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 +529,8 @@
   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 +538,7 @@
   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 +562,26 @@
   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 +617,11 @@
 }
 #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 +630,18 @@
   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 +680,22 @@
     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 +816,7 @@
     }
     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 +826,14 @@
 	  + (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 +878,22 @@
 
 /* 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 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 +932,11 @@
 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 +1109,7 @@
   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 */
@@ -1019,6 +1140,24 @@
   return CDS_DISC_OK;
 }
  
+/* gives current state of disc in drive */
+int cm206_disc_status(struct cdrom_device_info * cdi)
+{
+  uch xa;
+  get_drive_status();
+  if ((cd->dsb & dsb_not_useful) | !(cd->dsb & dsb_disc_present))
+    return CDS_NO_DISC;
+  get_disc_status();
+  if (DISC_STATUS & cds_all_audio) return CDS_AUDIO;
+  xa = DISC_STATUS >> 4;
+  switch (xa) {
+  case 0: return CDS_DATA_1;	/* can we detect CDS_DATA_2? */
+  case 1: return CDS_XA_2_1;	/* untested */
+  case 2: return CDS_XA_2_2;
+  }
+  return 0;
+}
+
 /* locks or unlocks door lock==1: lock; return 0 upon success */
 int cm206_lock_door(struct cdrom_device_info * cdi, int lock)
 {
@@ -1029,7 +1168,7 @@
 }
   
 /* 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 +1253,9 @@
   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 */
 };
 
@@ -1206,7 +1347,7 @@
   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 +1374,14 @@
   /* 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 +1398,17 @@
   }
   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;
   }
   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 +1478,6 @@
 #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:
  */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov