diff -u --recursive --new-file v1.1.23/linux/Makefile linux/Makefile
--- v1.1.23/linux/Makefile	Tue Jun 28 22:30:25 1994
+++ linux/Makefile	Tue Jun 28 19:27:04 1994
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 23
+SUBLEVEL = 24
 
 all:	Version zImage
 
diff -u --recursive --new-file v1.1.23/linux/boot/setup.S linux/boot/setup.S
--- v1.1.23/linux/boot/setup.S	Wed Dec  1 14:44:15 1993
+++ linux/boot/setup.S	Tue Jun 28 12:24:46 1994
@@ -825,7 +825,7 @@
 ! Number of modes is the number of chip-specific svga modes plus the extended
 ! modes available on any vga (currently 2)
 
-moati:		.byte	0x04,	0x23, 0x33 
+moati:		.byte	0x06,	0x23, 0x33, 0x22, 0x21
 moahead:	.byte	0x07,	0x22, 0x23, 0x24, 0x2f, 0x34
 mocandt:	.byte	0x04,	0x60, 0x61
 mocirrus:	.byte	0x06,	0x1f, 0x20, 0x22, 0x31
@@ -844,7 +844,7 @@
 ! The first two modes are standard vga modes available on any vga.
 ! mode 0 is 80x50 and mode 1 is 80x28
 
-dscati:		.word	0x5032, 0x501c, 0x8419, 0x842c
+dscati:		.word	0x5032, 0x501c, 0x8419, 0x842c, 0x641e, 0x6419
 dscahead:	.word	0x5032, 0x501c, 0x842c, 0x8419, 0x841c, 0xa032, 0x5042
 dsccandt:	.word	0x5032, 0x501c, 0x8419, 0x8432
 dsccirrus:	.word	0x5032, 0x501c, 0x8419, 0x842c, 0x841e, 0x6425
diff -u --recursive --new-file v1.1.23/linux/drivers/block/README.sbpcd linux/drivers/block/README.sbpcd
--- v1.1.23/linux/drivers/block/README.sbpcd	Tue Jun 28 22:30:25 1994
+++ linux/drivers/block/README.sbpcd	Tue Jun 28 19:31:13 1994
@@ -1,4 +1,4 @@
-This README belongs to release 2.0 of the SoundBlaster Pro (Matsushita,
+This README belongs to release 2.1 of the SoundBlaster Pro (Matsushita,
 Kotobuki, Panasonic, CreativeLabs) CD-ROM driver for Linux.
 
 The driver is able to drive the whole family of IDE-style
@@ -48,14 +48,21 @@
 
 With the "new" drive family CR-562 and CR-563, the reading of audio frames is
 possible. This is currently implemented by an IOCTL function which reads only
-one frame of 2352 bytes at a time. The transfer rate is as slow as 32 kB/sec.
-This will get better, and the software interface may change. We have to 
-standardize it the day the SCSI driver supports it too.
-
-MultiSession is supported (even my "old" CR-521 can handle it), "ManySession"
-(not recommended, see below) alternatively.
-Photo CDs work, too. At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is Hadmut Danisch's
-package to convert photo CD image files.
+up to 4 frames of 2352 bytes at once. Reading more than 1 frame at once gives
+very poor quality. Reading the same frame a second time gives different data;
+it seems that the drive is out-of-sync at the beginning. See the program
+example below. This lack has to get corrected by higher level software.
+The transfer rate with reading audio (1-frame-pieces) is as slow as 32 kB/sec.
+This could be better reading bigger chunks, but the out-of-sync parts occur at
+the beginning of each single frame.
+The software interface possibly may change a bit the day the SCSI driver
+supports it too.
+
+MultiSession is supported, "ManySession" (not recommended, see below)
+alternatively.
+Photo CDs work, too (even with my "old" CR-521).
+At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is Hadmut Danisch's package to convert
+photo CD image files.
 
 The transfer rate will reach 150 kB/sec with "old" drives and 300 kB/sec with
 double-speed drives. XA (PhotoCD) disks with "old" drives give only 50 kB/sec.
@@ -339,6 +346,10 @@
     }
 }
 /*===================== end program ========================================*/
+
+At ftp.gwdg.de:/pub/linux/misc/cdda2wav-sbpcd.tar.gz is an adapted version of
+Heiko Eissfeldt's digital-audio to .WAV converter (the original is there, too).
+This is preliminary, as Heiko himself will care about it.
 
 
 Known problems:
diff -u --recursive --new-file v1.1.23/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v1.1.23/linux/drivers/block/floppy.c	Tue Jun 28 22:30:25 1994
+++ linux/drivers/block/floppy.c	Tue Jun 28 20:42:30 1994
@@ -407,7 +407,7 @@
  * to the desired drive, but it will probably not survive the sleep if
  * several floppies are used at the same time: thus the loop.
  */
-int floppy_change(struct buffer_head * bh)
+static int floppy_change(struct buffer_head * bh)
 {
 	unsigned int mask = 1 << (bh->b_dev & 0x03);
 
@@ -1289,14 +1289,13 @@
 	int drive;
 	int old_dev;
 
-	if (floppy_grab_irq_and_dma()) {
-		return -EBUSY;
-	}
 	drive = inode->i_rdev & 3;
 	old_dev = fd_device[drive];
 	if (fd_ref[drive])
 		if (old_dev != inode->i_rdev)
 			return -EBUSY;
+	if (floppy_grab_irq_and_dma())
+		return -EBUSY;
 	fd_ref[drive]++;
 	fd_device[drive] = inode->i_rdev;
 	buffer_drive = buffer_track = -1;
@@ -1309,7 +1308,7 @@
 
 static void floppy_release(struct inode * inode, struct file * filp)
 {
-	sync_dev(inode->i_rdev);
+	fsync_dev(inode->i_rdev);
 	if (!fd_ref[inode->i_rdev & 3]--) {
 		printk("floppy_release with fd_ref == 0");
 		fd_ref[inode->i_rdev & 3] = 0;
@@ -1317,6 +1316,18 @@
         floppy_release_irq_and_dma();
 }
 
+static int check_floppy_change(dev_t dev)
+{
+	int i;
+	struct buffer_head * bh;
+
+	if (!(bh = getblk(dev,0,1024)))
+		return 0;
+	i = floppy_change(bh);
+	brelse(bh);
+	return i;
+}
+
 static struct file_operations floppy_fops = {
 	NULL,			/* lseek - default */
 	block_read,		/* read - general block-dev read */
@@ -1327,26 +1338,13 @@
 	NULL,			/* mmap */
 	floppy_open,		/* open */
 	floppy_release,		/* release */
-	block_fsync		/* fsync */
+	block_fsync,		/* fsync */
+	NULL,			/* fasync */
+	check_floppy_change,	/* media_change */
+	NULL			/* revalidate */
 };
 
 
-/*
- * The version command is not supposed to generate an interrupt, but
- * my FDC does, except when booting in SVGA screen mode.
- * When it does generate an interrupt, it doesn't return any status bytes.
- * It appears to have something to do with the version command...
- *
- * This should never be called, because of the reset after the version check.
- */
-static void ignore_interrupt(void)
-{
-	printk(DEVICE_NAME ": weird interrupt ignored (%d)\n", result());
-	reset = 1;
-	CLEAR_INTR;	/* ignore only once */
-}
-
-
 static void floppy_interrupt(int unused)
 {
 	void (*handler)(void) = DEVICE_INTR;
@@ -1381,7 +1379,6 @@
 	timer_active &= ~(1 << FLOPPY_TIMER);
 	config_types();
 	/* Try to determine the floppy controller type */
-	DEVICE_INTR = ignore_interrupt;	/* don't ask ... */
 	output_byte(FD_VERSION);	/* get FDC version code */
 	if (result() != 1) {
 		printk(DEVICE_NAME ": FDC failed to return version byte\n");
@@ -1404,8 +1401,12 @@
 	}
 }
 
+static int usage_count = 0;
+
 static int floppy_grab_irq_and_dma(void)
 {
+	if (usage_count++)
+		return 0;
 	if (irqaction(FLOPPY_IRQ,&floppy_sigaction)) {
 		printk("Unable to grab IRQ%d for the floppy driver\n", FLOPPY_IRQ);
 		return -1;
@@ -1421,6 +1422,8 @@
 
 static void floppy_release_irq_and_dma(void)
 {
+	if (--usage_count)
+		return;
 	disable_dma(FLOPPY_DMA);
 	free_dma(FLOPPY_DMA);
 	disable_irq(FLOPPY_IRQ);
diff -u --recursive --new-file v1.1.23/linux/drivers/block/sbpcd.c linux/drivers/block/sbpcd.c
--- v1.1.23/linux/drivers/block/sbpcd.c	Tue Jun 28 22:30:26 1994
+++ linux/drivers/block/sbpcd.c	Tue Jun 28 19:31:14 1994
@@ -5,7 +5,7 @@
  *            and for "no-sound" interfaces like Lasermate and the
  *            Panasonic CI-101P.
  *
- *  NOTE:     This is release 2.0.
+ *  NOTE:     This is release 2.1.
  *            It works with my SbPro & drive CR-521 V2.11 from 2/92
  *            and with the new CR-562-B V0.75 on a "naked" Panasonic
  *            CI-101P interface. And vice versa. 
@@ -106,6 +106,21 @@
  *       reset the drive and do again. Needs lots of resets here and sometimes
  *       that does not cure, so this can't be the solution.
  *
+ *  2.1  Found bug with multisession CDs (accessing frame 16).
+ *       "read audio" works now with address type CDROM_MSF, too.
+ *       Bigger audio frame buffer: allows reading max. 4 frames at time; but
+ *       reading more than one frame at once gives poor quality.
+ *
+ *
+ *  TODO
+ *
+ *     disk change detection
+ *     allow & synchronize multi-activity
+ *        (data + audio + ioctl + disk change, multiple drives)
+ *     implement multi-controller-support with a single driver
+ *     implement "read all subchannel data" (96 bytes per frame)
+ *
+ *
  *     special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine
  *     elaborated speed-up experiments (and the fabulous results!), for
  *     the "push" towards load-free wait loops, and for the extensive mail
@@ -172,7 +187,7 @@
 
 #include "blk.h"
 
-#define VERSION "2.0 Eberhard Moenkeberg <emoenke@gwdg.de>"
+#define VERSION "2.1 Eberhard Moenkeberg <emoenke@gwdg.de>"
 
 #define SBPCD_DEBUG
 
@@ -198,7 +213,6 @@
 #define XA_TEST2
 
 #define TEST_UPC 0
-#define READ_AUDIO 1
 #define SPEA_TEST 0
 #define PRINTK_BUG 0
 #define TEST_STI 0
@@ -289,10 +303,11 @@
 {
   CDROM_PORT, SBPRO, /* probe with user's setup first */
   0x230, 1, /* Soundblaster Pro and 16 (default) */
-  0x300, 0, /* CI-101P (default), Galaxy (default), Reveal (one default) */
+  0x300, 0, /* CI-101P (default), WDH-7001C (default),
+	       Galaxy (default), Reveal (one default) */
   0x250, 1, /* OmniCD default, Soundblaster Pro and 16 */
   0x260, 1, /* OmniCD */
-  0x320, 0, /* Lasermate, CI-101P, Galaxy, Reveal (other default) */
+  0x320, 0, /* Lasermate, CI-101P, WDH-7001C, Galaxy, Reveal (other default) */
   0x340, 0, /* Lasermate, CI-101P */
   0x360, 0, /* Lasermate, CI-101P */
   0x270, 1, /* Soundblaster 16 */
@@ -304,11 +319,11 @@
   0x350, 2, /* SPEA Media FX */
 #if 0
 /* some "hazardous" locations (ethernet cards) */
-  0x330, 0, /* Lasermate, CI-101P */
+  0x330, 0, /* Lasermate, CI-101P, WDH-7001C */
   0x350, 0, /* Lasermate, CI-101P */
   0x370, 0, /* Lasermate, CI-101P */
   0x290, 1, /* Soundblaster 16 */
-  0x310, 0, /* Lasermate, CI-101P */
+  0x310, 0, /* Lasermate, CI-101P, WDH-7001C */
 /* excluded due to incomplete address decoding of the SbPro card */
   0x630, 0, /* "sound card #9" (default) */
   0x650, 0, /* "sound card #9" */
@@ -323,8 +338,9 @@
  * the forward references:
  */
 static void sbp_read_cmd(void);
-static int  sbp_data(void);
+static int sbp_data(void);
 static int cmd_out(void);
+static int DiskInfo(void);
 
 /*==========================================================================*/
 
@@ -370,12 +386,7 @@
 #else
 static int sbpcd_debug =  (1<<DBG_INF) |
                           (1<<DBG_TOC) |
-                          (1<<DBG_UPC) |
-                          (1<<DBG_TIM) |
-                          (1<<DBG_LCK) |
-                          (1<<DBG_CHK) |
-                          (1<<DBG_AUD) |
-                          (1<<DBG_IOX);
+                          (1<<DBG_UPC);
 #endif
 #endif
 static int sbpcd_ioaddr = CDROM_PORT;	/* default I/O base address */
@@ -404,7 +415,8 @@
 
 /*==========================================================================*/
 
-#define SBP_BUFFER_FRAMES 4 /* driver's own read_ahead */
+#define SBP_BUFFER_FRAMES 4 /* driver's own read_ahead, data mode */
+#define SBP_BUFFER_AUDIO_FRAMES 4 /* driver's own read_ahead, read audio mode */
 
 /*==========================================================================*/
 
@@ -419,6 +431,7 @@
 static u_char xa_head_buf[CD_XA_HEAD];
 static u_char xa_tail_buf[CD_XA_TAIL];
 
+static u_char busy_data=0, busy_audio=0; /* true semaphores would be safer */
 static u_char timed_out=0;
 static u_int datarate= 1000000;
 static u_int maxtim16=16000000;
@@ -460,11 +473,8 @@
   int sbp_current;       /* Frame being currently read */
 
   u_char mode;           /* read_mode: READ_M1, READ_M2, READ_SC, READ_AU */
-#if READ_AUDIO
   u_char *aud_buf;                  /* Pointer to audio data buffer,
                                  space allocated during sbpcd_init() */
-#endif READ_AUDIO
-
   u_char drv_type;
   u_char drv_options;
   u_char status_byte;
@@ -671,22 +681,34 @@
   return (i);
 }
 /*==========================================================================*/
+/*
+ *  convert m-s-f_number (3 bytes only) to logical_block_address 
+ */
+static int msf2lba(u_char *msf)
+{
+  int i;
+
+  i=(msf[0] * CD_SECS + msf[1]) * CD_FRAMES + msf[2] - CD_BLOCK_OFFSET;
+  if (i<0) return (0);
+  return (i);
+}
+/*==========================================================================*/
 /* evaluate xx_ReadError code (still mysterious) */ 
 static int sta2err(int sta)
 {
   if (sta<=2) return (sta);
-  if (sta==0x05) return (-4);
-  if (sta==0x06) return (-6);
-  if (sta==0x0d) return (-6);
-  if (sta==0x0e) return (-3);
-  if (sta==0x14) return (-3);
-  if (sta==0x0c) return (-11);
-  if (sta==0x0f) return (-11);
-  if (sta==0x10) return (-11);
-  if (sta>=0x16) return (-12);
+  if (sta==0x05) return (-4); /* CRC error */
+  if (sta==0x06) return (-6); /* seek error */
+  if (sta==0x0d) return (-6); /* seek error */
+  if (sta==0x0e) return (-3); /* unknown command */
+  if (sta==0x14) return (-3); /* unknown command */
+  if (sta==0x0c) return (-11); /* read fault */
+  if (sta==0x0f) return (-11); /* read fault */
+  if (sta==0x10) return (-11); /* read fault */
+  if (sta>=0x16) return (-12); /* general failure */
   DriveStruct[d].CD_changed=0xFF;
-  if (sta==0x11) return (-15);
-  return (-2);
+  if (sta==0x11) return (-15); /* invalid disk change */
+  return (-2); /* drive not ready */
 }
 /*==========================================================================*/
 static void clr_cmdbuf(void)
@@ -1208,6 +1230,7 @@
       response_count=0;
       i=cmd_out();
     }
+  sbp_sleep(100); /* wait a second */
   flush_status();
   i=GetStatus();
   if (i>=0) return -1;
@@ -1244,7 +1267,7 @@
     }
   while (!st_diskok);
   DriveStruct[d].CD_changed=1;
-  i=SetSpeed();
+  i=DiskInfo();
   if (i<0) return (-2);
   return (0);
 }
@@ -1730,13 +1753,13 @@
 /*==========================================================================*/
 #if FUTURE
 static int yy_SubChanInfo(int frame, int count, u_char *buffer)
-/* "frame" is a RED BOOK address */
+/* "frame" is a RED BOOK (msf-bin) address */
 {
   int i;
 
-  if (!new_drive) return (-3);
+  if (!new_drive) return (-ENOSYS); /* drive firmware lacks it */
 #if 0
-  if (DriveStruct[d].audio_state!=audio_playing) return (-2);
+  if (DriveStruct[d].audio_state!=audio_playing) return (-ENODATA);
 #endif
   clr_cmdbuf();
   drvcmd[0]=0x11;
@@ -1748,7 +1771,7 @@
   flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
   cmd_type=READ_SC;
   DriveStruct[d].frame_size=CD_FRAMESIZE_SUB;
-  i=cmd_out(); /* read directly into user's buffer */
+  i=cmd_out(); /* which buffer to use? */
   return (i);
 }
 #endif FUTURE
@@ -2076,7 +2099,7 @@
 /* fake entry for LeadOut Track */
   DriveStruct[d].TocBuffer[j].nixbyte=0;
   DriveStruct[d].TocBuffer[j].ctl_adr=0;
-  DriveStruct[d].TocBuffer[j].number=0;
+  DriveStruct[d].TocBuffer[j].number=CDROM_LEADOUT;
   DriveStruct[d].TocBuffer[j].format=0;
   DriveStruct[d].TocBuffer[j].address=DriveStruct[d].size_msf;
 
@@ -2088,9 +2111,7 @@
 {
   int i, j;
 
-#if READ_AUDIO
       DriveStruct[d].mode=READ_M1;
-#endif READ_AUDIO
 
 #undef LOOP_COUNT
 #define LOOP_COUNT 20 /* needed for some "old" drives */
@@ -2579,7 +2600,6 @@
       DriveStruct[d].mode=READ_M2;
       return (0);
 
-#if READ_AUDIO
     case CDROMREADAUDIO:
       { /* start of CDROMREADAUDIO */
 	int i=0, j=0, frame, block;
@@ -2596,21 +2616,30 @@
 
 	DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADAUDIO requested.\n"));
 
+#if 0
+	if (!new_drive) return (-EINVAL);
+#endif
+	if (DriveStruct[d].aud_buf==NULL) return (-EINVAL);
 	i=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_read_audio));
 	if (i) return (i);
 	memcpy_fromfs(&read_audio, (void *) arg, sizeof(struct cdrom_read_audio));
-	i=verify_area(VERIFY_WRITE, read_audio.buf, CD_FRAMESIZE_RAW);
+	if (read_audio.nframes>SBP_BUFFER_AUDIO_FRAMES) return (-EINVAL);
+	i=verify_area(VERIFY_WRITE, read_audio.buf,
+		      read_audio.nframes*CD_FRAMESIZE_RAW);
 	if (i) return (i);
 
 	if (read_audio.addr_format==CDROM_MSF) /* MSF-bin specification of where to start */
-	  block=msf2blk(read_audio.addr.lba);
+	  block=msf2lba(&read_audio.addr.msf.minute);
 	else if (read_audio.addr_format==CDROM_LBA) /* lba specification of where to start */
 	  block=read_audio.addr.lba;
 	else return (-EINVAL);
-	if (read_audio.nframes!=1) return (-EINVAL);
 	DPRINTF((DBG_AUD,"SBPCD: read_audio: lba: %d, msf: %06X\n",
 		 block, blk2msf(block)));
 	DPRINTF((DBG_AUD,"SBPCD: read_audio: before xx_ReadStatus.\n"));
+
+	while (busy_data) sbp_sleep(10); /* wait a bit */
+	busy_audio=1;
+
 	for (data_tries=5; data_tries>0; data_tries--)
 	  {
 	    DPRINTF((DBG_AUD,"SBPCD: data_tries=%d ...\n", data_tries));
@@ -2641,7 +2670,7 @@
 		drvcmd[2]=(block>>8)&0x000000ff;
 		drvcmd[3]=block&0x000000ff;
 		drvcmd[4]=0;
-		drvcmd[5]=1;   /* # of frames */
+		drvcmd[5]=read_audio.nframes;   /* # of frames */
 		drvcmd[6]=0;
 	      }
 	    else /* if new_drive */
@@ -2692,7 +2721,13 @@
 		error_flag=0;
 		p = DriveStruct[d].aud_buf;
 		if (sbpro_type==1) OUT(CDo_sel_d_i,0x01);
-		READ_DATA(CDi_data, p, CD_FRAMESIZE_RAW);
+#if 0
+		cli();
+#endif
+		READ_DATA(CDi_data, p, read_audio.nframes*CD_FRAMESIZE_RAW);
+#if 0
+		sti();
+#endif
 		if (sbpro_type==1) OUT(CDo_sel_d_i,0x00);
 		data_retrying = 0;
 	      }
@@ -2747,13 +2782,15 @@
 		continue;
 	      }
 	    memcpy_tofs((u_char *) read_audio.buf,
-			(u_char *) DriveStruct[d].aud_buf, CD_FRAMESIZE_RAW);
+			(u_char *) DriveStruct[d].aud_buf,
+			read_audio.nframes*CD_FRAMESIZE_RAW);
 	    DPRINTF((DBG_AUD,"SBPCD: read_audio: memcpy_tofs done.\n"));
 	    break;
 	  }
 	xx_ModeSelect(CD_FRAMESIZE);
 	xx_ModeSense();
 	DriveStruct[d].mode=READ_M1;
+	busy_audio=0;
 	if (data_tries == 0)
 	  {
 	    DPRINTF((DBG_AUD,"SBPCD: read_audio: failed after 5 tries.\n"));
@@ -2762,7 +2799,6 @@
 	DPRINTF((DBG_AUD,"SBPCD: read_audio: successful return.\n"));
 	return (0);
       } /* end of CDROMREADAUDIO */
-#endif READ_AUDIO
 
     case BLKRASET:
       if(!suser())  return -EACCES;
@@ -2811,14 +2847,14 @@
 
   sti();
 
-  if ((CURRENT==NULL)||(CURRENT->dev<0)) return;
-  if (CURRENT -> sector == -1)	return;
+  if ((CURRENT==NULL)||(CURRENT->dev<0)) goto done;
+  if (CURRENT -> sector == -1) goto done;
 
   dev = MINOR(CURRENT->dev);
   if ( (dev<0) || (dev>=NR_SBPCD) )
     {
       printk("SBPCD: do_request: bad device: %d\n", dev);
-      return;
+      goto done;
     }
   switch_drive(dev);
 
@@ -2847,6 +2883,9 @@
   if (i!=0)
     DPRINTF((DBG_INF,"SBPCD: \"prepare\" tells error %d -- ignored\n", i));
 
+  while (busy_audio) sbp_sleep(100); /* wait a bit */
+  busy_data=1;
+
   if (!st_spinning) xx_SpinUp();
 
 #ifdef XA_TEST1
@@ -2884,6 +2923,10 @@
   end_request(0);
   sbp_sleep(10);    /* wait a bit, try again */
   goto request_loop;
+
+done:
+  busy_data=0;
+  return;
 }
 /*==========================================================================*/
 /*
@@ -2904,13 +2947,13 @@
       DPRINTF((DBG_MUL,"SBPCD: read MSF %08X\n", blk2msf(block)));
       if ( (DriveStruct[d].f_multisession) && (multisession_valid) )
 	{
-	  DPRINTF((DBG_MUL,"SBPCD: MultiSession: use %08X for %08X (msf)\n",
+	  DPRINTF((DBG_MUL,"SBPCD: ManySession: use %08X for %08X (msf)\n",
 		         blk2msf(DriveStruct[d].lba_multi+block),
                          blk2msf(block)));
 	  block=DriveStruct[d].lba_multi+block;
 	}
 #else
-      if ( (block==CD_BLOCK_OFFSET+16) && (DriveStruct[d].f_multisession) && (multisession_valid) )
+      if ( (block==16) && (DriveStruct[d].f_multisession) && (multisession_valid) )
 	{
 	  DPRINTF((DBG_MUL,"SBPCD: MultiSession: use %08X for %08X (msf)\n",
 		         blk2msf(DriveStruct[d].lba_multi+16),
@@ -3418,6 +3461,9 @@
   check_datarate();
   DPRINTF((DBG_INI,"SBPCD: check_datarate done.\n"));
 
+  OUT(CDo_reset,0);
+  sbp_sleep(100);
+
   for (j=0;j<NR_SBPCD;j++)
     {
       if (DriveStruct[j].drv_minor==-1) continue;
@@ -3484,10 +3530,12 @@
  */ 
       DriveStruct[j].sbp_buf=(u_char *)mem_start;
       mem_start += SBP_BUFFER_FRAMES*CD_FRAMESIZE;
-#if READ_AUDIO
-      DriveStruct[j].aud_buf=(u_char *)mem_start;
-      mem_start += CD_FRAMESIZE_RAW;
-#endif READ_AUDIO
+      if (new_drive)
+	{
+	  DriveStruct[j].aud_buf=(u_char *)mem_start;
+	  mem_start += SBP_BUFFER_AUDIO_FRAMES*CD_FRAMESIZE_RAW;
+	}
+      else DriveStruct[j].aud_buf=NULL;
 /*
  * set the block size
  */
diff -u --recursive --new-file v1.1.23/linux/fs/buffer.c linux/fs/buffer.c
--- v1.1.23/linux/fs/buffer.c	Thu Jun  9 18:56:12 1994
+++ linux/fs/buffer.c	Tue Jun 28 19:06:19 1994
@@ -29,25 +29,6 @@
 #include <asm/segment.h>
 #include <asm/io.h>
 
-#ifdef CONFIG_SCSI
-#ifdef CONFIG_BLK_DEV_SR
-extern int check_cdrom_media_change(int, int);
-#endif
-#ifdef CONFIG_BLK_DEV_SD
-extern int check_scsidisk_media_change(int, int);
-extern int revalidate_scsidisk(int, int);
-#endif
-#endif
-#ifdef CONFIG_CDU31A
-extern int check_cdu31a_media_change(int, int);
-#endif
-#ifdef CONFIG_MCD
-extern int check_mcd_media_change(int, int);
-#endif
-#ifdef CONFIG_SBPCD
-extern int check_sbpcd_media_change(int, int);
-#endif
-
 #define NR_SIZES 4
 static char buffersize_index[9] = {-1,  0,  1, -1,  2, -1, -1, -1, 3};
 static short int bufferindex_size[NR_SIZES] = {512, 1024, 2048, 4096};
@@ -284,85 +265,6 @@
 					  bh->b_dirt = bh->b_req = 0;
 		}
 	}
-}
-
-/*
- * This routine checks whether a floppy has been changed, and
- * invalidates all buffer-cache-entries in that case. This
- * is a relatively slow routine, so we have to try to minimize using
- * it. Thus it is called only upon a 'mount' or 'open'. This
- * is the best way of combining speed and utility, I think.
- * People changing diskettes in the middle of an operation deserve
- * to loose :-)
- *
- * NOTE! Although currently this is only for floppies, the idea is
- * that any additional removable block-device will use this routine,
- * and that mount/open needn't know that floppies/whatever are
- * special.
- */
-void check_disk_change(dev_t dev)
-{
-	int i;
-	struct buffer_head * bh;
-
-	switch(MAJOR(dev)){
-	case FLOPPY_MAJOR:
-		if (!(bh = getblk(dev,0,1024)))
-			return;
-		i = floppy_change(bh);
-		brelse(bh);
-		break;
-
-#if defined(CONFIG_BLK_DEV_SD) && defined(CONFIG_SCSI)
-         case SCSI_DISK_MAJOR:
-		i = check_scsidisk_media_change(dev, 0);
-		break;
-#endif
-
-#if defined(CONFIG_BLK_DEV_SR) && defined(CONFIG_SCSI)
-	 case SCSI_CDROM_MAJOR:
-		i = check_cdrom_media_change(dev, 0);
-		break;
-#endif
-
-#if defined(CONFIG_CDU31A)
-         case CDU31A_CDROM_MAJOR:
-		i = check_cdu31a_media_change(dev, 0);
-		break;
-#endif
-
-#if defined(CONFIG_MCD)
-         case MITSUMI_CDROM_MAJOR:
-		i = check_mcd_media_change(dev, 0);
-		break;
-#endif
-
-#if defined(CONFIG_SBPCD)
-         case MATSUSHITA_CDROM_MAJOR:
-		i = check_sbpcd_media_change(dev, 0);
-		break;
-#endif
-
-         default:
-		return;
-	};
-
-	if (!i)	return;
-
-	printk("VFS: Disk change detected on device %d/%d\n",
-					MAJOR(dev), MINOR(dev));
-	for (i=0 ; i<NR_SUPER ; i++)
-		if (super_blocks[i].s_dev == dev)
-			put_super(super_blocks[i].s_dev);
-	invalidate_inodes(dev);
-	invalidate_buffers(dev);
-
-#if defined(CONFIG_BLK_DEV_SD) && defined(CONFIG_SCSI)
-/* This is trickier for a removable hardisk, because we have to invalidate
-   all of the partitions that lie on the disk. */
-	if (MAJOR(dev) == SCSI_DISK_MAJOR)
-		revalidate_scsidisk(dev, 0);
-#endif
 }
 
 #define _hashfn(dev,block) (((unsigned)(dev^block))%nr_hash)
diff -u --recursive --new-file v1.1.23/linux/fs/devices.c linux/fs/devices.c
--- v1.1.23/linux/fs/devices.c	Tue Apr 19 10:53:20 1994
+++ linux/fs/devices.c	Tue Jun 28 19:26:06 1994
@@ -15,6 +15,29 @@
 #include <linux/fcntl.h>
 #include <linux/errno.h>
 
+/*
+ * Ugly. We'll fix this once all the drivers use the f_ops->check_media_change()
+ * stuff instead..
+ */
+#ifdef CONFIG_SCSI
+#ifdef CONFIG_BLK_DEV_SR
+extern int check_cdrom_media_change(int, int);
+#endif
+#ifdef CONFIG_BLK_DEV_SD
+extern int check_scsidisk_media_change(int, int);
+extern int revalidate_scsidisk(int, int);
+#endif
+#endif
+#ifdef CONFIG_CDU31A
+extern int check_cdu31a_media_change(int, int);
+#endif
+#ifdef CONFIG_MCD
+extern int check_mcd_media_change(int, int);
+#endif
+#ifdef CONFIG_SBPCD
+extern int check_sbpcd_media_change(int, int);
+#endif
+
 struct device_struct {
 	const char * name;
 	struct file_operations * fops;
@@ -108,6 +131,88 @@
 	blkdevs[major].name = NULL;
 	blkdevs[major].fops = NULL;
 	return 0;
+}
+
+/*
+ * This routine checks whether a removable media has been changed,
+ * and invalidates all buffer-cache-entries in that case. This
+ * is a relatively slow routine, so we have to try to minimize using
+ * it. Thus it is called only upon a 'mount' or 'open'. This
+ * is the best way of combining speed and utility, I think.
+ * People changing diskettes in the middle of an operation deserve
+ * to loose :-)
+ */
+void check_disk_change(dev_t dev)
+{
+	int i;
+	struct file_operations * fops;
+
+	i = MAJOR(dev);
+	if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL)
+		return;
+	if (fops->check_media_change != NULL) {
+		if (!fops->check_media_change(dev))
+			return;
+	} 
+#if 1 /* this will go soon.. */
+	else switch(MAJOR(dev)){
+#if defined(CONFIG_BLK_DEV_SD) && defined(CONFIG_SCSI)
+         case SCSI_DISK_MAJOR:
+		if (!check_scsidisk_media_change(dev, 0))
+			return;
+		break;
+#endif
+
+#if defined(CONFIG_BLK_DEV_SR) && defined(CONFIG_SCSI)
+	 case SCSI_CDROM_MAJOR:
+		if (!check_cdrom_media_change(dev, 0))
+			return;
+		break;
+#endif
+
+#if defined(CONFIG_CDU31A)
+         case CDU31A_CDROM_MAJOR:
+		if (!check_cdu31a_media_change(dev, 0))
+			return;
+		break;
+#endif
+
+#if defined(CONFIG_MCD)
+         case MITSUMI_CDROM_MAJOR:
+		if (!check_mcd_media_change(dev, 0))
+			return;
+		break;
+#endif
+
+#if defined(CONFIG_SBPCD)
+         case MATSUSHITA_CDROM_MAJOR:
+		if (!check_sbpcd_media_change(dev, 0))
+			return;
+		break;
+#endif
+
+         default:
+		return;
+	}
+#endif	/* will go away */
+
+	printk("VFS: Disk change detected on device %d/%d\n",
+					MAJOR(dev), MINOR(dev));
+	for (i=0 ; i<NR_SUPER ; i++)
+		if (super_blocks[i].s_dev == dev)
+			put_super(super_blocks[i].s_dev);
+	invalidate_inodes(dev);
+	invalidate_buffers(dev);
+
+	if (fops->revalidate)
+		fops->revalidate(dev);
+
+#if defined(CONFIG_BLK_DEV_SD) && defined(CONFIG_SCSI)
+/* This is trickier for a removable hardisk, because we have to invalidate
+   all of the partitions that lie on the disk. */
+	if (MAJOR(dev) == SCSI_DISK_MAJOR)
+		revalidate_scsidisk(dev, 0);
+#endif
 }
 
 /*
diff -u --recursive --new-file v1.1.23/linux/include/linux/cdrom.h linux/include/linux/cdrom.h
--- v1.1.23/linux/include/linux/cdrom.h	Tue Jun 28 22:30:27 1994
+++ linux/include/linux/cdrom.h	Tue Jun 28 19:31:14 1994
@@ -14,7 +14,7 @@
 /*
  * some fix numbers
  */
-#define CD_MINS                   75  /* minutes per CD                  */
+#define CD_MINS                   74  /* max. minutes per CD             */
 #define CD_SECS                   60  /* seconds per minute              */
 #define CD_FRAMES                 75  /* frames per second               */
 #define CD_FRAMESIZE            2048  /* bytes per frame, cooked mode    */
@@ -238,10 +238,9 @@
 /*
  * CD-ROM address types (cdrom_tocentry.cdte_format)
  */
+#define	CDROM_LBA 0x01 /* "logical block": first frame is #0 */
+#define	CDROM_MSF 0x02 /* "minute-second-frame": binary, not bcd here! */
 
-#define	CDROM_LBA	0x01
-#define	CDROM_MSF	0x02
-
 /*
  * bit to tell whether track is data or audio
  */
@@ -328,7 +327,7 @@
 	      int	lba;
 	    } addr; /* frame address */
 	  u_char addr_format; /* CDROM_LBA or CDROM_MSF */
-	  int nframes; /* number of 2352-byte-frames to read at once, currently only 1 allowed */
+	  int nframes; /* number of 2352-byte-frames to read at once, limited by the drivers */
 	  u_char *buf; /* frame buffer (size: nframes*2352 bytes) */
 	};
 
@@ -366,7 +365,7 @@
                                                 /* vlume control		*/
 
 #define	CDROMSUBCHNL		0x530b		/* (struct cdrom_subchnl)	*/
-                                                /* read sub-channel data 	*/
+                                                /* read Q sub-channel data 	*/
 
 #define	CDROMREADMODE2		0x530c		/* (struct cdrom_read)		*/
                                                 /* read type-2 data (not suppt)	*/
diff -u --recursive --new-file v1.1.23/linux/include/linux/fs.h linux/include/linux/fs.h
--- v1.1.23/linux/include/linux/fs.h	Tue May 24 00:34:55 1994
+++ linux/include/linux/fs.h	Tue Jun 28 20:42:53 1994
@@ -292,6 +292,8 @@
 	void (*release) (struct inode *, struct file *);
 	int (*fsync) (struct inode *, struct file *);
 	int (*fasync) (struct inode *, struct file *, int);
+	int (*check_media_change) (dev_t dev);
+	int (*revalidate) (dev_t dev);
 };
 
 struct inode_operations {
@@ -414,7 +416,6 @@
 extern void check_disk_change(dev_t dev);
 extern void invalidate_inodes(dev_t dev);
 extern void invalidate_buffers(dev_t dev);
-extern int floppy_change(struct buffer_head * first_block);
 extern void sync_inodes(dev_t dev);
 extern void sync_dev(dev_t dev);
 extern int fsync_dev(dev_t dev);
diff -u --recursive --new-file v1.1.23/linux/include/linux/mcd.h linux/include/linux/mcd.h
--- v1.1.23/linux/include/linux/mcd.h	Wed Apr  6 11:18:19 1994
+++ linux/include/linux/mcd.h	Tue Jun 28 22:27:14 1994
@@ -25,7 +25,7 @@
 #define MCD_BASE_ADDR	        0x300
 
 /* *** change this to set the interrupt number */
-#define MCD_INTR_NR		11
+#define MCD_INTR_NR		10
 
 /* Increase this if you get lots of timeouts */
 #define MCD_STATUS_DELAY	100
diff -u --recursive --new-file v1.1.23/linux/include/linux/sbpcd.h linux/include/linux/sbpcd.h
--- v1.1.23/linux/include/linux/sbpcd.h	Tue Jun 28 22:30:27 1994
+++ linux/include/linux/sbpcd.h	Tue Jun 28 19:31:14 1994
@@ -23,7 +23,7 @@
  * and specify the type of your interface in SBPRO.
  *
  * SBPRO addresses typically are 0x0230 (=0x220+0x10), 0x0250, ...
- * LASERMATE (CI-101P) adresses typically are 0x0300, 0x0310, ...
+ * LASERMATE (CI-101P, WDH-7001C) adresses typically are 0x0300, 0x0310, ...
  * SPEA addresses are 0x320, 0x330, 0x340, 0x350
  * there are some soundcards on the market with 0x0630, 0x0650, ...
  *
