diff -u --recursive v1.1.28/linux/Makefile linux/Makefile
--- v1.1.28/linux/Makefile	Thu Jul 14 00:48:20 1994
+++ linux/Makefile	Thu Jul 14 10:55:24 1994
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 28
+SUBLEVEL = 29
 
 all:	Version zImage
 
diff -u --recursive v1.1.28/linux/drivers/block/README.sbpcd linux/drivers/block/README.sbpcd
--- v1.1.28/linux/drivers/block/README.sbpcd	Sat Jul  9 16:30:45 1994
+++ linux/drivers/block/README.sbpcd	Wed Jul 13 21:42:32 1994
@@ -1,4 +1,4 @@
-This README belongs to release 2.2 of the SoundBlaster Pro (Matsushita,
+This README belongs to release 2.3 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,12 +48,16 @@
 
 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
-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.
+up to 4 frames of 2352 bytes at once. Reading more than 1 frame at once misses
+some chunks at each frame boundary. Reading the same frame a second time gives
+different data; the frame data start at a different position. But all read
+bytes are valid, and we always read 98 consecutive chunks (of 24 Bytes) as a
+frame. This lack has to get corrected by higher level software which reads the
+same frame again and tries to find and eliminate overlapping chunks
+(24-byte-pieces).
+
 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
+This could be better reading bigger chunks, but the "missing" chunks occur at
 the beginning of each single frame.
 The software interface possibly may change a bit the day the SCSI driver
 supports it too.
@@ -234,15 +238,20 @@
  * (c) 1994 Eberhard Moenkeberg <emoenke@gwdg.de>
  *          may be used & enhanced freely
  *
- * Due to non-existent sync bytes at the beginning of each audio frame,
- * it is currently a kind of fortune if two consecutive frames fit together.
- * Usually, they overlap, or a little piece is missing. This has to get
- * fixed by higher-level software (reading until an overlap occurs, and then
- * eliminate the overlapping bytes). Possibly the first read bytes of each
- * frame must get discarded because they are read before we got synchronized.
- * 
+ * Due to non-existent sync bytes at the beginning of each audio frame (or due
+ * to a firmware bug within all known drives?), it is currently a kind of
+ * fortune if two consecutive frames fit together.
+ * Usually, they overlap, or a little piece is missing. This happens in units
+ * of 24-byte chunks. It has to get fixed by higher-level software (reading
+ * until an overlap occurs, and then eliminate the overlapping chunks). 
+ * ftp.gwdg.de:/pub/linux/misc/cdda2wav-sbpcd.*.tar.gz holds an example of
+ * such an algorithm.
  * This example program further is missing to obtain the SubChannel data
  * which belong to each frame.
+ *
+ * This is only an example of the low-level access routine. The read data are
+ * pure 16-bit CDDA values; they have to get converted to make sound out of
+ * them.
  */
 #include <stdio.h>
 #include <sys/ioctl.h>
@@ -283,9 +292,10 @@
  * get and display all TocEntries
  */
   fprintf(stdout, "getting TocEntries...\n");
-  for (i=1;i<=hdr.cdth_trk1;i++)
+  for (i=1;i<=hdr.cdth_trk1+1;i++)
     {
-      entry[i].cdte_track = i;
+      if (i!=hdr.cdth_trk1+1) entry[i].cdte_track = i;
+      else entry[i].cdte_track = CDROM_LEADOUT;
       entry[i].cdte_format = CDROM_LBA;
       err=ioctl(drive, CDROMREADTOCENTRY, &entry[i]);
       if (err!=0)
@@ -323,7 +333,7 @@
       exit (-1);
     }
   arg.addr.lba=entry[track].cdte_addr.lba;
-  arg.addr_format=CDROM_LBA; /* CDROM_MSF is still buggy, I know that */
+  arg.addr_format=CDROM_LBA; /* CDROM_MSF would be possible here, too. */
   arg.nframes=1;
   arg.buf=&buffer[0];
   limit=entry[track+1].cdte_addr.lba;
@@ -347,7 +357,7 @@
 }
 /*===================== end program ========================================*/
 
-At ftp.gwdg.de:/pub/linux/misc/cdda2wav-sbpcd.tar.gz is an adapted version of
+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.
 
@@ -355,11 +365,7 @@
 Known problems:
 ---------------
 
-Currently, the detection of disk change or removal does not work as good as it
-should.
-
-The "door (un)lock" commands get done at every "(u)mount" (only the "new"
-drives support it), but after an unlock, locking again does not work properly.
+Currently, the detection of disk change or removal is actively disabled.
 
 All attempts to read the UPC/EAN code result in a stream of zeroes. All my
 drives are telling there is no UPC/EAN code on disk or there is, but it is an
diff -u --recursive v1.1.28/linux/drivers/block/blk.h linux/drivers/block/blk.h
--- v1.1.28/linux/drivers/block/blk.h	Sat Jul  9 16:30:45 1994
+++ linux/drivers/block/blk.h	Thu Jul 14 10:50:29 1994
@@ -304,6 +304,7 @@
 	CURRENT = req->next;
 	if ((p = req->waiting) != NULL) {
 		req->waiting = NULL;
+		p->swapping = 0;
 		p->state = TASK_RUNNING;
 		if (p->counter > current->counter)
 			need_resched = 1;
diff -u --recursive v1.1.28/linux/drivers/block/hd.c linux/drivers/block/hd.c
--- v1.1.28/linux/drivers/block/hd.c	Mon Jun 27 16:46:58 1994
+++ linux/drivers/block/hd.c	Wed Jul 13 23:59:00 1994
@@ -184,8 +184,11 @@
 {
 	unsigned short port;
 
-	if (drive>1 || head>15)
-		panic("Trying to write bad sector");
+	if (drive>1 || head>15) {
+		printk("bad drive mapping, trying to access drive=%d, cyl=%d, head=%d, sect=%d\n",
+			drive, cyl, head, sect);
+		panic("harddisk driver problem");
+	}
 #if (HD_DELAY > 0)
 	while (read_timer() - last_req < HD_DELAY)
 		/* nothing */;
diff -u --recursive v1.1.28/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v1.1.28/linux/drivers/block/ll_rw_blk.c	Thu Jun  9 18:56:09 1994
+++ linux/drivers/block/ll_rw_blk.c	Thu Jul 14 10:50:29 1994
@@ -327,8 +327,12 @@
 	req->waiting = current;
 	req->bh = NULL;
 	req->next = NULL;
+	current->swapping = 1;
 	current->state = TASK_SWAPPING;
 	add_request(major+blk_dev,req);
+	/* The I/O may have inadvertently chagned the task state.
+	   Make sure we really wait until the I/O is done */
+	if (current->swapping) current->state = TASK_SWAPPING;
 	schedule();
 }
 
@@ -462,8 +466,12 @@
 		req->waiting = current;
 		req->bh = NULL;
 		req->next = NULL;
+		current->swapping = 1;
 		current->state = TASK_UNINTERRUPTIBLE;
 		add_request(major+blk_dev,req);
+		/* The I/O may have inadvertently chagned the task state.
+		   Make sure we really wait until the I/O is done */
+		if (current->swapping) current->state = TASK_UNINTERRUPTIBLE;
 		schedule();
 	}
 }
diff -u --recursive v1.1.28/linux/drivers/block/sbpcd.c linux/drivers/block/sbpcd.c
--- v1.1.28/linux/drivers/block/sbpcd.c	Sat Jul  9 16:30:45 1994
+++ linux/drivers/block/sbpcd.c	Wed Jul 13 21:42:33 1994
@@ -5,7 +5,7 @@
  *            and for "no-sound" interfaces like Lasermate and the
  *            Panasonic CI-101P.
  *
- *  NOTE:     This is release 2.2.
+ *  NOTE:     This is release 2.3.
  *            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. 
@@ -108,11 +108,15 @@
  *
  *  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.
+ *       Bigger audio frame buffer: allows reading max. 4 frames at time; this
+ *       gives a significant speedup, but reading more than one frame at once
+ *       gives missing chunks at each single frame boundary.
  *
- *  2.2  
+ *  2.2  Kernel interface cleanups: timers, init, setup, media check.
  *
+ *  2.3  Let "door lock" and "eject" live together.
+ *       Implemented "close tray" (done automatically during open).
+ *
  *  TODO
  *
  *     disk change detection
@@ -188,7 +192,7 @@
 
 #include "blk.h"
 
-#define VERSION "2.2 Eberhard Moenkeberg <emoenke@gwdg.de>"
+#define VERSION "2.3 Eberhard Moenkeberg <emoenke@gwdg.de>"
 
 #define SBPCD_DEBUG
 
@@ -224,22 +228,18 @@
  */
 #if !(SBPCD_ISSUE-1)
 #define DO_SBPCD_REQUEST(a) do_sbpcd_request(a)
-#define SBPCD_SETUP(a,b) sbpcd_setup(a,b)
 #define SBPCD_INIT(a,b) sbpcd_init(a,b)
 #endif
 #if !(SBPCD_ISSUE-2)
 #define DO_SBPCD_REQUEST(a) do_sbpcd2_request(a)
-#define SBPCD_SETUP(a,b) sbpcd2_setup(a,b)
 #define SBPCD_INIT(a,b) sbpcd2_init(a,b)
 #endif
 #if !(SBPCD_ISSUE-3)
 #define DO_SBPCD_REQUEST(a) do_sbpcd3_request(a)
-#define SBPCD_SETUP(a,b) sbpcd3_setup(a,b)
 #define SBPCD_INIT(a,b) sbpcd3_init(a,b)
 #endif
 #if !(SBPCD_ISSUE-4)
 #define DO_SBPCD_REQUEST(a) do_sbpcd4_request(a)
-#define SBPCD_SETUP(a,b) sbpcd4_setup(a,b)
 #define SBPCD_INIT(a,b) sbpcd4_init(a,b)
 #endif
 /*==========================================================================*/
@@ -1269,9 +1269,14 @@
       if (!st_caddy_in) break;
     }
   while (!st_diskok);
+#if 000
   DriveStruct[d].CD_changed=1;
-  i=DiskInfo();
-  if (i<0) return (-2);
+#endif
+  if ((st_door_closed) && (st_caddy_in))
+    {
+      i=DiskInfo();
+      if (i<0) return (-2);
+    }
   return (0);
 }
 /*==========================================================================*/
@@ -1311,6 +1316,21 @@
   return (i);
 }
 /*==========================================================================*/
+static int yy_CloseTray(void)
+{
+  int i;
+
+  if (!new_drive) return (0);
+  DPRINTF((DBG_LCK,"SBPCD: yy_CloseTray (drive %d)\n", d));
+
+  clr_cmdbuf();
+  drvcmd[0]=0x07;
+  flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
+  response_count=0;
+  i=cmd_out();
+  return (i);
+}
+/*==========================================================================*/
 static int xx_ReadSubQ(void)
 {
   int i,j;
@@ -1608,10 +1628,12 @@
   DriveStruct[d].TocEnt_format=infobuf[3];
   if (new_drive) i=4;
   else i=5;
-  DriveStruct[d].TocEnt_address=make32(make16(0,infobuf[i]),make16(infobuf[i+1],infobuf[i+2]));
+  DriveStruct[d].TocEnt_address=make32(make16(0,infobuf[i]),
+				       make16(infobuf[i+1],infobuf[i+2]));
   DPRINTF((DBG_TOC,"SBPCD: TocEntry: %02X %02X %02X %02X %08X\n",
-	   DriveStruct[d].TocEnt_nixbyte,DriveStruct[d].TocEnt_ctl_adr,DriveStruct[d].TocEnt_number,
-	   DriveStruct[d].TocEnt_format,DriveStruct[d].TocEnt_address));
+	   DriveStruct[d].TocEnt_nixbyte, DriveStruct[d].TocEnt_ctl_adr,
+	   DriveStruct[d].TocEnt_number, DriveStruct[d].TocEnt_format,
+	   DriveStruct[d].TocEnt_address));
   return (0);
 }
 /*==========================================================================*/
@@ -2527,7 +2549,11 @@
       DriveStruct[d].CD_changed=0xFF;
       DriveStruct[d].diskstate_flags=0;
 #endif WORKMAN
+      do i=yy_LockDoor(0);
+      while (i!=0);
+      DriveStruct[d].open_count=0; /* to get it locked next time again */
       i=yy_SpinDown();
+      DPRINTF((DBG_IOX,"SBPCD: ioctl: yy_SpinDown returned %d.\n", i));
       if (i<0) return (-EIO);
       DriveStruct[d].audio_state=0;
       return (0);
@@ -3193,6 +3219,10 @@
     }
   switch_drive(i);
 
+  flags_cmd_out |= f_respo2;
+  xx_ReadStatus();                         /* command: give 1-byte status */
+  i=ResponseStatus();
+  if (!st_door_closed) yy_CloseTray();
   if (!st_spinning) xx_SpinUp();
 
   flags_cmd_out |= f_respo2;
@@ -3207,7 +3237,7 @@
   if (!st_door_closed||!st_caddy_in)
     {
       printk("SBPCD: sbpcd_open: no disk in drive\n");
-      return (-EIO);
+      return (-ENXIO);
     }
 
 /*
@@ -3245,7 +3275,7 @@
   switch_drive(i);
 
   DriveStruct[d].sbp_first_frame=DriveStruct[d].sbp_last_frame=-1;
-  fsync_dev(ip->i_rdev);                   /* nonsense if read only device? */
+  sync_dev(ip->i_rdev);                   /* nonsense if read only device? */
   invalidate_buffers(ip->i_rdev);
   DriveStruct[d].diskstate_flags &= ~cd_size_bit;
 
@@ -3254,11 +3284,14 @@
  */
   DPRINTF((DBG_LCK,"SBPCD: open_count: %d -> %d\n",
 	   DriveStruct[d].open_count,DriveStruct[d].open_count-1));
-  if (--DriveStruct[d].open_count==0) 
+  if (DriveStruct[d].open_count!=0) /* CDROMEJECT may have been done */
     {
-      do
-	i=yy_LockDoor(0);
-      while (i!=0);
+      if (--DriveStruct[d].open_count==0) 
+	{
+	  do
+	    i=yy_LockDoor(0);
+	  while (i!=0);
+	}
     }
 }
 /*==========================================================================*/
@@ -3305,7 +3338,7 @@
 #if (SBPCD_ISSUE-1)
 static
 #endif
-void SBPCD_SETUP(char *s, int *p)
+void sbpcd_setup(char *s, int *p)
 {
   DPRINTF((DBG_INI,"SBPCD: sbpcd_setup called with %04X,%s\n",p[1], s));
   sbpro_type=0;
@@ -3422,7 +3455,7 @@
       if (autoprobe[port_index+1]==0) type=str_lm;
       else if (autoprobe[port_index+1]==1) type=str_sb;
       else type=str_sp;
-      SBPCD_SETUP(type, addr);
+      sbpcd_setup(type, addr);
       DPRINTF((DBG_INF,"SBPCD: Trying to detect a %s CD-ROM drive at 0x%X.\n",
 	             type, CDo_command));
 
diff -u --recursive v1.1.28/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.1.28/linux/drivers/scsi/scsi.c	Thu Jul 14 00:48:24 1994
+++ linux/drivers/scsi/scsi.c	Thu Jul 14 10:51:42 1994
@@ -220,7 +220,7 @@
   int dev, lun, type;
   unsigned char scsi_cmd [12];
   unsigned char scsi_result [256];
-  Scsi_Device * SDpnt;
+  Scsi_Device * SDpnt, *SDtail;
   Scsi_Cmnd  SCmd;
   
   ++in_scan;
@@ -229,6 +229,10 @@
   SCmd.next = NULL;
   SCmd.prev = NULL;
   SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device));
+  SDtail = scsi_devices;
+  if(scsi_devices) {
+    while(SDtail->next) SDtail = SDtail->next;
+  }
 
   shpnt->host_queue = &SCmd;  /* We need this so that
 					 commands can time out */
@@ -465,8 +469,13 @@
 		    
 		    while (SCmd.request.dev != 0xfffe);
 		  };
-		  SDpnt->next = scsi_devices;
-		  scsi_devices = SDpnt;
+		  /* Add this device to the linked list at the end */
+		  if(SDtail)
+		    SDtail->next = SDpnt;
+		  else
+		    scsi_devices = SDpnt;
+		  SDtail = SDpnt;
+
 		  ++NR_SCSI_DEVICES;
 		  SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device));
 		  /* Some scsi devices cannot be polled for lun != 0
diff -u --recursive v1.1.28/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v1.1.28/linux/drivers/scsi/scsi.h	Thu Jul 14 00:48:24 1994
+++ linux/drivers/scsi/scsi.h	Thu Jul 14 10:50:29 1994
@@ -556,6 +556,7 @@
 	DEVICE_OFF(req->dev);
 	if ((p = req->waiting) != NULL) {
 		req->waiting = NULL;
+		p->swapping = 0;
 		p->state = TASK_RUNNING;
 		if (p->counter > current->counter)
 			need_resched = 1;
@@ -585,20 +586,17 @@
 #endif
 
 #define SCSI_SLEEP(QUEUE, CONDITION) {				\
-	long old_state;						\
 	if (CONDITION) {					\
 		struct wait_queue wait = { current, NULL};	\
 		add_wait_queue(QUEUE, &wait);			\
 sleep_repeat:							\
-		old_state = current->state;			\
 		current->state = TASK_UNINTERRUPTIBLE;		\
 		if (CONDITION) {				\
 			schedule();				\
 			goto sleep_repeat;			\
 		}						\
 		remove_wait_queue(QUEUE, &wait);		\
-		if (current->state == TASK_UNINTERRUPTIBLE)	\
-			current->state = old_state;		\
+		current->state = TASK_RUNNING;			\
 	}; }
 
 #endif
diff -u --recursive v1.1.28/linux/include/linux/cdrom.h linux/include/linux/cdrom.h
--- v1.1.28/linux/include/linux/cdrom.h	Thu Jul  7 21:37:13 1994
+++ linux/include/linux/cdrom.h	Wed Jul 13 21:42:33 1994
@@ -17,7 +17,10 @@
 #define CD_MINS                   74  /* max. minutes per CD             */
 #define CD_SECS                   60  /* seconds per minute              */
 #define CD_FRAMES                 75  /* frames per second               */
+#define CD_CHUNK_SIZE             24  /* lowest-level "data bytes piece" */
+#define CD_NUM_OF_CHUNKS          98  /* chunks per frame                */
 #define CD_FRAMESIZE            2048  /* bytes per frame, cooked mode    */
+#define CD_FRAMESIZE_RAW0       2336  /* bytes per frame, "raw" mode     */
 #define CD_FRAMESIZE_XA         2340  /* bytes per frame, "xa" mode      */
 #define CD_FRAMESIZE_RAW        2352  /* bytes per frame, "raw" mode     */
 #define CD_FRAMESIZE_SUB          96  /* subchannel data size            */
diff -u --recursive v1.1.28/linux/include/linux/sched.h linux/include/linux/sched.h
--- v1.1.28/linux/include/linux/sched.h	Tue Jun 21 14:16:25 1994
+++ linux/include/linux/sched.h	Thu Jul 14 10:50:29 1994
@@ -264,6 +264,7 @@
 	unsigned long personality;
 	int dumpable:1;
 	int did_exec:1;
+	volatile int swapping:1;
 	int pid,pgrp,session,leader;
 	int	groups[NGROUPS];
 	/* 
@@ -331,7 +332,7 @@
 /* schedlink */	&init_task,&init_task, \
 /* signals */	{{ 0, },}, \
 /* stack */	0,(unsigned long) &init_kernel_stack, \
-/* ec,brk... */	0,0,0,0,0, \
+/* ec,brk... */	0,0,0,0,0,0, \
 /* pid etc.. */	0,0,0,0, \
 /* suppl grps*/ {NOGROUP,}, \
 /* proc links*/ &init_task,&init_task,NULL,NULL,NULL,NULL, \
diff -u --recursive v1.1.28/linux/kernel/fork.c linux/kernel/fork.c
--- v1.1.28/linux/kernel/fork.c	Sat Jul  9 16:30:47 1994
+++ linux/kernel/fork.c	Thu Jul 14 10:50:29 1994
@@ -188,6 +188,7 @@
 		(*p->binfmt->use_count)++;
 
 	p->did_exec = 0;
+	p->swapping = 0;
 	p->kernel_stack_page = 0;
 	p->state = TASK_UNINTERRUPTIBLE;
 	p->flags &= ~(PF_PTRACED|PF_TRACESYS);
