diff -u --recursive --new-file v1.2.7/linux/Makefile linux/Makefile
--- v1.2.7/linux/Makefile	Sat Apr 29 12:42:20 1995
+++ linux/Makefile	Tue May  2 08:18:15 1995
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 2
-SUBLEVEL = 7
+SUBLEVEL = 8
 
 ARCH = i386
 
diff -u --recursive --new-file v1.2.7/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c
--- v1.2.7/linux/arch/i386/kernel/vm86.c	Wed Mar 29 06:52:56 1995
+++ linux/arch/i386/kernel/vm86.c	Tue May  2 08:02:12 1995
@@ -358,6 +358,14 @@
 			IP(regs) += 2;
 			set_vflags_long(popl(ssp, sp), regs);
 			return;
+
+		/* iretd */
+		case 0xcf:
+			SP(regs) += 12;
+			IP(regs) = (unsigned short)popl(ssp, sp);
+			regs->cs = (unsigned short)popl(ssp, sp);
+			set_vflags_long(popl(ssp, sp), regs);
+			return;
 		}
 
 	/* pushf */
diff -u --recursive --new-file v1.2.7/linux/drivers/block/README.sbpcd linux/drivers/block/README.sbpcd
--- v1.2.7/linux/drivers/block/README.sbpcd	Wed Mar 29 06:52:57 1995
+++ linux/drivers/block/README.sbpcd	Tue Apr 25 00:54:36 1995
@@ -1,4 +1,4 @@
-This README belongs to release 3.4 or newer of the SoundBlaster Pro
+This README belongs to release 3.5 or newer of the SoundBlaster Pro
 (Matsushita, Kotobuki, Panasonic, CreativeLabs, Longshine and soon TEAC, too)
 CD-ROM driver for Linux.
 
@@ -16,28 +16,18 @@
 an internal drive, and you can use it as an internal, too - f.e. plug it into
 a soundcard).
 
-The quad-speed TEAC CD-55A drive uses the same interface types, but has a
-totally different command and flow control scheme. Support is under
-construction, but split: Greg Nowicki (nowicki@tardis.larc.nasa.gov)
-cares about the separate driver "teaccd". Please, do not mail him merely for
-asking "user questions" at the moment - the project is still a "baby".
-
 CreativeLabs has a new drive "CD-200". Support is under construction.
-Detection should already work.
-
-Regarding CD200 support:
-    Please, don't mail me about it if you are not a competent BETA tester 
-            (if you are: mail!; I do not have such drives).
-    Please, don't drop simple questions about the new drives in the
-            newsgroups. Full support needs more or less time.
-If you like to help, you can mail me the "SBPCD:..." messages, regarding the
-new drives. But I mostly will not answer (just use) it.
+Drive detection and playing audio should already work. I need qualified
+feedback about the bugs within the data functions or a drive (I never saw
+a CD200).
+
+The quad-speed TEAC CD-55A drive is supported. The routines may still be
+a little bit buggy, but the data rate already reaches 500 kB/sec if you
+set SBP_BUFFER_FRAMES to 64. The drive is able to deliver 600 kB/sec, so
+this has to get a point of work.
 
 This driver is NOT for Mitsumi or Sony or Aztech or Philips or XXX drives,
 and this driver is in no way usable for any new IDE ATAPI drive.
-For Aztech CDA-268 drives (and for some Wearnes, Okano and Orchid drives),
-Werner Zimmermann has done a driver which currently resides at ftp.gwdg.de
-under /pub/linux/cdrom/drivers/aztech/.
 
 This driver will work with the soundcard interfaces (SB Pro, SB 16, Galaxy,
 SoundFX, ...) and/or with the "no-sound" cards (Panasonic CI-101P, LaserMate,
@@ -53,8 +43,8 @@
 because the behavior of some sound card interfaces is different.
 
 The driver respects all known drive firmware releases - my old drive is a 2.11,
-but it should work with "old" drives <2.01 ... >3.00 and with "new" drives
-(which count the releases around 0.75 or 1.00).
+but it should work with CR-52x drives <2.01 ... >3.00 and with CR-56x drives
+<0.75 .. 5.00.
 
 Up to 4 drives per interface card, and up to 4 interface cards are supported.
 All supported drive families can be mixed, but the CR-521 drives are 
@@ -90,28 +80,30 @@
 
 With the CR-562 and CR-563 drives, the reading of audio frames is possible.
 This is implemented by an IOCTL function which per default reads only up to
-4 frames of 2352 bytes at once (configurable with the "READ_AUDIO" define).
+4 frames of 2352 bytes at once (configurable with the "READ_AUDIO" define,
+"55" is the maximum if you use sbpcd as a "module").
 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. Reading more than 1 frame
-at once misses some chunks at each frame boundary.This lack has to get 
-corrected by external, "higher level" software which reads the same frame 
+at once possibly misses some chunks at each frame boundary. This lack has to
+get corrected by external, "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 "missing" chunks occur at
-the beginning of each single frame.
+This could be better reading bigger chunks, but the "missing" chunks possibly
+occur at the beginning of each single frame.
 The software interface possibly may change a bit the day the SCSI driver
 supports it too.
 
-With the CR-562 and CR-563 drives, MultiSession is supported.
+With all but the CR-52x drives, MultiSession is supported.
 Photo CDs work (the "old" drives like CR-521 can access only the first
 session of a photoCD).
 At ftp.gwdg.de:/pub/linux/hpcdtoppm/ you will find Hadmut Danisch's package to
 convert photo CD image files and Gerd Knorr's viewing utility.
 
-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.
+The transfer rate will reach 150 kB/sec with "old" drives, 300 kB/sec with
+double-speed drives, and about 500 kB/sec with quad speed drives.
+XA (PhotoCD) disks with "old" drives give only 50 kB/sec.
 
 This release is part of the standard kernel and consists of
 - this README file
@@ -138,6 +130,7 @@
           If you configure "SBPRO" wrong, the playing of audio CDs will work,
           but you will not be able to mount a data CD.
       a2. Tell the address of your CDROM_PORT (not of the sound port).
+      a3. Set DISTRIBUTION to 0.
    b. Additionally for 2.a1 and 2.a2, the setup may be done during
       boot time (via the "kernel command line" or "LILO option"):
           sbpcd=0x230,SoundBlaster
@@ -145,7 +138,6 @@
           sbpcd=0x320,LaserMate
       or
           sbpcd=0x330,SPEA
-      (these strings are case sensitive!).
       This is especially useful if you install a fresh distribution.
 2. "cd /usr/src/linux" and do a "make config" and select "y" for Matsushita
    CD-ROM support and for ISO9660 FileSystem support. If you do not have a
@@ -198,11 +190,15 @@
 "make config" of your kernel, you can build the "loadable module" sbpcd.o.
 Read /usr/src/linux/README.modules on this.
 
-If sbpcd gets used as a module, the "audio copy" feature is disabled, and the
-internal read-ahead buffer has a reduced size (the latter may affect throughput
-a little bit under "slow" CPUs). Further, support of more than one interface
+If sbpcd gets used as a module, the support of more than one interface
 card (i.e. drives 4...15) is disabled.
 
+You can specify interface address and type with the "insmod" command like:
+ # insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x340,0
+or
+ # insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x230,1
+where the last number represents the SBPRO setting (no strings allowed here).
+
 
 Things of interest:
 -------------------
@@ -215,7 +211,6 @@
 
 To reduce or increase the amount of kernel messages, edit sbpcd.c and play
 with the "DBG_xxx" switches (initialization of the variable "sbpcd_debug").
-This is the way to get rid of the initial warning message block, too.
 
 The driver uses the "variable BLOCK_SIZE" feature. To use it, you have to
 specify "block=2048" as a mount option. Doing this will disable the direct
@@ -229,120 +224,13 @@
 
 At the beginning of sbpcd.c, you will find some "#define"s (f.e. EJECT and
 JUKEBOX). With that, you can configure the driver for some special things.
-The following program disables the auto-eject feature during runtime:
-
-/*=================== begin program ========================================*/
-/*
- * set the "eject" switch (enable/disable auto-ejecting)
- *
- * (c) 1994 Eberhard Moenkeberg <emoenke@gwdg.de>
- *          may be used & enhanced freely
- *
- * Disables or enables the auto-eject feature at run time.
- * Works only if a CD is in the drive (just like the feature itself ;-) 
- * Useful for a "quiet" shutdown or for weird audio player programs.
- */
-#define EJECT 0 /* 0: disable, 1: enable auto-ejecting */
-
-#include <stdio.h>
-#include <sys/ioctl.h>
-#include <linux/cdrom.h>
-
-static char arg=EJECT;
-static int drive;
-static int err;
-
-main(int argc, char *argv[])
-{
-/*
- * open /dev/cdrom
- */
-  drive=open("/dev/cdrom", 0);
-  if (drive<0)
-    {
-      fprintf(stderr, "can't open drive /dev/cdrom.\n");
-      exit (-1);
-    }
-/*
- * set EJECT_SW
- */
-  err=ioctl(drive, CDROMEJECT_SW, arg);
-  if (err!=0)
-    {
-      fprintf(stderr, "can't set EJECT_SW (error %d).\n", err);
-      exit (-1);
-    }
-  else
-    fprintf(stdout, "EJECT_SW set to %d\n", arg);
-}
-/*===================== end program ========================================*/
-
-Jeff Tranter's "eject" utility can do this, too (and more) for you.
+You can use the appended program "cdtester" to set the auto-eject feature
+during runtime. Jeff Tranter's "eject" utility can do this, too (and more)
+for you.
 
 There is a new ioctl CDROMMULTISESSION to obtain with a user program if
 the CD is an XA disk and - if it is - where the last session starts. The
-following example illustrates how to call it:
-
-/*=================== begin program ========================================*/
-/*
- * ask for multisession redirection info
- *
- * (c) 1994 Eberhard Moenkeberg <emoenke@gwdg.de>
- *          may be used & enhanced freely
- *
- */
-#include <stdio.h>
-#include <sys/ioctl.h>
-#include <linux/cdrom.h>
-
-static struct cdrom_multisession ms_info;
-static int drive;
-static int err;
-
-main(int argc, char *argv[])
-{
-/*
- * open /dev/cdrom
- */
-  drive=open("/dev/cdrom", 0);
-  if (drive<0)
-    {
-      fprintf(stderr, "can't open drive /dev/cdrom.\n");
-      exit (-1);
-    }
-/*
- * 
- */
-  ms_info.addr_format=CDROM_LBA;
-  err=ioctl(drive, CDROMMULTISESSION, &ms_info);
-  if (err!=0)
-    {
-      fprintf(stderr, "CDROMMULTISESSION(lba) returns error %d.\n", err);
-      exit (-1);
-    }
-  else
-	if (ms_info.xa_flag)
-	    fprintf(stdout, "lba: %d\n", ms_info.addr.lba);
-	else
-	    fprintf(stdout, "not an XA disk.\n");
-
-  ms_info.addr_format=CDROM_MSF;
-  err=ioctl(drive, CDROMMULTISESSION, &ms_info);
-  if (err!=0)
-    {
-      fprintf(stderr, "CDROMMULTISESSION(msf) returns error %d.\n", err);
-      exit (-1);
-    }
-  else
-	if (ms_info.xa_flag)
-	    fprintf(stdout, "msf: %02d:%02d:%02d\n",
-				 ms_info.addr.msf.minute,
-				 ms_info.addr.msf.second,
-				 ms_info.addr.msf.frame);
-	else
-	    fprintf(stdout, "not an XA disk.\n");
-}
-/*===================== end program ========================================*/
+"cdtester" program illustrates how to call it.
 
 
 Auto-probing at boot time:
@@ -354,7 +242,8 @@
 SBPCD's auto-probing happens before the initialization of the net drivers.
 Those "hazardous" addresses are excluded from auto-probing; the "kernel 
 command line" feature has to be used during installation if you have your 
-drive at those addresses.
+drive at those addresses. The "module" version is allowed to probe at those
+addresses, too.
 
 The auto-probing looks first at the configured address resp. the address
 submitted by the kernel command line. With this, it is possible to use this
@@ -382,7 +271,7 @@
 without fearing NE2000 cards).
 
 To shorten the auto-probing list to a single entry, set DISTRIBUTION 0 within
-sbpcd.c.
+sbpcd.h.
 
 
 Setting up address and interface type:
@@ -569,3 +458,537 @@
                          D-37083 Goettingen
                          Germany
 ---
+
+
+Appendix -- the "cdtester" utility:
+
+/*
+ * cdtester.c -- test the audio functions of a CD driver
+ *
+ * (c) 1995 Eberhard Moenkeberg <emoenke@gwdg.de>
+ *          published under the GPL
+ *
+ *          made under heavy use of the "Tiny Audio CD Player"
+ *          from Werner Zimmermann <zimmerma@rz.fht-esslingen.de>
+ *          (see linux/drivers/block/README.aztcd)
+ */
+#undef AZT_PRIVATE_IOCTLS /* not supported by every CDROM driver */
+#define SBP_PRIVATE_IOCTLS /* not supported by every CDROM driver */
+
+#include <stdio.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <sys/ioctl.h>
+#include <linux/cdrom.h>
+
+#ifdef AZT_PRIVATE_IOCTLS
+#include <linux/aztcd.h>
+#endif AZT_PRIVATE_IOCTLS
+#ifdef SBP_PRIVATE_IOCTLS
+#include <linux/sbpcd.h>
+#include <linux/fs.h>
+#endif SBP_PRIVATE_IOCTLS
+
+struct cdrom_tochdr hdr;
+struct cdrom_tochdr tocHdr;
+struct cdrom_tocentry TocEntry[101];
+struct cdrom_tocentry entry;
+struct cdrom_multisession ms_info;
+struct cdrom_read_audio read_audio;
+struct cdrom_ti ti;
+struct cdrom_subchnl subchnl;
+struct cdrom_msf msf;
+struct cdrom_volctrl volctrl;
+#ifdef AZT_PRIVATE_IOCTLS
+union
+{
+	struct cdrom_msf msf;
+	unsigned char buf[CD_FRAMESIZE_RAW];
+} azt;
+#endif AZT_PRIVATE_IOCTLS
+int i, i1, i2, i3, j, k;
+unsigned char sequence=0;
+unsigned char command[80];
+unsigned char first=1, last=1;
+char *default_device="/dev/cdrom";
+char dev[20];
+char filename[20];
+int drive;
+int datafile;
+int rc;
+
+void help(void)
+{
+	printf("Available Commands:\n");
+	printf("STOP          s      EJECT        e       QUIT         q\n");
+	printf("PLAY TRACK    t      PAUSE        p       RESUME       r\n");
+	printf("NEXT TRACK    n      REPEAT LAST  l       HELP         h\n");
+	printf("SUBCHANNEL_Q  c      TRACK INFO   i       PLAY AT      a\n");
+	printf("READ          d      READ RAW     w       READ AUDIO   A\n");
+	printf("MS-INFO       M      TOC          T       START        S\n");
+	printf("SET EJECTSW   X      DEVICE       D       DEBUG        Y\n");
+	printf("AUDIO_BUFSIZ  Z      RESET        R       BLKRASET     B\n");
+	printf("SET VOLUME    v      GET VOLUME   V\n");
+}
+
+/*
+ *  convert MSF number (3 bytes only) to Logical_Block_Address 
+ */
+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);
+}
+/*
+ *  convert logical_block_address to m-s-f_number (3 bytes only)
+ */
+void lba2msf(int lba, unsigned char *msf)
+{
+	lba += CD_BLOCK_OFFSET;
+	msf[0] = lba / (CD_SECS*CD_FRAMES);
+	lba %= CD_SECS*CD_FRAMES;
+	msf[1] = lba / CD_FRAMES;
+	msf[2] = lba % CD_FRAMES;
+}
+
+int init_drive(char *dev)
+{
+	unsigned char msf_ent[3];
+
+	/*
+	 * open the device
+	 */
+	drive=open(dev,0);
+	if (drive<0) return (-1);
+	/*
+	 * get TocHeader
+	 */
+	printf("getting TocHeader...\n");
+	rc=ioctl(drive,CDROMREADTOCHDR,&hdr);
+	if (rc!=0)
+	{
+		printf("can't get TocHeader (error %d).\n",rc);
+		return (-2);
+	}
+	else
+		first=hdr.cdth_trk0;
+		last=hdr.cdth_trk1;
+		printf("TocHeader: %d %d\n",hdr.cdth_trk0,hdr.cdth_trk1);
+	/*
+	 * get and display all TocEntries
+	 */
+	printf("getting TocEntries...\n");
+	for (i=1;i<=hdr.cdth_trk1+1;i++)
+	{
+		if (i!=hdr.cdth_trk1+1) TocEntry[i].cdte_track = i;
+		else TocEntry[i].cdte_track = CDROM_LEADOUT;
+		TocEntry[i].cdte_format = CDROM_LBA;
+		rc=ioctl(drive,CDROMREADTOCENTRY,&TocEntry[i]);
+		if (rc!=0)
+		{
+			printf("can't get TocEntry #%d (error %d).\n",i,rc);
+		}
+		else
+		{
+			lba2msf(TocEntry[i].cdte_addr.lba,&msf_ent[0]);
+			if (TocEntry[i].cdte_track==CDROM_LEADOUT)
+			{
+				printf("TocEntry #%02X: %1X %1X %02d:%02d:%02d (lba: 0x%06X) %02X\n",
+				       TocEntry[i].cdte_track,
+				       TocEntry[i].cdte_adr,
+				       TocEntry[i].cdte_ctrl,
+				       msf_ent[0],
+				       msf_ent[1],
+				       msf_ent[2],
+				       TocEntry[i].cdte_addr.lba,
+				       TocEntry[i].cdte_datamode);
+			}
+			else
+			{
+				printf("TocEntry #%02d: %1X %1X %02d:%02d:%02d (lba: 0x%06X) %02X\n",
+				       TocEntry[i].cdte_track,
+				       TocEntry[i].cdte_adr,
+				       TocEntry[i].cdte_ctrl,
+				       msf_ent[0],
+				       msf_ent[1],
+				       msf_ent[2],
+				       TocEntry[i].cdte_addr.lba,
+				       TocEntry[i].cdte_datamode);
+			}
+		}
+	}
+	return (hdr.cdth_trk1); /* number of tracks */
+}
+
+void display(int size,unsigned char *buffer)
+{
+	k=0;
+	getchar();
+	for (i=0;i<(size+1)/16;i++)
+	{
+		printf("%4d:",i*16);
+		for (j=0;j<16;j++)
+		{
+			printf(" %02X",buffer[i*16+j]);
+		}
+		printf("  ");
+		for (j=0;j<16;j++)
+		{
+			if (isalnum(buffer[i*16+j])) 
+				printf("%c",buffer[i*16+j]);
+			else
+				printf(".");
+		}
+		printf("\n"); 
+		k++;
+		if (k>=20)
+		{
+			printf("press ENTER to continue\n");
+			getchar();
+			k=0;
+		}
+	} 
+} 
+
+main(int argc, char *argv[])
+{
+	printf("\nTesting tool for a CDROM driver's audio functions V0.1\n");
+	printf("(C) 1995 Eberhard Moenkeberg <emoenke@gwdg.de>\n");
+	printf("initializing...\n");
+	
+	rc=init_drive(default_device);
+	if (rc<0) printf("could not open %s (rc=%d).\n",default_device,rc);
+	help();
+	while (1)
+	{
+		printf("Give a one-letter command (h = help): ");
+		scanf("%s",command);
+		command[1]=0;
+		switch (command[0])
+		{
+		case 'D':
+			printf("device name (f.e. /dev/sbpcd3): ? ");
+			scanf("%s",&dev);
+			close(drive);
+			rc=init_drive(dev);
+			if (rc<0) printf("could not open %s (rc %d).\n",dev,rc);
+			break;
+		case 'e':
+			rc=ioctl(drive,CDROMEJECT);
+			if (rc<0) printf("CDROMEJECT: rc=%d.\n",rc);
+			break;
+		case 'p':
+			rc=ioctl(drive,CDROMPAUSE);
+			if (rc<0) printf("CDROMPAUSE: rc=%d.\n",rc);
+			break;
+		case 'r':
+			rc=ioctl(drive,CDROMRESUME);
+			if (rc<0) printf("CDROMRESUME: rc=%d.\n",rc);
+			break;
+		case 's':
+			rc=ioctl(drive,CDROMSTOP);
+			if (rc<0) printf("CDROMSTOP: rc=%d.\n",rc);
+			break;
+		case 'S':
+			rc=ioctl(drive,CDROMSTART);
+			if (rc<0) printf("CDROMSTART: rc=%d.\n",rc);
+			break;
+		case 't':
+			rc=ioctl(drive,CDROMREADTOCHDR,&tocHdr);
+			if (rc<0)
+			{
+				printf("CDROMREADTOCHDR: rc=%d.\n",rc);
+				break;
+			}
+			first=tocHdr.cdth_trk0;
+			last= tocHdr.cdth_trk1;
+			if ((first==0)||(first>last))
+			{
+				printf ("--got invalid TOC data.\n");
+			}
+			else
+			{
+				printf("--enter track number(first=%d, last=%d): ",first,last);
+				scanf("%d",&i1);
+				ti.cdti_trk0=i1;
+				if (ti.cdti_trk0<first) ti.cdti_trk0=first;
+				if (ti.cdti_trk0>last) ti.cdti_trk0=last;
+				ti.cdti_ind0=0;
+				ti.cdti_trk1=last;
+				ti.cdti_ind1=0;
+				rc=ioctl(drive,CDROMSTOP);
+				rc=ioctl(drive,CDROMPLAYTRKIND,&ti);
+				if (rc<0) printf("CDROMPLAYTRKIND: rc=%d.\n",rc);
+			}
+			break;
+		case 'n':
+			rc=ioctl(drive,CDROMSTOP);
+			if (++ti.cdti_trk0>last) ti.cdti_trk0=last;
+			ti.cdti_ind0=0;
+			ti.cdti_trk1=last;
+			ti.cdti_ind1=0;
+			rc=ioctl(drive,CDROMPLAYTRKIND,&ti);
+			if (rc<0) printf("CDROMPLAYTRKIND: rc=%d.\n",rc);
+			break;
+		case 'l':
+			rc=ioctl(drive,CDROMSTOP);
+			if (--ti.cdti_trk0<first) ti.cdti_trk0=first;
+			ti.cdti_ind0=0;
+			ti.cdti_trk1=last;
+			ti.cdti_ind1=0;
+			rc=ioctl(drive,CDROMPLAYTRKIND,&ti);
+			if (rc<0) printf("CDROMPLAYTRKIND: rc=%d.\n",rc);
+			break;
+		case 'c':
+			subchnl.cdsc_format=CDROM_MSF;
+			rc=ioctl(drive,CDROMSUBCHNL,&subchnl);
+			if (rc<0) printf("CDROMSUBCHNL: rc=%d.\n",rc);
+			else
+			{
+				printf("AudioStatus:%s  Track:%d  Mode:%d  MSF=%02d:%02d:%02d\n",
+				       subchnl.cdsc_audiostatus==CDROM_AUDIO_PLAY ? "PLAYING":"NOT PLAYING",
+				       subchnl.cdsc_trk,subchnl.cdsc_adr, 
+				       subchnl.cdsc_absaddr.msf.minute,
+				       subchnl.cdsc_absaddr.msf.second,
+				       subchnl.cdsc_absaddr.msf.frame);
+			}
+			break;              
+		case 'i':
+			printf("Track No.: ");
+			scanf("%d",&i1);
+			entry.cdte_track=i1;
+			if (entry.cdte_track<first) entry.cdte_track=first;
+			if (entry.cdte_track>last)  entry.cdte_track=last;
+			entry.cdte_format=CDROM_MSF;
+			rc=ioctl(drive,CDROMREADTOCENTRY,&entry);
+			if (rc<0) printf("CDROMREADTOCENTRY: rc=%d.\n",rc);
+			else
+			{
+				printf("Mode %d Track, starts at %02d:%02d:%02d\n",
+				       entry.cdte_adr,
+				       entry.cdte_addr.msf.minute,
+				       entry.cdte_addr.msf.second,
+				       entry.cdte_addr.msf.frame);
+			}
+			break;
+		case 'a':
+			printf("Address (min:sec:frm)  ");
+			scanf("%d:%d:%d",&i1,&i2,&i3);
+			msf.cdmsf_min0=i1;
+			msf.cdmsf_sec0=i2;
+			msf.cdmsf_frame0=i3;
+			if (msf.cdmsf_sec0>59) msf.cdmsf_sec0=59;
+			if (msf.cdmsf_frame0>74) msf.cdmsf_frame0=74;
+			lba2msf(TocEntry[last+1].cdte_addr.lba-1,&msf.cdmsf_min1);
+			rc=ioctl(drive,CDROMSTOP);
+			rc=ioctl(drive,CDROMPLAYMSF,&msf);
+			if (rc<0) printf("CDROMPLAYMSF: rc=%d.\n",rc);
+			break;
+#ifdef AZT_PRIVATE_IOCTLS /*not supported by every CDROM driver*/
+		case 'd':
+			printf("Address (min:sec:frm)  ");
+			scanf("%d:%d:%d",&i1,&i2,&i3);
+			azt.msf.cdmsf_min0=i1;
+			azt.msf.cdmsf_sec0=i2;
+			azt.msf.cdmsf_frame0=i3;
+			if (azt.msf.cdmsf_sec0>59) azt.msf.cdmsf_sec0=59;
+			if (azt.msf.cdmsf_frame0>74) azt.msf.cdmsf_frame0=74;
+			rc=ioctl(drive,CDROMREADMODE1,&azt.msf);
+			if (rc<0) printf("CDROMREADMODE1: rc=%d.\n",rc);
+			else display(CD_FRAMESIZE,azt.buf);
+			break;
+		case 'w':
+			printf("Address (min:sec:frame)  ");
+			scanf("%d:%d:%d",&i1,&i2,&i3);
+			azt.msf.cdmsf_min0=i1;
+			azt.msf.cdmsf_sec0=i2;
+			azt.msf.cdmsf_frame0=i3;
+			if (azt.msf.cdmsf_sec0>59) azt.msf.cdmsf_sec0=59;
+			if (azt.msf.cdmsf_frame0>74) azt.msf.cdmsf_frame0=74;
+			rc=ioctl(drive,CDROMREADMODE2,&azt.msf);
+			if (rc<0) printf("CDROMREADMODE2: rc=%d.\n",rc);
+			else display(CD_FRAMESIZE_RAW,azt.buf); /* currently only 2336 */
+			break;  
+#endif
+		case 'v':
+			printf("--Channel 0 (Left)  (0-255): ");
+			scanf("%d",&i1);
+			volctrl.channel0=i1;
+			printf("--Channel 1 (Right) (0-255): ");
+			scanf("%d",&i1);
+			volctrl.channel1=i1;
+			volctrl.channel2=0;
+			volctrl.channel3=0;
+			rc=ioctl(drive,CDROMVOLCTRL,&volctrl);
+			if (rc<0) printf("CDROMVOLCTRL: rc=%d.\n",rc);
+			break;  
+		case 'q':
+			close(drive);
+			exit(0);
+		case 'h':
+			help();
+			break;
+		case 'T': /* display TOC entry - without involving the driver */
+			scanf("%d",&i);
+			if ((i<hdr.cdth_trk0)||(i>hdr.cdth_trk1))
+				printf("invalid track number.\n");
+			else
+				printf("TocEntry %02d: adr=%01X ctrl=%01X msf=%02d:%02d:%02d mode=%02X\n",
+				       TocEntry[i].cdte_track,
+				       TocEntry[i].cdte_adr,
+				       TocEntry[i].cdte_ctrl,
+				       TocEntry[i].cdte_addr.msf.minute,
+				       TocEntry[i].cdte_addr.msf.second,
+				       TocEntry[i].cdte_addr.msf.frame,
+				       TocEntry[i].cdte_datamode);
+			break;
+		case 'A': /* read audio data into file */
+			printf("Address (min:sec:frm) ? ");
+			scanf("%d:%d:%d",&i1,&i2,&i3);
+			read_audio.addr.msf.minute=i1;
+			read_audio.addr.msf.second=i2;
+			read_audio.addr.msf.frame=i3;
+			read_audio.addr_format=CDROM_MSF;
+			printf("# of frames ? ");
+			scanf("%d",&i1);
+			read_audio.nframes=i1;
+			k=read_audio.nframes*CD_FRAMESIZE_RAW;
+			read_audio.buf=malloc(k);
+			if (read_audio.buf==NULL)
+			{
+				printf("can't malloc %d bytes.\n",k);
+				break;
+			}
+			sprintf(filename,"audio_%02d%02d%02d_%02d.%02d\0",
+				read_audio.addr.msf.minute,
+				read_audio.addr.msf.second,
+				read_audio.addr.msf.frame,
+				read_audio.nframes,
+				++sequence);
+			datafile=creat(filename, 0755);
+			if (datafile<0)
+			{
+				printf("can't open datafile %s.\n",filename);
+				break;
+			}
+			rc=ioctl(drive,CDROMREADAUDIO,&read_audio);
+			if (rc!=0)
+			{
+				printf("CDROMREADAUDIO: rc=%d.\n",rc);
+			}
+			else
+			{
+				rc=write(datafile,&read_audio.buf,k);
+				if (rc!=k) printf("datafile I/O error (%d).\n",rc);
+			}
+			close(datafile);
+			break;
+		case 'X': /* set EJECT_SW (0: disable, 1: enable auto-ejecting) */
+			scanf("%d",&i);
+			rc=ioctl(drive,CDROMEJECT_SW,i);
+			if (rc!=0)
+				printf("CDROMEJECT_SW: rc=%d.\n",rc);
+			else
+				printf("EJECT_SW set to %d\n",i);
+			break;
+		case 'M': /* get the multisession redirection info */
+			ms_info.addr_format=CDROM_LBA;
+			rc=ioctl(drive,CDROMMULTISESSION,&ms_info);
+			if (rc!=0)
+			{
+				printf("CDROMMULTISESSION(lba): rc=%d.\n",rc);
+			}
+			else
+			{
+				if (ms_info.xa_flag) printf("MultiSession offset (lba): %d (0x%06X)\n",ms_info.addr.lba,ms_info.addr.lba);
+				else
+				{
+					printf("this CD is not an XA disk.\n");
+					break;
+				}
+			}
+			ms_info.addr_format=CDROM_MSF;
+			rc=ioctl(drive,CDROMMULTISESSION,&ms_info);
+			if (rc!=0)
+			{
+				printf("CDROMMULTISESSION(msf): rc=%d.\n",rc);
+			}
+			else
+			{
+				if (ms_info.xa_flag)
+					printf("MultiSession offset (msf): %02d:%02d:%02d (0x%02X%02X%02X)\n",
+					       ms_info.addr.msf.minute,
+					       ms_info.addr.msf.second,
+					       ms_info.addr.msf.frame,
+					       ms_info.addr.msf.minute,
+					       ms_info.addr.msf.second,
+					       ms_info.addr.msf.frame);
+				else printf("this CD is not an XA disk.\n");
+			}
+			break;
+#ifdef SBP_PRIVATE_IOCTLS
+		case 'Y': /* set the driver's message level */
+#if 0 /* not implemented yet */
+			printf("enter switch name (f.e. DBG_CMD): ");
+			scanf("%s",&dbg_switch);
+			j=get_dbg_num(dbg_switch);
+#else
+			printf("enter DDIOCSDBG switch number: ");
+			scanf("%d",&j);
+#endif
+			printf("enter 0 for \"off\", 1 for \"on\": ");
+			scanf("%d",&i);
+			if (i==0) j|=0x80;
+			printf("calling \"ioctl(drive,DDIOCSDBG,%d)\"\n",j);
+			rc=ioctl(drive,DDIOCSDBG,j);
+			printf("DDIOCSDBG: rc=%d.\n",rc);
+			break;
+		case 'Z': /* set the audio buffer size */
+			printf("# frames wanted: ? ");
+			scanf("%d",&j);
+			rc=ioctl(drive,CDROMAUDIOBUFSIZ,j);
+			printf("%d frames granted.\n",rc);
+			break;
+		case 'V':
+			rc=ioctl(drive,CDROMVOLREAD,&volctrl);
+			if (rc<0) printf("CDROMVOLCTRL: rc=%d.\n",rc);
+			printf("Volume: channel 0 (left) %d, channel 1 (right) %d\n",volctrl.channel0,volctrl.channel1);
+			break;  
+		case 'R':
+			rc=ioctl(drive,CDROMRESET);
+			if (rc<0) printf("CDROMRESET: rc=%d.\n",rc);
+			break;
+		case 'B': /* set the driver's (?) read ahead value */
+			printf("enter read-ahead size: ? ");
+			scanf("%d",&i);
+			rc=ioctl(drive,BLKRASET,i);
+			if (rc<0) printf("BLKRASET: rc=%d.\n",rc);
+			break;
+#endif SBP_PRIVATE_IOCTLS
+		default:
+			printf("unknown command: \"%s\".\n",command);
+			break;
+		}
+	}
+}
+/*==========================================================================*/
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file. 
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
+
diff -u --recursive --new-file v1.2.7/linux/drivers/block/sbpcd.c linux/drivers/block/sbpcd.c
--- v1.2.7/linux/drivers/block/sbpcd.c	Wed Mar 29 06:52:57 1995
+++ linux/drivers/block/sbpcd.c	Tue May  2 07:26:00 1995
@@ -6,15 +6,12 @@
  *            Panasonic CI-101P.
  *            Also for the Longshine LCS-7260 drive.
  *            Also for the IBM "External ISA CD-Rom" drive.
- *            Still not for the CreativeLabs CD200 drive (but should work soon).
- *            Not for the TEAC CD-55A drive (separate project now).
+ *            Also for the CreativeLabs CD200 drive (but I still need some
+ *            detailed bug reports).
+ *            Also for the TEAC CD-55A drive.
  *            Not for Funai or Sanyo drives.
  *
- *  NOTE:     This is release 3.4.
- *            It works with my SbPro & drive CR-521 V2.11 from 2/92
- *            and with the CR-562-B V0.75 on a "naked" Panasonic
- *            CI-101P interface. And vice versa. 
- *  
+ *  NOTE:     This is release 3.6.
  *
  *  VERSION HISTORY
  *
@@ -31,8 +28,8 @@
  *
  *  0.4  use MAJOR 25 definitely.
  *       Almost total re-design to support double-speed drives and
- *       "naked" (no sound) interface cards.
- *       Flow control should be exact now (tell me if not).
+ *       "naked" (no sound) interface cards ("LaserMate" interface type).
+ *       Flow control should be exact now.
  *       Don't occupy the SbPro IRQ line (not needed either); will
  *       live together with Hannu Savolainen's sndkit now.
  *	 Speeded up data transfer to 150 kB/sec, with help from Kai
@@ -55,12 +52,12 @@
  *       Formal redesign to add DDI debugging.
  *       There are still flaws in IOCTL (workman with double speed drive).
  *
- *  1.0  Added support for all drive ids (0...3, no longer only 0)
+ *  1.0  Added support for all drive IDs (0...3, no longer only 0)
  *       and up to 4 drives on one controller.
  *       Added "#define MANY_SESSION" for "old" multi session CDs.
  *
  *  1.1  Do SpinUp for new drives, too.
- *       Revised for clean compile under "old" kernels (pl9).
+ *       Revised for clean compile under "old" kernels (0.99pl9).
  *
  *  1.2  Found the "workman with double-speed drive" bug: use the driver's
  *       audio_state, not what the drive is reporting with ReadSubQ.
@@ -68,8 +65,8 @@
  *  1.3  Minor cleanups.
  *       Refinements regarding Workman.
  *
- *  1.4  Read XA disks (PhotoCDs) with "old" drives, too (but possibly only
- *       the first session - I could not try a "multi-session" CD yet).
+ *  1.4  Read XA disks (PhotoCDs) with "old" drives, too (but only the first
+ *       session - no chance to fully access a "multi-session" CD).
  *       This currently still is too slow (50 kB/sec) - but possibly
  *       the old drives won't do it faster.
  *       Implemented "door (un)lock" for new drives (still does not work
@@ -123,7 +120,7 @@
  *       Implemented "close tray" (done automatically during open).
  *
  *  2.4  Use different names for device registering.
- *       
+ *
  *  2.5  Added "#if EJECT" code (default: enabled) to automatically eject
  *       the tray during last call to "sbpcd_release".
  *       Added "#if JUKEBOX" code (default: disabled) to automatically eject
@@ -132,11 +129,11 @@
  *       SOUND_BASE (in sbpcd.h) accordingly (default: disabled).
  *
  *  2.6  Nothing new.  
- *       
+ *
  *  2.7  Added CDROMEJECT_SW ioctl to set the "EJECT" behavior on the fly:
  *       0 disables, 1 enables auto-ejecting. Useful to keep the tray in
  *       during shutdown.
- *       
+ *
  *  2.8  Added first support (still BETA, I need feedback or a drive) for
  *       the Longshine LCS-7260 drives. They appear as double-speed drives
  *       using the "old" command scheme, extended by tray control and door
@@ -148,8 +145,8 @@
  *       16..20).
  *       Changed default of the "JUKEBOX" define. If you use this default,
  *       your tray will eject if you try to mount without a disk in. Next
- *       mount command will insert the tray - so, just insert a disk. ;-)
- *       
+ *       mount command will insert the tray - so, just fill in a disk. ;-)
+ *
  *  2.9  Fulfilled the Longshine LCS-7260 support; with great help and
  *       experiments by Serge Robyns.
  *       First attempts to support the TEAC CD-55A drives; but still not
@@ -176,10 +173,10 @@
  *       jumpered drive ID. This implies modifications to the /dev/sbpcd*
  *       entries for some people, but will help the DAU (german TLA, english:
  *       "newbie", maybe ;-) to install his "first" system from a CD.
- *     
+ *
  *  3.2  Still testing with CD200 and CD-55A drives.
  *
- *  3.3  Working with CD200 support. Maybe a simple read is already possible.
+ *  3.3  Working with CD200 support.
  *
  *  3.4  Auto-probing stops if an address of 0 is seen (to be entered with
  *       the kernel command line).
@@ -187,20 +184,40 @@
  *       disabled, and the internal read ahead data buffer has a reduced size
  *       of 4 kB; so, throughput may be reduced a little bit with slow CPUs.
  *
+ *  3.5  Provisions to handle weird photoCDs which have an interrupted
+ *       "formatting" immediately after the last frames of some files: simply
+ *       never "read ahead" with MultiSession CDs. By this, CPU usage may be
+ *       increased with those CDs, and there may be a loss in speed.
+ *       Re-structured the messaging system.
+ *       The "loadable" version no longer has a limited READ_AUDIO buffer
+ *       size.
+ *       Removed "MANY_SESSION" handling for "old" multi session CDs.
+ *       Added "private" IOCTLs CDROMRESET and CDROMVOLREAD.
+ *       Started again to support the TEAC CD-55A drives, now that I found
+ *       the money for "my own" drive. ;-)
+ *       The TEAC CD-55A support is fairly working now.
+ *       I have measured that the drive "delivers" at 600 kB/sec (even with
+ *       bigger requests than the drive's 64 kB buffer can satisfy), but
+ *       the "real" rate does not exceed 520 kB/sec at the moment. 
+ *       Caused by the various changes to build in TEAC support, the timed
+ *       loops are de-optimized at the moment (less throughput with CR-52x
+ *       drives, and the TEAC will give speed only with SBP_BUFFER_FRAMES 64).
+ *
+ *  3.6  Fixed TEAC data read problems with SbPro interfaces.
+ *       Initial size of the READ_AUDIO buffer is 0. Can get set to any size
+ *       during runtime.
+ *
  *  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
  *     thread which brought additional hints and bug fixes.
- * 
  *
  *   Copyright (C) 1993, 1994, 1995  Eberhard Moenkeberg <emoenke@gwdg.de>
  *
@@ -232,10 +249,12 @@
 #ifdef MODULE
 #include <linux/module.h>
 #include <linux/version.h>
-#include <linux/malloc.h>
 #ifndef CONFIG_MODVERSIONS
 char kernel_version[]=UTS_RELEASE;
 #endif
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
 #endif MODULE
 
 #include <linux/errno.h>
@@ -247,12 +266,12 @@
 #include <linux/cdrom.h>
 #include <linux/ioport.h>
 #include <linux/major.h> 
-#include <linux/sbpcd.h>
 #include <linux/string.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/segment.h>
 #include <stdarg.h>
+#include <linux/sbpcd.h>
 
 #if !(SBPCD_ISSUE-1)
 #define MAJOR_NR MATSUSHITA_CDROM_MAJOR
@@ -267,38 +286,9 @@
 #define MAJOR_NR MATSUSHITA_CDROM4_MAJOR /* fourth driver issue */
 #endif
 
-#ifdef MODULE
-#include "/usr/src/linux/drivers/block/blk.h"
-#else
 #include "blk.h"
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif MODULE
-
-#define VERSION "3.4 Eberhard Moenkeberg <emoenke@gwdg.de>"
-
-/*
- *
- */
-#define READ_AUDIO 4 /* max. number of audio frames to read with one */
-                     /* request (allocates n* 2352 bytes kernel memory!) */
-#define JUKEBOX 1 /* tray control: eject tray if no disk is in */
-#define EJECT 1 /* tray control: eject tray after last use */
-#define LONG_TIMING 0 /* test against timeouts with "gold" CDs on CR-521 */
-#define MANY_SESSION 0 /* this will conflict with "true" multi-session! */
-#undef  FUTURE
-#define WORKMAN 1 /* some testing stuff to make it better */
-#define CDMKE /* makes timing independent of processor speed */
-
-#undef XA_TEST1
-#define XA_TEST2
-
-#define TEST_UPC 0
-#define SPEA_TEST 0
-#define PRINTK_BUG 0
-#define TEST_STI 0
 
-#define DISTRIBUTION 1 /* I use it with a 0 here */
+#define VERSION "v3.6-1 Eberhard Moenkeberg <emoenke@gwdg.de>"
 
 #if 0
 #define INLINE
@@ -328,11 +318,6 @@
 #define SBPCD_INIT(a,b) sbpcd4_init(a,b)
 #endif
 /*==========================================================================*/
-#if MANY_SESSION
-#undef LONG_TIMING
-#define LONG_TIMING 1
-#endif
-/*==========================================================================*/
 #if SBPCD_DIS_IRQ
 #define SBPCD_CLI cli()
 #define SBPCD_STI sti()
@@ -351,58 +336,58 @@
  * The possibly conflicting ethernet card addresses get NOT probed 
  * by default - to minimize the hang possibilities. 
  *
- * The SB Pro addresses get "mirrored" at 0x6xx - to avoid a type error,
- * the 0x2xx-addresses must get checked before 0x6xx.
+ * The SB Pro addresses get "mirrored" at 0x6xx and some more locations - to
+ * avoid a type error, the 0x2xx-addresses must get checked before 0x6xx.
  *
  * send mail to emoenke@gwdg.de if your interface card is not FULLY
  * represented here.
  */
 #if !(SBPCD_ISSUE-1)
-static int sbpcd_probe[] = 
+static int sbpcd[] = 
 {
-  CDROM_PORT, SBPRO, /* probe with user's setup first */
+	CDROM_PORT, SBPRO, /* probe with user's setup first */
 #if DISTRIBUTION
-  0x230, 1, /* Soundblaster Pro and 16 (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, WDH-7001C, Galaxy, Reveal (other default),
-               Longshine LCS-6853 (default) */
-  0x338, 0, /* Reveal Sound Wave 32 card model #SC600 */
-  0x340, 0, /* Mozart sound card (default), Lasermate, CI-101P */
-  0x360, 0, /* Lasermate, CI-101P */
-  0x270, 1, /* Soundblaster 16 */
-  0x670, 0, /* "sound card #9" */
-  0x690, 0, /* "sound card #9" */
-  0x330, 2, /* SPEA Media FX (default) */
-  0x320, 2, /* SPEA Media FX */
-  0x340, 2, /* SPEA Media FX */
-  0x634, 0, /* some newer sound cards */
-  0x638, 0, /* some newer sound cards */
-/* due to incomplete address decoding of the SbPro card, these must be last */
-  0x630, 0, /* "sound card #9" (default) */
-  0x650, 0, /* "sound card #9" */
+	0x230, 1, /* Soundblaster Pro and 16 (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, WDH-7001C, Galaxy, Reveal (other default),
+		     Longshine LCS-6853 (default) */
+	0x338, 0, /* Reveal Sound Wave 32 card model #SC600 */
+	0x340, 0, /* Mozart sound card (default), Lasermate, CI-101P */
+	0x360, 0, /* Lasermate, CI-101P */
+	0x270, 1, /* Soundblaster 16 */
+	0x670, 0, /* "sound card #9" */
+	0x690, 0, /* "sound card #9" */
+	0x330, 2, /* SPEA Media FX (default) */
+	0x320, 2, /* SPEA Media FX */
+	0x340, 2, /* SPEA Media FX */
+	0x634, 0, /* some newer sound cards */
+	0x638, 0, /* some newer sound cards */
+	0x230, 1, /* some newer sound cards */
+	/* due to incomplete address decoding of the SbPro card, these must be last */
+	0x630, 0, /* "sound card #9" (default) */
+	0x650, 0, /* "sound card #9" */
 #ifdef MODULE
-/*
- * some "hazardous" locations (no harm with the loadable version)
- * (will stop the bus if a NE2000 ethernet card resides at offset -0x10)
- */
-  0x330, 0, /* Lasermate, CI-101P, WDH-7001C */
-  0x350, 0, /* Lasermate, CI-101P */
-  0x350, 2, /* SPEA Media FX */
-  0x370, 0, /* Lasermate, CI-101P */
-  0x290, 1, /* Soundblaster 16 */
-  0x310, 0, /* Lasermate, CI-101P, WDH-7001C */
+	/*
+	 * some "hazardous" locations (no harm with the loadable version)
+	 * (will stop the bus if a NE2000 ethernet card resides at offset -0x10)
+	 */
+	0x330, 0, /* Lasermate, CI-101P, WDH-7001C */
+	0x350, 0, /* Lasermate, CI-101P */
+	0x350, 2, /* SPEA Media FX */
+	0x370, 0, /* Lasermate, CI-101P */
+	0x290, 1, /* Soundblaster 16 */
+	0x310, 0, /* Lasermate, CI-101P, WDH-7001C */
 #endif MODULE
 #endif DISTRIBUTION
 };
 #else
-static int sbpcd_probe[] = {CDROM_PORT, SBPRO}; /* probe with user's setup only */
+static int sbpcd[] = {CDROM_PORT, SBPRO}; /* probe with user's setup only */
 #endif
 
-#define NUM_PROBE  (sizeof(sbpcd_probe) / sizeof(int))
-
+#define NUM_PROBE  (sizeof(sbpcd) / sizeof(int))
 
 /*==========================================================================*/
 /*
@@ -425,9 +410,15 @@
 /*
  * the forward references:
  */
+static void sbp_sleep(u_int);
+static void mark_timeout_delay(u_long);
+static void mark_timeout_data(u_long);
+#if 0
+static void mark_timeout_audio(u_long);
+#endif
 static void sbp_read_cmd(void);
 static int sbp_data(void);
-static int cmd_out(int);
+static int cmd_out(void);
 static int DiskInfo(void);
 static int sbpcd_chk_disk_change(dev_t);
 
@@ -445,11 +436,11 @@
  * (1<<DBG_TOC)  tell TocEntry values
  * (1<<DBG_IOC)  ioctl trace
  * (1<<DBG_STA)  "ResponseStatus" trace
- * (1<<DBG_ERR)  "xx_ReadError" trace
+ * (1<<DBG_ERR)  "cc_ReadError" trace
  * (1<<DBG_CMD)  "cmd_out" trace
  * (1<<DBG_WRN)  give explanation before auto-probing
  * (1<<DBG_MUL)  multi session code test
- * (1<<DBG_ID)   "drive_id != 0" test code
+ * (1<<DBG_IDX)  "drive_id != 0" test code
  * (1<<DBG_IOX)  some special information
  * (1<<DBG_DID)  drive ID test
  * (1<<DBG_RES)  drive reset info
@@ -457,24 +448,24 @@
  * (1<<DBG_IOS)  ioctl trace: "subchannel"
  * (1<<DBG_IO2)  ioctl trace: general
  * (1<<DBG_UPC)  show UPC info
- * (1<<DBG_XA)   XA mode debugging
+ * (1<<DBG_XA1)  XA mode debugging
  * (1<<DBG_LCK)  door (un)lock info
- * (1<<DBG_SQ)   dump SubQ frame
+ * (1<<DBG_SQ1)   dump SubQ frame
  * (1<<DBG_AUD)  "read audio" debugging
  * (1<<DBG_SEQ)  Sequoia interface configuration trace
  * (1<<DBG_LCS)  Longshine LCS-7260 debugging trace
  * (1<<DBG_CD2)  MKE CD200 debugging trace
+ * (1<<DBG_TEA)  TEAC CD-55A debugging trace
+ * (1<<DBG_TE2)  TEAC CD-55A debugging trace, 2nd level
  * (1<<DBG_000)  unnecessary information
  */
 #if DISTRIBUTION
-static int sbpcd_debug =  (1<<DBG_INF) |
-                          (1<<DBG_WRN) |
-                          (1<<DBG_MUL);
+static int sbpcd_debug = (1<<DBG_INF);
 #else
-static int sbpcd_debug =  (1<<DBG_INF) |
-                          (1<<DBG_TOC) |
-                          (1<<DBG_MUL) |
-                          (1<<DBG_UPC);
+static int sbpcd_debug = ((1<<DBG_INF) |
+			  (1<<DBG_TOC) |
+			  (1<<DBG_MUL) |
+			  (1<<DBG_UPC));
 #endif DISTRIBUTION
 
 static int sbpcd_ioaddr = CDROM_PORT;	/* default I/O base address */
@@ -493,12 +484,16 @@
 static struct cdrom_read_audio read_audio;
 static struct cdrom_multisession ms_info;
 
+static unsigned char msgnum=0;
+static char msgbuf[80];
+
 static char *str_sb = "SoundBlaster";
 static char *str_sb_l = "soundblaster";
 static char *str_lm = "LaserMate";
 static char *str_sp = "SPEA";
 static char *str_sp_l = "spea";
 char *type;
+
 #if !(SBPCD_ISSUE-1)
 static char *major_name="sbpcd";
 #endif
@@ -519,21 +514,17 @@
 #endif FUTURE
 
 /*==========================================================================*/
-#ifdef MODULE
-/* some restrictions for the "loadable" version */
-#define SBP_BUFFER_FRAMES 2 /* kmalloc() limit */
-#define SBP_BUFFER_AUDIO_FRAMES 0
-#else
-#define SBP_BUFFER_FRAMES 4 /* driver's own read_ahead, data mode */
-#define SBP_BUFFER_AUDIO_FRAMES READ_AUDIO /* buffer for read audio mode */
-#endif MODULE
+#define SBP_BUFFER_FRAMES 8 /* driver's own read_ahead, data mode */
 /*==========================================================================*/
 
 static u_char family0[]="MATSHITA"; /* MKE CR-52x */
-static u_char family1[]="CR-56"; /* MKE CR-56x */
-static u_char family2[]="CD200"; /* MKE CD200 */
+static u_char family1[]="CR-56";    /* MKE CR-56x */
+static u_char family2[]="CD200";    /* MKE CD200 */
 static u_char familyL[]="LCS-7260"; /* Longshine LCS-7260 */
+static u_char familyT[]="CD-55";    /* TEAC CD-55A */
 
+static u_int recursion=0; /* internal testing only */
+static u_int fatal_err=0; /* internal testing only */
 static u_int response_count=0;
 static u_int flags_cmd_out;
 static u_char cmd_type=0;
@@ -542,8 +533,13 @@
 static u_char xa_head_buf[CD_XA_HEAD];
 static u_char xa_tail_buf[CD_XA_TAIL];
 
+static u_long timeout;
 static u_char busy_data=0, busy_audio=0; /* true semaphores would be safer */
-static u_char timed_out=0;
+static volatile u_char timed_out_delay=0;
+static volatile u_char timed_out_data=0;
+#if 0
+static volatile u_char timed_out_audio=0;
+#endif
 static u_int datarate= 1000000;
 static u_int maxtim16=16000000;
 static u_int maxtim04= 4000000;
@@ -562,7 +558,7 @@
 /*==========================================================================*/
 
 static int ndrives=0;
-static u_char drv_pattern[4]={speed_auto,speed_auto,speed_auto,speed_auto};
+static u_char drv_pattern[NR_SBPCD]={speed_auto,speed_auto,speed_auto,speed_auto};
 static int sbpcd_blocksizes[NR_SBPCD] = {0, };
 
 /*==========================================================================*/
@@ -572,163 +568,211 @@
 static int d=0; /* DriveStruct index: drive number */
 
 static struct {
-  char drv_id; /* "jumpered" drive ID or -1 */
-  char drv_sel; /* drive select lines bits */
-
-  char drive_model[9];
-  u_char firmware_version[4];
-  char f_eject; /* auto-eject flag: 0 or 1 */
-  u_char *sbp_buf; /* Pointer to internal data buffer,
-                           space allocated during sbpcd_init() */
-  int sbp_first_frame;  /* First frame in buffer */
-  int sbp_last_frame;   /* Last frame in buffer  */
-  int sbp_read_frames;   /* Number of frames being read to buffer */
-  int sbp_current;       /* Frame being currently read */
-
-  u_char mode;           /* read_mode: READ_M1, READ_M2, READ_SC, READ_AU */
-  u_char *aud_buf;                  /* Pointer to audio data buffer,
-                                 space allocated during sbpcd_init() */
-  u_char drv_type;
-  u_char drv_options;
-  u_char status_byte;
-  u_char diskstate_flags;
-  u_char sense_byte;
-  
-  u_char CD_changed;
-  u_char open_count;
-  u_char error_byte;
-  
-  u_char f_multisession;
-  u_int lba_multi;
-  int first_session;
-  int last_session;
-  
-  u_char audio_state;
-  u_int pos_audio_start;
-  u_int pos_audio_end;
-  char vol_chan0;
-  u_char vol_ctrl0;
-  char vol_chan1;
-  u_char vol_ctrl1;
+	char drv_id;           /* "jumpered" drive ID or -1 */
+	char drv_sel;          /* drive select lines bits */
+	
+	char drive_model[9];
+	u_char firmware_version[4];
+	char f_eject;          /* auto-eject flag: 0 or 1 */
+	u_char *sbp_buf;       /* Pointer to internal data buffer,
+				  space allocated during sbpcd_init() */
+	u_int sbp_bufsiz;      /* size of sbp_buf (# of frames) */
+	int sbp_first_frame;   /* First frame in buffer */
+	int sbp_last_frame;    /* Last frame in buffer  */
+	int sbp_read_frames;   /* Number of frames being read to buffer */
+	int sbp_current;       /* Frame being currently read */
+	
+	u_char mode;           /* read_mode: READ_M1, READ_M2, READ_SC, READ_AU */
+	u_char *aud_buf;       /* Pointer to audio data buffer,
+				  space allocated during sbpcd_init() */
+	u_int sbp_audsiz;      /* size of aud_buf (# of raw frames) */
+	u_char drv_type;
+	u_char drv_options;
+	int status_bits;
+	u_char diskstate_flags;
+	u_char sense_byte;
+	
+	u_char CD_changed;
+	char open_count;
+	u_char error_byte;
+	
+	u_char f_multisession;
+	u_int lba_multi;
+	int first_session;
+	int last_session;
+	
+	u_char audio_state;
+	u_int pos_audio_start;
+	u_int pos_audio_end;
+	char vol_chan0;
+	u_char vol_ctrl0;
+	char vol_chan1;
+	u_char vol_ctrl1;
 #if 000 /* no supported drive has it */
-  char vol_chan2;
-  u_char vol_ctrl2;
-  char vol_chan3;
-  u_char vol_ctrl3;
+	char vol_chan2;
+	u_char vol_ctrl2;
+	char vol_chan3;
+	u_char vol_ctrl3;
 #endif 000
-  
-  u_char SubQ_ctl_adr;
-  u_char SubQ_trk;
-  u_char SubQ_pnt_idx;
-  u_int SubQ_run_tot;
-  u_int SubQ_run_trk;
-  u_char SubQ_whatisthis;
-  
-  u_char UPC_ctl_adr;
-  u_char UPC_buf[7];
-  
-  int CDsize_blk;
-  int frame_size;
-  int CDsize_frm;
-  
-  u_char xa_byte; /* 0x20: XA capabilities */
-  u_char n_first_track; /* binary */
-  u_char n_last_track; /* binary (not bcd), 0x01...0x63 */
-  u_int size_msf; /* time of whole CD, position of LeadOut track */
-  u_int size_blk;
-  
-  u_char TocEnt_nixbyte; /* em */
-  u_char TocEnt_ctl_adr;
-  u_char TocEnt_number;
-  u_char TocEnt_format; /* em */
-  u_int TocEnt_address;
-  u_char ored_ctl_adr; /* to detect if CDROM contains data tracks */
-  
-  struct {
-    u_char nixbyte; /* em */
-    u_char ctl_adr; /* 0x4x: data, 0x0x: audio */
-    u_char number;
-    u_char format; /* em */ /* 0x00: lba, 0x01: msf */
-    u_int address;
-  } TocBuffer[MAX_TRACKS+1]; /* last entry faked */ 
-  
-  int in_SpinUp;
-  
-} DriveStruct[NR_SBPCD];
+	u_char volume_control; /* TEAC on/off bits */
+	
+	u_char SubQ_ctl_adr;
+	u_char SubQ_trk;
+	u_char SubQ_pnt_idx;
+	u_int SubQ_run_tot;
+	u_int SubQ_run_trk;
+	u_char SubQ_whatisthis;
+	
+	u_char UPC_ctl_adr;
+	u_char UPC_buf[7];
+	
+	int CDsize_blk;
+	int frame_size;
+	int CDsize_frm;
+	
+	u_char xa_byte; /* 0x20: XA capabilities */
+	u_char n_first_track; /* binary */
+	u_char n_last_track; /* binary (not bcd), 0x01...0x63 */
+	u_int size_msf; /* time of whole CD, position of LeadOut track */
+	u_int size_blk;
+	
+	u_char TocEnt_nixbyte; /* em */
+	u_char TocEnt_ctl_adr;
+	u_char TocEnt_number;
+	u_char TocEnt_format; /* em */
+	u_int TocEnt_address;
+	u_char ored_ctl_adr; /* to detect if CDROM contains data tracks */
+	
+	struct {
+		u_char nixbyte; /* em */
+		u_char ctl_adr; /* 0x4x: data, 0x0x: audio */
+		u_char number;
+		u_char format; /* em */ /* 0x00: lba, 0x01: msf */
+		u_int address;
+	} TocBuffer[MAX_TRACKS+1]; /* last entry faked */ 
+	
+	int in_SpinUp; /* CR-52x test flag */
+	int n_bytes; /* TEAC awaited response count */
+	u_char error_state, b3, b4; /* TEAC command error state */
+	u_char f_drv_error; /* TEAC command error flag */
+	u_char speed_byte;
+	int frmsiz;
+	u_char f_XA; /* 1: XA */
+	u_char type_byte; /* 0, 1, 3 */
+	u_char mode_xb_6;
+	u_char mode_yb_7;
+	u_char mode_xb_8;
+	u_char delay;
+	
+} D_S[NR_SBPCD];
 
 /*
  * drive space ends here (needed separate for each unit)
  */
 /*==========================================================================*/
+#if 0
+unsigned long cli_sti; /* for saving the processor flags */
+#endif
+/*==========================================================================*/
+static struct timer_list delay_timer = { NULL, NULL, 0, 0, mark_timeout_delay};
+static struct timer_list data_timer = { NULL, NULL, 0, 0, mark_timeout_data};
+#if 0
+static struct timer_list audio_timer = { NULL, NULL, 0, 0, mark_timeout_audio};
+#endif
 /*==========================================================================*/
 /*
  * DDI interface
  */
-static void sbpcd_dprintf(int level, char *fmt, ...)
+static void msg(int level, char *fmt, ...)
 {
-  char buff[256];
-  va_list args;
-  extern int vsprintf(char *buf, const char *fmt, va_list args);
-
-  if (! (sbpcd_debug & (1 << level))) return;
-
-  va_start(args, fmt);
-  vsprintf(buff, fmt, args);
-  va_end(args);
-  printk(buff);
-#if PRINTK_BUG
-  sti(); /* to avoid possible "printk" bug */
-#endif
+	char buf[256];
+	va_list args;
+	extern int vsprintf(char *, const char *, va_list);
+	
+	if (!(sbpcd_debug&(1<<level))) return;
+	
+	msgnum++;
+	if (msgnum>99) msgnum=0;
+	sprintf(buf, "%s-%d [%02d]:  ", major_name, d, msgnum);
+	va_start(args, fmt);
+	vsprintf(&buf[15], fmt, args);
+	va_end(args);
+	printk(buf);
+	sbp_sleep(55); /* else messages get lost */
+	return;
 }
-
+/*==========================================================================*/
 /*
  * DDI interface: runtime trace bit pattern maintenance
  */
 static int sbpcd_dbg_ioctl(unsigned long arg, int level)
 {
-  int val;
-
-  val = get_fs_long((int *) arg);
-  switch(val)
-    {
-    case 0:	/* OFF */
-      sbpcd_debug = 0;
-      break;
-
-    default:
-      if (val >= 128) sbpcd_debug &= ~(1 << (val - 128));
-      else sbpcd_debug |= (1 << val);
-    }
-  return(0);
+	switch(arg)
+	{
+	case 0:	/* OFF */
+		sbpcd_debug = DBG_INF;
+		break;
+		
+	default:
+		if (arg>=128) sbpcd_debug &= ~(1<<(arg-128));
+		else sbpcd_debug |= (1<<arg);
+	}
+	return (arg);
+}
+/*==========================================================================*/
+static void mark_timeout_delay(u_long i)
+{
+	timed_out_delay=1;
+	msg(DBG_TIM,"delay timer expired.\n");
+}
+/*==========================================================================*/
+static void mark_timeout_data(u_long i)
+{
+	timed_out_data=1;
+	msg(DBG_TIM,"data timer expired.\n");
 }
-
 /*==========================================================================*/
+#if 0
+static void mark_timeout_audio(u_long i)
+{
+	timed_out_audio=1;
+	msg(DBG_TIM,"audio timer expired.\n");
+}
+#endif
 /*==========================================================================*/
 /*
- * Wait a little while (used for polling the drive).  If in initialization,
- * setting a timeout doesn't work, so just loop for a while.
+ * Wait a little while (used for polling the drive).
  */
-static INLINE void sbp_sleep(u_int jifs)
+static void sbp_sleep(u_int time)
 {
-  sti();
-  current->state = TASK_INTERRUPTIBLE;
-  current->timeout = jiffies + jifs;
-  schedule();
-  sti();
+#ifndef MODULE
+	if (current == task[0]) 
+	{
+		del_timer(&delay_timer);
+		delay_timer.expires=time;
+		timed_out_delay=0;
+		add_timer(&delay_timer);
+		while (!timed_out_delay) ;
+		return;
+	}
+#endif MODULE
+	sti();
+	current->state = TASK_INTERRUPTIBLE;
+	current->timeout = jiffies + time;
+	schedule();
+	sti();
 }
-
-/*==========================================================================*/
 /*==========================================================================*/
 /*
  *  convert logical_block_address to m-s-f_number (3 bytes only)
  */
 static INLINE void lba2msf(int lba, u_char *msf)
 {
-  lba += CD_BLOCK_OFFSET;
-  msf[0] = lba / (CD_SECS*CD_FRAMES);
-  lba %= CD_SECS*CD_FRAMES;
-  msf[1] = lba / CD_FRAMES;
-  msf[2] = lba % CD_FRAMES;
+	lba += CD_BLOCK_OFFSET;
+	msf[0] = lba / (CD_SECS*CD_FRAMES);
+	lba %= CD_SECS*CD_FRAMES;
+	msf[1] = lba / CD_FRAMES;
+	msf[2] = lba % CD_FRAMES;
 }
 /*==========================================================================*/
 /*==========================================================================*/
@@ -737,56 +781,56 @@
  */
 static INLINE void bin2bcdx(u_char *p)  /* must work only up to 75 or 99 */
 {
-  *p=((*p/10)<<4)|(*p%10);
+	*p=((*p/10)<<4)|(*p%10);
 }
 /*==========================================================================*/
 static INLINE u_int blk2msf(u_int blk)
 {
-  MSF msf;
-  u_int mm;
-
-  msf.c[3] = 0;
-  msf.c[2] = (blk + CD_BLOCK_OFFSET) / (CD_SECS * CD_FRAMES);
-  mm = (blk + CD_BLOCK_OFFSET) % (CD_SECS * CD_FRAMES);
-  msf.c[1] = mm / CD_FRAMES;
-  msf.c[0] = mm % CD_FRAMES;
-  return (msf.n);
+	MSF msf;
+	u_int mm;
+	
+	msf.c[3] = 0;
+	msf.c[2] = (blk + CD_BLOCK_OFFSET) / (CD_SECS * CD_FRAMES);
+	mm = (blk + CD_BLOCK_OFFSET) % (CD_SECS * CD_FRAMES);
+	msf.c[1] = mm / CD_FRAMES;
+	msf.c[0] = mm % CD_FRAMES;
+	return (msf.n);
 }
 /*==========================================================================*/
 static INLINE u_int make16(u_char rh, u_char rl)
 {
-  return ((rh<<8)|rl);
+	return ((rh<<8)|rl);
 }
 /*==========================================================================*/
 static INLINE u_int make32(u_int rh, u_int rl)
 {
-  return ((rh<<16)|rl);
+	return ((rh<<16)|rl);
 }
 /*==========================================================================*/
 static INLINE u_char swap_nibbles(u_char i)
 {
-  return ((i<<4)|(i>>4));
+	return ((i<<4)|(i>>4));
 }
 /*==========================================================================*/
 static INLINE u_char byt2bcd(u_char i)
 {
-  return (((i/10)<<4)+i%10);
+	return (((i/10)<<4)+i%10);
 }
 /*==========================================================================*/
 static INLINE u_char bcd2bin(u_char bcd)
 {
-  return ((bcd>>4)*10+(bcd&0x0F));
+	return ((bcd>>4)*10+(bcd&0x0F));
 }
 /*==========================================================================*/
 static INLINE int msf2blk(int msfx)
 {
-  MSF msf;
-  int i;
-
-  msf.n=msfx;
-  i=(msf.c[2] * CD_SECS + msf.c[1]) * CD_FRAMES + msf.c[0] - CD_BLOCK_OFFSET;
-  if (i<0) return (0);
-  return (i);
+	MSF msf;
+	int i;
+	
+	msf.n=msfx;
+	i=(msf.c[2] * CD_SECS + msf.c[1]) * CD_FRAMES + msf.c[0] - CD_BLOCK_OFFSET;
+	if (i<0) return (0);
+	return (i);
 }
 /*==========================================================================*/
 /*
@@ -794,1869 +838,2578 @@
  */
 static INLINE 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);
+	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) */ 
+/* evaluate cc_ReadError code */ 
 static int sta2err(int sta)
 {
-  if (sta<=2) return (sta);
-  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); /* invalid disk change (LCS: removed) */
-  if (famL_drive)
-    if (sta==0x12) return (-15); /* invalid disk change (inserted) */
-  return (-2); /* drive not ready */
+	if (famT_drive)
+	{
+		if (sta==0x00) return (0);
+		if (sta==0x01) return (-604); /* CRC error */
+		if (sta==0x02) return (-602); /* drive not ready */
+		if (sta==0x03) return (-607); /* unknown media */
+		if (sta==0x04) return (-612); /* general failure */
+		if (sta==0x05) return (0);
+		if (sta==0x06) return (-615); /* invalid disk change */
+		if (sta==0x0b) return (-612); /* general failure */
+		if (sta==0xff) return (-612); /* general failure */
+		return (0);
+	}
+	else
+	{
+		if (sta<=2) return (sta);
+		if (sta==0x05) return (-604); /* CRC error */
+		if (sta==0x06) return (-606); /* seek error */
+		if (sta==0x0d) return (-606); /* seek error */
+		if (sta==0x0e) return (-603); /* unknown command */
+		if (sta==0x14) return (-603); /* unknown command */
+		if (sta==0x0c) return (-611); /* read fault */
+		if (sta==0x0f) return (-611); /* read fault */
+		if (sta==0x10) return (-611); /* read fault */
+		if (sta>=0x16) return (-612); /* general failure */
+		D_S[d].CD_changed=0xFF;
+		if (sta==0x11) return (-615); /* invalid disk change (LCS: removed) */
+		if (famL_drive)
+			if (sta==0x12) return (-615); /* invalid disk change (inserted) */
+		return (-602); /* drive not ready */
+	}
 }
 /*==========================================================================*/
 static INLINE void clr_cmdbuf(void)
 {
-  int i;
-
-  for (i=0;i<10;i++) drvcmd[i]=0;
-  cmd_type=0;
-}
-/*==========================================================================*/
-static void mark_timeout(unsigned long i)
-{
-  timed_out=1;
-  DPRINTF((DBG_TIM,"SBPCD: timer expired.\n"));
+	int i;
+	
+	for (i=0;i<10;i++) drvcmd[i]=0;
+	cmd_type=0;
 }
 /*==========================================================================*/
-static struct timer_list delay_timer = { NULL, NULL, 0, 0, mark_timeout};
-#if 0
-static struct timer_list data_timer = { NULL, NULL, 0, 0, mark_timeout};
-static struct timer_list audio_timer = { NULL, NULL, 0, 0, mark_timeout};
-#endif
-/*==========================================================================*/
 static void flush_status(void)
 {
-#ifdef CDMKE
-  int i;
-
+	int i;
+	
 #ifdef MODULE
-  sbp_sleep(150);
-  for (i=maxtim_data;i!=0;i--) inb(CDi_status);
+	sbp_sleep(150);
+	for (i=maxtim_data;i!=0;i--) inb(CDi_status);
 #else
-  if (current == task[0])
-    for (i=maxtim02;i!=0;i--) inb(CDi_status);
-  else 
-    {
-      sbp_sleep(150);
-      for (i=maxtim_data;i!=0;i--) inb(CDi_status);
-    }
+	if (current == task[0])
+		for (i=maxtim02;i!=0;i--) inb(CDi_status);
+	else 
+	{
+		sbp_sleep(150);
+		for (i=maxtim_data;i!=0;i--) inb(CDi_status);
+	}
 #endif MODULE
-#else
-  timed_out=0;
-#if 0
-  del_timer(&delay_timer);
-#endif
-  delay_timer.expires = 150;
-  add_timer(&delay_timer);
-  do { }
-  while (!timed_out);
-#if 0
-  del_timer(&delay_timer);
-#endif 0
-  inb(CDi_status);
-#endif CDMKE
 }
 /*==========================================================================*/
 static int CDi_stat_loop(void)
 {
-  int i,j;
-  u_long timeout;
-  
+	int i,j;
+	
 #ifdef MODULE
-    for(timeout = jiffies + 1000, i=maxtim_data; timeout > jiffies; )
-      {
-	for ( ;i!=0;i--)
-	  {
-	    j=inb(CDi_status);
-	    if (!(j&s_not_data_ready)) return (j);
-	    if (!(j&s_not_result_ready)) return (j);
-	    if (fam0L_drive) if (j&s_attention) return (j);
-	  }
-	sbp_sleep(1);
-	i = 1;
-      }
+	for(timeout = jiffies + 1000, i=maxtim_data; timeout > jiffies; )
+	{
+		for ( ;i!=0;i--)
+		{
+			j=inb(CDi_status);
+			if (!(j&s_not_data_ready)) return (j);
+			if (!(j&s_not_result_ready)) return (j);
+			if (fam0L_drive) if (j&s_attention) return (j);
+		}
+		sbp_sleep(1);
+		i = 1;
+	}
 #else
-  if (current == task[0])
-    for(i=maxtim16;i!=0;i--)
-      {
-	j=inb(CDi_status);
-        if (!(j&s_not_data_ready)) return (j);
-        if (!(j&s_not_result_ready)) return (j);
-        if (fam0L_drive) if (j&s_attention) return (j);
-      }
-  else
-    for(timeout = jiffies + 1000, i=maxtim_data; timeout > jiffies; )
-      {
-	for ( ;i!=0;i--)
-	  {
-	    j=inb(CDi_status);
-	    if (!(j&s_not_data_ready)) return (j);
-	    if (!(j&s_not_result_ready)) return (j);
-	    if (fam0L_drive) if (j&s_attention) return (j);
-	  }
-	sbp_sleep(1);
-	i = 1;
-      }
+	if (current == task[0])
+		for(i=maxtim16;i!=0;i--)
+		{
+			j=inb(CDi_status);
+			if (!(j&s_not_data_ready)) return (j);
+			if (!(j&s_not_result_ready)) return (j);
+			if (fam0L_drive) if (j&s_attention) return (j);
+		}
+	else
+		for(timeout = jiffies + 1000, i=maxtim_data; timeout > jiffies; )
+		{
+			for ( ;i!=0;i--)
+			{
+				j=inb(CDi_status);
+				if (!(j&s_not_data_ready)) return (j);
+				if (!(j&s_not_result_ready)) return (j);
+				if (fam0L_drive) if (j&s_attention) return (j);
+			}
+			sbp_sleep(1);
+			i = 1;
+		}
 #endif MODULE
-  DPRINTF((DBG_LCS,"SBPCD: CDi_stat_loop failed\n"));
-  return (-1);
+	msg(DBG_LCS,"CDi_stat_loop failed\n");
+	return (-1);
+}
+/*==========================================================================*/
+#if 00000
+/*==========================================================================*/
+static int tst_DataReady(void)
+{
+	int i;
+	
+	i=inb(CDi_status);
+	if (i&s_not_data_ready) return (0);
+	return (1);
+}
+/*==========================================================================*/
+static int tst_ResultReady(void)
+{
+	int i;
+	
+	i=inb(CDi_status);
+	if (i&s_not_result_ready) return (0);
+	return (1);
+}
+/*==========================================================================*/
+static int tst_Attention(void)
+{
+	int i;
+	
+	i=inb(CDi_status);
+	if (i&s_attention) return (1);
+	return (0);
 }
 /*==========================================================================*/
+#endif 00000
+/*==========================================================================*/
 static int ResponseInfo(void)
 {
-  int i,j, st=0;
-  u_long timeout;
-
-  DPRINTF((DBG_000,"SBPCD: ResponseInfo entered.\n"));
+	int i,j,st=0;
+	u_long timeout;
+	
 #ifdef MODULE
-  for (i=0, timeout = jiffies + 100; i < response_count; i++) 
-    {
-      for (j=maxtim_data; ; )
-	{
-	  for ( ;j!=0;j-- )
-	    {
-	      st=inb(CDi_status);
-	      if (!(st&s_not_result_ready)) break;
-	    }
-	  if (j != 0 || timeout <= jiffies) break;
-	  sbp_sleep(0);
-	  j = 1;
-	}
-      if (timeout <= jiffies) return (-1);
-      infobuf[i]=inb(CDi_info);
-    }
+	if (0)
 #else
-  if (current == task[0])
-    for (i=0;i<response_count;i++)
-      {
-	for (j=maxtim_8;j!=0;j--)
-	  {
-	    st=inb(CDi_status);
-	    if (!(st&s_not_result_ready)) break;
-	  }
-	if (j==0)
-	  {
-	    DPRINTF((DBG_SEQ,"SBPCD: ResponseInfo: not_result_ready (got %d of %d bytes).\n", i, response_count));
-	    return (-1);
-	  }
-	infobuf[i]=inb(CDi_info);
-      }
-  else 
-    {
-      for (i=0, timeout = jiffies + 100; i < response_count; i++) 
-	{
-	  for (j=maxtim_data; ; )
-	    {
-	      for ( ;j!=0;j-- )
-		{
-		  st=inb(CDi_status);
-		  if (!(st&s_not_result_ready)) break;
-		}
-	      if (j != 0 || timeout <= jiffies) break;
-	      sbp_sleep(0);
-	      j = 1;
-	    }
-	  if (timeout <= jiffies) return (-1);
-	  infobuf[i]=inb(CDi_info);
-	}
-    }
+	if (current == task[0])
 #endif MODULE
-  DPRINTF((DBG_000,"SBPCD: ResponseInfo: done.\n"));
-  return (0);
+		for (i=0;i<response_count;i++)
+		{
+			for (j=maxtim_8;j!=0;j--)
+			{
+				st=inb(CDi_status);
+				if (!(st&s_not_result_ready)) break;
+			}
+			if (j==0) 
+			{
+				msg(DBG_SEQ,"ResponseInfo: not_result_ready (got %d of %d bytes).\n", i, response_count);
+				break;
+			}
+			infobuf[i]=inb(CDi_info);
+		}
+	else 
+	{
+		for (i=0,timeout=jiffies+100;i<response_count;i++) 
+		{
+			for (j=maxtim_data; ; )
+			{
+				for ( ;j!=0;j-- )
+				{
+					st=inb(CDi_status);
+					if (!(st&s_not_result_ready)) break;
+				}
+				if (j != 0 || timeout <= jiffies) break;
+				sbp_sleep(0);
+				j = 1;
+			}
+			if (timeout <= jiffies) break;
+			infobuf[i]=inb(CDi_info);
+		}
+	}
+	for (j=0;j<i;j++)
+		sprintf(&msgbuf[j*3]," %02X",infobuf[j]);
+	msgbuf[j*3]=0;
+	msg(DBG_CMD,"ResponseInfo:%s (%d,%d)\n",msgbuf,response_count,i);
+	st=response_count-i;
+	if (st>0) st=-st;
+	return (st);
 }
 /*==========================================================================*/
 static void EvaluateStatus(int st)
 {
-  DriveStruct[d].status_byte=0;
-  if (fam0_drive)
-    {
-      if (st&p_caddin_old) DriveStruct[d].status_byte |= p_door_closed|p_caddy_in;
-      if (st&p_spinning) DriveStruct[d].status_byte |= p_spinning;
-      if (st&p_check) DriveStruct[d].status_byte |= p_check;
-      if (st&p_busy_old) DriveStruct[d].status_byte |= p_busy_new;
-      if (st&p_disk_ok) DriveStruct[d].status_byte |= p_disk_ok;
-    }
-  else if (famL_drive)
-    {
-      if (st&p_caddin_old) DriveStruct[d].status_byte |= p_disk_ok|p_caddy_in;
-      if (st&p_spinning) DriveStruct[d].status_byte |= p_spinning;
-      if (st&p_check) DriveStruct[d].status_byte |= p_check;
-      if (st&p_busy_old) DriveStruct[d].status_byte |= p_busy_new;
-      if (st&p_lcs_door_closed) DriveStruct[d].status_byte |= p_door_closed;
-      if (st&p_lcs_door_locked) DriveStruct[d].status_byte |= p_door_locked;
-    }
-  else if (fam2_drive)
-    {
-      if (st&p2_check) DriveStruct[d].status_byte |= p1_check;
-      if (st&p2_door_closed) DriveStruct[d].status_byte |= p1_door_closed;
-      if (st&p2_disk_in) DriveStruct[d].status_byte |= p1_disk_in;
-      if (st&p2_busy1) DriveStruct[d].status_byte |= p1_busy;
-      if (st&p2_busy2) DriveStruct[d].status_byte |= p1_busy;
-      if (st&p2_spinning) DriveStruct[d].status_byte |= p1_spinning;
-      if (st&p2_door_locked) DriveStruct[d].status_byte |= p1_door_locked;
-      if (st&p2_disk_ok) DriveStruct[d].status_byte |= p1_disk_ok;
-    }
-  else if (fam1_drive) DriveStruct[d].status_byte=st;
-  return;
+	D_S[d].status_bits=0;
+	if (fam1_drive) D_S[d].status_bits=st|p_success;
+	else if (fam0_drive)
+	{
+		if (st&p_caddin_old) D_S[d].status_bits |= p_door_closed|p_caddy_in;
+		if (st&p_spinning) D_S[d].status_bits |= p_spinning;
+		if (st&p_check) D_S[d].status_bits |= p_check;
+ 		if (st&p_success_old) D_S[d].status_bits |= p_success;
+ 		if (st&p_busy_old) D_S[d].status_bits |= p_busy_new;
+		if (st&p_disk_ok) D_S[d].status_bits |= p_disk_ok;
+	}
+	else if (famL_drive)
+	{
+ 		D_S[d].status_bits |= p_success;
+		if (st&p_caddin_old) D_S[d].status_bits |= p_disk_ok|p_caddy_in;
+		if (st&p_spinning) D_S[d].status_bits |= p_spinning;
+		if (st&p_check) D_S[d].status_bits |= p_check;
+		if (st&p_busy_old) D_S[d].status_bits |= p_busy_new;
+		if (st&p_lcs_door_closed) D_S[d].status_bits |= p_door_closed;
+		if (st&p_lcs_door_locked) D_S[d].status_bits |= p_door_locked;
+	}
+	else if (fam2_drive)
+	{
+ 		D_S[d].status_bits |= p_success;
+		if (st&p2_check) D_S[d].status_bits |= p1_check;
+		if (st&p2_door_closed) D_S[d].status_bits |= p1_door_closed;
+		if (st&p2_disk_in) D_S[d].status_bits |= p1_disk_in;
+		if (st&p2_busy1) D_S[d].status_bits |= p1_busy;
+		if (st&p2_busy2) D_S[d].status_bits |= p1_busy;
+		if (st&p2_spinning) D_S[d].status_bits |= p1_spinning;
+		if (st&p2_door_locked) D_S[d].status_bits |= p1_door_locked;
+		if (st&p2_disk_ok) D_S[d].status_bits |= p1_disk_ok;
+	}
+	else if (famT_drive)
+	{
+		return; /* still needs to get coded */
+ 		D_S[d].status_bits |= p_success;
+		if (st&p2_check) D_S[d].status_bits |= p1_check;
+		if (st&p2_door_closed) D_S[d].status_bits |= p1_door_closed;
+		if (st&p2_disk_in) D_S[d].status_bits |= p1_disk_in;
+		if (st&p2_busy1) D_S[d].status_bits |= p1_busy;
+		if (st&p2_busy2) D_S[d].status_bits |= p1_busy;
+		if (st&p2_spinning) D_S[d].status_bits |= p1_spinning;
+		if (st&p2_door_locked) D_S[d].status_bits |= p1_door_locked;
+		if (st&p2_disk_ok) D_S[d].status_bits |= p1_disk_ok;
+	}
+	return;
+}
+/*==========================================================================*/
+static int get_state_T(void)
+{
+	int i;
+	
+	static int cmd_out_T(void);
+
+	msg(DBG_TE2,"doing get_state_T...\n");
+	clr_cmdbuf();
+	D_S[d].n_bytes=1;
+	drvcmd[0]=CMDT_STATUS;
+	i=cmd_out_T();
+	if (i>=0) i=infobuf[0];
+	else
+	{
+		msg(DBG_TEA,"get_state_T error %d\n", i);
+		return (i);
+	}
+	if (i>=0)
+		/* 2: closed, disk in */
+		D_S[d].status_bits=p1_door_closed|p1_disk_in|p1_spinning|p1_disk_ok;
+	else if (D_S[d].error_state==6)
+		/* 3: closed, disk in, changed ("06 xx xx") */
+		D_S[d].status_bits=p1_door_closed|p1_disk_in;
+	else if ((D_S[d].error_state!=2)||(D_S[d].b3!=0x3A)||(D_S[d].b4==0x00))
+	{
+		/* 1: closed, no disk ("xx yy zz"or "02 3A 00") */
+		D_S[d].status_bits=p1_door_closed;
+		D_S[d].open_count=0;
+	}
+	else if (D_S[d].b4==0x01)
+	{
+		/* 0: open ("02 3A 01") */
+		D_S[d].status_bits=0;
+		D_S[d].open_count=0;
+	}
+	else
+	{
+		/* 1: closed, no disk ("02 3A xx") */
+		D_S[d].status_bits=p1_door_closed;
+		D_S[d].open_count=0;
+	}
+	msg(DBG_TE2,"get_state_T done (%02X)...\n", D_S[d].status_bits);
+	return (D_S[d].status_bits);
 }
 /*==========================================================================*/
 static int ResponseStatus(void)
 {
-  int i,j;
-  u_long timeout;
-
-  DPRINTF((DBG_STA,"SBPCD: doing ResponseStatus...\n"));
+	int i,j;
+	u_long timeout;
+	
+	msg(DBG_STA,"doing ResponseStatus...\n");
+	if (famT_drive) return (get_state_T());
 #ifdef MODULE
-  if (flags_cmd_out & f_respo3) timeout = jiffies;
-  else if (flags_cmd_out & f_respo2) timeout = jiffies + 1600;
-  else timeout = jiffies + 400;
-  j=maxtim_8;
-  do
-    {
-      for ( ;j!=0;j--)
-	{ 
-	  i=inb(CDi_status);
-	  if (!(i&s_not_result_ready)) break;
-	}
-      if (j != 0 || timeout <= jiffies) break;
-      sbp_sleep(0);
-      j = 1;
-    }
-  while (1);
+	if (0)
 #else
-  if (current == task[0])
-    {
-      if (flags_cmd_out & f_respo3) j = maxtim_8;
-      else if (flags_cmd_out&f_respo2) j=maxtim16;
-      else j=maxtim04;
-      for (;j!=0;j--)
+	if (current == task[0])
+#endif MODULE
 	{
-	  i=inb(CDi_status);
-	  if (!(i&s_not_result_ready)) break;
+		if (flags_cmd_out & f_respo3) j = maxtim_8;
+		else if (flags_cmd_out&f_respo2) j=maxtim16;
+		else j=maxtim04;
+		for (;j!=0;j--)
+		{
+			i=inb(CDi_status);
+			if (!(i&s_not_result_ready)) break;
+		}
 	}
-    }
-  else
-    {
-      if (flags_cmd_out & f_respo3) timeout = jiffies;
-      else if (flags_cmd_out & f_respo2) timeout = jiffies + 1600;
-      else timeout = jiffies + 400;
-      j=maxtim_8;
-      do
-	{
-	  for ( ;j!=0;j--)
-	    { 
-	      i=inb(CDi_status);
-	      if (!(i&s_not_result_ready)) break;
-	    }
-	  if (j != 0 || timeout <= jiffies) break;
-	  sbp_sleep(0);
-	  j = 1;
+	else
+	{
+		if (flags_cmd_out & f_respo3) timeout = jiffies;
+		else if (flags_cmd_out & f_respo2) timeout = jiffies + 1600;
+		else timeout = jiffies + 400;
+		j=maxtim_8;
+		do
+		{
+			for ( ;j!=0;j--)
+			{ 
+				i=inb(CDi_status);
+				if (!(i&s_not_result_ready)) break;
+			}
+			if ((j!=0)||(timeout<jiffies)) break;
+			sbp_sleep(1);
+			j = 1;
+		}
+		while (1);
 	}
-      while (1);
-    }
-#endif MODULE
-  if (j==0) 
-    { if ((flags_cmd_out & f_respo3) == 0)
-	DPRINTF((DBG_STA,"SBPCD: ResponseStatus: timeout.\n"));
-      DriveStruct[d].status_byte=0;
-      return (-1);
-    }
-  i=inb(CDi_info);
-  DPRINTF((DBG_STA,"SBPCD: ResponseStatus: response %2X.\n", i));
-  EvaluateStatus(i);
-  return (i);
-}
-/*==========================================================================*/
-static void xx_ReadStatus(void)
-{
-  int i;
-
-  DPRINTF((DBG_STA,"SBPCD: giving xx_ReadStatus command\n"));
-  SBPCD_CLI;
-  if (fam0L_drive) OUT(CDo_command,CMD0_STATUS);
-  else if (fam1_drive) OUT(CDo_command,CMD1_STATUS);
-  else if (fam2_drive) OUT(CDo_command,CMD2_STATUS);
-  if (!fam0L_drive) for (i=0;i<6;i++) OUT(CDo_command,0);
-  SBPCD_STI;
+	if (j==0) 
+	{
+		if ((flags_cmd_out & f_respo3) == 0)
+			msg(DBG_STA,"ResponseStatus: timeout.\n");
+		D_S[d].status_bits=0;
+		return (-401);
+	}
+	i=inb(CDi_info);
+	msg(DBG_STA,"ResponseStatus: response %02X.\n", i);
+	EvaluateStatus(i);
+#if 0
+	if (fam0_drive)
+#endif
+		msg(DBG_STA,"status_bits=%02X, i=%02X\n",D_S[d].status_bits,i);
+#if 1
+	return (D_S[d].status_bits);
+#else
+	return (i);
+#endif 0
 }
 /*==========================================================================*/
-static int xx_ReadError(void)
+static void cc_ReadStatus(void)
 {
-  int i;
-
-  clr_cmdbuf();
-  DPRINTF((DBG_ERR,"SBPCD: giving xx_ReadError command.\n"));
-  if (fam1_drive)
-    {
-      drvcmd[0]=CMD1_READ_ERR;
-      response_count=8;
-      flags_cmd_out=f_putcmd|f_ResponseStatus;
-    }
-  else if (fam0L_drive)
-    {
-      drvcmd[0]=CMD0_READ_ERR;
-      response_count=6;
-      if (famL_drive)
-	flags_cmd_out=f_putcmd;
-      else
-	flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus;
-    }
-  else if (fam2_drive)
-    {
-      drvcmd[0]=CMD2_READ_ERR;
-      response_count=6;
-      flags_cmd_out=f_putcmd;
-    }
-  i=cmd_out(7);
-  DriveStruct[d].error_byte=0;
-  DPRINTF((DBG_ERR,"SBPCD: xx_ReadError: cmd_out(82) returns %d (%02X)\n",i,i));
-  if (i<0) return (i);
-  if (fam0_drive) i=1;
-  else i=2;
-  DriveStruct[d].error_byte=infobuf[i];
-  DPRINTF((DBG_ERR,"SBPCD: xx_ReadError: infobuf[%d] is %d (%02X)\n",i,DriveStruct[d].error_byte,DriveStruct[d].error_byte));
-  i=sta2err(infobuf[i]);
-  return (i);
-}
-/*==========================================================================*/
-static int cmd_out(int len)
-{
-  int i=0;
-
-  if (flags_cmd_out&f_putcmd)
-    { 
-      DPRINTF((DBG_CMD,"SBPCD: cmd_out: put"));
-      for (i=0;i<len;i++) DPRINTF((DBG_CMD," %02X",drvcmd[i]));
-      DPRINTF((DBG_CMD,"\n"));
-
-      cli();
-      for (i=0;i<len;i++) OUT(CDo_command,drvcmd[i]);
-      sti();
-    }
-  if (response_count!=0)
-    {
-      if (cmd_type!=0)
-	{
-	  if (sbpro_type==1) OUT(CDo_sel_i_d,1);
-	  DPRINTF((DBG_INF,"SBPCD: misleaded to try ResponseData.\n"));
-	  if (sbpro_type==1) OUT(CDo_sel_i_d,0);
-	  return (-22);
+	int i;
+	
+	msg(DBG_STA,"giving cc_ReadStatus command\n");
+	if (famT_drive) return;
+	SBPCD_CLI;
+	if (fam0L_drive) OUT(CDo_command,CMD0_STATUS);
+	else if (fam1_drive) OUT(CDo_command,CMD1_STATUS);
+	else if (fam2_drive) OUT(CDo_command,CMD2_STATUS);
+	if (!fam0L_drive) for (i=0;i<6;i++) OUT(CDo_command,0);
+	SBPCD_STI;
+}
+/*==========================================================================*/
+static int cc_ReadError(void)
+{
+	int i;
+
+	clr_cmdbuf();
+	msg(DBG_ERR,"giving cc_ReadError command.\n");
+	if (fam1_drive)
+	{
+		drvcmd[0]=CMD1_READ_ERR;
+		response_count=8;
+		flags_cmd_out=f_putcmd|f_ResponseStatus;
+	}
+	else if (fam0L_drive)
+	{
+		drvcmd[0]=CMD0_READ_ERR;
+		response_count=6;
+		if (famL_drive)
+			flags_cmd_out=f_putcmd;
+		else
+			flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus;
+	}
+	else if (fam2_drive)
+	{
+		drvcmd[0]=CMD2_READ_ERR;
+		response_count=6;
+		flags_cmd_out=f_putcmd;
+	}
+	else if (famT_drive)
+	{
+		response_count=5;
+		drvcmd[0]=CMDT_READ_ERR;
+	}
+	i=cmd_out();
+	D_S[d].error_byte=0;
+	msg(DBG_ERR,"cc_ReadError: cmd_out(CMDx_READ_ERR) returns %d (%02X)\n",i,i);
+	if (i<0) return (i);
+	if (fam0_drive) i=1;
+	else i=2;
+	D_S[d].error_byte=infobuf[i];
+	msg(DBG_ERR,"cc_ReadError: infobuf[%d] is %d (%02X)\n",i,D_S[d].error_byte,D_S[d].error_byte);
+	i=sta2err(infobuf[i]);
+	return (i);
+}
+/*==========================================================================*/
+static int cmd_out_T(void)
+{
+#undef CMDT_TRIES
+#define CMDT_TRIES 100
+	
+	static int cc_DriveReset(void);
+	int i, j, l, ntries;
+	
+	D_S[d].error_state=0;
+	D_S[d].b3=0;
+	D_S[d].b4=0;
+	D_S[d].f_drv_error=0;
+	for (i=0;i<10;i++) sprintf(&msgbuf[i*3]," %02X",drvcmd[i]);
+	msgbuf[i*3]=0;
+	msg(DBG_CMD,"cmd_out_T:%s\n",msgbuf);
+
+	OUT(CDo_sel_i_d,0);
+	OUT(CDo_enable,D_S[d].drv_sel);
+	i=inb(CDi_status);
+	if (!(i&s_not_result_ready))
+	do
+	{
+		j=inb(CDi_info);
+		i=inb(CDi_status);
+		sbp_sleep(0);
+		msg(DBG_TEA,"cmd_out_T: spurious !s_not_result_ready. (%02X)\n", j);
+	}
+	while (!(i&s_not_result_ready));
+	cli();
+	for (i=0;i<10;i++) OUT(CDo_command,drvcmd[i]);
+	sti();
+	for (ntries=CMDT_TRIES;ntries>0;ntries--)
+	{
+		if (drvcmd[0]==CMDT_READ_VER) sbp_sleep(100);
+#if 1
+		OUT(CDo_sel_i_d,0);
+#endif
+		i=inb(CDi_status);
+		if (!(i&s_not_data_ready)) /* f.e. CMDT_DISKINFO */
+		{
+			OUT(CDo_sel_i_d,1);
+			if (drvcmd[0]==CMDT_READ) return (0); /* handled elsewhere */
+			if (drvcmd[0]==CMDT_DISKINFO)
+			{
+				l=0;
+				do
+				{
+					infobuf[l++]=inb(CDi_data);
+					i=inb(CDi_status);
+				}
+				while (!(i&s_not_data_ready));
+				for (j=0;j<l;j++) sprintf(&msgbuf[j*3]," %02X",infobuf[j]);
+				msgbuf[j*3]=0;
+				msg(DBG_CMD,"cmd_out_T data response:%s\n", msgbuf);
+			}
+			else
+			{
+				msg(DBG_TEA,"cmd_out_T: data response with cmd_%02X !!!!!!!!!!!!!!!!!!!!\n", drvcmd[0]);
+				j=0;
+				do
+				{
+					i=inb(CDi_data);
+					j++;
+					i=inb(CDi_status);
+				}
+				while (!(i&s_not_data_ready));
+				msg(DBG_TEA,"cmd_out_T: data response: discarded %d bytes.\n", j);
+				fatal_err++;
+			}
+		}
+		i=inb(CDi_status);
+		if (!(i&s_not_result_ready))
+		{
+			OUT(CDo_sel_i_d,0);
+			l=0;
+			do
+			{
+				infobuf[l++]=inb(CDi_info);
+				i=inb(CDi_status);
+			}
+			while (!(i&s_not_result_ready));
+			for (j=0;j<l;j++) sprintf(&msgbuf[j*3]," %02X",infobuf[j]);
+			msgbuf[j*3]=0;
+			msg(DBG_CMD,"cmd_out_T info response:%s\n", msgbuf);
+			if (infobuf[0]!=0x02) return (l); /* info length */
+			do
+			{
+				++recursion;
+				if (recursion>1) msg(DBG_TEA,"cmd_out_T READ_ERR recursion (%02X): %d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", drvcmd[0], recursion);
+				clr_cmdbuf();
+				drvcmd[0]=CMDT_READ_ERR;
+				j=cmd_out_T(); /* !!! recursive here !!! */
+				--recursion;
+				sbp_sleep(1);
+			}
+			while (j<0);
+			D_S[d].error_state=infobuf[2];
+			D_S[d].b3=infobuf[3];
+			D_S[d].b4=infobuf[4];
+			if (D_S[d].f_drv_error)
+			{
+				D_S[d].f_drv_error=0;
+				cc_DriveReset();
+				D_S[d].error_state=2;
+			}
+			return (-D_S[d].error_state-400);
+		}
+		if (drvcmd[0]==CMDT_READ) return (0); /* handled elsewhere */
+		sbp_sleep(1);
+		if (ntries>(CMDT_TRIES-50)) continue;
+		msg(DBG_TEA,"cmd_out_T: next CMDT_TRIES (%02X): %d.\n", drvcmd[0], ntries-1);
+	}
+	D_S[d].f_drv_error=1;
+	cc_DriveReset();
+	D_S[d].error_state=2;
+	return (-99);
+}
+/*==========================================================================*/
+static int cmd_out(void)
+{
+	int i=0;
+	
+	if (famT_drive) return(cmd_out_T());
+	
+	if (flags_cmd_out&f_putcmd)
+	{ 
+		for (i=0;i<7;i++)
+			sprintf(&msgbuf[i*3], " %02X", drvcmd[i]);
+		msgbuf[i*3]=0;
+		msg(DBG_CMD,"cmd_out:%s\n", msgbuf);
+		cli();
+		for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]);
+		sti();
 	}
-      else i=ResponseInfo();
-      if (i<0) return (-9);
-    }
-  if (DriveStruct[d].in_SpinUp != 0) DPRINTF((DBG_SPI,"SBPCD: to CDi_stat_loop.\n"));
-  if (flags_cmd_out&f_lopsta)
-    {
-      i=CDi_stat_loop();
-      if ((i<0)||!(i&s_attention)) return (-9);
-    }
-  if (!(flags_cmd_out&f_getsta)) goto LOC_229;
-  
-LOC_228:
-  if (DriveStruct[d].in_SpinUp != 0) DPRINTF((DBG_SPI,"SBPCD: to xx_ReadStatus.\n"));
-  xx_ReadStatus();
-
-LOC_229:
-  if (flags_cmd_out&f_ResponseStatus) 
-    {
-      if (DriveStruct[d].in_SpinUp != 0) DPRINTF((DBG_SPI,"SBPCD: to ResponseStatus.\n"));
-      i=ResponseStatus();
-                   /* builds status_byte, returns orig. status or p_busy_new */
-      if (i<0) return (-9);
-      if (flags_cmd_out&(f_bit1|f_wait_if_busy))
-	{
-	  if (!st_check)
-	    {
-	      if (flags_cmd_out&f_bit1) if (i&p_success_old) goto LOC_232;
-	      if (!(flags_cmd_out&f_wait_if_busy)) goto LOC_228;
-	      if (!st_busy) goto LOC_228;
-	    }
+	if (response_count!=0)
+	{
+		if (cmd_type!=0)
+		{
+			if (sbpro_type==1) OUT(CDo_sel_i_d,1);
+			msg(DBG_INF,"misleaded to try ResponseData.\n");
+			if (sbpro_type==1) OUT(CDo_sel_i_d,0);
+			return (-22);
+		}
+		else i=ResponseInfo();
+		if (i<0) return (i);
 	}
-    }
-LOC_232:
-  if (!(flags_cmd_out&f_obey_p_check)) return (0);
-  if (!st_check) return (0);
-  if (DriveStruct[d].in_SpinUp != 0) DPRINTF((DBG_SPI,"SBPCD: to xx_ReadError.\n"));
-  i=xx_ReadError();
-  if (DriveStruct[d].in_SpinUp != 0) DPRINTF((DBG_SPI,"SBPCD: to cmd_out OK.\n"));
-  return (i);
-}
-/*==========================================================================*/
-static int xx_Seek(u_int pos, char f_blk_msf)
-{
-  int i;
-
-  clr_cmdbuf();
-  if (f_blk_msf>1) return (-3);
-  if (fam0_drive)
-    {
-      drvcmd[0]=CMD0_SEEK;
-      if (f_blk_msf==1) pos=msf2blk(pos);
-      drvcmd[2]=(pos>>16)&0x00FF;
-      drvcmd[3]=(pos>>8)&0x00FF;
-      drvcmd[4]=pos&0x00FF;
-      flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta |
-                      f_ResponseStatus | f_obey_p_check | f_bit1;
-    }
-  else if (fam1L_drive)
-    {
-      drvcmd[0]=CMD1_SEEK; /* same as CMD1_ and CMDL_ */
-      if (f_blk_msf==0) pos=blk2msf(pos);
-      drvcmd[1]=(pos>>16)&0x00FF;
-      drvcmd[2]=(pos>>8)&0x00FF;
-      drvcmd[3]=pos&0x00FF;
-      if (famL_drive)
-	flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
-      else
-	flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
-    }
-  else if (fam2_drive)
-    {
-      drvcmd[0]=CMD2_SEEK;
-      if (f_blk_msf==0) pos=blk2msf(pos);
-      drvcmd[2]=(pos>>16)&0x00FF;
-      drvcmd[3]=(pos>>16)&0x00FF;
-      drvcmd[4]=(pos>>8)&0x00FF;
-      drvcmd[5]=pos&0x00FF;
-      flags_cmd_out=f_putcmd|f_ResponseStatus;
-    }
-  response_count=0;
-  i=cmd_out(7);
-  return (i);
-}
-/*==========================================================================*/
-static int xx_SpinUp(void)
-{
-  int i;
-
-  DPRINTF((DBG_SPI,"SBPCD: SpinUp.\n"));
-  DriveStruct[d].in_SpinUp = 1;
-  clr_cmdbuf();
-  if (fam0L_drive)
-    {
-      drvcmd[0]=CMD0_SPINUP;
-      flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|
-	f_ResponseStatus|f_obey_p_check|f_bit1;
-    }
-  else if (fam1_drive)
-    {
-      drvcmd[0]=CMD1_SPINUP;
-      flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
-    }
-  else if (fam2_drive)
-    {
-      drvcmd[0]=CMD2_TRAY_CTL;
-      drvcmd[4]=0x01;
-      flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
-    }
-  response_count=0;
-  i=cmd_out(7);
-  DriveStruct[d].in_SpinUp = 0;
-  return (i);
-}
-/*==========================================================================*/
-static int yy_SpinDown(void)
-{
-  int i;
-
-  if (fam0_drive) return (-3);
-  clr_cmdbuf();
-  response_count=0;
-  if (fam1_drive)
-    {
-      drvcmd[0]=CMD1_SPINDOWN;
-      flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
-    }
-  else if (fam2_drive)
-    {
-      drvcmd[0]=CMD2_TRAY_CTL;
-      drvcmd[4]=0x02; /* "eject" */
-      flags_cmd_out=f_putcmd|f_ResponseStatus;
-    }
-  else if (famL_drive)
-    {
-      drvcmd[0]=CMDL_SPINDOWN;
-      drvcmd[1]=1;
-      flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
-    }
-  i=cmd_out(7);
-  return (i);
+	if (D_S[d].in_SpinUp) msg(DBG_SPI,"in_SpinUp: to CDi_stat_loop.\n");
+	if (flags_cmd_out&f_lopsta)
+	{
+		i=CDi_stat_loop();
+		if ((i<0)||!(i&s_attention)) return (-8);
+	}
+	if (!(flags_cmd_out&f_getsta)) goto LOC_229;
+	
+ LOC_228:
+	if (D_S[d].in_SpinUp) msg(DBG_SPI,"in_SpinUp: to cc_ReadStatus.\n");
+	cc_ReadStatus();
+	
+ LOC_229:
+	if (flags_cmd_out&f_ResponseStatus) 
+	{
+		if (D_S[d].in_SpinUp) msg(DBG_SPI,"in_SpinUp: to ResponseStatus.\n");
+		i=ResponseStatus();
+		/* builds status_bits, returns orig. status or p_busy_new */
+		if (i<0) return (-9);
+		if (flags_cmd_out&(f_bit1|f_wait_if_busy))
+		{
+			if (!st_check)
+			{
+				if ((flags_cmd_out&f_bit1)&&(i&p_success)) goto LOC_232;
+				if ((!(flags_cmd_out&f_wait_if_busy))||(!st_busy)) goto LOC_228;
+			}
+		}
+	}
+ LOC_232:
+	if (!(flags_cmd_out&f_obey_p_check)) return (0);
+	if (!st_check) return (0);
+	if (D_S[d].in_SpinUp) msg(DBG_SPI,"in_SpinUp: to cc_ReadError.\n");
+	i=cc_ReadError();
+	if (D_S[d].in_SpinUp) msg(DBG_SPI,"in_SpinUp: to cmd_out OK.\n");
+	msg(DBG_000,"cmd_out: cc_ReadError=%d\n", i);
+	return (i);
 }
 /*==========================================================================*/
-static int yy_SetSpeed(u_char speed, u_char x1, u_char x2)
+static int cc_Seek(u_int pos, char f_blk_msf)
 {
-  int i;
-
-  if (fam0L_drive) return (-3);
+	int i;
+	
   clr_cmdbuf();
-  response_count=0;
-  if (fam1_drive)
-    {
-      drvcmd[0]=CMD1_SETMODE;
-      drvcmd[1]=0x03;
-      drvcmd[2]=speed;
-      drvcmd[3]=x1;
-      drvcmd[4]=x2;
-      flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-    }
-  else if (fam2_drive)
-    {
-      drvcmd[0]=CMD2_SETSPEED;
-      if (speed&speed_auto)
+	if (f_blk_msf>1) return (-3);
+	if (fam0_drive)
 	{
-	  drvcmd[2]=0xFF;
-	  drvcmd[3]=0xFF;
+		drvcmd[0]=CMD0_SEEK;
+		if (f_blk_msf==1) pos=msf2blk(pos);
+		drvcmd[2]=(pos>>16)&0x00FF;
+		drvcmd[3]=(pos>>8)&0x00FF;
+		drvcmd[4]=pos&0x00FF;
+		flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta |
+			f_ResponseStatus | f_obey_p_check | f_bit1;
+	}
+	else if (fam1L_drive)
+	{
+		drvcmd[0]=CMD1_SEEK; /* same as CMD1_ and CMDL_ */
+		if (f_blk_msf==0) pos=blk2msf(pos);
+		drvcmd[1]=(pos>>16)&0x00FF;
+		drvcmd[2]=(pos>>8)&0x00FF;
+		drvcmd[3]=pos&0x00FF;
+		if (famL_drive)
+			flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
+		else
+			flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
+	}
+	else if (fam2_drive)
+	{
+		drvcmd[0]=CMD2_SEEK;
+		if (f_blk_msf==0) pos=blk2msf(pos);
+		drvcmd[2]=(pos>>24)&0x00FF;
+		drvcmd[3]=(pos>>16)&0x00FF;
+		drvcmd[4]=(pos>>8)&0x00FF;
+		drvcmd[5]=pos&0x00FF;
+		flags_cmd_out=f_putcmd|f_ResponseStatus;
+	}
+	else if (famT_drive)
+	{
+		drvcmd[0]=CMDT_SEEK;
+		if (f_blk_msf==1) pos=msf2blk(pos);
+		drvcmd[2]=(pos>>24)&0x00FF;
+		drvcmd[3]=(pos>>16)&0x00FF;
+		drvcmd[4]=(pos>>8)&0x00FF;
+		drvcmd[5]=pos&0x00FF;
+		D_S[d].n_bytes=1;
+	}
+	response_count=0;
+	i=cmd_out();
+	return (i);
+}
+/*==========================================================================*/
+static int cc_SpinUp(void)
+{
+	int i;
+	
+	msg(DBG_SPI,"SpinUp.\n");
+	D_S[d].in_SpinUp = 1;
+	clr_cmdbuf();
+	if (fam0L_drive)
+	{
+		drvcmd[0]=CMD0_SPINUP;
+		flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|
+			f_ResponseStatus|f_obey_p_check|f_bit1;
+	}
+	else if (fam1_drive)
+	{
+		drvcmd[0]=CMD1_SPINUP;
+		flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
+	}
+	else if (fam2_drive)
+	{
+		drvcmd[0]=CMD2_TRAY_CTL;
+		drvcmd[4]=0x01; /* "spinup" */
+		flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
+	}
+	else if (famT_drive)
+	{
+		drvcmd[0]=CMDT_TRAY_CTL;
+		drvcmd[4]=0x03; /* "insert", it hopefully spins the drive up */
+	}
+	response_count=0;
+	i=cmd_out();
+	D_S[d].in_SpinUp = 0;
+	return (i);
+}
+/*==========================================================================*/
+static int cc_SpinDown(void)
+{
+	int i;
+	
+	if (fam0_drive) return (0);
+	clr_cmdbuf();
+	response_count=0;
+	if (fam1_drive)
+	{
+		drvcmd[0]=CMD1_SPINDOWN;
+		flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
+	}
+	else if (fam2_drive)
+	{
+		drvcmd[0]=CMD2_TRAY_CTL;
+		drvcmd[4]=0x02; /* "eject" */
+		flags_cmd_out=f_putcmd|f_ResponseStatus;
+	}
+	else if (famL_drive)
+	{
+		drvcmd[0]=CMDL_SPINDOWN;
+		drvcmd[1]=1;
+		flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
+	}
+	else if (famT_drive)
+	{
+		drvcmd[0]=CMDT_TRAY_CTL;
+		drvcmd[4]=0x02; /* "eject" */
+	}
+	i=cmd_out();
+	return (i);
+}
+/*==========================================================================*/
+static int cc_get_mode_T(void)
+{
+	int i;
+	
+	clr_cmdbuf();
+	response_count=10;
+	drvcmd[0]=CMDT_GETMODE;
+	drvcmd[4]=response_count;
+	i=cmd_out_T();
+	return (i);
+}
+/*==========================================================================*/
+static int cc_set_mode_T(void)
+{
+	int i;
+	
+	clr_cmdbuf();
+	response_count=1;
+	drvcmd[0]=CMDT_SETMODE;
+	drvcmd[1]=D_S[d].speed_byte;
+	drvcmd[2]=D_S[d].frmsiz>>8;
+	drvcmd[3]=D_S[d].frmsiz&0x0FF;
+	drvcmd[4]=D_S[d].f_XA; /* 1: XA */
+	drvcmd[5]=D_S[d].type_byte; /* 0, 1, 3 */
+	drvcmd[6]=D_S[d].mode_xb_6;
+	drvcmd[7]=D_S[d].mode_yb_7|D_S[d].volume_control;
+	drvcmd[8]=D_S[d].mode_xb_8;
+	drvcmd[9]=D_S[d].delay;
+	i=cmd_out_T();
+	return (i);
+}
+/*==========================================================================*/
+static int cc_prep_mode_T(void)
+{
+	int i, j;
+	
+	i=cc_get_mode_T();
+	if (i<0) return (i);
+	for (i=0;i<10;i++)
+		sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
+	msgbuf[i*3]=0;
+	msg(DBG_TEA,"CMDT_GETMODE:%s\n", msgbuf);
+	D_S[d].speed_byte=0x02; /* 0x02: auto quad, 0x82: quad, 0x81: double, 0x80: single */
+	D_S[d].frmsiz=make16(infobuf[2],infobuf[3]);
+	D_S[d].f_XA=infobuf[4];
+	if (D_S[d].f_XA==0) D_S[d].type_byte=0;
+	else D_S[d].type_byte=1;
+	D_S[d].mode_xb_6=infobuf[6];
+	D_S[d].mode_yb_7=1;
+	D_S[d].mode_xb_8=infobuf[8];
+	D_S[d].delay=0; /* 0, 1, 2, 3 */
+	j=cc_set_mode_T();
+	i=cc_get_mode_T();
+	for (i=0;i<10;i++)
+		sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
+	msgbuf[i*3]=0;
+	msg(DBG_TEA,"CMDT_GETMODE:%s\n", msgbuf);
+	return (j);
+}
+/*==========================================================================*/
+static int cc_SetSpeed(u_char speed, u_char x1, u_char x2)
+{
+	int i;
+	
+	if (fam0L_drive) return (-3);
+	clr_cmdbuf();
+	response_count=0;
+	if (fam1_drive)
+	{
+		drvcmd[0]=CMD1_SETMODE;
+		drvcmd[1]=0x03;
+		drvcmd[2]=speed;
+		drvcmd[3]=x1;
+		drvcmd[4]=x2;
+		flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
 	}
-      else
+	else if (fam2_drive)
 	{
-	  drvcmd[2]=0;
-	  drvcmd[3]=150;
+		drvcmd[0]=CMD2_SETSPEED;
+		if (speed&speed_auto)
+		{
+			drvcmd[2]=0xFF;
+			drvcmd[3]=0xFF;
+		}
+		else
+		{
+			drvcmd[2]=0;
+			drvcmd[3]=150;
+		}
+		flags_cmd_out=f_putcmd|f_ResponseStatus;
 	}
-      flags_cmd_out=f_putcmd|f_ResponseStatus;
-    }
-  i=cmd_out(7);
-  return (i);
+	else if (famT_drive)
+	{
+		return (0);
+	}
+	i=cmd_out();
+	return (i);
 }
 /*==========================================================================*/
-static int xx_SetVolume(void)
+static int cc_SetVolume(void)
 {
-  int i;
-  u_char channel0,channel1,volume0,volume1;
-  u_char control0,value0,control1,value1;
-
-  DriveStruct[d].diskstate_flags &= ~volume_bit;
-  clr_cmdbuf();
-  channel0=DriveStruct[d].vol_chan0;
-  volume0=DriveStruct[d].vol_ctrl0;
-  channel1=control1=DriveStruct[d].vol_chan1;
-  volume1=value1=DriveStruct[d].vol_ctrl1;
-  control0=value0=0;
-
-  if (((DriveStruct[d].drv_options&audio_mono)!=0)&&(DriveStruct[d].drv_type>=drv_211))
-    {
-      if ((volume0!=0)&&(volume1==0))
+	int i;
+	u_char channel0,channel1,volume0,volume1;
+	u_char control0,value0,control1,value1;
+	
+	D_S[d].diskstate_flags &= ~volume_bit;
+	clr_cmdbuf();
+	channel0=D_S[d].vol_chan0;
+	volume0=D_S[d].vol_ctrl0;
+	channel1=control1=D_S[d].vol_chan1;
+	volume1=value1=D_S[d].vol_ctrl1;
+	control0=value0=0;
+	
+	if (((D_S[d].drv_options&audio_mono)!=0)&&(D_S[d].drv_type>=drv_211))
 	{
-	  volume1=volume0;
-	  channel1=channel0;
+		if ((volume0!=0)&&(volume1==0))
+		{
+			volume1=volume0;
+			channel1=channel0;
+		}
+		else if ((volume0==0)&&(volume1!=0))
+		{
+			volume0=volume1;
+			channel0=channel1;
+		}
 	}
-      else if ((volume0==0)&&(volume1!=0))
+	if (channel0>1)
 	{
-	  volume0=volume1;
-	  channel0=channel1;
+		channel0=0;
+		volume0=0;
 	}
-    }
-  if (channel0>1)
-    {
-      channel0=0;
-      volume0=0;
-    }
-  if (channel1>1)
-    {
-      channel1=1;
-      volume1=0;
-    }
-  
-  if (fam1_drive)
-    {
-      control0=channel0+1;
-      control1=channel1+1;
-      value0=(volume0>volume1)?volume0:volume1;
-      value1=value0;
-      if (volume0==0) control0=0;
-      if (volume1==0) control1=0;
-      drvcmd[0]=CMD1_SETMODE;
-      drvcmd[1]=0x05;
-      drvcmd[3]=control0;
-      drvcmd[4]=value0;
-      drvcmd[5]=control1;
-      drvcmd[6]=value1;
-      flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-    }
-  else if (fam2_drive)
-    {
-      control0=channel0+1;
-      control1=channel1+1;
-      value0=(volume0>volume1)?volume0:volume1;
-      value1=value0;
-      if (volume0==0) control0=0;
-      if (volume1==0) control1=0;
-      drvcmd[0]=CMD2_SETMODE;
-      drvcmd[1]=0x0E;
-      drvcmd[3]=control0;
-      drvcmd[4]=value0;
-      drvcmd[5]=control1;
-      drvcmd[6]=value1;
-      flags_cmd_out=f_putcmd|f_ResponseStatus;
-    }
-  else if (famL_drive)
-    {
-      if ((volume0==0)||(channel0!=0)) control0 |= 0x80;
-      if ((volume1==0)||(channel1!=1)) control0 |= 0x40;
-      if (volume0|volume1) value0=0x80;
-      drvcmd[0]=CMDL_SETMODE;
-      drvcmd[1]=0x03;
-      drvcmd[4]=control0;
-      drvcmd[5]=value0;
-      flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
-    }
-  else if (fam0_drive) /* different firmware levels */
-    {
-      if (DriveStruct[d].drv_type>=drv_300)
-	{
-	  control0=volume0&0xFC;
-	  value0=volume1&0xFC;
-	  if ((volume0!=0)&&(volume0<4)) control0 |= 0x04;
-	  if ((volume1!=0)&&(volume1<4)) value0 |= 0x04;
-	  if (channel0!=0) control0 |= 0x01;
-	  if (channel1==1) value0 |= 0x01;
-	}
-      else
-	{
-	  value0=(volume0>volume1)?volume0:volume1;
-	  if (DriveStruct[d].drv_type<drv_211)
-	    {
-	      if (channel0!=0)
-		{
-		  i=channel1;
-		  channel1=channel0;
-		  channel0=i;
-		  i=volume1;
-		  volume1=volume0;
-		  volume0=i;
-		}
-	      if (channel0==channel1)
-		{
-		  if (channel0==0)
-		    {
-		      channel1=1;
-		      volume1=0;
-		      volume0=value0;
-		    }
-		  else
-		    {
-		      channel0=0;
-		      volume0=0;
-		      volume1=value0;
-		    }
-		}
-	    }
-
-	  if ((volume0!=0)&&(volume1!=0))
-	    {
-	      if (volume0==0xFF) volume1=0xFF;
-	      else if (volume1==0xFF) volume0=0xFF;
-	    }
-	  else if (DriveStruct[d].drv_type<drv_201) volume0=volume1=value0;
-
-	  if (DriveStruct[d].drv_type>=drv_201)
-	    {
-	      if (volume0==0) control0 |= 0x80;
-	      if (volume1==0) control0 |= 0x40;
-	    }
-	  if (DriveStruct[d].drv_type>=drv_211)
-	    {
-	      if (channel0!=0) control0 |= 0x20;
-	      if (channel1!=1) control0 |= 0x10;
-	    }
-	}
-      drvcmd[0]=CMD0_SETMODE;
-      drvcmd[1]=0x83;
-      drvcmd[4]=control0;
-      drvcmd[5]=value0;
-      flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
-    }
-  response_count=0;
-  i=cmd_out(7);
-  if (i>0) return (i);
-  DriveStruct[d].diskstate_flags |= volume_bit;
-  return (0);
+	if (channel1>1)
+	{
+		channel1=1;
+		volume1=0;
+	}
+	
+	if (fam1_drive)
+	{
+		control0=channel0+1;
+		control1=channel1+1;
+		value0=(volume0>volume1)?volume0:volume1;
+		value1=value0;
+		if (volume0==0) control0=0;
+		if (volume1==0) control1=0;
+		drvcmd[0]=CMD1_SETMODE;
+		drvcmd[1]=0x05;
+		drvcmd[3]=control0;
+		drvcmd[4]=value0;
+		drvcmd[5]=control1;
+		drvcmd[6]=value1;
+		flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+	}
+	else if (fam2_drive)
+	{
+		control0=channel0+1;
+		control1=channel1+1;
+		value0=(volume0>volume1)?volume0:volume1;
+		value1=value0;
+		if (volume0==0) control0=0;
+		if (volume1==0) control1=0;
+		drvcmd[0]=CMD2_SETMODE;
+		drvcmd[1]=0x0E;
+		drvcmd[3]=control0;
+		drvcmd[4]=value0;
+		drvcmd[5]=control1;
+		drvcmd[6]=value1;
+		flags_cmd_out=f_putcmd|f_ResponseStatus;
+	}
+	else if (famL_drive)
+	{
+		if ((volume0==0)||(channel0!=0)) control0 |= 0x80;
+		if ((volume1==0)||(channel1!=1)) control0 |= 0x40;
+		if (volume0|volume1) value0=0x80;
+		drvcmd[0]=CMDL_SETMODE;
+		drvcmd[1]=0x03;
+		drvcmd[4]=control0;
+		drvcmd[5]=value0;
+		flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
+	}
+	else if (fam0_drive) /* different firmware levels */
+	{
+		if (D_S[d].drv_type>=drv_300)
+		{
+			control0=volume0&0xFC;
+			value0=volume1&0xFC;
+			if ((volume0!=0)&&(volume0<4)) control0 |= 0x04;
+			if ((volume1!=0)&&(volume1<4)) value0 |= 0x04;
+			if (channel0!=0) control0 |= 0x01;
+			if (channel1==1) value0 |= 0x01;
+		}
+		else
+		{
+			value0=(volume0>volume1)?volume0:volume1;
+			if (D_S[d].drv_type<drv_211)
+			{
+				if (channel0!=0)
+				{
+					i=channel1;
+					channel1=channel0;
+					channel0=i;
+					i=volume1;
+					volume1=volume0;
+					volume0=i;
+				}
+				if (channel0==channel1)
+				{
+					if (channel0==0)
+					{
+						channel1=1;
+						volume1=0;
+						volume0=value0;
+					}
+					else
+					{
+						channel0=0;
+						volume0=0;
+						volume1=value0;
+					}
+				}
+			}
+			
+			if ((volume0!=0)&&(volume1!=0))
+			{
+				if (volume0==0xFF) volume1=0xFF;
+				else if (volume1==0xFF) volume0=0xFF;
+			}
+			else if (D_S[d].drv_type<drv_201) volume0=volume1=value0;
+			
+			if (D_S[d].drv_type>=drv_201)
+			{
+				if (volume0==0) control0 |= 0x80;
+				if (volume1==0) control0 |= 0x40;
+			}
+			if (D_S[d].drv_type>=drv_211)
+			{
+				if (channel0!=0) control0 |= 0x20;
+				if (channel1!=1) control0 |= 0x10;
+			}
+		}
+		drvcmd[0]=CMD0_SETMODE;
+		drvcmd[1]=0x83;
+		drvcmd[4]=control0;
+		drvcmd[5]=value0;
+		flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
+	}
+	else if (famT_drive)
+	{
+		D_S[d].volume_control=0;
+		if (!volume0) D_S[d].volume_control|=0x10;
+		if (!volume1) D_S[d].volume_control|=0x20;
+		i=cc_prep_mode_T();
+		if (i<0) return (i);
+	}
+	if (!famT_drive)
+	{
+		response_count=0;
+		i=cmd_out();
+		if (i<0) return (i);
+	}
+	D_S[d].diskstate_flags |= volume_bit;
+	return (0);
 }
 /*==========================================================================*/
 static int GetStatus(void)
 {
-  int i;
-
-  flags_cmd_out=f_getsta|f_ResponseStatus|f_obey_p_check;
-  response_count=0;
-  cmd_type=0;
-  i=cmd_out(7);
-  return (i);
-}
-/*==========================================================================*/
-static int xy_DriveReset(void)
-{
-  int i;
-
-  DPRINTF((DBG_RES,"SBPCD: xy_DriveReset called.\n"));
-  clr_cmdbuf();
-  response_count=0;
-  if (fam0L_drive) OUT(CDo_reset,0x00);
-  else if (fam1_drive)
-    {
-      drvcmd[0]=CMD1_RESET;
-      flags_cmd_out=f_putcmd;
-      i=cmd_out(7);
-    }
-  else if (fam2_drive)
-    {
-      drvcmd[0]=CMD2_RESET;
-      flags_cmd_out=f_putcmd;
-      i=cmd_out(7);
-      OUT(CDo_reset,0x00);
-    }
-  if (famL_drive) sbp_sleep(500); /* wait 5 seconds */
-  else sbp_sleep(100); /* wait a second */
-  flush_status();
-  i=GetStatus();
-  if (i>=0) return -1;
-  if (DriveStruct[d].error_byte!=aud_12) return -1;
-  return (0);
+	int i;
+	
+	if (famT_drive) return (0);
+	flags_cmd_out=f_getsta|f_ResponseStatus|f_obey_p_check;
+	response_count=0;
+	cmd_type=0;
+	i=cmd_out();
+	return (i);
+}
+/*==========================================================================*/
+static int cc_DriveReset(void)
+{
+	int i;
+	
+	msg(DBG_RES,"cc_DriveReset called.\n");
+	clr_cmdbuf();
+	response_count=0;
+	if (fam0L_drive) OUT(CDo_reset,0x00);
+	else if (fam1_drive)
+	{
+		drvcmd[0]=CMD1_RESET;
+		flags_cmd_out=f_putcmd;
+		i=cmd_out();
+	}
+	else if (fam2_drive)
+	{
+		drvcmd[0]=CMD2_RESET;
+		flags_cmd_out=f_putcmd;
+		i=cmd_out();
+		OUT(CDo_reset,0x00);
+	}
+	else if (famT_drive)
+	{
+		OUT(CDo_sel_i_d,0);
+		OUT(CDo_enable,D_S[d].drv_sel);
+		OUT(CDo_command,CMDT_RESET);
+		for (i=1;i<10;i++) OUT(CDo_command,0);
+	}
+	if (fam0L_drive) sbp_sleep(500); /* wait 5 seconds */
+	else sbp_sleep(100); /* wait a second */
+#if 1
+	if (famT_drive)
+	{
+		msg(DBG_TEA, "================CMDT_RESET given=================.\n");
+		sbp_sleep(300);
+	}
+#endif 1
+	flush_status();
+	i=GetStatus();
+	if (i<0) return i;
+	if (!famT_drive)
+		if (D_S[d].error_byte!=aud_12) return -501;
+	return (0);
 }
 /*==========================================================================*/
 static int SetSpeed(void)
 {
-  int i, speed;
-
-  if (!(DriveStruct[d].drv_options&(speed_auto|speed_300|speed_150))) return (0);
-  speed=speed_auto;
-  if (!(DriveStruct[d].drv_options&speed_auto))
-    {
-      speed |= speed_300;
-      if (!(DriveStruct[d].drv_options&speed_300)) speed=0;
-    }
-  i=yy_SetSpeed(speed,0,0);
-  return (i);
+	int i, speed;
+	
+	if (!(D_S[d].drv_options&(speed_auto|speed_300|speed_150))) return (0);
+	speed=speed_auto;
+	if (!(D_S[d].drv_options&speed_auto))
+	{
+		speed |= speed_300;
+		if (!(D_S[d].drv_options&speed_300)) speed=0;
+	}
+	i=cc_SetSpeed(speed,0,0);
+	return (i);
 }
 /*==========================================================================*/
 static int DriveReset(void)
 {
-  int i;
-
-  i=xy_DriveReset();
-  if (i<0) return (-2);
-  do
-    {
-      i=GetStatus();
-      if ((i<0)&&(i!=-15)) return (-2); /* i!=-15 is from sta2err */
-      if (!st_caddy_in) break;
-    }
-  while (!st_diskok);
+	int i;
+	
+	i=cc_DriveReset();
+	if (i<0) return (-22);
+	do
+	{
+		i=GetStatus();
+		if ((i<0)&&(i!=-615)) return (-2); /* i!=-615 is from sta2err */
+		if (!st_caddy_in) break;
+		sbp_sleep(1);
+	}
+	while (!st_diskok);
 #if 000
-  DriveStruct[d].CD_changed=1;
+	D_S[d].CD_changed=1;
 #endif
-  if ((st_door_closed) && (st_caddy_in))
-    {
-      i=DiskInfo();
-      if (i<0) return (-2);
-    }
-  return (0);
+	if ((st_door_closed) && (st_caddy_in))
+	{
+		i=DiskInfo();
+		if (i<0) return (-23);
+	}
+	return (0);
 }
 /*==========================================================================*/
-static int xx_Pause_Resume(int pau_res)
+static int cc_PlayAudio(int pos_audio_start,int pos_audio_end)
 {
-  int i;
-
-  clr_cmdbuf();
-  response_count=0;
-  if (fam1_drive)
-    {
-      drvcmd[0]=CMD1_PAU_RES;
-      if (pau_res!=1) drvcmd[1]=0x80;
-      flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
-    }
-  else if (fam2_drive)
-    {
-      drvcmd[0]=CMD2_PAU_RES;
-      if (pau_res!=1) drvcmd[2]=0x01;
-      flags_cmd_out=f_putcmd|f_ResponseStatus;
-    }
-  else if (fam0L_drive)
-    {
-      drvcmd[0]=CMD0_PAU_RES;
-      if (pau_res!=1) drvcmd[1]=0x80;
-      if (famL_drive)
-	flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|
-	  f_obey_p_check|f_bit1;
-      else
-	flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|
-	  f_obey_p_check;
-    }
-  i=cmd_out(7);
-  return (i);
+	int i, j, n;
+	
+	if (D_S[d].audio_state==audio_playing) return (-EINVAL);
+	clr_cmdbuf();
+	response_count=0;
+	if (famL_drive)
+	{
+		drvcmd[0]=CMDL_PLAY;
+		i=msf2blk(pos_audio_start);
+		n=msf2blk(pos_audio_end)+1-i;
+		drvcmd[1]=(i>>16)&0x00FF;
+		drvcmd[2]=(i>>8)&0x00FF;
+		drvcmd[3]=i&0x00FF;
+		drvcmd[4]=(n>>16)&0x00FF;
+		drvcmd[5]=(n>>8)&0x00FF;
+		drvcmd[6]=n&0x00FF;
+		flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta |
+			f_ResponseStatus | f_obey_p_check | f_wait_if_busy;
+	}
+	else
+	{
+		j=1;
+		if (fam1_drive)
+		{
+			drvcmd[0]=CMD1_PLAY_MSF;
+			flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus |
+				f_obey_p_check | f_wait_if_busy;
+		}
+		else if (fam2_drive)
+		{
+			drvcmd[0]=CMD2_PLAY_MSF;
+			flags_cmd_out = f_putcmd | f_ResponseStatus;
+		}
+		else if (famT_drive)
+		{
+			drvcmd[0]=CMDT_PLAY_MSF;
+			j=3;
+			response_count=1;
+		}
+		else if (fam0_drive)
+		{
+			drvcmd[0]=CMD0_PLAY_MSF;
+			flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta |
+				f_ResponseStatus | f_obey_p_check | f_wait_if_busy;
+		}
+		drvcmd[j]=(pos_audio_start>>16)&0x00FF;
+		drvcmd[j+1]=(pos_audio_start>>8)&0x00FF;
+		drvcmd[j+2]=pos_audio_start&0x00FF;
+		drvcmd[j+3]=(pos_audio_end>>16)&0x00FF;
+		drvcmd[j+4]=(pos_audio_end>>8)&0x00FF;
+		drvcmd[j+5]=pos_audio_end&0x00FF;
+	}
+	i=cmd_out();
+	return (i);
 }
 /*==========================================================================*/
-static int yy_LockDoor(char lock)
+static int cc_Pause_Resume(int pau_res)
 {
-  int i;
-
-  if (fam0_drive) return (0);
-  DPRINTF((DBG_LCK,"SBPCD: yy_LockDoor: %d (drive %d)\n", lock, d));
-  DPRINTF((DBG_LCS,"SBPCD: p_door_locked bit %d before\n", st_door_locked));
-  clr_cmdbuf();
-  response_count=0;
-  if (fam1_drive)
-    {
-      drvcmd[0]=CMD1_LOCK_CTL;
-      if (lock==1) drvcmd[1]=0x01;
-      flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-    }
-  else if (fam2_drive)
-    {
-      drvcmd[0]=CMD2_LOCK_CTL;
-      if (lock==1) drvcmd[4]=0x01;
-      flags_cmd_out=f_putcmd|f_ResponseStatus;
-    }
-  else if (famL_drive)
-    {
-      drvcmd[0]=CMDL_LOCK_CTL;
-      if (lock==1) drvcmd[1]=0x01;
-      flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
-    }
-  i=cmd_out(7);
-  DPRINTF((DBG_LCS,"SBPCD: p_door_locked bit %d after\n", st_door_locked));
-  return (i);
+	int i;
+	
+	clr_cmdbuf();
+	response_count=0;
+	if (fam1_drive)
+	{
+		drvcmd[0]=CMD1_PAU_RES;
+		if (pau_res!=1) drvcmd[1]=0x80;
+		flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
+	}
+	else if (fam2_drive)
+	{
+		drvcmd[0]=CMD2_PAU_RES;
+		if (pau_res!=1) drvcmd[2]=0x01;
+		flags_cmd_out=f_putcmd|f_ResponseStatus;
+	}
+	else if (fam0L_drive)
+	{
+		drvcmd[0]=CMD0_PAU_RES;
+		if (pau_res!=1) drvcmd[1]=0x80;
+		if (famL_drive)
+			flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|
+				f_obey_p_check|f_bit1;
+		else
+			flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|
+				f_obey_p_check;
+	}
+	else if (famT_drive)
+	{
+		if (pau_res==3)	return (cc_PlayAudio(D_S[d].pos_audio_start,D_S[d].pos_audio_end));
+		else if (pau_res==1) drvcmd[0]=CMDT_PAUSE;
+		else return (-56);
+	}
+	i=cmd_out();
+	return (i);
 }
 /*==========================================================================*/
-static int yy_CloseTray(void)
+static int cc_LockDoor(char lock)
 {
-  int i;
-
-  if (fam0_drive) return (0);
-  DPRINTF((DBG_LCK,"SBPCD: yy_CloseTray (drive %d)\n", d));
-  DPRINTF((DBG_LCS,"SBPCD: p_door_closed bit %d before\n", st_door_closed));
-
-  clr_cmdbuf();
-  response_count=0;
-  if (fam1_drive)
-    {
-      drvcmd[0]=CMD1_TRAY_CTL;
-      flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
-    }
-  else if (fam2_drive)
-    {
-      drvcmd[0]=CMD2_TRAY_CTL;
-      drvcmd[1]=0x01;
-      drvcmd[4]=0x03; /* "insert" */
-      flags_cmd_out=f_putcmd|f_ResponseStatus;
-    }
-  else if (famL_drive)
-    {
-      drvcmd[0]=CMDL_TRAY_CTL;
-      flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|
- 	f_ResponseStatus|f_obey_p_check|f_bit1;
-    }
-  i=cmd_out(7);
-  DPRINTF((DBG_LCS,"SBPCD: p_door_closed bit %d after\n", st_door_closed));
-  return (i);
+	int i;
+	
+	if (fam0_drive) return (0);
+	msg(DBG_LCK,"cc_LockDoor: %d (drive %d)\n", lock, d);
+	msg(DBG_LCS,"p_door_locked bit %d before\n", st_door_locked);
+	clr_cmdbuf();
+	response_count=0;
+	if (fam1_drive)
+	{
+		drvcmd[0]=CMD1_LOCK_CTL;
+		if (lock==1) drvcmd[1]=0x01;
+		flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+	}
+	else if (fam2_drive)
+	{
+		drvcmd[0]=CMD2_LOCK_CTL;
+		if (lock==1) drvcmd[4]=0x01;
+		flags_cmd_out=f_putcmd|f_ResponseStatus;
+	}
+	else if (famL_drive)
+	{
+		drvcmd[0]=CMDL_LOCK_CTL;
+		if (lock==1) drvcmd[1]=0x01;
+		flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
+	}
+	else if (famT_drive)
+	{
+		drvcmd[0]=CMDT_LOCK_CTL;
+		if (lock==1) drvcmd[4]=0x01;
+	}
+	i=cmd_out();
+	msg(DBG_LCS,"p_door_locked bit %d after\n", st_door_locked);
+	return (i);
 }
 /*==========================================================================*/
-static int xx_ReadSubQ(void)
+/*==========================================================================*/
+static int UnLockDoor(void)
 {
-  int i,j;
-
-  DriveStruct[d].diskstate_flags &= ~subq_bit;
-  for (j=255;j>0;j--)
-    {
-      clr_cmdbuf();
-      if (fam1_drive)
+	int i,j;
+	
+	j=20;
+	do
 	{
-	  drvcmd[0]=CMD1_READSUBQ;
-	  flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-	  response_count=11;
+		i=cc_LockDoor(0);
+		--j;
+		sbp_sleep(1);
 	}
-      else if (fam2_drive)
+	while ((i<0)&&(j));
+	if (i<0)
 	{
-	  drvcmd[0]=CMD2_READSUBQ;
-	  drvcmd[1]=0x02;
-	  drvcmd[3]=0x01;
-	  flags_cmd_out=f_putcmd;
-	  response_count=10;
+		cc_DriveReset();
+		return -84;
 	}
-      else if (fam0L_drive)
+	return (0);
+}
+/*==========================================================================*/
+static int LockDoor(void)
+{
+	int i,j;
+	
+	j=20;
+	do
 	{
-	  drvcmd[0]=CMD0_READSUBQ;
-	  drvcmd[1]=0x02;
- 	  if (famL_drive)
- 	    flags_cmd_out=f_putcmd;
- 	  else
- 	    flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
-	  response_count=13;
+		i=cc_LockDoor(1);
+		--j;
+		sbp_sleep(1);
 	}
-      i=cmd_out(7);
-      if (i<0) return (i);
-      DPRINTF((DBG_SQ,"SBPCD: xx_ReadSubQ:"));
-      for (i=0;i<response_count;i++)
+	while ((i<0)&&(j));
+	if (j==0) cc_DriveReset();
+	j=20;
+	do
 	{
-	  DPRINTF((DBG_SQ," %02X", infobuf[i]));
+		i=cc_LockDoor(1);
+		--j;
+		sbp_sleep(1);
 	}
-      DPRINTF((DBG_SQ,"\n"));
-      if (infobuf[0]!=0) break;
-      if ((!st_spinning) || (j==1))
+	while ((i<0)&&(j));
+	return (i);
+}
+/*==========================================================================*/
+static int cc_CloseTray(void)
+{
+	int i;
+	
+	if (fam0_drive) return (0);
+	msg(DBG_LCK,"cc_CloseTray (drive %d)\n", d);
+	msg(DBG_LCS,"p_door_closed bit %d before\n", st_door_closed);
+	
+	clr_cmdbuf();
+	response_count=0;
+	if (fam1_drive)
 	{
-	  DriveStruct[d].SubQ_ctl_adr=DriveStruct[d].SubQ_trk=DriveStruct[d].SubQ_pnt_idx=DriveStruct[d].SubQ_whatisthis=0;
-	  DriveStruct[d].SubQ_run_tot=DriveStruct[d].SubQ_run_trk=0;
-	  return (0);
+		drvcmd[0]=CMD1_TRAY_CTL;
+		flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
 	}
-    }
-  DriveStruct[d].SubQ_ctl_adr=swap_nibbles(infobuf[1]);
-  DriveStruct[d].SubQ_trk=byt2bcd(infobuf[2]);
-  DriveStruct[d].SubQ_pnt_idx=byt2bcd(infobuf[3]);
-  i=4;
-  if (fam0L_drive) i=5;
-  DriveStruct[d].SubQ_run_tot=make32(make16(0,infobuf[i]),make16(infobuf[i+1],infobuf[i+2])); /* msf-bin */
-  i=7;
-  if (fam0L_drive) i=9;
-  DriveStruct[d].SubQ_run_trk=make32(make16(0,infobuf[i]),make16(infobuf[i+1],infobuf[i+2])); /* msf-bin */
-  DriveStruct[d].SubQ_whatisthis=infobuf[i+3];
-  DriveStruct[d].diskstate_flags |= subq_bit;
-  return (0);
+	else if (fam2_drive)
+	{
+		drvcmd[0]=CMD2_TRAY_CTL;
+		drvcmd[1]=0x01;
+		drvcmd[4]=0x03; /* "insert" */
+		flags_cmd_out=f_putcmd|f_ResponseStatus;
+	}
+	else if (famL_drive)
+	{
+		drvcmd[0]=CMDL_TRAY_CTL;
+		flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|
+			f_ResponseStatus|f_obey_p_check|f_bit1;
+	}
+	else if (famT_drive)
+	{
+		drvcmd[0]=CMDT_TRAY_CTL;
+		drvcmd[4]=0x03; /* "insert" */
+	}
+	i=cmd_out();
+	msg(DBG_LCS,"p_door_closed bit %d after\n", st_door_closed);
+	return (i);
 }
 /*==========================================================================*/
-static int xx_ModeSense(void)
+static int cc_ReadSubQ(void)
 {
-  int i;
-
-  if (fam2_drive) return (0);
-  DriveStruct[d].diskstate_flags &= ~frame_size_bit;
-  clr_cmdbuf();
-  if (fam1_drive)
-    {
-      drvcmd[0]=CMD1_GETMODE;
-      flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-      response_count=5;
-    }
-  else if (fam0L_drive)
-    {
-      drvcmd[0]=CMD0_GETMODE;
-      if (famL_drive)
-	flags_cmd_out=f_putcmd;
-      else
-	flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
-      response_count=2;
-    }
-  i=cmd_out(7);
-  if (i<0) return (i);
-  i=0;
-  if (fam1_drive) DriveStruct[d].sense_byte=infobuf[i++];
-  else if (fam0L_drive) DriveStruct[d].sense_byte=0;
-  DriveStruct[d].frame_size=make16(infobuf[i],infobuf[i+1]);
-
-  DPRINTF((DBG_XA,"SBPCD: xx_ModeSense: "));
-  for (i=0;i<(fam1_drive?5:2);i++)
-    {
-      DPRINTF((DBG_XA,"%02X ", infobuf[i]));
-    }
-  DPRINTF((DBG_XA,"\n"));
+	int i,j;
 
-  DriveStruct[d].diskstate_flags |= frame_size_bit;
-  return (0);
+	D_S[d].diskstate_flags &= ~subq_bit;
+	for (j=255;j>0;j--)
+	{
+		clr_cmdbuf();
+		if (fam1_drive)
+		{
+			drvcmd[0]=CMD1_READSUBQ;
+			flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+			response_count=11;
+		}
+		else if (fam2_drive)
+		{
+			drvcmd[0]=CMD2_READSUBQ;
+			drvcmd[1]=0x02;
+			drvcmd[3]=0x01;
+			flags_cmd_out=f_putcmd;
+			response_count=10;
+		}
+		else if (fam0L_drive)
+		{
+			drvcmd[0]=CMD0_READSUBQ;
+			drvcmd[1]=0x02;
+			if (famL_drive)
+				flags_cmd_out=f_putcmd;
+			else
+				flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
+			response_count=13;
+		}
+		else if (famT_drive)
+		{
+			response_count=12;
+			drvcmd[0]=CMDT_READSUBQ;
+			drvcmd[1]=0x02;
+			drvcmd[2]=0x40;
+			drvcmd[3]=0x01;
+			drvcmd[8]=response_count;
+		}
+		i=cmd_out();
+		if (i<0) return (i);
+		for (i=0;i<response_count;i++)
+		{
+			sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
+			msgbuf[i*3]=0;
+			msg(DBG_SQ1,"cc_ReadSubQ:%s\n", msgbuf);
+		}
+		if (famT_drive) break;
+		if (infobuf[0]!=0) break;
+		if ((!st_spinning) || (j==1))
+		{
+			D_S[d].SubQ_ctl_adr=D_S[d].SubQ_trk=D_S[d].SubQ_pnt_idx=D_S[d].SubQ_whatisthis=0;
+			D_S[d].SubQ_run_tot=D_S[d].SubQ_run_trk=0;
+			return (0);
+		}
+	}
+	if (famT_drive) D_S[d].SubQ_ctl_adr=infobuf[1];
+	else D_S[d].SubQ_ctl_adr=swap_nibbles(infobuf[1]);
+	D_S[d].SubQ_trk=byt2bcd(infobuf[2]);
+	D_S[d].SubQ_pnt_idx=byt2bcd(infobuf[3]);
+	if (fam0L_drive) i=5;
+	else if (fam12_drive) i=4;
+	else if (famT_drive) i=8;
+	D_S[d].SubQ_run_tot=make32(make16(0,infobuf[i]),make16(infobuf[i+1],infobuf[i+2])); /* msf-bin */
+	i=7;
+	if (fam0L_drive) i=9;
+	else if (fam12_drive) i=7;
+	else if (famT_drive) i=4;
+	D_S[d].SubQ_run_trk=make32(make16(0,infobuf[i]),make16(infobuf[i+1],infobuf[i+2])); /* msf-bin */
+	D_S[d].SubQ_whatisthis=infobuf[i+3];
+	D_S[d].diskstate_flags |= subq_bit;
+	return (0);
+}
+/*==========================================================================*/
+static int cc_ModeSense(void)
+{
+	int i;
+	
+	if (fam2_drive) return (0);
+	D_S[d].diskstate_flags &= ~frame_size_bit;
+	clr_cmdbuf();
+	if (fam1_drive)
+	{
+		response_count=5;
+		drvcmd[0]=CMD1_GETMODE;
+		flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+	}
+	else if (fam0L_drive)
+	{
+		response_count=2;
+		drvcmd[0]=CMD0_GETMODE;
+		if (famL_drive) flags_cmd_out=f_putcmd;
+		else flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
+	}
+	else if (famT_drive)
+	{
+		response_count=10;
+		drvcmd[0]=CMDT_GETMODE;
+		drvcmd[4]=response_count;
+	}
+	i=cmd_out();
+	if (i<0) return (i);
+	i=0;
+	if (fam1_drive) D_S[d].sense_byte=infobuf[i++];
+	else if (fam0L_drive) D_S[d].sense_byte=0;
+	else if (famT_drive)
+	{
+		D_S[d].sense_byte=0;
+		if (infobuf[4]==0x01) D_S[d].xa_byte=0x20;
+		i=2;
+	}
+	D_S[d].frame_size=make16(infobuf[i],infobuf[i+1]);
+	for (i=0;i<response_count;i++)
+		sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
+	msgbuf[i*3]=0;
+	msg(DBG_XA1,"cc_ModeSense:%s\n", msgbuf);
+	
+	D_S[d].diskstate_flags |= frame_size_bit;
+	return (0);
 }
 /*==========================================================================*/
 /*==========================================================================*/
-static int xx_ModeSelect(int framesize)
+static int cc_ModeSelect(int framesize)
 {
-  int i;
-
-  if (fam2_drive) return (0);
-  DriveStruct[d].diskstate_flags &= ~frame_size_bit;
-  clr_cmdbuf();
-  DriveStruct[d].frame_size=framesize;
-  if (framesize==CD_FRAMESIZE_RAW) DriveStruct[d].sense_byte=0x82;
-  else DriveStruct[d].sense_byte=0x00;
-
-  DPRINTF((DBG_XA,"SBPCD: xx_ModeSelect: %02X %04X\n",
-	   DriveStruct[d].sense_byte, DriveStruct[d].frame_size));
-
-  if (fam1_drive)
-    {
-      drvcmd[0]=CMD1_SETMODE;
-      drvcmd[1]=0x00;
-      drvcmd[2]=DriveStruct[d].sense_byte;
-      drvcmd[3]=(DriveStruct[d].frame_size>>8)&0xFF;
-      drvcmd[4]=DriveStruct[d].frame_size&0xFF;
-      flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-    }
-  else if (fam0L_drive)
-    {
-      drvcmd[0]=CMD0_SETMODE;
-      drvcmd[1]=0x00;
-      drvcmd[2]=(DriveStruct[d].frame_size>>8)&0xFF;
-      drvcmd[3]=DriveStruct[d].frame_size&0xFF;
-      drvcmd[4]=0x00;
-      if(famL_drive)
-	flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check;
-      else
-	flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
-    }
-  response_count=0;
-  i=cmd_out(7);
-  if (i<0) return (i);
-  DriveStruct[d].diskstate_flags |= frame_size_bit;
-  return (0);
+	int i;
+	
+	if (fam2_drive) return (0);
+	D_S[d].diskstate_flags &= ~frame_size_bit;
+	clr_cmdbuf();
+	D_S[d].frame_size=framesize;
+	if (framesize==CD_FRAMESIZE_RAW) D_S[d].sense_byte=0x82;
+	else D_S[d].sense_byte=0x00;
+	
+	msg(DBG_XA1,"cc_ModeSelect: %02X %04X\n",
+	    D_S[d].sense_byte, D_S[d].frame_size);
+	
+	if (fam1_drive)
+	{
+		drvcmd[0]=CMD1_SETMODE;
+		drvcmd[1]=0x00;
+		drvcmd[2]=D_S[d].sense_byte;
+		drvcmd[3]=(D_S[d].frame_size>>8)&0xFF;
+		drvcmd[4]=D_S[d].frame_size&0xFF;
+		flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+	}
+	else if (fam0L_drive)
+	{
+		drvcmd[0]=CMD0_SETMODE;
+		drvcmd[1]=0x00;
+		drvcmd[2]=(D_S[d].frame_size>>8)&0xFF;
+		drvcmd[3]=D_S[d].frame_size&0xFF;
+		drvcmd[4]=0x00;
+		if(famL_drive)
+			flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check;
+		else
+			flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
+	}
+	else if (famT_drive)
+	{
+		return (-1);
+	}
+	response_count=0;
+	i=cmd_out();
+	if (i<0) return (i);
+	D_S[d].diskstate_flags |= frame_size_bit;
+	return (0);
 }
 /*==========================================================================*/
-#if 0000
-static int xx_TellVolume(void)
+static int cc_GetVolume(void)
 {
-  int i;
-  u_char switches;
-  u_char chan0,vol0,chan1,vol1;
-
-  DriveStruct[d].diskstate_flags &= ~volume_bit;
-  clr_cmdbuf();
-  if (fam1_drive)
-    {
-      drvcmd[0]=CMD1_GETMODE;
-      drvcmd[1]=0x05;
-      response_count=5;
-      flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-    }
-  else if (fam2_drive)
-    {
-      drvcmd[0]=CMD2_GETMODE;
-      drvcmd[1]=0x0E;
-      response_count=5;
-      flags_cmd_out=f_putcmd;
-    }
-  else if (fam0L_drive)
-    {
-      drvcmd[0]=CMD0_GETMODE;
-      drvcmd[1]=0x03;
-      response_count=2;
-      if(famL_drive)
-	flags_cmd_out=f_putcmd;
-      else
-	flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
-    }
-  i=cmd_out(7);
-  if (i<0) return (i);
-  if (fam1_drive)
-    {
-      chan0=infobuf[1]&0x0F;
-      vol0=infobuf[2];
-      chan1=infobuf[3]&0x0F;
-      vol1=infobuf[4];
-      if (chan0==0)
-	{
-	  chan0=1;
-	  vol0=0;
+	int i;
+	u_char switches;
+	u_char chan0=0;
+	u_char vol0=0;
+	u_char chan1=1;
+	u_char vol1=0;
+	
+	D_S[d].diskstate_flags &= ~volume_bit;
+	clr_cmdbuf();
+	if (fam1_drive)
+	{
+		drvcmd[0]=CMD1_GETMODE;
+		drvcmd[1]=0x05;
+		response_count=5;
+		flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+	}
+	else if (fam2_drive)
+	{
+		drvcmd[0]=CMD2_GETMODE;
+		drvcmd[1]=0x0E;
+		response_count=5;
+		flags_cmd_out=f_putcmd;
+	}
+	else if (fam0L_drive)
+	{
+		drvcmd[0]=CMD0_GETMODE;
+		drvcmd[1]=0x03;
+		response_count=2;
+		if(famL_drive)
+			flags_cmd_out=f_putcmd;
+		else
+			flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
+	}
+	else if (famT_drive)
+	{
+		i=cc_get_mode_T();
+		if (i<0) return (i);
+	}
+	if (!famT_drive)
+	{
+		i=cmd_out();
+		if (i<0) return (i);
+	}
+	if (fam1_drive)
+	{
+		chan0=infobuf[1]&0x0F;
+		vol0=infobuf[2];
+		chan1=infobuf[3]&0x0F;
+		vol1=infobuf[4];
+		if (chan0==0)
+		{
+			chan0=1;
+			vol0=0;
+		}
+		if (chan1==0)
+		{
+			chan1=2;
+			vol1=0;
+		}
+		chan0 >>= 1;
+		chan1 >>= 1;
 	}
-      if (chan1==0)
+	else if (fam2_drive)
 	{
-	  chan1=2;
-	  vol1=0;
+		chan0=infobuf[1];
+		vol0=infobuf[2];
+		chan1=infobuf[3];
+		vol1=infobuf[4];
+	}
+	else if (famL_drive)
+	{
+		chan0=0;
+		chan1=1;
+		vol0=vol1=infobuf[1];
+		switches=infobuf[0];
+		if ((switches&0x80)!=0) chan0=1;
+		if ((switches&0x40)!=0) chan1=0;
+	}
+	else if (fam0_drive) /* different firmware levels */
+	{
+		chan0=0;
+		chan1=1;
+		vol0=vol1=infobuf[1];
+		if (D_S[d].drv_type>=drv_201)
+		{
+			if (D_S[d].drv_type<drv_300)
+			{
+				switches=infobuf[0];
+				if ((switches&0x80)!=0) vol0=0;
+				if ((switches&0x40)!=0) vol1=0;
+				if (D_S[d].drv_type>=drv_211)
+				{
+					if ((switches&0x20)!=0) chan0=1;
+					if ((switches&0x10)!=0) chan1=0;
+				}
+			}
+			else
+			{
+				vol0=infobuf[0];
+				if ((vol0&0x01)!=0) chan0=1;
+				if ((vol1&0x01)==0) chan1=0;
+				vol0 &= 0xFC;
+				vol1 &= 0xFC;
+				if (vol0!=0) vol0 += 3;
+				if (vol1!=0) vol1 += 3;
+			}
+		}
 	}
-      chan0 >>= 1;
-      chan1 >>= 1;
-    }
-  else if (fam2_drive)
-    {
-      chan0=infobuf[1];
-      vol0=infobuf[2];
-      chan1=infobuf[3];
-      vol1=infobuf[4];
-    }
-  else if (famL_drive)
-    {
-      chan0=0;
-      chan1=1;
-      vol0=vol1=infobuf[1];
-      switches=infobuf[0];
-      if ((switches&0x80)!=0) chan0=1;
-      if ((switches&0x40)!=0) chan1=0;
-    }
-  else if (fam0_drive) /* different firmware levels */
-    {
-      chan0=0;
-      chan1=1;
-      vol0=vol1=infobuf[1];
-      if (DriveStruct[d].drv_type>=drv_201)
-	{
-	  if (DriveStruct[d].drv_type<drv_300)
-	    {
-	      switches=infobuf[0];
-	      if ((switches&0x80)!=0) vol0=0;
-	      if ((switches&0x40)!=0) vol1=0;
-	      if (DriveStruct[d].drv_type>=drv_211)
-		{
-		  if ((switches&0x20)!=0) chan0=1;
-		  if ((switches&0x10)!=0) chan1=0;
-		}
-            }
-          else
-	    {
-              vol0=infobuf[0];
-              if ((vol0&0x01)!=0) chan0=1;
-              if ((vol1&0x01)==0) chan1=0;
-              vol0 &= 0xFC;
-              vol1 &= 0xFC;
-              if (vol0!=0) vol0 += 3;
-              if (vol1!=0) vol1 += 3;
-            }
-        }
-    }
-  DriveStruct[d].vol_chan0=chan0;
-  DriveStruct[d].vol_ctrl0=vol0;
-  DriveStruct[d].vol_chan1=chan1;
-  DriveStruct[d].vol_ctrl1=vol1;
-  DriveStruct[d].vol_chan2=2;
-  DriveStruct[d].vol_ctrl2=0xFF;
-  DriveStruct[d].vol_chan3=3;
-  DriveStruct[d].vol_ctrl3=0xFF;
-  DriveStruct[d].diskstate_flags |= volume_bit;
-  return (0);
+	else if (famT_drive)
+	{
+		D_S[d].volume_control=infobuf[7];
+		chan0=0;
+		chan1=1;
+		if (D_S[d].volume_control&0x10) vol0=0;
+		else vol0=0xff;
+		if (D_S[d].volume_control&0x20) vol1=0;
+		else vol1=0xff;
+	}
+	D_S[d].vol_chan0=chan0;
+	D_S[d].vol_ctrl0=vol0;
+	D_S[d].vol_chan1=chan1;
+	D_S[d].vol_ctrl1=vol1;
+#if 000
+	D_S[d].vol_chan2=2;
+	D_S[d].vol_ctrl2=0xFF;
+	D_S[d].vol_chan3=3;
+	D_S[d].vol_ctrl3=0xFF;
+#endif 000
+	D_S[d].diskstate_flags |= volume_bit;
+	return (0);
 }
-#endif
 /*==========================================================================*/
-static int xx_ReadCapacity(void)
+static int cc_ReadCapacity(void)
 {
-  int i;
+	int i, j;
+	
+	if (famL_drive) return (0);
+	D_S[d].diskstate_flags &= ~cd_size_bit;
+	for (j=3;j>0;j--)
+	{
+		clr_cmdbuf();
+		if (fam1_drive)
+		{
+			drvcmd[0]=CMD1_CAPACITY;
+			response_count=5;
+			flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+		}
+		else if (fam2_drive)
+		{
+			drvcmd[0]=CMD2_CAPACITY;
+			response_count=8;
+			flags_cmd_out=f_putcmd;
+		}
+		else if (fam0_drive)
+		{
+			drvcmd[0]=CMD0_CAPACITY;
+			response_count=5;
+			flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
+		}
+		else if (famT_drive)
+		{
+			response_count=12;
+			drvcmd[0]=CMDT_DISKINFO;
+			drvcmd[1]=0x02;
+			drvcmd[6]=CDROM_LEADOUT;
+			drvcmd[8]=response_count;
+			drvcmd[9]=0x00;
+		}
+		i=cmd_out();
+		if (i>=0) break;
+		msg(DBG_000,"cc_ReadCapacity: cmd_out: err %d\n", i);
+		cc_ReadError();
+	}
+	if (j==0) return (i);
+	if (fam1_drive) D_S[d].CDsize_frm=msf2blk(make32(make16(0,infobuf[0]),make16(infobuf[1],infobuf[2])))+CD_BLOCK_OFFSET;
+	else if (fam0_drive) D_S[d].CDsize_frm=make32(make16(0,infobuf[0]),make16(infobuf[1],infobuf[2]));
+	else if (fam2_drive) D_S[d].CDsize_frm=make32(make16(infobuf[0],infobuf[1]),make16(infobuf[2],infobuf[3]));
+	else if (famT_drive)
+	{
+		D_S[d].CDsize_frm=make32(make16(infobuf[8],infobuf[9]),make16(infobuf[10],infobuf[11]));
+		D_S[d].n_first_track=infobuf[2];
+		D_S[d].n_last_track=infobuf[3];
 
-  if (famL_drive) return (0);
-  DriveStruct[d].diskstate_flags &= ~cd_size_bit;
-  clr_cmdbuf();
-  if (fam1_drive)
-    {
-      drvcmd[0]=CMD1_CAPACITY;
-      response_count=5;
-      flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-    }
-  else if (fam2_drive)
-    {
-      drvcmd[0]=CMD2_CAPACITY;
-      response_count=8;
-      flags_cmd_out=f_putcmd;
-    }
-  else if (fam0_drive)
-    {
-      drvcmd[0]=CMD0_CAPACITY;
-      response_count=5;
-      if(famL_drive)
-	flags_cmd_out=f_putcmd;
-      else
-	flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
-    }
-  i=cmd_out(7);
-  if (i<0) return (i);
-  if (fam1_drive) DriveStruct[d].CDsize_frm=msf2blk(make32(make16(0,infobuf[0]),make16(infobuf[1],infobuf[2])))+CD_BLOCK_OFFSET;
-  else if (fam0_drive) DriveStruct[d].CDsize_frm=make32(make16(0,infobuf[0]),make16(infobuf[1],infobuf[2]));
-  else if (fam2_drive) DriveStruct[d].CDsize_frm=make32(make16(infobuf[0],infobuf[1]),make16(infobuf[2],infobuf[3]));
-  DriveStruct[d].diskstate_flags |= cd_size_bit;
-  return (0);
+	}
+	D_S[d].diskstate_flags |= cd_size_bit;
+	msg(DBG_000,"cc_ReadCapacity: %d frames.\n", D_S[d].CDsize_frm);
+	return (0);
 }
 /*==========================================================================*/
-static int xx_ReadTocDescr(void)
+static int cc_ReadTocDescr(void)
 {
-  int i;
-
-  DriveStruct[d].diskstate_flags &= ~toc_bit;
-  clr_cmdbuf();
-  if (fam1_drive)
-    {
-      drvcmd[0]=CMD1_DISKINFO;
-      response_count=6;
-      flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-    }
-  else if (fam0L_drive)
-    {
-      drvcmd[0]=CMD0_DISKINFO;
-      response_count=6;
-      if(famL_drive)
-	flags_cmd_out=f_putcmd;
-      else
-	flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
-    }
-  else if (fam2_drive)
-    {
-      /* possibly longer timeout periods necessary */
-      DriveStruct[d].f_multisession=0;
-      drvcmd[0]=CMD2_DISKINFO;
-      drvcmd[1]=0x02;
-      drvcmd[2]=0xAB;
-      drvcmd[3]=0xFF; /* session */
-      response_count=8;
-      flags_cmd_out=f_putcmd;
-    }
-  i=cmd_out(7);
-  if (i<0) return (i);
-  DriveStruct[d].xa_byte=infobuf[0];
-  if (fam2_drive)
-    {
-      DriveStruct[d].first_session=infobuf[1];
-      DriveStruct[d].last_session=infobuf[2];
-      DriveStruct[d].n_first_track=infobuf[3];
-      DriveStruct[d].n_last_track=infobuf[4];
-      if (DriveStruct[d].first_session!=DriveStruct[d].last_session)
-	{
-	  DriveStruct[d].f_multisession=1;
-	  DriveStruct[d].lba_multi=msf2blk(make32(make16(0,infobuf[5]),make16(infobuf[6],infobuf[7])));
-	}
+	int i;
+	
+	D_S[d].diskstate_flags &= ~toc_bit;
+	clr_cmdbuf();
+	if (fam1_drive)
+	{
+		drvcmd[0]=CMD1_DISKINFO;
+		response_count=6;
+		flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+	}
+	else if (fam0L_drive)
+	{
+		drvcmd[0]=CMD0_DISKINFO;
+		response_count=6;
+		if(famL_drive)
+			flags_cmd_out=f_putcmd;
+		else
+			flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
+	}
+	else if (fam2_drive)
+	{
+		/* possibly longer timeout periods necessary */
+		D_S[d].f_multisession=0;
+		drvcmd[0]=CMD2_DISKINFO;
+		drvcmd[1]=0x02;
+		drvcmd[2]=0xAB;
+		drvcmd[3]=0xFF; /* session */
+		response_count=8;
+		flags_cmd_out=f_putcmd;
+	}
+	else if (famT_drive)
+	{
+		D_S[d].f_multisession=0;
+		response_count=12;
+		drvcmd[0]=CMDT_DISKINFO;
+		drvcmd[1]=0x02;
+		drvcmd[6]=CDROM_LEADOUT;
+		drvcmd[8]=response_count;
+		drvcmd[9]=0x00;
+	}
+	i=cmd_out();
+	if (i<0) return (i);
+	if ((fam1_drive)||(fam2_drive)||(famL_drive)||(fam0_drive))
+		D_S[d].xa_byte=infobuf[0];
+	if (fam2_drive)
+	{
+		D_S[d].first_session=infobuf[1];
+		D_S[d].last_session=infobuf[2];
+		D_S[d].n_first_track=infobuf[3];
+		D_S[d].n_last_track=infobuf[4];
+		if (D_S[d].first_session!=D_S[d].last_session)
+		{
+			D_S[d].f_multisession=1;
+			D_S[d].lba_multi=msf2blk(make32(make16(0,infobuf[5]),make16(infobuf[6],infobuf[7])));
+		}
 #if 0
-      if (DriveStruct[d].first_session!=DriveStruct[d].last_session)
-	{
-	  if (DriveStruct[d].last_session<=20)
-	    zwanzig=DriveStruct[d].last_session+1;
-	  else zwanzig=20;
-	  for (count=DriveStruct[d].first_session;count<zwanzig;count++)
-	    {
-	      drvcmd[0]=CMD2_DISKINFO;
-	      drvcmd[1]=0x02;
-	      drvcmd[2]=0xAB;
-	      drvcmd[3]=count;
-	      response_count=8;
-	      flags_cmd_out=f_putcmd;
-	      i=cmd_out(7);
-	      if (i<0) return (i);
-	      DriveStruct[d].msf_multi_n[count]=make32(make16(0,infobuf[5]),make16(infobuf[6],infobuf[7]));
-	    }
-	  DriveStruct[d].diskstate_flags |= multisession_bit;
-	}
-#endif
-      drvcmd[0]=CMD2_DISKINFO;
-      drvcmd[1]=0x02;
-      drvcmd[2]=0xAA;
-      drvcmd[3]=0xFF;
-      response_count=5;
-      flags_cmd_out=f_putcmd;
-      i=cmd_out(7);
-      if (i<0) return (i);
-      DriveStruct[d].size_msf=make32(make16(0,infobuf[2]),make16(infobuf[3],infobuf[4]));
-      DriveStruct[d].size_blk=msf2blk(DriveStruct[d].size_msf);
-    }
-  else
-    {
-      DriveStruct[d].n_first_track=infobuf[1];
-      DriveStruct[d].n_last_track=infobuf[2];
-      DriveStruct[d].size_msf=make32(make16(0,infobuf[3]),make16(infobuf[4],infobuf[5]));
-      DriveStruct[d].size_blk=msf2blk(DriveStruct[d].size_msf);
-      if (famL_drive) DriveStruct[d].CDsize_frm=DriveStruct[d].size_blk+1;
-    }
-  DriveStruct[d].diskstate_flags |= toc_bit;
-  DPRINTF((DBG_TOC,"SBPCD: TocDesc: %02X %02X %02X %08X\n",
-	   DriveStruct[d].xa_byte,
-	   DriveStruct[d].n_first_track,
-	   DriveStruct[d].n_last_track,
-	   DriveStruct[d].size_msf));
-  return (0);
+		if (D_S[d].first_session!=D_S[d].last_session)
+		{
+			if (D_S[d].last_session<=20)
+				zwanzig=D_S[d].last_session+1;
+			else zwanzig=20;
+			for (count=D_S[d].first_session;count<zwanzig;count++)
+			{
+				drvcmd[0]=CMD2_DISKINFO;
+				drvcmd[1]=0x02;
+				drvcmd[2]=0xAB;
+				drvcmd[3]=count;
+				response_count=8;
+				flags_cmd_out=f_putcmd;
+				i=cmd_out();
+				if (i<0) return (i);
+				D_S[d].msf_multi_n[count]=make32(make16(0,infobuf[5]),make16(infobuf[6],infobuf[7]));
+			}
+			D_S[d].diskstate_flags |= multisession_bit;
+		}
+#endif
+		drvcmd[0]=CMD2_DISKINFO;
+		drvcmd[1]=0x02;
+		drvcmd[2]=0xAA;
+		drvcmd[3]=0xFF;
+		response_count=5;
+		flags_cmd_out=f_putcmd;
+		i=cmd_out();
+		if (i<0) return (i);
+		D_S[d].size_msf=make32(make16(0,infobuf[2]),make16(infobuf[3],infobuf[4]));
+		D_S[d].size_blk=msf2blk(D_S[d].size_msf);
+	}
+	else if (famT_drive)
+	{
+		D_S[d].size_msf=make32(make16(infobuf[8],infobuf[9]),make16(infobuf[10],infobuf[11]));
+		D_S[d].size_blk=msf2blk(D_S[d].size_msf);
+		D_S[d].n_first_track=infobuf[2];
+		D_S[d].n_last_track=infobuf[3];
+	}
+	else
+	{
+		D_S[d].n_first_track=infobuf[1];
+		D_S[d].n_last_track=infobuf[2];
+		D_S[d].size_msf=make32(make16(0,infobuf[3]),make16(infobuf[4],infobuf[5]));
+		D_S[d].size_blk=msf2blk(D_S[d].size_msf);
+		if (famL_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",
+	    D_S[d].xa_byte,
+	    D_S[d].n_first_track,
+	    D_S[d].n_last_track,
+	    D_S[d].size_msf);
+	return (0);
 }
 /*==========================================================================*/
-static int xx_ReadTocEntry(int num)
+static int cc_ReadTocEntry(int num)
 {
-  int i;
-
-  clr_cmdbuf();
-  if (fam1_drive)
-    {
-      drvcmd[0]=CMD1_READTOC;
-      response_count=8;
-      flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-    }
-  else if (fam2_drive)
-    {
-      /* possibly longer timeout periods necessary */
-      drvcmd[0]=CMD2_DISKINFO;
-      drvcmd[1]=0x02;
-      response_count=5;
-      flags_cmd_out=f_putcmd;
-    }
-  else if (fam0L_drive)
-    {
-      drvcmd[0]=CMD0_READTOC;
-      drvcmd[1]=0x02;
-      response_count=8;
-      if(famL_drive)
-	flags_cmd_out=f_putcmd;
-      else
+	int i;
+	
+	clr_cmdbuf();
+	if (fam1_drive)
+	{
+		drvcmd[0]=CMD1_READTOC;
+		drvcmd[2]=num;
+		response_count=8;
+		flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+	}
+	else if (fam2_drive)
+	{
+		/* possibly longer timeout periods necessary */
+		drvcmd[0]=CMD2_DISKINFO;
+		drvcmd[1]=0x02;
+		drvcmd[2]=num;
+		response_count=5;
+		flags_cmd_out=f_putcmd;
+	}
+	else if (fam0L_drive)
+	{
+		drvcmd[0]=CMD0_READTOC;
+		drvcmd[1]=0x02;
+		drvcmd[2]=num;
+		response_count=8;
+		if(famL_drive)
+			flags_cmd_out=f_putcmd;
+		else
 	flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
-    }
-  drvcmd[2]=num;
-  i=cmd_out(7);
-  if (i<0) return (i);
-  if (fam2_drive) i=0;
-  else
-    {
-      DriveStruct[d].TocEnt_nixbyte=infobuf[0];
-      i=1;
-    }
-  DriveStruct[d].TocEnt_ctl_adr=swap_nibbles(infobuf[i++]);
-  if (!(fam2_drive))
-    {
-      DriveStruct[d].TocEnt_number=infobuf[i++];
-      DriveStruct[d].TocEnt_format=infobuf[i];
-    }
-  if (fam1_drive) i=4;
-  else if (fam0L_drive) i=5;
-  else if (fam2_drive) 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));
-  return (0);
+	}
+	else if (famT_drive)
+	{
+		response_count=12;
+		drvcmd[0]=CMDT_DISKINFO;
+		drvcmd[1]=0x02;
+		drvcmd[6]=num;
+		drvcmd[8]=response_count;
+		drvcmd[9]=0x00;
+	}
+	i=cmd_out();
+	if (i<0) return (i);
+	if ((fam1_drive)||(famL_drive)||(fam0_drive))
+	{
+		D_S[d].TocEnt_nixbyte=infobuf[0];
+		i=1;
+	}
+	else if (fam2_drive) i=0;
+	else if (famT_drive)
+	{
+		i=5;
+	}
+	D_S[d].TocEnt_ctl_adr=swap_nibbles(infobuf[i++]);
+	if ((fam1_drive)||(famL_drive)||(fam0_drive))
+	{
+		D_S[d].TocEnt_number=infobuf[i++];
+		D_S[d].TocEnt_format=infobuf[i];
+	}
+	else D_S[d].TocEnt_number=num;
+	if (fam1_drive) i=4;
+	else if (fam0L_drive) i=5;
+	else if (fam2_drive) i=2;
+	else if (famT_drive) i=9;
+	D_S[d].TocEnt_address=make32(make16(0,infobuf[i]),
+				     make16(infobuf[i+1],infobuf[i+2]));
+	msg(DBG_TOC,"TocEntry: %02X %02X %02X %02X %08X\n",
+	    D_S[d].TocEnt_nixbyte, D_S[d].TocEnt_ctl_adr,
+	    D_S[d].TocEnt_number, D_S[d].TocEnt_format,
+	    D_S[d].TocEnt_address);
+	return (0);
 }
 /*==========================================================================*/
-static int xx_ReadPacket(void)
+static int cc_ReadPacket(void)
 {
-  int i;
-
-  clr_cmdbuf();
-  drvcmd[0]=CMD0_PACKET;
-  drvcmd[1]=response_count;
-  if(famL_drive)
-    flags_cmd_out=f_putcmd;
-  else if (fam01_drive)
-    flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
-  else if (fam2_drive) return (-1); /* not implemented yet */
-  i=cmd_out(7);
-  return (i);
+	int i;
+	
+	clr_cmdbuf();
+	drvcmd[0]=CMD0_PACKET;
+	drvcmd[1]=response_count;
+	if(famL_drive) flags_cmd_out=f_putcmd;
+	else if (fam01_drive)
+		flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
+	else if (fam2_drive) return (-1); /* not implemented yet */
+	else if (famT_drive)
+	{
+		return (-1);
+	}
+	i=cmd_out();
+	return (i);
 }
 /*==========================================================================*/
 static int convert_UPC(u_char *p)
 {
-  int i;
-
-  p++;
-  if (fam0L_drive) p[13]=0;
-  for (i=0;i<7;i++)
-    {
-      if (fam1_drive) DriveStruct[d].UPC_buf[i]=swap_nibbles(*p++);
-      else if (fam0L_drive)
-	{
-	  DriveStruct[d].UPC_buf[i]=((*p++)<<4)&0xFF;
-	  DriveStruct[d].UPC_buf[i] |= *p++;
-	}
-      else /* CD200 */
+	int i;
+	
+	p++;
+	if (fam0L_drive) p[13]=0;
+	for (i=0;i<7;i++)
 	{
-	  return (-1);
+		if (fam1_drive) D_S[d].UPC_buf[i]=swap_nibbles(*p++);
+		else if (fam0L_drive)
+		{
+			D_S[d].UPC_buf[i]=((*p++)<<4)&0xFF;
+			D_S[d].UPC_buf[i] |= *p++;
+		}
+		else if (famT_drive)
+		{
+			return (-1);
+		}
+		else /* CD200 */
+		{
+			return (-1);
+		}
 	}
-    }
-  DriveStruct[d].UPC_buf[6] &= 0xF0;
-  return (0);
+	D_S[d].UPC_buf[6] &= 0xF0;
+	return (0);
 }
 /*==========================================================================*/
-static int xx_ReadUPC(void)
+static int cc_ReadUPC(void)
 {
-  int i;
+	int i;
 #if TEST_UPC
-  int block, checksum;
+	int block, checksum;
 #endif TEST_UPC
-
-  if (fam2_drive) return (0); /* not implemented yet */
-
-  DriveStruct[d].diskstate_flags &= ~upc_bit;
+	
+	if (fam2_drive) return (0); /* not implemented yet */
+	if (famT_drive)	return (0); /* not implemented yet */
+#if 1
+	if (fam0_drive) return (0); /* but it should work */
+#endif 1
+	
+	D_S[d].diskstate_flags &= ~upc_bit;
 #if TEST_UPC
-  for (block=CD_BLOCK_OFFSET+1;block<CD_BLOCK_OFFSET+200;block++)
-    {
-#endif TEST_UPC
-      clr_cmdbuf();
-      if (fam1_drive)
+	for (block=CD_BLOCK_OFFSET+1;block<CD_BLOCK_OFFSET+200;block++)
 	{
-	  drvcmd[0]=CMD1_READ_UPC;
+#endif TEST_UPC
+		clr_cmdbuf();
+		if (fam1_drive)
+		{
+			drvcmd[0]=CMD1_READ_UPC;
 #if TEST_UPC
-	  drvcmd[1]=(block>>16)&0xFF;
-	  drvcmd[2]=(block>>8)&0xFF;
-	  drvcmd[3]=block&0xFF;
+			drvcmd[1]=(block>>16)&0xFF;
+			drvcmd[2]=(block>>8)&0xFF;
+			drvcmd[3]=block&0xFF;
 #endif TEST_UPC
-	  response_count=8;
-	  flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-	}
-      else if (fam0L_drive)
-	{
-	  drvcmd[0]=CMD0_READ_UPC;
+			response_count=8;
+			flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+		}
+		else if (fam0L_drive)
+		{
+			drvcmd[0]=CMD0_READ_UPC;
 #if TEST_UPC
-	  drvcmd[2]=(block>>16)&0xFF;
-	  drvcmd[3]=(block>>8)&0xFF;
-	  drvcmd[4]=block&0xFF;
+			drvcmd[2]=(block>>16)&0xFF;
+			drvcmd[3]=(block>>8)&0xFF;
+			drvcmd[4]=block&0xFF;
 #endif TEST_UPC
-	  response_count=0;
-	  flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
-	}
-      else /* CD200 */
-	{
-	  return (-1);
-	}
-      i=cmd_out(7);
-      if (i<0) return (i);
-      if (fam0L_drive)
-	{
-	  response_count=16;
- 	  if (famL_drive) flags_cmd_out=f_putcmd;
-	  i=xx_ReadPacket();
-	  if (i<0) return (i);
-	}
+			response_count=0;
+			flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1;
+		}
+		else if (fam2_drive)
+		{
+			return (-1);
+		}
+		else if (famT_drive)
+		{
+			return (-1);
+		}
+		i=cmd_out();
+		if (i<0)
+		{
+			msg(DBG_000,"cc_ReadUPC cmd_out: err %d\n", i);
+			return (i);
+		}
+		if (fam0L_drive)
+		{
+			response_count=16;
+			if (famL_drive) flags_cmd_out=f_putcmd;
+			i=cc_ReadPacket();
+			if (i<0)
+			{
+				msg(DBG_000,"cc_ReadUPC ReadPacket: err %d\n", i);
+				return (i);
+			}
+		}
 #if TEST_UPC
-      checksum=0;
+		checksum=0;
 #endif TEST_UPC
-      DPRINTF((DBG_UPC,"SBPCD: UPC info: "));
-      for (i=0;i<(fam1_drive?8:16);i++)
-	{
+		for (i=0;i<(fam1_drive?8:16);i++)
+		{
 #if TEST_UPC
-	  checksum |= infobuf[i];
+			checksum |= infobuf[i];
 #endif TEST_UPC
-	  DPRINTF((DBG_UPC,"%02X ", infobuf[i]));
-	}
-      DPRINTF((DBG_UPC,"\n"));
+			sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
+		}
+		msgbuf[i*3]=0;
+		msg(DBG_UPC,"UPC info:%s\n", msgbuf);
 #if TEST_UPC
-      if ((checksum&0x7F)!=0) break;
-    }
+		if ((checksum&0x7F)!=0) break;
+	}
 #endif TEST_UPC
-  DriveStruct[d].UPC_ctl_adr=0;
-  if (fam1_drive) i=0;
-  else i=2;
-  if ((infobuf[i]&0x80)!=0)
-    {
-      convert_UPC(&infobuf[i]);
-      DriveStruct[d].UPC_ctl_adr = (DriveStruct[d].TocEnt_ctl_adr & 0xF0) | 0x02;
-    }
-
-  DPRINTF((DBG_UPC,"SBPCD: UPC code: "));
-  DPRINTF((DBG_UPC,"(%02X) ", DriveStruct[d].UPC_ctl_adr));
-  for (i=0;i<7;i++)
-    {
-      DPRINTF((DBG_UPC,"%02X ", DriveStruct[d].UPC_buf[i]));
-    }
-  DPRINTF((DBG_UPC,"\n"));
-
-  DriveStruct[d].diskstate_flags |= upc_bit;
-  return (0);
+	D_S[d].UPC_ctl_adr=0;
+	if (fam1_drive) i=0;
+	else i=2;
+	if ((infobuf[i]&0x80)!=0)
+	{
+		convert_UPC(&infobuf[i]);
+		D_S[d].UPC_ctl_adr = (D_S[d].TocEnt_ctl_adr & 0xF0) | 0x02;
+	}
+	for (i=0;i<7;i++)
+		sprintf(&msgbuf[i*3], " %02X", D_S[d].UPC_buf[i]);
+	sprintf(&msgbuf[i*3], " (%02X)", D_S[d].UPC_ctl_adr);
+	msgbuf[i*3+5]=0;
+	msg(DBG_UPC,"UPC code:%s\n", msgbuf);
+	D_S[d].diskstate_flags |= upc_bit;
+	return (0);
 }
 /*==========================================================================*/
-static int yy_CheckMultiSession(void)
+static int cc_CheckMultiSession(void)
 {
-  int i;
-
-  if (fam2_drive) return (0);
-  DriveStruct[d].f_multisession=0;
-  DriveStruct[d].lba_multi=0;
-  if (fam0_drive) return (0);
-  clr_cmdbuf();
-  if (fam1_drive)
-    {
-      drvcmd[0]=CMD1_MULTISESS;
-      response_count=6;
-      flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
-      i=cmd_out(7);
-      if (i<0) return (i);
-      if ((infobuf[0]&0x80)!=0)
-	{
-	  DriveStruct[d].f_multisession=1;
-	  DriveStruct[d].lba_multi=msf2blk(make32(make16(0,infobuf[1]),
-						  make16(infobuf[2],infobuf[3])));
-	  DPRINTF((DBG_MUL,"SBPCD: MultiSession CD detected: %02X %02X %02X %02X %02X %02X (%d)\n",
-		   infobuf[0], infobuf[1], infobuf[2],
-		   infobuf[3], infobuf[4], infobuf[5],
-		   DriveStruct[d].lba_multi));
+	int i;
+	
+	if (fam2_drive) return (0);
+	D_S[d].f_multisession=0;
+	D_S[d].lba_multi=0;
+	if (fam0_drive) return (0);
+	clr_cmdbuf();
+	if (fam1_drive)
+	{
+		drvcmd[0]=CMD1_MULTISESS;
+		response_count=6;
+		flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
+		i=cmd_out();
+		if (i<0) return (i);
+		if ((infobuf[0]&0x80)!=0)
+		{
+			D_S[d].f_multisession=1;
+			D_S[d].lba_multi=msf2blk(make32(make16(0,infobuf[1]),
+							make16(infobuf[2],infobuf[3])));
+		}
 	}
-    }
-  else if (famL_drive)
-    {
-      drvcmd[0]=CMDL_MULTISESS;
-      drvcmd[1]=3;
-      drvcmd[2]=1;
-      response_count=8;
-      flags_cmd_out=f_putcmd;
-      i=cmd_out(7);
-      if (i<0) return (i);
-      DriveStruct[d].lba_multi=msf2blk(make32(make16(0,infobuf[5]),
-					      make16(infobuf[6],infobuf[7])));
-      DPRINTF((DBG_MUL,"SBPCD: MultiSession Info: %02X %02X %02X %02X %02X %02X %02X %02X (%d)\n",
-	       infobuf[0], infobuf[1], infobuf[2], infobuf[3],
-	       infobuf[4], infobuf[5], infobuf[6], infobuf[7],
-	       DriveStruct[d].lba_multi));
-      if (DriveStruct[d].lba_multi>200)
+	else if (famL_drive)
+	{
+		drvcmd[0]=CMDL_MULTISESS;
+		drvcmd[1]=3;
+		drvcmd[2]=1;
+		response_count=8;
+		flags_cmd_out=f_putcmd;
+		i=cmd_out();
+		if (i<0) return (i);
+		D_S[d].lba_multi=msf2blk(make32(make16(0,infobuf[5]),
+						make16(infobuf[6],infobuf[7])));
+	}
+	else if (famT_drive)
+	{
+		response_count=12;
+		drvcmd[0]=CMDT_DISKINFO;
+		drvcmd[1]=0x02;
+		drvcmd[6]=0;
+		drvcmd[8]=response_count;
+		drvcmd[9]=0x40;
+		i=cmd_out();
+		if (i<0) return (i);
+		D_S[d].lba_multi=msf2blk(make32(make16(0,infobuf[9]),make16(infobuf[10],infobuf[11])));
+	}
+	for (i=0;i<response_count;i++)
+		sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
+	msgbuf[i*3]=0;
+	msg(DBG_MUL,"MultiSession Info:%s (%d)\n", msgbuf, D_S[d].lba_multi);
+	if (D_S[d].lba_multi>200)
 	{
-	  DPRINTF((DBG_MUL,"SBPCD: MultiSession base: %06X\n", DriveStruct[d].lba_multi));
-	  DriveStruct[d].f_multisession=1;
+		D_S[d].f_multisession=1;
+		msg(DBG_MUL,"MultiSession base: %06X\n", D_S[d].lba_multi);
 	}
-    }
-  return (0);
+	return (0);
 }
 /*==========================================================================*/
 #if FUTURE
-static int yy_SubChanInfo(int frame, int count, u_char *buffer)
-/* "frame" is a RED BOOK (msf-bin) address */
+static int cc_SubChanInfo(int frame, int count, u_char *buffer)
+	/* "frame" is a RED BOOK (msf-bin) address */
 {
-  int i;
-
-  if (fam0L_drive) return (-ENOSYS); /* drive firmware lacks it */
+	int i;
+	
+	if (fam0L_drive) return (-ENOSYS); /* drive firmware lacks it */
+	if (famT_drive)
+	{
+		return (-1);
+	}
 #if 0
-  if (DriveStruct[d].audio_state!=audio_playing) return (-ENODATA);
+	if (D_S[d].audio_state!=audio_playing) return (-ENODATA);
 #endif
-  clr_cmdbuf();
-  drvcmd[0]=CMD1_SUBCHANINF;
-  drvcmd[1]=(frame>>16)&0xFF;
-  drvcmd[2]=(frame>>8)&0xFF;
-  drvcmd[3]=frame&0xFF;
-  drvcmd[5]=(count>>8)&0xFF;
-  drvcmd[6]=count&0xFF;
-  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(7); /* which buffer to use? */
-  return (i);
+	clr_cmdbuf();
+	drvcmd[0]=CMD1_SUBCHANINF;
+	drvcmd[1]=(frame>>16)&0xFF;
+	drvcmd[2]=(frame>>8)&0xFF;
+	drvcmd[3]=frame&0xFF;
+	drvcmd[5]=(count>>8)&0xFF;
+	drvcmd[6]=count&0xFF;
+	flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check;
+	cmd_type=READ_SC;
+	D_S[d].frame_size=CD_FRAMESIZE_SUB;
+	i=cmd_out(); /* which buffer to use? */
+	return (i);
 }
 #endif FUTURE
 /*==========================================================================*/
 static void check_datarate(void)
 {
-#ifdef CDMKE
-  int i=0;
-
-  DPRINTF((DBG_IOX,"SBPCD: check_datarate entered.\n"));
-  datarate=0;
+	int i=0;
+	
+	msg(DBG_IOX,"check_datarate entered.\n");
+	datarate=0;
 #if TEST_STI
-  for (i=0;i<=1000;i++) printk(".");
+	for (i=0;i<=1000;i++) printk(".");
 #endif
-  /* set a timer to make (timed_out!=0) after 1.1 seconds */
-#if 0
-  del_timer(&delay_timer);
+	/* set a timer to make (timed_out_delay!=0) after 1.1 seconds */
+#if 1
+	del_timer(&delay_timer);
 #endif
-  delay_timer.expires = 110;
-  timed_out=0;
-  add_timer(&delay_timer);
-  DPRINTF((DBG_TIM,"SBPCD: timer started (110).\n"));
-  do
-    {
-      i=inb(CDi_status);
-      datarate++;
-#if 00000
-      if (datarate>0x0FFFFFFF) break;
+	delay_timer.expires=110;
+	timed_out_delay=0;
+	add_timer(&delay_timer);
+	msg(DBG_TIM,"delay timer started (110).\n");
+	do
+	{
+		i=inb(CDi_status);
+		datarate++;
+#if 1
+		if (datarate>0x6FFFFFFF) break;
 #endif 00000
-    }
-  while (!timed_out); /* originally looping for 1.1 seconds */
-#if 0
-  del_timer(&delay_timer);
-#endif 0
-  DPRINTF((DBG_TIM,"SBPCD: datarate: %d\n", datarate));
-  if (datarate<65536) datarate=65536;
-
-  maxtim16=datarate*16;
-  maxtim04=datarate*4;
-  maxtim02=datarate*2;
-  maxtim_8=datarate/32;
+	}
+	while (!timed_out_delay);
+	del_timer(&delay_timer);
+	msg(DBG_TIM,"datarate: %04X\n", datarate);
+	if (datarate<65536) datarate=65536;
+	maxtim16=datarate*16;
+	maxtim04=datarate*4;
+	maxtim02=datarate*2;
+	maxtim_8=datarate/32;
 #if LONG_TIMING
-  maxtim_data=datarate/100;
+	maxtim_data=datarate/100;
 #else
-  maxtim_data=datarate/300;
+	maxtim_data=datarate/300;
 #endif LONG_TIMING
-  DPRINTF((DBG_TIM,"SBPCD: maxtim_8 %d, maxtim_data %d.\n",
-	   maxtim_8, maxtim_data));
-#endif CDMKE
+	msg(DBG_TIM,"maxtim_8 %d, maxtim_data %d.\n",
+	    maxtim_8, maxtim_data);
 }
 /*==========================================================================*/
-#ifdef CD200
-
 #if 0
-
-static int xx_ReadVersion(int fam)
-{
-  int i;
-
-  clr_cmdbuf();
-  clear_response_buffer(13);
-  if (fam==1)
-    {
-      drvcmd[0]=CMD0_READ_VER; /* same as CMD1_ and CMDL_ */
-      response_count=13;
-      i=do_cmd(f_putcmd|f_lopsta|f_getsta|f_ResponseStatus);
-    }
-  else if (fam==2)
-    {
-      drvcmd[0]=CMD2_READ_VER;
-      response_count=12;
-      i=do_cmd(f_putcmd);
-    }
-  else return (-1);
-  return (i);
-}
-
-static int yy_ReadError(int fam)
+static int c2_ReadError(int fam)
 {
-  int i;
-
-  clr_cmdbuf();
-  response_count=9;
-  clr_respo_buf(9);
-  if (fam==1)
-    {
-      drvcmd[0]=CMD0_READ_ERR; /* same as CMD1_ and CMDL_ */
-      i=do_cmd(f_putcmd|f_lopsta|f_getsta|f_ResponseStatus);
-    }
-  else if (fam==2)
-    {
-      drvcmd[0]=CMD2_READ_ERR;
-      i=do_cmd(f_putcmd);
-    }
-  else return (-1);
-  return (i);
+	int i;
+	
+	clr_cmdbuf();
+	response_count=9;
+	clr_respo_buf(9);
+	if (fam==1)
+	{
+		drvcmd[0]=CMD0_READ_ERR; /* same as CMD1_ and CMDL_ */
+		i=do_cmd(f_putcmd|f_lopsta|f_getsta|f_ResponseStatus);
+	}
+	else if (fam==2)
+	{
+		drvcmd[0]=CMD2_READ_ERR;
+		i=do_cmd(f_putcmd);
+	}
+	else return (-1);
+	return (i);
 }
 #endif
-
-#endif CD200
 /*==========================================================================*/
 static void ask_mail(void)
 {
-  int i;
-
-  printk("SBPCD: please mail the following lines to emoenke@gwdg.de:\n");
-  printk("SBPCD: address %03X, type %s, drive ID %d\n", CDo_command, type, DriveStruct[d].drv_id);
-  printk("SBPCD: infobuf = \"");
-  for (i=0;i<12;i++) printk("%02X ",infobuf[i]);
-  printk("\"\nSBPCD: infobuf = \"");
-  for (i=0;i<12;i++) printk("%c",infobuf[i]);
-  printk("\"\n");
+	int i;
+	
+	msg(DBG_INF, "please mail the following lines to emoenke@gwdg.de:\n");
+	msg(DBG_INF, "%s\n", VERSION);
+	msg(DBG_INF, "address %03X, type %s, drive %s (ID %d)\n",
+	    CDo_command, type, D_S[d].drive_model, D_S[d].drv_id);
+	for (i=0;i<12;i++)
+		sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
+	msgbuf[i*3]=0;
+	msg(DBG_INF,"infobuf =%s\n", msgbuf);
+	for (i=0;i<12;i++)
+		sprintf(&msgbuf[i*3], " %c ", infobuf[i]);
+	msgbuf[i*3]=0;
+	msg(DBG_INF,"infobuf =%s\n", msgbuf);
 }
 /*==========================================================================*/
 static int check_version(void)
 {
-  int i, j;
-  u_char lcs_firm[][4]={"A4F4","A E1"};
-
-  DPRINTF((DBG_INI,"SBPCD: check_version entered.\n"));
-  DriveStruct[d].drv_type=0;
-
-  /* check for CD200 */
-  clr_cmdbuf();
-  drvcmd[0]=CMD2_READ_ERR;
-  response_count=9;
-  flags_cmd_out=f_putcmd;
-  i=cmd_out(7);
-  if (i<0) DPRINTF((DBG_INI,"SBPCD: CMD2_READERR returns %d (ok anyway).\n",i));
-  /* read drive version */
-  clr_cmdbuf();
-  for (i=0;i<12;i++) infobuf[i]=0;
-  if (sbpro_type==1) OUT(CDo_sel_i_d,0);
+	int i, j, l;
+	int teac_possible=0;
+	
+	msg(DBG_INI,"check_version entered.\n");
+	msg(DBG_TE2,"check_version: id=%d, d=%d.\n", D_S[d].drv_id, d);
+	D_S[d].drv_type=0;
+
+	/* check for CR-52x, CR-56x and LCS-7260 */
+	/* clear any pending error state */
+	clr_cmdbuf();
+	drvcmd[0]=CMD0_READ_ERR; /* same as CMD1_ and CMDL_ */
+	response_count=9;
+	flags_cmd_out=f_putcmd;
+	i=cmd_out();
+	if (i<0) msg(DBG_INI,"CMD0_READERR returns %d (ok anyway).\n",i);
+	/* read drive version */
+	clr_cmdbuf();
+	for (i=0;i<12;i++) infobuf[i]=0;
+	drvcmd[0]=CMD0_READ_VER; /* same as CMD1_ and CMDL_ */
+	response_count=12; /* fam1: only 11 */
+	flags_cmd_out=f_putcmd;
+	i=cmd_out();
+	if (i<-1) msg(DBG_INI,"CMD0_READ_VER returns %d\n",i);
+	if (i==-11) teac_possible++;
+	j=0;
+	for (i=0;i<12;i++) j+=infobuf[i];
+	if (j)
+	{
+		for (i=0;i<12;i++)
+			sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
+		msgbuf[i*3]=0;
+		msg(DBG_IDX,"infobuf =%s\n", msgbuf);
+		msg(DBG_000,"infobuf =%s\n", msgbuf);
+		for (i=0;i<12;i++)
+			sprintf(&msgbuf[i*3], " %c ", infobuf[i]);
+		msgbuf[i*3]=0;
+		msg(DBG_IDX,"infobuf =%s\n", msgbuf);
+		msg(DBG_000,"infobuf =%s\n", msgbuf);
+	}
+	for (i=0;i<4;i++) if (infobuf[i]!=family1[i]) break;
+	if (i==4)
+	{
+		D_S[d].drive_model[0]='C';
+		D_S[d].drive_model[1]='R';
+		D_S[d].drive_model[2]='-';
+		D_S[d].drive_model[3]='5';
+		D_S[d].drive_model[4]=infobuf[i++];
+		D_S[d].drive_model[5]=infobuf[i++];
+		D_S[d].drive_model[6]=0;
+		D_S[d].drv_type=drv_fam1;
+	}
+	if (!D_S[d].drv_type)
+	{
+		for (i=0;i<8;i++) if (infobuf[i]!=family0[i]) break;
+		if (i==8)
+		{
+			D_S[d].drive_model[0]='C';
+			D_S[d].drive_model[1]='R';
+			D_S[d].drive_model[2]='-';
+			D_S[d].drive_model[3]='5';
+			D_S[d].drive_model[4]='2';
+			D_S[d].drive_model[5]='x';
+			D_S[d].drive_model[6]=0;
+			D_S[d].drv_type=drv_fam0;
+		}
+	}
+	if (!D_S[d].drv_type)
+	{
+		for (i=0;i<8;i++) if (infobuf[i]!=familyL[i]) break;
+		if (i==8)
+		{
+			for (j=0;j<8;j++)
+				D_S[d].drive_model[j]=infobuf[j];
+			D_S[d].drive_model[8]=0;
+			D_S[d].drv_type=drv_famL;
+		}
+	}
+	if (!D_S[d].drv_type)
+	{
+		/* check for CD200 */
+		clr_cmdbuf();
+		drvcmd[0]=CMD2_READ_ERR;
+		response_count=9;
+		flags_cmd_out=f_putcmd;
+		i=cmd_out();
+		if (i<0) msg(DBG_INI,"CMD2_READERR returns %d (ok anyway).\n",i);
+		if (i<0) msg(DBG_000,"CMD2_READERR returns %d (ok anyway).\n",i);
+		/* read drive version */
+		clr_cmdbuf();
+		for (i=0;i<12;i++) infobuf[i]=0;
+		if (sbpro_type==1) OUT(CDo_sel_i_d,0);
 #if 0
-  OUT(CDo_reset,0);
-  sbp_sleep(600);
-  OUT(CDo_enable,DriveStruct[d].drv_sel);
-#endif
-  drvcmd[0]=CMD2_READ_VER;
-  response_count=12;
-  flags_cmd_out=f_putcmd;
-  i=cmd_out(7);
-  if (i<0) DPRINTF((DBG_INI,"SBPCD: CMD2_READ_VER returns %d\n",i));
-  if (i>=0) /* from CD200 */
-    {
-      for (i=0, j=0;i<12;i++) j+=infobuf[i];
-      if (j)
-	{
-	  DPRINTF((DBG_ID,"SBPCD: infobuf = \""));
-	  for (i=0;i<12;i++) DPRINTF((DBG_ID,"%02X ",infobuf[i]));
-	  for (i=0;i<12;i++) DPRINTF((DBG_ID,"%c",infobuf[i]));
-	  DPRINTF((DBG_ID,"\"\n"));
-	}
-      for (i=0;i<5;i++) if (infobuf[i]!=family2[i]) break;
-      if (i==5)
-	{
-	  DriveStruct[d].drive_model[0]='C';
-	  DriveStruct[d].drive_model[1]='D';
-	  DriveStruct[d].drive_model[2]='2';
-	  DriveStruct[d].drive_model[3]='0';
-	  DriveStruct[d].drive_model[4]='0';
-	  DriveStruct[d].drive_model[5]=infobuf[i++];
-	  DriveStruct[d].drive_model[6]=infobuf[i++];
-	  DriveStruct[d].drive_model[7]=0;
-	  DriveStruct[d].drv_type=drv_fam2;
+		OUT(CDo_reset,0);
+		sbp_sleep(600);
+		OUT(CDo_enable,D_S[d].drv_sel);
+#endif 0
+		drvcmd[0]=CMD2_READ_VER;
+		response_count=12;
+		flags_cmd_out=f_putcmd;
+		i=cmd_out();
+		if (i<0) msg(DBG_INI,"CMD2_READ_VER returns %d\n",i);
+		if (i==-7) teac_possible++;
+		j=0;
+		for (i=0;i<12;i++) j+=infobuf[i];
+		if (j)
+		{
+			for (i=0;i<12;i++)
+				sprintf(&msgbuf[i*3], " %02X", infobuf[i]);
+			msgbuf[i*3]=0;
+			msg(DBG_IDX,"infobuf =%s\n", msgbuf);
+			for (i=0;i<12;i++)
+				sprintf(&msgbuf[i*3], " %c ", infobuf[i]);
+			msgbuf[i*3]=0;
+			msg(DBG_IDX,"infobuf =%s\n", msgbuf);
+		}
+		if (i>=0)
+		{
+			for (i=0;i<5;i++) if (infobuf[i]!=family2[i]) break;
+			if (i==5)
+			{
+				D_S[d].drive_model[0]='C';
+				D_S[d].drive_model[1]='D';
+				D_S[d].drive_model[2]='2';
+				D_S[d].drive_model[3]='0';
+				D_S[d].drive_model[4]='0';
+				D_S[d].drive_model[5]=infobuf[i++];
+				D_S[d].drive_model[6]=infobuf[i++];
+				D_S[d].drive_model[7]=0;
+				D_S[d].drv_type=drv_fam2;
+			}
+		}
 	}
-    }
+	if (!D_S[d].drv_type)
+	{
+		/* check for TEAC CD-55A */
+		msg(DBG_TEA,"teac_possible: %d\n",teac_possible);
+		for (j=1;j<=((D_S[d].drv_id==0)?3:1);j++)
+		{
+			for (l=1;l<=((D_S[d].drv_id==0)?10:1);l++)
+			{
+				msg(DBG_TEA,"TEAC reset #%d-%d.\n", j, l);
+				if (sbpro_type==1) OUT(CDo_reset,0);
+				else
+				{
+					OUT(CDo_enable,D_S[d].drv_sel);
+					OUT(CDo_sel_i_d,0);
+					OUT(CDo_command,CMDT_RESET);
+					for (i=0;i<9;i++) OUT(CDo_command,0);
+				}
+				sbp_sleep(50);
+				OUT(CDo_enable,D_S[d].drv_sel);
+				OUT(CDo_sel_i_d,0);
+				i=inb(CDi_status);
+				msg(DBG_TEA,"TEAC CDi_status: %02X.\n",i);
+#if 0
+				if (i&s_not_result_ready) continue; /* drive not present or ready */
+#endif
+				i=inb(CDi_info);
+				msg(DBG_TEA,"TEAC CDi_info: %02X.\n",i);
+				if (i==0x55) break; /* drive found */
+			}
+			if (i==0x55) break; /* drive found */
+		}
+		if (i==0x55) /* drive found */
+		{
+			msg(DBG_TEA,"TEAC drive found.\n");
+			clr_cmdbuf();
+			flags_cmd_out=f_putcmd;
+			response_count=12;
+			drvcmd[0]=CMDT_READ_VER;
+			drvcmd[4]=response_count;
+			for (i=0;i<12;i++) infobuf[i]=0;
+			i=cmd_out_T();
+			if (i!=0) msg(DBG_TEA,"cmd_out_T(CMDT_READ_VER) returns %d.\n",i);
+			for (i=1;i<6;i++) if (infobuf[i]!=familyT[i-1]) break;
+			if (i==6)
+			{
+				D_S[d].drive_model[0]='C';
+				D_S[d].drive_model[1]='D';
+				D_S[d].drive_model[2]='-';
+				D_S[d].drive_model[3]='5';
+				D_S[d].drive_model[4]='5';
+				D_S[d].drive_model[5]=0;
+				D_S[d].drv_type=drv_famT;
+			}
+		}
+	}
+	if (!D_S[d].drv_type)
+	{
+		msg(DBG_TEA,"no drive found at address %03X under ID %d.\n",CDo_command,D_S[d].drv_id);
+		return (-522);
+	}
+	for (j=0;j<4;j++) D_S[d].firmware_version[j]=infobuf[i+j];
+	if (famL_drive)
+	{
+		u_char lcs_firm_e1[]="A E1";
+		u_char lcs_firm_f4[]="A4F4";
+		
+		for (j=0;j<4;j++)
+			if (D_S[d].firmware_version[j]!=lcs_firm_e1[j]) break;
+		if (j==4) D_S[d].drv_type=drv_e1;
+
+		for (j=0;j<4;j++)
+			if (D_S[d].firmware_version[j]!=lcs_firm_f4[j]) break;
+		if (j==4) D_S[d].drv_type=drv_f4;
 
-  if (!DriveStruct[d].drv_type)
-    {
-      /* check for CR-52x, CR-56x and LCS-7260 */
-      /* clear any pending error state */
-      clr_cmdbuf();
-      drvcmd[0]=CMD0_READ_ERR; /* same as CMD1_ and CMDL_ */
-      response_count=9;
-      flags_cmd_out=f_putcmd;
-      i=cmd_out(7);
-      if (i<0) DPRINTF((DBG_INI,"SBPCD: CMD0_READERR returns %d (ok anyway).\n",i));
-      /* read drive version */
-      clr_cmdbuf();
-      for (i=0;i<12;i++) infobuf[i]=0;
-      drvcmd[0]=CMD0_READ_VER; /* same as CMD1_ and CMDL_ */
-      response_count=12;
-      flags_cmd_out=f_putcmd;
-      i=cmd_out(7);
-      if (i<0) DPRINTF((DBG_INI,"SBPCD: CMD0_READ_VER returns %d\n",i));
-
-      for (i=0, j=0;i<12;i++) j+=infobuf[i];
-      if (j)
-	{
-	  DPRINTF((DBG_ID,"SBPCD: infobuf = \""));
-	  for (i=0;i<12;i++) DPRINTF((DBG_ID,"%02X ",infobuf[i]));
-	  for (i=0;i<12;i++) DPRINTF((DBG_ID,"%c",infobuf[i]));
-	  DPRINTF((DBG_ID,"\"\n"));
-	}
-
-      for (i=0;i<4;i++) if (infobuf[i]!=family1[i]) break;
-      if (i==4)
-	{
-	  DriveStruct[d].drive_model[0]='C';
-	  DriveStruct[d].drive_model[1]='R';
-	  DriveStruct[d].drive_model[2]='-';
-	  DriveStruct[d].drive_model[3]='5';
-	  DriveStruct[d].drive_model[4]=infobuf[i++];
-	  DriveStruct[d].drive_model[5]=infobuf[i++];
-	  DriveStruct[d].drive_model[6]=0;
-	  DriveStruct[d].drv_type=drv_fam1;
-	}
-      if (!DriveStruct[d].drv_type)
-	{
-	  for (i=0;i<8;i++) if (infobuf[i]!=family0[i]) break;
-	  if (i==8)
-	    {
-	      DriveStruct[d].drive_model[0]='C';
-	      DriveStruct[d].drive_model[1]='R';
-	      DriveStruct[d].drive_model[2]='-';
-	      DriveStruct[d].drive_model[3]='5';
-	      DriveStruct[d].drive_model[4]='2';
-	      DriveStruct[d].drive_model[5]='x';
-	      DriveStruct[d].drive_model[6]=0;
-	      DriveStruct[d].drv_type=drv_fam0;
-	    }
-	}
-      if (!DriveStruct[d].drv_type)
-	{
-	  for (i=0;i<8;i++) if (infobuf[i]!=familyL[i]) break;
-	  if (i==8)
-	    {
-	      for (j=0;j<8;j++)
-		DriveStruct[d].drive_model[j]=infobuf[j];
-	      DriveStruct[d].drive_model[8]=0;
-	      DriveStruct[d].drv_type=drv_famL;
-	    }
+		if (!D_S[d].drv_type) ask_mail();
 	}
-    }
-  if (!DriveStruct[d].drv_type)
-    {
-      DPRINTF((DBG_INI,"SBPCD: check_version: error.\n"));
-      return (-1);
-    }
-  for (j=0;j<4;j++) DriveStruct[d].firmware_version[j]=infobuf[i+j];
-  if (famL_drive)
-    {
-      for (i=0;i<2;i++)
-	{
-	  for (j=0;j<4;j++)
-	    if (DriveStruct[d].firmware_version[j]!=lcs_firm[i][j]) break;
-	  if (j==4) break;
+	else if (famT_drive)
+	{
+		j=infobuf[4]; /* one-byte version??? - here: 0x15 */
+		if (j=='5')
+		{
+			D_S[d].firmware_version[0]=infobuf[7];
+			D_S[d].firmware_version[1]=infobuf[8];
+			D_S[d].firmware_version[2]=infobuf[10];
+			D_S[d].firmware_version[3]=infobuf[11];
+		}
+		else
+		{
+			if (j!=0x15) ask_mail();
+			D_S[d].firmware_version[0]='0';
+			D_S[d].firmware_version[1]='.';
+			D_S[d].firmware_version[2]='0'+(j>>4);
+			D_S[d].firmware_version[3]='0'+(j&0x0f);
+		}
 	}
-      if (j!=4) ask_mail();
-      DriveStruct[d].drv_type=drv_260;
-    }
-  else
-    {
-      j = (DriveStruct[d].firmware_version[0] & 0x0F) * 100 +
-	(DriveStruct[d].firmware_version[2] & 0x0F) *10 +
-	  (DriveStruct[d].firmware_version[3] & 0x0F);
-      if (fam0_drive)
-	{
-	  if (j<200) DriveStruct[d].drv_type=drv_199;
-	  else if (j<201) DriveStruct[d].drv_type=drv_200;
-	  else if (j<210) DriveStruct[d].drv_type=drv_201;
-	  else if (j<211) DriveStruct[d].drv_type=drv_210;
-	  else if (j<300) DriveStruct[d].drv_type=drv_211;
-	  else if (j>=300) DriveStruct[d].drv_type=drv_300;
-	}
-      else if (fam1_drive)
-	{
-	  if (j<100) DriveStruct[d].drv_type=drv_099;
-	  else
-	    {
-	      DriveStruct[d].drv_type=drv_100;
-	      ask_mail();
-	    }
-	}
-      else if (fam2_drive)
-	{
-	  printk("\n\nSBPCD: new drive CD200 (%s)detected.\n",
-		 DriveStruct[d].firmware_version);
-	  printk("SBPCD: support is not fulfilled yet.\n");
-	  if (j!=101) ask_mail(); /* only 1.01 known at time */
+	else /* CR-52x, CR-56x, CD200 */
+	{
+		j = (D_S[d].firmware_version[0] & 0x0F) * 100 +
+			(D_S[d].firmware_version[2] & 0x0F) *10 +
+				(D_S[d].firmware_version[3] & 0x0F);
+		if (fam0_drive)
+		{
+			if (j<200) D_S[d].drv_type=drv_199;
+			else if (j<201) D_S[d].drv_type=drv_200;
+			else if (j<210) D_S[d].drv_type=drv_201;
+			else if (j<211) D_S[d].drv_type=drv_210;
+			else if (j<300) D_S[d].drv_type=drv_211;
+			else if (j>=300) D_S[d].drv_type=drv_300;
+		}
+		else if (fam1_drive)
+		{
+			if (j<100) D_S[d].drv_type=drv_099;
+			else
+			{
+				D_S[d].drv_type=drv_100;
+				if ((j!=500)||(j!=102)) ask_mail();
+			}
+		}
+		else if (fam2_drive)
+		{
+			msg(DBG_INF,"new drive CD200 (%s)detected.\n", D_S[d].firmware_version);
+			msg(DBG_INF,"support is not fulfilled yet - audio should work.\n");
+			if ((j!=101)&&(j!=35)) ask_mail(); /* only 1.01 and 0.35 known at time */
+		}
 	}
-    }
-  DPRINTF((DBG_LCS,"SBPCD: drive type %02X\n",DriveStruct[d].drv_type));
-  DPRINTF((DBG_INI,"SBPCD: check_version done.\n"));
-  return (0);
+	msg(DBG_LCS,"drive type %02X\n",D_S[d].drv_type);
+	msg(DBG_INI,"check_version done.\n");
+	return (0);
 }
 /*==========================================================================*/
-static int switch_drive(int i)
-{
-  d=i;
-  if (DriveStruct[d].drv_id!=-1)
-    {
-      OUT(CDo_enable,DriveStruct[d].drv_sel);
-      DPRINTF((DBG_DID,"SBPCD: drive %d (ID=%d) activated.\n", i, DriveStruct[d].drv_id));
-      return (0);
-    }
-  else return (-1);
+static void switch_drive(int i)
+{
+	d=i;
+	OUT(CDo_enable,D_S[d].drv_sel);
+	msg(DBG_DID,"drive %d (ID=%d) activated.\n", i, D_S[d].drv_id);
+	return;
 }
 /*==========================================================================*/
+#ifdef PATH_CHECK
 /*
- * probe for the presence of drives on the selected controller
+ * probe for the presence of an interface card
  */
-static int check_drives(void)
+static int check_card(int port)
 {
-  int i, j;
-  char *printk_header="";
-
-  DPRINTF((DBG_INI,"SBPCD: check_drives entered.\n"));
-
-  ndrives=0;
-  for (j=0;j<NR_SBPCD;j++)
-    {
-      DriveStruct[ndrives].drv_id=j;
-      if (sbpro_type==1) DriveStruct[ndrives].drv_sel=(j&0x01)<<1|(j&0x02)>>1;
-      else DriveStruct[ndrives].drv_sel=j;
-      switch_drive(ndrives);
-      DPRINTF((DBG_INI,"SBPCD: check_drives: drive %d (ID=%d) activated.\n",ndrives,j));
-      i=check_version();
-      if (i<0) DPRINTF((DBG_INI,"SBPCD: check_version returns %d.\n",i));
-      else
-	{
-	  DriveStruct[d].drv_options=drv_pattern[j];
-	  if (fam0L_drive) DriveStruct[d].drv_options&=~(speed_auto|speed_300|speed_150);
-	  printk("%sDrive %d (ID=%d): %.9s (%.4s)\n", printk_header, d,
-		 DriveStruct[d].drv_id,
-		 DriveStruct[d].drive_model,
-		 DriveStruct[d].firmware_version);
-	  printk_header="       - ";
-	  ndrives++;
-	}
-
-    }
-  for (j=ndrives;j<NR_SBPCD;j++) DriveStruct[j].drv_id=-1;
-  if (ndrives==0) return (-1);
-  return (0);
+#undef N_RESPO
+#define N_RESPO 20
+	int i, j, k;
+	u_char response[N_RESPO];
+	u_char save_port0;
+	u_char save_port3;
+	
+	msg(DBG_INI,"check_card entered.\n");
+	save_port0=inb(port+0);
+	save_port3=inb(port+3);
+	
+	for (j=0;j<NR_SBPCD;j++)
+	{
+		OUT(port+3,j) ; /* enable drive #j */
+		OUT(port+0,CMD0_PATH_CHECK);
+		for (i=10;i>0;i--) OUT(port+0,0);
+		for (k=0;k<N_RESPO;k++) response[k]=0;
+		for (k=0;k<N_RESPO;k++)
+		{
+			for (i=10000;i>0;i--)
+			{
+				if (inb(port+1)&s_not_result_ready) continue;
+				response[k]=inb(port+0);
+				break;
+			}
+		}
+		for (i=0;i<N_RESPO;i++)
+			sprintf(&msgbuf[i*3], " %02X", response[i]);
+		msgbuf[i*3]=0;
+		msg(DBG_TEA,"path check 00 (%d): %s\n", j, msgbuf);
+		OUT(port+0,CMD0_PATH_CHECK);
+		for (i=10;i>0;i--) OUT(port+0,0);
+		for (k=0;k<N_RESPO;k++) response[k]=0xFF;
+		for (k=0;k<N_RESPO;k++)
+		{
+			for (i=10000;i>0;i--)
+			{
+				if (inb(port+1)&s_not_result_ready) continue;
+				response[k]=inb(port+0);
+				break;
+			}
+		}
+		for (i=0;i<N_RESPO;i++)
+			sprintf(&msgbuf[i*3], " %02X", response[i]);
+		msgbuf[i*3]=0;
+		msg(DBG_TEA,"path check 00 (%d): %s\n", j, msgbuf);
+
+		if (response[0]==0xAA)
+			if (response[1]==0x55)
+				return (0);
+	}
+	for (j=0;j<NR_SBPCD;j++)
+	{
+		OUT(port+3,j) ; /* enable drive #j */
+		OUT(port+0,CMD2_READ_VER);
+		for (i=10;i>0;i--) OUT(port+0,0);
+		for (k=0;k<N_RESPO;k++) response[k]=0;
+		for (k=0;k<N_RESPO;k++)
+		{
+			for (i=1000000;i>0;i--)
+			{
+				if (inb(port+1)&s_not_result_ready) continue;
+				response[k]=inb(port+0);
+				break;
+			}
+		}
+		for (i=0;i<N_RESPO;i++)
+			sprintf(&msgbuf[i*3], " %02X", response[i]);
+		msgbuf[i*3]=0;
+		msg(DBG_TEA,"path check 12 (%d): %s\n", j, msgbuf);
+
+		OUT(port+0,CMD2_READ_VER);
+		for (i=10;i>0;i--) OUT(port+0,0);
+		for (k=0;k<N_RESPO;k++) response[k]=0xFF;
+		for (k=0;k<N_RESPO;k++)
+		{
+			for (i=1000000;i>0;i--)
+			{
+				if (inb(port+1)&s_not_result_ready) continue;
+				response[k]=inb(port+0);
+				break;
+			}
+		}
+		for (i=0;i<N_RESPO;i++)
+			sprintf(&msgbuf[i*3], " %02X", response[i]);
+		msgbuf[i*3]=0;
+		msg(DBG_TEA,"path check 12 (%d): %s\n", j, msgbuf);
+
+		if (response[0]==0xAA)
+			if (response[1]==0x55)
+				return (0);
+	}
+	OUT(port+0,save_port0);
+	OUT(port+3,save_port3);
+	return (0); /* in any case - no real "function" at time */
 }
+#endif PATH_CHECK
 /*==========================================================================*/
-#if 000
-static void timewait(void)
+/*==========================================================================*/
+/*
+ * probe for the presence of drives on the selected controller
+ */
+static int check_drives(void)
 {
-  int i;
-  for (i=0; i<65500; i++);
+	int i, j;
+	
+	msg(DBG_INI,"check_drives entered.\n");
+	ndrives=0;
+	for (j=0;j<NR_SBPCD;j++)
+	{
+		D_S[ndrives].drv_id=j;
+		if (sbpro_type==1) D_S[ndrives].drv_sel=(j&0x01)<<1|(j&0x02)>>1;
+		else D_S[ndrives].drv_sel=j;
+		switch_drive(ndrives);
+		msg(DBG_INI,"check_drives: drive %d (ID=%d) activated.\n",ndrives,j);
+		msg(DBG_000,"check_drives: drive %d (ID=%d) activated.\n",ndrives,j);
+		i=check_version();
+		if (i<0) msg(DBG_INI,"check_version returns %d.\n",i);
+		else
+		{
+			D_S[d].drv_options=drv_pattern[j];
+			if (fam0L_drive) D_S[d].drv_options&=~(speed_auto|speed_300|speed_150);
+			msg(DBG_INF, "Drive %d (ID=%d): %.9s (%.4s) at 0x%03X (type %d)\n",
+			    d,
+			    D_S[d].drv_id,
+			    D_S[d].drive_model,
+			    D_S[d].firmware_version,
+			    CDo_command,
+			    sbpro_type);
+			ndrives++;
+		}
+	}
+	for (j=ndrives;j<NR_SBPCD;j++) D_S[j].drv_id=-1;
+	if (ndrives==0) return (-1);
+	return (0);
 }
-#endif 000
 /*==========================================================================*/
 #if FUTURE
 /*
@@ -2664,41 +3417,40 @@
  */            
 static int obey_audio_state(u_char audio_state, u_char func,u_char subfunc)
 {
-  switch (audio_state)                   /* audio status from controller  */
-    {
-    case aud_11: /* "audio play in progress" */
-    case audx11:
-      switch (func)                      /* DOS command code */
-	{
-	case cmd_07: /* input flush  */
-	case cmd_0d: /* open device  */
-	case cmd_0e: /* close device */
-	case cmd_0c: /* ioctl output */
-	  return (1);
-	case cmd_03: /* ioctl input  */
-	  switch (subfunc)
-	    /* DOS ioctl input subfunction */
-	    {
-	    case cxi_00:
-	    case cxi_06:
-	    case cxi_09:
-	      return (1);
-	    default:
-	      return (ERROR15);
-	    }
-	  return (1);
+	switch (audio_state)                   /* audio status from controller  */
+	{
+	case aud_11: /* "audio play in progress" */
+	case audx11:
+		switch (func)                      /* DOS command code */
+		{
+		case cmd_07: /* input flush  */
+		case cmd_0d: /* open device  */
+		case cmd_0e: /* close device */
+		case cmd_0c: /* ioctl output */
+			return (1);
+		case cmd_03: /* ioctl input  */
+			switch (subfunc)
+				/* DOS ioctl input subfunction */
+			{
+			case cxi_00:
+			case cxi_06:
+			case cxi_09:
+				return (1);
+			default:
+				return (ERROR15);
+			}
+			return (1);
+		default:
+			return (ERROR15);
+		}
+		return (1);
+	case aud_12:                  /* "audio play paused"      */
+	case audx12:
+		return (1);
 	default:
-	  return (ERROR15);
+		return (2);
 	}
-      return (1);
-    case aud_12:                  /* "audio play paused"      */
-    case audx12:
-      return (1);
-    default:
-      return (2);
-    }
 }
-#endif FUTURE
 /*==========================================================================*/
 /* allowed is only
  * ioctl_o, flush_input, open_device, close_device, 
@@ -2708,320 +3460,266 @@
 static int check_allowed1(u_char func1, u_char func2)
 {
 #if 000
-  if (func1==ioctl_o) return (0);
-  if (func1==read_long) return (-1);
-  if (func1==read_long_prefetch) return (-1);
-  if (func1==seek) return (-1);
-  if (func1==audio_play) return (-1);
-  if (func1==audio_pause) return (-1);
-  if (func1==audio_resume) return (-1);
-  if (func1!=ioctl_i) return (0);
-  if (func2==tell_SubQ_run_tot) return (-1);
-  if (func2==tell_cdsize) return (-1);
-  if (func2==tell_TocDescrip) return (-1);
-  if (func2==tell_TocEntry) return (-1);
-  if (func2==tell_subQ_info) return (-1);
-  if (fam1_drive) if (func2==tell_SubChanInfo) return (-1);
-  if (func2==tell_UPC) return (-1);
+	if (func1==ioctl_o) return (0);
+	if (func1==read_long) return (-1);
+	if (func1==read_long_prefetch) return (-1);
+	if (func1==seek) return (-1);
+	if (func1==audio_play) return (-1);
+	if (func1==audio_pause) return (-1);
+	if (func1==audio_resume) return (-1);
+	if (func1!=ioctl_i) return (0);
+	if (func2==tell_SubQ_run_tot) return (-1);
+	if (func2==tell_cdsize) return (-1);
+	if (func2==tell_TocDescrip) return (-1);
+	if (func2==tell_TocEntry) return (-1);
+	if (func2==tell_subQ_info) return (-1);
+	if (fam1_drive) if (func2==tell_SubChanInfo) return (-1);
+	if (func2==tell_UPC) return (-1);
 #else
-  return (0);
+	return (0);
 #endif 000
 }
 /*==========================================================================*/
 static int check_allowed2(u_char func1, u_char func2)
 {
 #if 000
-  if (func1==read_long) return (-1);
-  if (func1==read_long_prefetch) return (-1);
-  if (func1==seek) return (-1);
-  if (func1==audio_play) return (-1);
+	if (func1==read_long) return (-1);
+	if (func1==read_long_prefetch) return (-1);
+	if (func1==seek) return (-1);
+	if (func1==audio_play) return (-1);
   if (func1!=ioctl_o) return (0);
-  if (fam1_drive)
-    {
-      if (func2==EjectDisk) return (-1);
-      if (func2==CloseTray) return (-1);
-    }
+	if (fam1_drive)
+	{
+		if (func2==EjectDisk) return (-1);
+		if (func2==CloseTray) return (-1);
+	}
 #else
-  return (0);
+	return (0);
 #endif 000
 }
 /*==========================================================================*/
 static int check_allowed3(u_char func1, u_char func2)
 {
 #if 000
-  if (func1==ioctl_i)
-    {
-      if (func2==tell_address) return (0);
-      if (func2==tell_capabiliti) return (0);
-      if (func2==tell_CD_changed) return (0);
-      if (fam0L_drive) if (func2==tell_SubChanInfo) return (0);
-      return (-1);
-    }
-  if (func1==ioctl_o)
-    {
-      if (func2==DriveReset) return (0);
-      if (fam0L_drive)
+	if (func1==ioctl_i)
 	{
-	  if (func2==EjectDisk) return (0);
-	  if (func2==LockDoor) return (0);
-	  if (func2==CloseTray) return (0);
+		if (func2==tell_address) return (0);
+		if (func2==tell_capabiliti) return (0);
+		if (func2==tell_CD_changed) return (0);
+		if (fam0L_drive) if (func2==tell_SubChanInfo) return (0);
+		return (-1);
 	}
-      return (-1);
+	if (func1==ioctl_o)
+	{
+		if (func2==DriveReset) return (0);
+		if (fam0L_drive)
+		{
+			if (func2==EjectDisk) return (0);
+			if (func2==LockDoor) return (0);
+	  if (func2==CloseTray) return (0);
+		}
+		return (-1);
     }
-  if (func1==flush_input) return (-1);
-  if (func1==read_long) return (-1);
-  if (func1==read_long_prefetch) return (-1);
-  if (func1==seek) return (-1);
-  if (func1==audio_play) return (-1);
-  if (func1==audio_pause) return (-1);
-  if (func1==audio_resume) return (-1);
+	if (func1==flush_input) return (-1);
+	if (func1==read_long) return (-1);
+	if (func1==read_long_prefetch) return (-1);
+	if (func1==seek) return (-1);
+	if (func1==audio_play) return (-1);
+	if (func1==audio_pause) return (-1);
+	if (func1==audio_resume) return (-1);
 #else
-  return (0);
+	return (0);
 #endif 000
 }
 /*==========================================================================*/
 static int seek_pos_audio_end(void)
 {
-  int i;
+	int i;
 
-  i=msf2blk(DriveStruct[d].pos_audio_end)-1;
-  if (i<0) return (-1);
-  i=xx_Seek(i,0);
-  return (i);
+	i=msf2blk(D_S[d].pos_audio_end)-1;
+	if (i<0) return (-1);
+	i=cc_Seek(i,0);
+	return (i);
 }
+#endif FUTURE
 /*==========================================================================*/
 static int ReadToC(void)
 {
-  int i, j;
-  DriveStruct[d].diskstate_flags &= ~toc_bit;
-  DriveStruct[d].ored_ctl_adr=0;
-  for (j=DriveStruct[d].n_first_track;j<=DriveStruct[d].n_last_track;j++)
-    {
-      i=xx_ReadTocEntry(j);
-      if (i<0) return (i);
-      DriveStruct[d].TocBuffer[j].nixbyte=DriveStruct[d].TocEnt_nixbyte;
-      DriveStruct[d].TocBuffer[j].ctl_adr=DriveStruct[d].TocEnt_ctl_adr;
-      DriveStruct[d].TocBuffer[j].number=DriveStruct[d].TocEnt_number;
-      DriveStruct[d].TocBuffer[j].format=DriveStruct[d].TocEnt_format;
-      DriveStruct[d].TocBuffer[j].address=DriveStruct[d].TocEnt_address;
-      DriveStruct[d].ored_ctl_adr |= DriveStruct[d].TocEnt_ctl_adr;
-    }
-/* fake entry for LeadOut Track */
-  DriveStruct[d].TocBuffer[j].nixbyte=0;
-  DriveStruct[d].TocBuffer[j].ctl_adr=0;
-  DriveStruct[d].TocBuffer[j].number=CDROM_LEADOUT;
-  DriveStruct[d].TocBuffer[j].format=0;
-  DriveStruct[d].TocBuffer[j].address=DriveStruct[d].size_msf;
-
-  DriveStruct[d].diskstate_flags |= toc_bit;
-  return (0);
+	int i, j;
+	D_S[d].diskstate_flags &= ~toc_bit;
+	D_S[d].ored_ctl_adr=0;
+	for (j=D_S[d].n_first_track;j<=D_S[d].n_last_track;j++)
+	{
+		i=cc_ReadTocEntry(j);
+		if (i<0)
+		{
+			msg(DBG_INF,"cc_ReadTocEntry(%d) returns %d.\n",j,i);
+			return (i);
+		}
+		D_S[d].TocBuffer[j].nixbyte=D_S[d].TocEnt_nixbyte;
+		D_S[d].TocBuffer[j].ctl_adr=D_S[d].TocEnt_ctl_adr;
+		D_S[d].TocBuffer[j].number=D_S[d].TocEnt_number;
+		D_S[d].TocBuffer[j].format=D_S[d].TocEnt_format;
+		D_S[d].TocBuffer[j].address=D_S[d].TocEnt_address;
+		D_S[d].ored_ctl_adr |= D_S[d].TocEnt_ctl_adr;
+	}
+	/* fake entry for LeadOut Track */
+	D_S[d].TocBuffer[j].nixbyte=0;
+	D_S[d].TocBuffer[j].ctl_adr=0;
+	D_S[d].TocBuffer[j].number=CDROM_LEADOUT;
+	D_S[d].TocBuffer[j].format=0;
+	D_S[d].TocBuffer[j].address=D_S[d].size_msf;
+	
+	D_S[d].diskstate_flags |= toc_bit;
+	return (0);
 }
 /*==========================================================================*/
 static int DiskInfo(void)
 {
-  int i, j;
-
-      DriveStruct[d].mode=READ_M1;
-
+	int i, j;
+	
+	D_S[d].mode=READ_M1;
+	
 #undef LOOP_COUNT
-#define LOOP_COUNT 20 /* needed for some "old" drives */
-
-  for (j=1;j<LOOP_COUNT;j++)
-    {
-      i=SetSpeed();
-      if (i<0)
-	{
-	  DPRINTF((DBG_INF,"SBPCD: DiskInfo: SetSpeed returns %d\n", i));
-	  continue;
-	}
-      i=xx_ModeSense();
-      if (i<0)
-	{
-	  DPRINTF((DBG_INF,"SBPCD: DiskInfo: xx_ModeSense returns %d\n", i));
-	  continue;
-	}
-      i=xx_ReadCapacity();
-      if (i>=0) break;
-      DPRINTF((DBG_INF,"SBPCD: DiskInfo: ReadCapacity #%d returns %d\n", j, i));
-      i=DriveReset();
-    }
-  if (j==LOOP_COUNT) return (-2); /* give up */
-
-  i=xx_ReadTocDescr();
-  if (i<0)
-    {
-      DPRINTF((DBG_INF,"SBPCD: DiskInfo: ReadTocDescr returns %d\n", i));
-      return (i);
-    }
-  i=ReadToC();
-  if (i<0)
-    {
-      DPRINTF((DBG_INF,"SBPCD: DiskInfo: ReadToC returns %d\n", i));
-      return (i);
-    }
-  i=yy_CheckMultiSession();
-  if (i<0)
-    {
-      DPRINTF((DBG_INF,"SBPCD: DiskInfo: yy_CheckMultiSession returns %d\n", i));
-      return (i);
-    }
-  i=xx_ReadTocEntry(DriveStruct[d].n_first_track);
-  if (i<0)
-    {
-      DPRINTF((DBG_INF,"SBPCD: DiskInfo: xx_ReadTocEntry(1) returns %d\n", i));
-      return (i);
-    }
-  i=xx_ReadUPC();
-  if (i<0)
-    {
-      DPRINTF((DBG_INF,"SBPCD: DiskInfo: xx_ReadUPC returns %d\n", i));
-      return (i);
-    }
-#ifdef XA_TEST2
-  if ((fam0L_drive) && (DriveStruct[d].xa_byte==0x20)) /* XA disk with old drive */
-      {
-	xx_ModeSelect(CD_FRAMESIZE_XA);
-	xx_ModeSense();
-      }
-#endif XA_TEST2
-
-  return (0);
+#define LOOP_COUNT 10 /* needed for some "old" drives */
+	
+	msg(DBG_000,"DiskInfo entered.\n");
+	for (j=1;j<LOOP_COUNT;j++)
+	{
+		i=SetSpeed();
+		if (i<0)
+		{
+			msg(DBG_INF,"DiskInfo: SetSpeed returns %d\n", i);
+			continue;
+		}
+		i=cc_ModeSense();
+		if (i<0)
+		{
+			msg(DBG_INF,"DiskInfo: cc_ModeSense returns %d\n", i);
+			continue;
+		}
+		i=cc_ReadCapacity();
+		if (i>=0) break;
+		msg(DBG_INF,"DiskInfo: ReadCapacity #%d returns %d\n", j, i);
+		i=cc_DriveReset();
+	}
+	if (j==LOOP_COUNT) return (-33); /* give up */
+	
+	i=cc_ReadTocDescr();
+	if (i<0)
+	{
+		msg(DBG_INF,"DiskInfo: ReadTocDescr returns %d\n", i);
+		return (i);
+	}
+	i=ReadToC();
+	if (i<0)
+	{
+		msg(DBG_INF,"DiskInfo: ReadToC returns %d\n", i);
+		return (i);
+	}
+	i=cc_CheckMultiSession();
+	if (i<0)
+	{
+		msg(DBG_INF,"DiskInfo: cc_CheckMultiSession returns %d\n", i);
+		return (i);
+	}
+	if (D_S[d].f_multisession) D_S[d].sbp_bufsiz=1;  /* possibly a weird PhotoCD */
+	
+	i=cc_ReadTocEntry(D_S[d].n_first_track);
+	if (i<0)
+	{
+		msg(DBG_INF,"DiskInfo: cc_ReadTocEntry(1) returns %d\n", i);
+		return (i);
+	}
+	i=cc_ReadUPC();
+	if (i<0) msg(DBG_INF,"DiskInfo: cc_ReadUPC returns %d\n", i);
+	if ((fam0L_drive) && (D_S[d].xa_byte==0x20))
+	{
+		/* XA disk with old drive */
+		cc_ModeSelect(CD_FRAMESIZE_XA);
+		cc_ModeSense();
+	}
+	if (famT_drive)	cc_prep_mode_T();
+	msg(DBG_000,"DiskInfo done.\n");
+	return (0);
 }
 /*==========================================================================*/
+#if FUTURE
 /*
  *  called always if driver gets entered
  *  returns 0 or ERROR2 or ERROR15
  */
 static int prepare(u_char func, u_char subfunc)
 {
-  int i;
-
-  if (fam0L_drive)
-    {
-      i=inb(CDi_status);
-      if (i&s_attention) GetStatus();
-    }
-  else if (fam1_drive) GetStatus();
-  else if (fam2_drive) GetStatus();
-  if (DriveStruct[d].CD_changed==0xFF)
-    {
-#if MANY_SESSION
-#else
-      DriveStruct[d].diskstate_flags=0;
-#endif MANY_SESSION
-      DriveStruct[d].audio_state=0;
-      if (!st_diskok)
-	{
-	  i=check_allowed1(func,subfunc);
-	  if (i<0) return (-2);
-	}
-      else 
-	{
-	  i=check_allowed3(func,subfunc);
-	  if (i<0)
-	    {
-	      DriveStruct[d].CD_changed=1;
-	      return (-15);
-	    }
+	int i;
+	
+	if (fam0L_drive)
+	{
+		i=inb(CDi_status);
+		if (i&s_attention) GetStatus();
+	}
+	else if (fam1_drive) GetStatus();
+	else if (fam2_drive) GetStatus();
+	else if (famT_drive) GetStatus();
+	if (D_S[d].CD_changed==0xFF)
+	{
+		D_S[d].diskstate_flags=0;
+		D_S[d].audio_state=0;
+		if (!st_diskok)
+		{
+			i=check_allowed1(func,subfunc);
+			if (i<0) return (-2);
+		}
+		else 
+		{
+			i=check_allowed3(func,subfunc);
+			if (i<0)
+			{
+				D_S[d].CD_changed=1;
+				return (-15);
+			}
+		}
 	}
-    }
-  else
-    {
-      if (!st_diskok)
+	else
 	{
-#if MANY_SESSION
-#else
-	  DriveStruct[d].diskstate_flags=0;
-#endif MANY_SESSION
-	  DriveStruct[d].audio_state=0;
-	  i=check_allowed1(func,subfunc);
-	  if (i<0) return (-2);
-	}
-      else
-	{ 
-	  if (st_busy)
-	    {
-	      if (DriveStruct[d].audio_state!=audio_pausing)
-		{
-		  i=check_allowed2(func,subfunc);
-		  if (i<0) return (-2);
-		}
-	    }
-	  else
-	    {
-	      if (DriveStruct[d].audio_state==audio_playing) seek_pos_audio_end();
-	      DriveStruct[d].audio_state=0;
-	    }
-	  if (!frame_size_valid)
-	    {
-	      i=DiskInfo();
-	      if (i<0)
+		if (!st_diskok)
 		{
-#if MANY_SESSION
-#else
-		  DriveStruct[d].diskstate_flags=0;
-#endif MANY_SESSION
-		  DriveStruct[d].audio_state=0;
-		  i=check_allowed1(func,subfunc);
-		  if (i<0) return (-2);
+			D_S[d].diskstate_flags=0;
+			D_S[d].audio_state=0;
+			i=check_allowed1(func,subfunc);
+			if (i<0) return (-2);
+		}
+		else
+		{ 
+			if (st_busy)
+			{
+				if (D_S[d].audio_state!=audio_pausing)
+				{
+					i=check_allowed2(func,subfunc);
+					if (i<0) return (-2);
+				}
+			}
+			else
+			{
+				if (D_S[d].audio_state==audio_playing) seek_pos_audio_end();
+				D_S[d].audio_state=0;
+			}
+			if (!frame_size_valid)
+			{
+				i=DiskInfo();
+				if (i<0)
+				{
+					D_S[d].diskstate_flags=0;
+					D_S[d].audio_state=0;
+					i=check_allowed1(func,subfunc);
+					if (i<0) return (-2);
+				}
+			}
 		}
-	    }
-	}
-    }
-  return (0);
-}
-/*==========================================================================*/
-static int xx_PlayAudio(int pos_audio_start,int pos_audio_end)
-{
-  int i, n;
-
-  if (DriveStruct[d].audio_state==audio_playing) return (-EINVAL);
-  clr_cmdbuf();
-  if (famL_drive)
-    {
-      drvcmd[0]=CMDL_PLAY;
-      i=msf2blk(pos_audio_start);
-      n=msf2blk(pos_audio_end)+1-i;
-      drvcmd[1]=(i>>16)&0x00FF;
-      drvcmd[2]=(i>>8)&0x00FF;
-      drvcmd[3]=i&0x00FF;
-      drvcmd[4]=(n>>16)&0x00FF;
-      drvcmd[5]=(n>>8)&0x00FF;
-      drvcmd[6]=n&0x00FF;
-      flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta |
-	f_ResponseStatus | f_obey_p_check | f_wait_if_busy;
-    }
-  else
-    {
-      if (fam1_drive)
-	{
-	  drvcmd[0]=CMD1_PLAY_MSF;
-	  flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus |
-	    f_obey_p_check | f_wait_if_busy;
-	}
-      else if (fam2_drive)
-	{
-	  drvcmd[0]=CMD2_PLAY_MSF;
-	  flags_cmd_out = f_putcmd | f_ResponseStatus;
-	}
-      else if (fam0_drive)
-	{
-	  drvcmd[0]=CMD0_PLAY_MSF;
-	  flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta |
-	    f_ResponseStatus | f_obey_p_check | f_wait_if_busy;
-	}
-      drvcmd[1]=(pos_audio_start>>16)&0x00FF;
-      drvcmd[2]=(pos_audio_start>>8)&0x00FF;
-      drvcmd[3]=pos_audio_start&0x00FF;
-      drvcmd[4]=(pos_audio_end>>16)&0x00FF;
-      drvcmd[5]=(pos_audio_end>>8)&0x00FF;
-      drvcmd[6]=pos_audio_end&0x00FF;
     }
-  response_count=0;
-  i=cmd_out(7);
-  return (i);
+	return (0);
 }
-/*==========================================================================*/
+#endif FUTURE
 /*==========================================================================*/
 /*==========================================================================*/
 /*
@@ -3029,43 +3727,43 @@
  */
 static int sbp_status(void)
 {
-  int st;
-
-  st=ResponseStatus();
-  if (st<0)
-    {
-      DPRINTF((DBG_INF,"SBPCD: sbp_status: timeout.\n"));
-      return (0);
-    }
-
-  if (!st_spinning) DPRINTF((DBG_SPI,"SBPCD: motor got off - ignoring.\n"));
-
-  if (st_check) 
-    {
-      DPRINTF((DBG_INF,"SBPCD: st_check detected - retrying.\n"));
-      return (0);
-    }
-  if (!st_door_closed)
-    {
-      DPRINTF((DBG_INF,"SBPCD: door is open - retrying.\n"));
-      return (0);
-    }
-  if (!st_caddy_in)
-    {
-      DPRINTF((DBG_INF,"SBPCD: disk removed - retrying.\n"));
-      return (0);
-    }
-  if (!st_diskok) 
-    {
-      DPRINTF((DBG_INF,"SBPCD: !st_diskok detected - retrying.\n"));
-      return (0);
-    }
-  if (st_busy) 
-    {
-      DPRINTF((DBG_INF,"SBPCD: st_busy detected - retrying.\n"));
-      return (0);
-    }
-  return (1);
+	int st;
+	
+	st=ResponseStatus();
+	if (st<0)
+	{
+		msg(DBG_INF,"sbp_status: timeout.\n");
+		return (0);
+	}
+	
+	if (!st_spinning) msg(DBG_SPI,"motor got off - ignoring.\n");
+	
+	if (st_check) 
+	{
+		msg(DBG_INF,"st_check detected - retrying.\n");
+		return (0);
+	}
+	if (!st_door_closed)
+	{
+		msg(DBG_INF,"door is open - retrying.\n");
+		return (0);
+	}
+	if (!st_caddy_in)
+	{
+		msg(DBG_INF,"disk removed - retrying.\n");
+		return (0);
+	}
+	if (!st_diskok) 
+	{
+		msg(DBG_INF,"!st_diskok detected - retrying.\n");
+		return (0);
+	}
+	if (st_busy) 
+	{
+		msg(DBG_INF,"st_busy detected - retrying.\n");
+		return (0);
+	}
+	return (1);
 }
 /*==========================================================================*/
 
@@ -3077,507 +3775,546 @@
 static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
 		       u_long arg)
 {
-  int i, st;
-
-  DPRINTF((DBG_IO2,"SBPCD: ioctl(%d, 0x%08lX, 0x%08lX)\n",
-				MINOR(inode->i_rdev), cmd, arg));
-  if (!inode) return (-EINVAL);
-  i=MINOR(inode->i_rdev);
-  if ((i<0) || (i>=NR_SBPCD) || (DriveStruct[i].drv_id==-1))
-    {
-      printk("SBPCD: ioctl: bad device: %04X\n", inode->i_rdev);
-      return (-ENXIO);             /* no such drive */
-    }
-  switch_drive(i);
-
-  st=GetStatus();
-  if (st<0) return (-EIO);
-  
-  if (!toc_valid)
-    {
-      i=DiskInfo();
-      if (i<0) return (-EIO);	/* error reading TOC */
-    }
-  
-  DPRINTF((DBG_IO2,"SBPCD: ioctl: device %d, request %04X\n",i,cmd));
-  switch (cmd) 		/* Sun-compatible */
-    {
-    case DDIOCSDBG:		/* DDI Debug */
-      if (! suser()) return (-EPERM);
-      i = verify_area(VERIFY_READ, (int *) arg, sizeof(int));
-      if (i>=0) i=sbpcd_dbg_ioctl(arg,1);
-      return (i);
-
-    case CDROMPAUSE:     /* Pause the drive */
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMPAUSE entered.\n"));
-      /* pause the drive unit when it is currently in PLAY mode,         */
-      /* or reset the starting and ending locations when in PAUSED mode. */
-      /* If applicable, at the next stopping point it reaches            */
-      /* the drive will discontinue playing.                             */
-      switch (DriveStruct[d].audio_state)
-	{
-	case audio_playing:
-	  if (famL_drive) i=xx_ReadSubQ();
-	  else i=xx_Pause_Resume(1);
-	  if (i<0) return (-EIO);
-	  if (famL_drive) i=xx_Pause_Resume(1);
-	  else i=xx_ReadSubQ();
-	  if (i<0) return (-EIO);
-	  DriveStruct[d].pos_audio_start=DriveStruct[d].SubQ_run_tot;
-	  DriveStruct[d].audio_state=audio_pausing;
-	  return (0);
-	case audio_pausing:
-	  i=xx_Seek(DriveStruct[d].pos_audio_start,1);
-	  if (i<0) return (-EIO);
-	  return (0);
-	default:
-	  return (-EINVAL);
+	int i, st;
+	
+	msg(DBG_IO2,"ioctl(%d, 0x%08lX, 0x%08lX)\n",
+	    MINOR(inode->i_rdev), cmd, arg);
+	if (!inode) return (-EINVAL);
+	i=MINOR(inode->i_rdev);
+	if ((i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1))
+	{
+		msg(DBG_INF, "ioctl: bad device: %04X\n", inode->i_rdev);
+		return (-ENXIO);             /* no such drive */
 	}
-      
-    case CDROMRESUME: /* resume paused audio play */
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMRESUME entered.\n"));
-      /* resume playing audio tracks when a previous PLAY AUDIO call has  */
-      /* been paused with a PAUSE command.                                */
-      /* It will resume playing from the location saved in SubQ_run_tot.  */
-      if (DriveStruct[d].audio_state!=audio_pausing) return -EINVAL;
-      if (famL_drive)
-	i=xx_PlayAudio(DriveStruct[d].pos_audio_start,
-		       DriveStruct[d].pos_audio_end);
-      else i=xx_Pause_Resume(3);
-      if (i<0) return (-EIO);
-      DriveStruct[d].audio_state=audio_playing;
-      return (0);
-
-    case CDROMPLAYMSF:
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMPLAYMSF entered.\n"));
-      if (DriveStruct[d].audio_state==audio_playing)
-	{
-	  i=xx_Pause_Resume(1);
-	  if (i<0) return (-EIO);
-	  i=xx_ReadSubQ();
-	  if (i<0) return (-EIO);
-	  DriveStruct[d].pos_audio_start=DriveStruct[d].SubQ_run_tot;
-	  i=xx_Seek(DriveStruct[d].pos_audio_start,1);
-	}
-      st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_msf));
-      if (st) return (st);
-      memcpy_fromfs(&msf, (void *) arg, sizeof(struct cdrom_msf));
-      /* values come as msf-bin */
-      DriveStruct[d].pos_audio_start = (msf.cdmsf_min0<<16) |
+	if (d!=i) switch_drive(i);
+	
+#if 0
+	st=GetStatus();
+	if (st<0) return (-EIO);
+	
+	if (!toc_valid)
+	{
+		i=DiskInfo();
+		if (i<0) return (-EIO);	/* error reading TOC */
+	}
+#endif
+	
+	msg(DBG_IO2,"ioctl: device %d, request %04X\n",i,cmd);
+	switch (cmd) 		/* Sun-compatible */
+	{
+	case DDIOCSDBG:		/* DDI Debug */
+		if (!suser()) return (-EPERM);
+		i=sbpcd_dbg_ioctl(arg,1);
+		return (i);
+		
+	case CDROMPAUSE:     /* Pause the drive */
+		msg(DBG_IOC,"ioctl: CDROMPAUSE entered.\n");
+		/* pause the drive unit when it is currently in PLAY mode,         */
+		/* or reset the starting and ending locations when in PAUSED mode. */
+		/* If applicable, at the next stopping point it reaches            */
+		/* the drive will discontinue playing.                             */
+		switch (D_S[d].audio_state)
+		{
+		case audio_playing:
+			if (famL_drive) i=cc_ReadSubQ();
+			else i=cc_Pause_Resume(1);
+			if (i<0) return (-EIO);
+			if (famL_drive) i=cc_Pause_Resume(1);
+			else i=cc_ReadSubQ();
+			if (i<0) return (-EIO);
+			D_S[d].pos_audio_start=D_S[d].SubQ_run_tot;
+			D_S[d].audio_state=audio_pausing;
+			return (0);
+		case audio_pausing:
+			i=cc_Seek(D_S[d].pos_audio_start,1);
+			if (i<0) return (-EIO);
+			return (0);
+		default:
+			return (-EINVAL);
+		}
+		
+	case CDROMRESUME: /* resume paused audio play */
+		msg(DBG_IOC,"ioctl: CDROMRESUME entered.\n");
+		/* resume playing audio tracks when a previous PLAY AUDIO call has  */
+		/* been paused with a PAUSE command.                                */
+		/* It will resume playing from the location saved in SubQ_run_tot.  */
+		if (D_S[d].audio_state!=audio_pausing) return -EINVAL;
+		if (famL_drive)
+			i=cc_PlayAudio(D_S[d].pos_audio_start,
+				       D_S[d].pos_audio_end);
+		else i=cc_Pause_Resume(3);
+		if (i<0) return (-EIO);
+		D_S[d].audio_state=audio_playing;
+		return (0);
+		
+	case CDROMPLAYMSF:
+		msg(DBG_IOC,"ioctl: CDROMPLAYMSF entered.\n");
+		if (D_S[d].audio_state==audio_playing)
+		{
+			i=cc_Pause_Resume(1);
+			if (i<0) return (-EIO);
+			i=cc_ReadSubQ();
+			if (i<0) return (-EIO);
+			D_S[d].pos_audio_start=D_S[d].SubQ_run_tot;
+			i=cc_Seek(D_S[d].pos_audio_start,1);
+		}
+		st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_msf));
+		if (st) return (st);
+		memcpy_fromfs(&msf, (void *) arg, sizeof(struct cdrom_msf));
+		/* values come as msf-bin */
+		D_S[d].pos_audio_start = (msf.cdmsf_min0<<16) |
                         (msf.cdmsf_sec0<<8) |
-                        msf.cdmsf_frame0;
-      DriveStruct[d].pos_audio_end = (msf.cdmsf_min1<<16) |
-                      (msf.cdmsf_sec1<<8) |
-                      msf.cdmsf_frame1;
-      DPRINTF((DBG_IOX,"SBPCD: ioctl: CDROMPLAYMSF %08X %08X\n",
-	                       DriveStruct[d].pos_audio_start,DriveStruct[d].pos_audio_end));
-      i=xx_PlayAudio(DriveStruct[d].pos_audio_start,DriveStruct[d].pos_audio_end);
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: xx_PlayAudio returns %d\n",i));
+				msf.cdmsf_frame0;
+		D_S[d].pos_audio_end = (msf.cdmsf_min1<<16) |
+			(msf.cdmsf_sec1<<8) |
+				msf.cdmsf_frame1;
+		msg(DBG_IOX,"ioctl: CDROMPLAYMSF %08X %08X\n",
+		    D_S[d].pos_audio_start,D_S[d].pos_audio_end);
+		i=cc_PlayAudio(D_S[d].pos_audio_start,D_S[d].pos_audio_end);
+		msg(DBG_IOC,"ioctl: cc_PlayAudio returns %d\n",i);
 #if 0
-      if (i<0) return (-EIO);
+		if (i<0) return (-EIO);
 #endif 0
-      DriveStruct[d].audio_state=audio_playing;
-      return (0);
-
-    case CDROMPLAYTRKIND: /* Play a track.  This currently ignores index. */
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMPLAYTRKIND entered.\n"));
-      if (DriveStruct[d].audio_state==audio_playing)
-	{
-	  DPRINTF((DBG_IOX,"SBPCD: CDROMPLAYTRKIND: already audio_playing.\n"));
-	  return (0);
-	  return (-EINVAL);
-	}
-      st=verify_area(VERIFY_READ,(void *) arg,sizeof(struct cdrom_ti));
-      if (st<0)
-	{
-	  DPRINTF((DBG_IOX,"SBPCD: CDROMPLAYTRKIND: verify_area error.\n"));
-	  return (st);
-	}
-      memcpy_fromfs(&ti,(void *) arg,sizeof(struct cdrom_ti));
-      DPRINTF((DBG_IOX,"SBPCD: ioctl: trk0: %d, ind0: %d, trk1:%d, ind1:%d\n",
-	     ti.cdti_trk0,ti.cdti_ind0,ti.cdti_trk1,ti.cdti_ind1));
-      if (ti.cdti_trk0<DriveStruct[d].n_first_track) return (-EINVAL);
-      if (ti.cdti_trk0>DriveStruct[d].n_last_track) return (-EINVAL);
-      if (ti.cdti_trk1<ti.cdti_trk0) ti.cdti_trk1=ti.cdti_trk0;
-      if (ti.cdti_trk1>DriveStruct[d].n_last_track) ti.cdti_trk1=DriveStruct[d].n_last_track;
-      DriveStruct[d].pos_audio_start=DriveStruct[d].TocBuffer[ti.cdti_trk0].address;
-      DriveStruct[d].pos_audio_end=DriveStruct[d].TocBuffer[ti.cdti_trk1+1].address;
-      i=xx_PlayAudio(DriveStruct[d].pos_audio_start,DriveStruct[d].pos_audio_end);
+		D_S[d].audio_state=audio_playing;
+		return (0);
+		
+	case CDROMPLAYTRKIND: /* Play a track.  This currently ignores index. */
+		msg(DBG_IOC,"ioctl: CDROMPLAYTRKIND entered.\n");
+		if (D_S[d].audio_state==audio_playing)
+		{
+			msg(DBG_IOX,"CDROMPLAYTRKIND: already audio_playing.\n");
+			return (0);
+			return (-EINVAL);
+		}
+		st=verify_area(VERIFY_READ,(void *) arg,sizeof(struct cdrom_ti));
+		if (st<0)
+		{
+			msg(DBG_IOX,"CDROMPLAYTRKIND: verify_area error.\n");
+			return (st);
+		}
+		memcpy_fromfs(&ti,(void *) arg,sizeof(struct cdrom_ti));
+		msg(DBG_IOX,"ioctl: trk0: %d, ind0: %d, trk1:%d, ind1:%d\n",
+		    ti.cdti_trk0,ti.cdti_ind0,ti.cdti_trk1,ti.cdti_ind1);
+		if (ti.cdti_trk0<D_S[d].n_first_track) return (-EINVAL);
+		if (ti.cdti_trk0>D_S[d].n_last_track) return (-EINVAL);
+		if (ti.cdti_trk1<ti.cdti_trk0) ti.cdti_trk1=ti.cdti_trk0;
+		if (ti.cdti_trk1>D_S[d].n_last_track) ti.cdti_trk1=D_S[d].n_last_track;
+		D_S[d].pos_audio_start=D_S[d].TocBuffer[ti.cdti_trk0].address;
+		D_S[d].pos_audio_end=D_S[d].TocBuffer[ti.cdti_trk1+1].address;
+		i=cc_PlayAudio(D_S[d].pos_audio_start,D_S[d].pos_audio_end);
 #if 0
-      if (i<0) return (-EIO);
+		if (i<0) return (-EIO);
 #endif 0
-      DriveStruct[d].audio_state=audio_playing;
-      return (0);
-	    
-    case CDROMREADTOCHDR:        /* Read the table of contents header */
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADTOCHDR entered.\n"));
-      tochdr.cdth_trk0=DriveStruct[d].n_first_track;
-      tochdr.cdth_trk1=DriveStruct[d].n_last_track;
-      st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_tochdr));
-      if (st) return (st);
-      memcpy_tofs((void *) arg, &tochdr, sizeof(struct cdrom_tochdr));
-      return (0);
-
-    case CDROMREADTOCENTRY:      /* Read an entry in the table of contents */
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADTOCENTRY entered.\n"));
-      st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_tocentry));
-      if (st) return (st);
-      memcpy_fromfs(&tocentry, (void *) arg, sizeof(struct cdrom_tocentry));
-      i=tocentry.cdte_track;
-      if (i==CDROM_LEADOUT) i=DriveStruct[d].n_last_track+1;
-      else if (i<DriveStruct[d].n_first_track||i>DriveStruct[d].n_last_track) return (-EINVAL);
-      tocentry.cdte_adr=DriveStruct[d].TocBuffer[i].ctl_adr&0x0F;
-      tocentry.cdte_ctrl=(DriveStruct[d].TocBuffer[i].ctl_adr>>4)&0x0F;
-      tocentry.cdte_datamode=DriveStruct[d].TocBuffer[i].format;
-      if (tocentry.cdte_format==CDROM_MSF) /* MSF-bin required */
-	{ tocentry.cdte_addr.msf.minute=(DriveStruct[d].TocBuffer[i].address>>16)&0x00FF;
-	  tocentry.cdte_addr.msf.second=(DriveStruct[d].TocBuffer[i].address>>8)&0x00FF;
-	  tocentry.cdte_addr.msf.frame=DriveStruct[d].TocBuffer[i].address&0x00FF;
-	}
-      else if (tocentry.cdte_format==CDROM_LBA) /* blk required */
-	tocentry.cdte_addr.lba=msf2blk(DriveStruct[d].TocBuffer[i].address);
-      else return (-EINVAL);
-      st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_tocentry));
-      if (st) return (st);
-      memcpy_tofs((void *) arg, &tocentry, sizeof(struct cdrom_tocentry));
-      return (0);
-
-    case CDROMSTOP:      /* Spin down the drive */
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMSTOP entered.\n"));
-      i=xx_Pause_Resume(1);
-      DriveStruct[d].audio_state=0;
-      return (0);
-
-    case CDROMSTART:  /* Spin up the drive */
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMSTART entered.\n"));
-      xx_SpinUp();
-      DriveStruct[d].audio_state=0;
-      return (0);
-      
-    case CDROMEJECT:
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMEJECT entered.\n"));
-      if (fam0_drive) return (0);
-      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].CD_changed=0xFF;
-      DriveStruct[d].diskstate_flags=0;
-      DriveStruct[d].audio_state=0;
-      return (0);
-      
-    case CDROMEJECT_SW:
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMEJECT_SW entered.\n"));
-      if (fam0_drive) return (0);
-      DriveStruct[d].f_eject=arg;
-      return (0);
-      
-    case CDROMVOLCTRL:   /* Volume control */
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMVOLCTRL entered.\n"));
-      st=verify_area(VERIFY_READ,(void *) arg,sizeof(volctrl));
-      if (st) return (st);
-      memcpy_fromfs(&volctrl,(char *) arg,sizeof(volctrl));
-      DriveStruct[d].vol_chan0=0;
-      DriveStruct[d].vol_ctrl0=volctrl.channel0;
-      DriveStruct[d].vol_chan1=1;
-      DriveStruct[d].vol_ctrl1=volctrl.channel1;
-      i=xx_SetVolume();
-      return (0);
-
-    case CDROMSUBCHNL:   /* Get subchannel info */
-      DPRINTF((DBG_IOS,"SBPCD: ioctl: CDROMSUBCHNL entered.\n"));
-      if ((st_spinning)||(!subq_valid)) { i=xx_ReadSubQ();
-					  if (i<0) return (-EIO);
-					}
-      st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl));
-      if (st)	return (st);
-      memcpy_fromfs(&SC, (void *) arg, sizeof(struct cdrom_subchnl));
-      switch (DriveStruct[d].audio_state)
-	{
-	case audio_playing:
-	  SC.cdsc_audiostatus=CDROM_AUDIO_PLAY;
-	  break;
-	case audio_pausing:
-	  SC.cdsc_audiostatus=CDROM_AUDIO_PAUSED;
-	  break;
-	default:
-	  SC.cdsc_audiostatus=CDROM_AUDIO_NO_STATUS;
-	  break;
-	}
-      SC.cdsc_adr=DriveStruct[d].SubQ_ctl_adr;
-      SC.cdsc_ctrl=DriveStruct[d].SubQ_ctl_adr>>4;
-      SC.cdsc_trk=bcd2bin(DriveStruct[d].SubQ_trk);
-      SC.cdsc_ind=bcd2bin(DriveStruct[d].SubQ_pnt_idx);
-      if (SC.cdsc_format==CDROM_LBA)
-	{
-	  SC.cdsc_absaddr.lba=msf2blk(DriveStruct[d].SubQ_run_tot);
-	  SC.cdsc_reladdr.lba=msf2blk(DriveStruct[d].SubQ_run_trk);
-	}
-      else /* not only if (SC.cdsc_format==CDROM_MSF) */
-	{
-	  SC.cdsc_absaddr.msf.minute=(DriveStruct[d].SubQ_run_tot>>16)&0x00FF;
-	  SC.cdsc_absaddr.msf.second=(DriveStruct[d].SubQ_run_tot>>8)&0x00FF;
-	  SC.cdsc_absaddr.msf.frame=DriveStruct[d].SubQ_run_tot&0x00FF;
-	  SC.cdsc_reladdr.msf.minute=(DriveStruct[d].SubQ_run_trk>>16)&0x00FF;
-	  SC.cdsc_reladdr.msf.second=(DriveStruct[d].SubQ_run_trk>>8)&0x00FF;
-	  SC.cdsc_reladdr.msf.frame=DriveStruct[d].SubQ_run_trk&0x00FF;
-	}
-      memcpy_tofs((void *) arg, &SC, sizeof(struct cdrom_subchnl));
-      DPRINTF((DBG_IOS,"SBPCD: CDROMSUBCHNL: %1X %02X %08X %08X %02X %02X %06X %06X\n",
-	       SC.cdsc_format,SC.cdsc_audiostatus,
-	       SC.cdsc_adr,SC.cdsc_ctrl,
-	       SC.cdsc_trk,SC.cdsc_ind,
-	       SC.cdsc_absaddr,SC.cdsc_reladdr));
-      return (0);
-
-    case CDROMREADMODE1:
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADMODE1 requested.\n"));
-      xx_ModeSelect(CD_FRAMESIZE);
-      xx_ModeSense();
-      DriveStruct[d].mode=READ_M1;
-      return (0);
-
-    case CDROMREADMODE2: /* not usable at the moment */
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADMODE2 requested.\n"));
-      xx_ModeSelect(CD_FRAMESIZE_XA);
-      xx_ModeSense();
-      DriveStruct[d].mode=READ_M2;
-      return (0);
-
-    case CDROMREADAUDIO:
-      { /* start of CDROMREADAUDIO */
-	int i=0, j=0, frame, block;
-	u_int try=0;
-	u_long timeout;
-	u_char *p;
-	u_int data_tries = 0;
-	u_int data_waits = 0;
-	u_int data_retrying = 0;
-	int status_tries;
-	int error_flag;
-
-	DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADAUDIO requested.\n"));
-	if (fam0_drive) return (-EINVAL);
-	if (famL_drive) return (-EINVAL);
-	if (fam2_drive) return (-EINVAL);
-	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));
-	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=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);
-	i=yy_SetSpeed(speed_150,0,0);
-	if (i) DPRINTF((DBG_AUD,"SBPCD: read_audio: SetSpeed error %d\n", i));
-	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;
-	error_flag=0;
-	for (data_tries=5; data_tries>0; data_tries--)
-	  {
-	    DPRINTF((DBG_AUD,"SBPCD: data_tries=%d ...\n", data_tries));
-	    DriveStruct[d].mode=READ_AU;
-	    xx_ModeSelect(CD_FRAMESIZE_RAW);
-	    xx_ModeSense();
-	    for (status_tries=3; status_tries > 0; status_tries--)
-	      {
-		flags_cmd_out |= f_respo3;
-		xx_ReadStatus();
-		if (sbp_status() != 0) break;
-		sbp_sleep(1);    /* wait a bit, try again */
-	      }
-	    if (status_tries == 0)
-	      {
-		DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_status: failed after 3 tries.\n"));
-		continue;
-	      }
-	    DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_status: ok.\n"));
-	    
-	    flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus | f_obey_p_check;
-	    if (fam0L_drive)
-	      {
-		flags_cmd_out |= f_lopsta | f_getsta | f_bit1;
-		cmd_type=READ_M2;
-		drvcmd[0]=CMD0_READ_XA; /* "read XA frames", old drives */
-		drvcmd[1]=(block>>16)&0x000000ff;
-		drvcmd[2]=(block>>8)&0x000000ff;
-		drvcmd[3]=block&0x000000ff;
-		drvcmd[4]=0;
-		drvcmd[5]=read_audio.nframes; /* # of frames */
-		drvcmd[6]=0;
-	      }
-	    else if (fam1_drive)
-	      {
-		drvcmd[0]=CMD1_READ; /* "read frames", new drives */
-		lba2msf(block,&drvcmd[1]); /* msf-bin format required */
-		drvcmd[4]=0;
-		drvcmd[5]=0;
-		drvcmd[6]=read_audio.nframes; /* # of frames */
-	      }
-	    else if (fam2_drive) /* CD200: not implemented yet */
-	      {
-	      }
-	    DPRINTF((DBG_AUD,"SBPCD: read_audio: before giving \"read\" command.\n"));
-	    for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]);
-	    sbp_sleep(0);
-	    DPRINTF((DBG_AUD,"SBPCD: read_audio: after giving \"read\" command.\n"));
-	    for (frame=1;frame<2 && !error_flag; frame++)
-	      {
-		try=maxtim_data;
-		for (timeout=jiffies+900; ; )
-		  {
-		    for ( ; try!=0;try--)
-		      {
-			j=inb(CDi_status);
-			if (!(j&s_not_data_ready)) break;
-			if (!(j&s_not_result_ready)) break;
-			if (fam0L_drive) if (j&s_attention) break;
-		      }
-		    if (try != 0 || timeout <= jiffies) break;
-		    if (data_retrying == 0) data_waits++;
-		    data_retrying = 1;
-		    sbp_sleep(1);
-		    try = 1;
-		  }
-		if (try==0)
-		  {
-		    DPRINTF((DBG_INF,"SBPCD: read_audio: sbp_data: CDi_status timeout.\n"));
-		    error_flag++;
-		    break;
-		  }
-		DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_data: CDi_status ok.\n"));
-		if (j&s_not_data_ready)
-		  {
-		    printk("SBPCD: read_audio: sbp_data: DATA_READY timeout.\n");
-		    error_flag++;
-		    break;
-		  }
-		DPRINTF((DBG_AUD,"SBPCD: read_audio: before reading data.\n"));
-		error_flag=0;
-		p = DriveStruct[d].aud_buf;
-		if (sbpro_type==1) OUT(CDo_sel_i_d,1);
-#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_i_d,0);
-		data_retrying = 0;
-	      }
-	    DPRINTF((DBG_AUD,"SBPCD: read_audio: after reading data.\n"));
-	    if (error_flag)    /* must have been spurious D_RDY or (ATTN&&!D_RDY) */
-	      {
-		DPRINTF((DBG_AUD,"SBPCD: read_audio: read aborted by drive\n"));
+		D_S[d].audio_state=audio_playing;
+		return (0);
+		
+	case CDROMREADTOCHDR:        /* Read the table of contents header */
+		msg(DBG_IOC,"ioctl: CDROMREADTOCHDR entered.\n");
+		tochdr.cdth_trk0=D_S[d].n_first_track;
+		tochdr.cdth_trk1=D_S[d].n_last_track;
+		st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_tochdr));
+		if (st) return (st);
+		memcpy_tofs((void *) arg, &tochdr, sizeof(struct cdrom_tochdr));
+		return (0);
+		
+	case CDROMREADTOCENTRY:      /* Read an entry in the table of contents */
+		msg(DBG_IOC,"ioctl: CDROMREADTOCENTRY entered.\n");
+		st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_tocentry));
+		if (st) return (st);
+		memcpy_fromfs(&tocentry, (void *) arg, sizeof(struct cdrom_tocentry));
+		i=tocentry.cdte_track;
+		if (i==CDROM_LEADOUT) i=D_S[d].n_last_track+1;
+		else if (i<D_S[d].n_first_track||i>D_S[d].n_last_track) return (-EINVAL);
+		tocentry.cdte_adr=D_S[d].TocBuffer[i].ctl_adr&0x0F;
+		tocentry.cdte_ctrl=(D_S[d].TocBuffer[i].ctl_adr>>4)&0x0F;
+		tocentry.cdte_datamode=D_S[d].TocBuffer[i].format;
+		if (tocentry.cdte_format==CDROM_MSF) /* MSF-bin required */
+		{
+			tocentry.cdte_addr.msf.minute=(D_S[d].TocBuffer[i].address>>16)&0x00FF;
+			tocentry.cdte_addr.msf.second=(D_S[d].TocBuffer[i].address>>8)&0x00FF;
+			tocentry.cdte_addr.msf.frame=D_S[d].TocBuffer[i].address&0x00FF;
+		}
+		else if (tocentry.cdte_format==CDROM_LBA) /* blk required */
+			tocentry.cdte_addr.lba=msf2blk(D_S[d].TocBuffer[i].address);
+		else return (-EINVAL);
+		st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_tocentry));
+		if (st) return (st);
+		memcpy_tofs((void *) arg, &tocentry, sizeof(struct cdrom_tocentry));
+		return (0);
+		
+	case CDROMRESET:      /* hard reset the drive */
+		msg(DBG_IOC,"ioctl: CDROMRESET entered.\n");
+		i=DriveReset();
+		D_S[d].audio_state=0;
+		return (i);
+		
+	case CDROMSTOP:      /* Spin down the drive */
+		msg(DBG_IOC,"ioctl: CDROMSTOP entered.\n");
+		i=cc_Pause_Resume(1);
+		D_S[d].audio_state=0;
+		return (i);
+		
+	case CDROMSTART:  /* Spin up the drive */
+		msg(DBG_IOC,"ioctl: CDROMSTART entered.\n");
+		cc_SpinUp();
+		D_S[d].audio_state=0;
+		return (0);
+		
+	case CDROMEJECT:
+		msg(DBG_IOC,"ioctl: CDROMEJECT entered.\n");
+		if (fam0_drive) return (0);
+		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 (-EIO);
+		D_S[d].CD_changed=0xFF;
+		D_S[d].diskstate_flags=0;
+		D_S[d].audio_state=0;
+		return (0);
+		
+	case CDROMEJECT_SW:
+		msg(DBG_IOC,"ioctl: CDROMEJECT_SW entered.\n");
+		if (fam0_drive) return (0);
+		D_S[d].f_eject=arg;
+		return (0);
+		
+	case CDROMVOLCTRL:   /* Volume control */
+		msg(DBG_IOC,"ioctl: CDROMVOLCTRL entered.\n");
+		st=verify_area(VERIFY_READ,(void *) arg,sizeof(volctrl));
+		if (st) return (st);
+		memcpy_fromfs(&volctrl,(char *) arg,sizeof(volctrl));
+		D_S[d].vol_chan0=0;
+		D_S[d].vol_ctrl0=volctrl.channel0;
+		D_S[d].vol_chan1=1;
+		D_S[d].vol_ctrl1=volctrl.channel1;
+		i=cc_SetVolume();
+		return (0);
+		
+	case CDROMVOLREAD:   /* read Volume settings from drive */
+		msg(DBG_IOC,"ioctl: CDROMVOLREAD entered.\n");
+		st=verify_area(VERIFY_WRITE,(void *)arg,sizeof(volctrl));
+		if (st) return (st);
+		st=cc_GetVolume();
+		if (st<0) return (st);
+		volctrl.channel0=D_S[d].vol_ctrl0;
+		volctrl.channel1=D_S[d].vol_ctrl1;
+		volctrl.channel2=0;
+		volctrl.channel2=0;
+		memcpy_tofs((void *)arg,&volctrl,sizeof(volctrl));
+		return (0);
+
+	case CDROMSUBCHNL:   /* Get subchannel info */
+		msg(DBG_IOS,"ioctl: CDROMSUBCHNL entered.\n");
+		if ((st_spinning)||(!subq_valid)) { i=cc_ReadSubQ();
+						    if (i<0) return (-EIO);
+					    }
+		st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl));
+		if (st)	return (st);
+		memcpy_fromfs(&SC, (void *) arg, sizeof(struct cdrom_subchnl));
+		switch (D_S[d].audio_state)
+		{
+		case audio_playing:
+			SC.cdsc_audiostatus=CDROM_AUDIO_PLAY;
+			break;
+		case audio_pausing:
+			SC.cdsc_audiostatus=CDROM_AUDIO_PAUSED;
+			break;
+		default:
+			SC.cdsc_audiostatus=CDROM_AUDIO_NO_STATUS;
+			break;
+		}
+		SC.cdsc_adr=D_S[d].SubQ_ctl_adr;
+		SC.cdsc_ctrl=D_S[d].SubQ_ctl_adr>>4;
+		SC.cdsc_trk=bcd2bin(D_S[d].SubQ_trk);
+		SC.cdsc_ind=bcd2bin(D_S[d].SubQ_pnt_idx);
+		if (SC.cdsc_format==CDROM_LBA)
+		{
+			SC.cdsc_absaddr.lba=msf2blk(D_S[d].SubQ_run_tot);
+			SC.cdsc_reladdr.lba=msf2blk(D_S[d].SubQ_run_trk);
+		}
+		else /* not only if (SC.cdsc_format==CDROM_MSF) */
+		{
+			SC.cdsc_absaddr.msf.minute=(D_S[d].SubQ_run_tot>>16)&0x00FF;
+			SC.cdsc_absaddr.msf.second=(D_S[d].SubQ_run_tot>>8)&0x00FF;
+			SC.cdsc_absaddr.msf.frame=D_S[d].SubQ_run_tot&0x00FF;
+			SC.cdsc_reladdr.msf.minute=(D_S[d].SubQ_run_trk>>16)&0x00FF;
+			SC.cdsc_reladdr.msf.second=(D_S[d].SubQ_run_trk>>8)&0x00FF;
+			SC.cdsc_reladdr.msf.frame=D_S[d].SubQ_run_trk&0x00FF;
+		}
+		memcpy_tofs((void *) arg, &SC, sizeof(struct cdrom_subchnl));
+		msg(DBG_IOS,"CDROMSUBCHNL: %1X %02X %08X %08X %02X %02X %06X %06X\n",
+		    SC.cdsc_format,SC.cdsc_audiostatus,
+		    SC.cdsc_adr,SC.cdsc_ctrl,
+		    SC.cdsc_trk,SC.cdsc_ind,
+		    SC.cdsc_absaddr,SC.cdsc_reladdr);
+		return (0);
+		
+	case CDROMREADMODE1:
+		msg(DBG_IOC,"ioctl: CDROMREADMODE1 requested.\n");
+		cc_ModeSelect(CD_FRAMESIZE);
+		cc_ModeSense();
+		D_S[d].mode=READ_M1;
+		return (0);
+		
+	case CDROMREADMODE2: /* not usable at the moment */
+		msg(DBG_IOC,"ioctl: CDROMREADMODE2 requested.\n");
+		cc_ModeSelect(CD_FRAMESIZE_XA);
+		cc_ModeSense();
+		D_S[d].mode=READ_M2;
+		return (0);
+		
+	case CDROMAUDIOBUFSIZ: /* configure the audio buffer size */
+		msg(DBG_IOC,"ioctl: CDROMAUDIOBUFSIZ entered.\n");
+#ifdef MODULE
+		if (D_S[d].sbp_audsiz>0)
+			vfree(D_S[d].aud_buf);
+#endif MODULE
+		D_S[d].aud_buf=NULL;
+		D_S[d].sbp_audsiz=arg;
+		if (D_S[d].sbp_audsiz>0)
+		{
+			D_S[d].aud_buf=(u_char *) vmalloc(D_S[d].sbp_audsiz*CD_FRAMESIZE_RAW);
+			if (D_S[d].aud_buf==NULL)
+			{
+				msg(DBG_INF,"audio buffer (%d frames) not available.\n",D_S[d].sbp_audsiz);
+				D_S[d].sbp_audsiz=0;
+			}
+			else msg(DBG_INF,"audio buffer size: %d frames.\n",D_S[d].sbp_audsiz);
+		}
+		return (D_S[d].sbp_audsiz);
+
+	case CDROMREADAUDIO:
+	{ /* start of CDROMREADAUDIO */
+		int i=0, j=0, frame, block;
+		u_int try=0;
+		u_long timeout;
+		u_char *p;
+		u_int data_tries = 0;
+		u_int data_waits = 0;
+		u_int data_retrying = 0;
+		int status_tries;
+		int error_flag;
+		
+		msg(DBG_IOC,"ioctl: CDROMREADAUDIO entered.\n");
+		if (fam0_drive) return (-EINVAL);
+		if (famL_drive) return (-EINVAL);
+		if (fam2_drive) return (-EINVAL);
+		if (famT_drive) return (-EINVAL);
+		if (D_S[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));
+		if (read_audio.nframes>D_S[d].sbp_audsiz) 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=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);
+		i=cc_SetSpeed(speed_150,0,0);
+		if (i) msg(DBG_AUD,"read_audio: SetSpeed error %d\n", i);
+		msg(DBG_AUD,"read_audio: lba: %d, msf: %06X\n",
+		    block, blk2msf(block));
+		msg(DBG_AUD,"read_audio: before cc_ReadStatus.\n");
+		while (busy_data) sbp_sleep(10); /* wait a bit */
+		busy_audio=1;
+		error_flag=0;
+		for (data_tries=5; data_tries>0; data_tries--)
+		{
+			msg(DBG_AUD,"data_tries=%d ...\n", data_tries);
+			D_S[d].mode=READ_AU;
+			cc_ModeSelect(CD_FRAMESIZE_RAW);
+			cc_ModeSense();
+			for (status_tries=3; status_tries > 0; status_tries--)
+			{
+				flags_cmd_out |= f_respo3;
+				cc_ReadStatus();
+				if (sbp_status() != 0) break;
+				sbp_sleep(1);    /* wait a bit, try again */
+			}
+			if (status_tries == 0)
+			{
+				msg(DBG_AUD,"read_audio: sbp_status: failed after 3 tries.\n");
+				continue;
+			}
+			msg(DBG_AUD,"read_audio: sbp_status: ok.\n");
+			
+			flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus | f_obey_p_check;
+			if (fam0L_drive)
+			{
+				flags_cmd_out |= f_lopsta | f_getsta | f_bit1;
+				cmd_type=READ_M2;
+				drvcmd[0]=CMD0_READ_XA; /* "read XA frames", old drives */
+				drvcmd[1]=(block>>16)&0x000000ff;
+				drvcmd[2]=(block>>8)&0x000000ff;
+				drvcmd[3]=block&0x000000ff;
+				drvcmd[4]=0;
+				drvcmd[5]=read_audio.nframes; /* # of frames */
+				drvcmd[6]=0;
+			}
+			else if (fam1_drive)
+			{
+				drvcmd[0]=CMD1_READ; /* "read frames", new drives */
+				lba2msf(block,&drvcmd[1]); /* msf-bin format required */
+				drvcmd[4]=0;
+				drvcmd[5]=0;
+				drvcmd[6]=read_audio.nframes; /* # of frames */
+			}
+			else if (fam2_drive) /* CD200: not tested yet */
+			{
+			}
+			else if (famT_drive) /* CD-55A: not tested yet */
+			{
+			}
+			msg(DBG_AUD,"read_audio: before giving \"read\" command.\n");
+			for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]);
+			sbp_sleep(0);
+			msg(DBG_AUD,"read_audio: after giving \"read\" command.\n");
+			for (frame=1;frame<2 && !error_flag; frame++)
+			{
+				try=maxtim_data;
+				for (timeout=jiffies+900; ; )
+				{
+					for ( ; try!=0;try--)
+					{
+						j=inb(CDi_status);
+						if (!(j&s_not_data_ready)) break;
+						if (!(j&s_not_result_ready)) break;
+						if (fam0L_drive) if (j&s_attention) break;
+					}
+					if (try != 0 || timeout <= jiffies) break;
+					if (data_retrying == 0) data_waits++;
+					data_retrying = 1;
+					sbp_sleep(1);
+					try = 1;
+				}
+				if (try==0)
+				{
+					msg(DBG_INF,"read_audio: sbp_data: CDi_status timeout.\n");
+					error_flag++;
+					break;
+				}
+				msg(DBG_AUD,"read_audio: sbp_data: CDi_status ok.\n");
+				if (j&s_not_data_ready)
+				{
+					msg(DBG_INF, "read_audio: sbp_data: DATA_READY timeout.\n");
+					error_flag++;
+					break;
+				}
+				msg(DBG_AUD,"read_audio: before reading data.\n");
+				error_flag=0;
+				p = D_S[d].aud_buf;
+				if (sbpro_type==1) OUT(CDo_sel_i_d,1);
+				insb(CDi_data, p, read_audio.nframes*CD_FRAMESIZE_RAW);
+				if (sbpro_type==1) OUT(CDo_sel_i_d,0);
+				data_retrying = 0;
+			}
+			msg(DBG_AUD,"read_audio: after reading data.\n");
+			if (error_flag)    /* must have been spurious D_RDY or (ATTN&&!D_RDY) */
+			{
+				msg(DBG_AUD,"read_audio: read aborted by drive\n");
 #if 0000
-		i=DriveReset();                /* ugly fix to prevent a hang */
+				i=cc_DriveReset();                /* ugly fix to prevent a hang */
 #else
-		i=xx_ReadError();
+				i=cc_ReadError();
 #endif 0000
-		continue;
-	      }
-	    if (fam0L_drive)
-	      {
-		i=maxtim_data;
-		for (timeout=jiffies+900; timeout > jiffies; timeout--)
-		  {
-		    for ( ;i!=0;i--)
-		      {
-			j=inb(CDi_status);
-			if (!(j&s_not_data_ready)) break;
-			if (!(j&s_not_result_ready)) break;
-			if (j&s_attention) break;
-		      }
-		    if (i != 0 || timeout <= jiffies) break;
-		    sbp_sleep(0);
-		    i = 1;
-		  }
-		if (i==0) { DPRINTF((DBG_AUD,"SBPCD: read_audio: STATUS TIMEOUT AFTER READ")); }
-		if (!(j&s_attention))
-		  {
-		    DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_data: timeout waiting DRV_ATTN - retrying\n"));
-		    i=DriveReset();  /* ugly fix to prevent a hang */
-		  continue;
-		  }
-	      }
-	    do
-	      {
-		if (fam0L_drive) xx_ReadStatus();
-		i=ResponseStatus();  /* builds status_byte, returns orig. status (old) or faked p_success_old (new) */
-		if (i<0) { DPRINTF((DBG_AUD,
-				    "SBPCD: read_audio: xx_ReadStatus error after read: %02X\n",
-				    DriveStruct[d].status_byte));
-			   continue; /* FIXME */
-			 }
-	      }
-	    while ((fam0L_drive)&&(!st_check)&&(!(i&p_success_old)));
-	    if (st_check)
-	      {
-		i=xx_ReadError();
-		DPRINTF((DBG_AUD,"SBPCD: read_audio: xx_ReadError was necessary after read: %02X\n",i));
-		continue;
-	      }
-	    memcpy_tofs((u_char *) read_audio.buf,
-			(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"));
-	    return (-8);
-	  }
-	DPRINTF((DBG_AUD,"SBPCD: read_audio: successful return.\n"));
-	return (0);
-      } /* end of CDROMREADAUDIO */
-
-    case CDROMMULTISESSION: /* tell start-of-last-session */
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMMULTISESSION entered.\n"));
-      st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_multisession));
-      if (st) return (st);
-      memcpy_fromfs(&ms_info, (void *) arg, sizeof(struct cdrom_multisession));
-      if (ms_info.addr_format==CDROM_MSF) /* MSF-bin requested */
-	lba2msf(DriveStruct[d].lba_multi,&ms_info.addr.msf.minute);
-      else if (ms_info.addr_format==CDROM_LBA) /* lba requested */
-	ms_info.addr.lba=DriveStruct[d].lba_multi;
-      else return (-EINVAL);
-      if (DriveStruct[d].f_multisession) ms_info.xa_flag=1; /* valid redirection address */
-      else ms_info.xa_flag=0; /* invalid redirection address */
-      st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_multisession));
-      if (st) return (st);
-      memcpy_tofs((void *) arg, &ms_info, sizeof(struct cdrom_multisession));
-      DPRINTF((DBG_MUL,"SBPCD: ioctl: CDROMMULTISESSION done (%d, %08X).\n",
-	       ms_info.xa_flag, ms_info.addr.lba));
-      return (0);
-
-    case BLKRASET:
-      if(!suser())  return -EACCES;
-      if(!inode->i_rdev) return -EINVAL;
-      if(arg > 0xff) return -EINVAL;
-      read_ahead[MAJOR(inode->i_rdev)] = arg;
-      return (0);
-
-    default:
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: unknown function request %04X\n", cmd));
-      return (-EINVAL);
-    } /* end switch(cmd) */
+				continue;
+			}
+			if (fam0L_drive)
+			{
+				i=maxtim_data;
+				for (timeout=jiffies+900; timeout > jiffies; timeout--)
+				{
+					for ( ;i!=0;i--)
+					{
+						j=inb(CDi_status);
+						if (!(j&s_not_data_ready)) break;
+						if (!(j&s_not_result_ready)) break;
+						if (j&s_attention) break;
+					}
+					if (i != 0 || timeout <= jiffies) break;
+					sbp_sleep(0);
+					i = 1;
+				}
+				if (i==0) msg(DBG_AUD,"read_audio: STATUS TIMEOUT AFTER READ");
+				if (!(j&s_attention))
+				{
+					msg(DBG_AUD,"read_audio: sbp_data: timeout waiting DRV_ATTN - retrying\n");
+					i=cc_DriveReset();  /* ugly fix to prevent a hang */
+					continue;
+				}
+			}
+			do
+			{
+				if (fam0L_drive) cc_ReadStatus();
+				i=ResponseStatus();  /* builds status_bits, returns orig. status (old) or faked p_success (new) */
+				if (i<0) { msg(DBG_AUD,
+					       "read_audio: cc_ReadStatus error after read: %02X\n",
+					       D_S[d].status_bits);
+					   continue; /* FIXME */
+				   }
+			}
+			while ((fam0L_drive)&&(!st_check)&&(!(i&p_success)));
+			if (st_check)
+			{
+				i=cc_ReadError();
+				msg(DBG_AUD,"read_audio: cc_ReadError was necessary after read: %02X\n",i);
+				continue;
+			}
+			memcpy_tofs((u_char *) read_audio.buf,
+				    (u_char *) D_S[d].aud_buf,
+				    read_audio.nframes*CD_FRAMESIZE_RAW);
+			msg(DBG_AUD,"read_audio: memcpy_tofs done.\n");
+			break;
+		}
+		cc_ModeSelect(CD_FRAMESIZE);
+		cc_ModeSense();
+		D_S[d].mode=READ_M1;
+		busy_audio=0;
+		if (data_tries == 0)
+		{
+			msg(DBG_AUD,"read_audio: failed after 5 tries.\n");
+			return (-8);
+		}
+		msg(DBG_AUD,"read_audio: successful return.\n");
+		return (0);
+	} /* end of CDROMREADAUDIO */
+		
+	case CDROMMULTISESSION: /* tell start-of-last-session */
+		msg(DBG_IOC,"ioctl: CDROMMULTISESSION entered.\n");
+		st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_multisession));
+		if (st) return (st);
+		memcpy_fromfs(&ms_info, (void *) arg, sizeof(struct cdrom_multisession));
+		if (ms_info.addr_format==CDROM_MSF) /* MSF-bin requested */
+			lba2msf(D_S[d].lba_multi,&ms_info.addr.msf.minute);
+		else if (ms_info.addr_format==CDROM_LBA) /* lba requested */
+			ms_info.addr.lba=D_S[d].lba_multi;
+		else return (-EINVAL);
+		if (D_S[d].f_multisession) ms_info.xa_flag=1; /* valid redirection address */
+		else ms_info.xa_flag=0; /* invalid redirection address */
+		st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_multisession));
+		if (st) return (st);
+		memcpy_tofs((void *) arg, &ms_info, sizeof(struct cdrom_multisession));
+		msg(DBG_MUL,"ioctl: CDROMMULTISESSION done (%d, %08X).\n",
+		    ms_info.xa_flag, ms_info.addr.lba);
+		return (0);
+		
+	case BLKRASET:
+		if(!suser())  return -EACCES;
+		if(!inode->i_rdev) return -EINVAL;
+		if(arg > 0xff) return -EINVAL;
+		read_ahead[MAJOR(inode->i_rdev)] = arg;
+		return (0);
+		
+	default:
+		msg(DBG_IOC,"ioctl: unknown function request %04X\n", cmd);
+		return (-EINVAL);
+	} /* end switch(cmd) */
 }
 /*==========================================================================*/
 /*
@@ -3585,18 +4322,18 @@
  */
 static void sbp_transfer(void)
 {
-  long offs;
-  
-  while ( (CURRENT->nr_sectors > 0) &&
-	  (CURRENT->sector/4 >= DriveStruct[d].sbp_first_frame) &&
-	  (CURRENT->sector/4 <= DriveStruct[d].sbp_last_frame) )
-    {
-      offs = (CURRENT->sector - DriveStruct[d].sbp_first_frame * 4) * 512;
-      memcpy(CURRENT->buffer, DriveStruct[d].sbp_buf + offs, 512);
-      CURRENT->nr_sectors--;
-      CURRENT->sector++;
-      CURRENT->buffer += 512;
-    }
+	long offs;
+	
+	while ( (CURRENT->nr_sectors > 0) &&
+	       (CURRENT->sector/4 >= D_S[d].sbp_first_frame) &&
+	       (CURRENT->sector/4 <= D_S[d].sbp_last_frame) )
+	{
+		offs = (CURRENT->sector - D_S[d].sbp_first_frame * 4) * 512;
+		memcpy(CURRENT->buffer, D_S[d].sbp_buf + offs, 512);
+		CURRENT->nr_sectors--;
+		CURRENT->sector++;
+		CURRENT->buffer += 512;
+	}
 }
 /*==========================================================================*/
 /*
@@ -3604,328 +4341,459 @@
  */
 static void DO_SBPCD_REQUEST(void)
 {
-  u_int block;
-  u_int nsect;
-  int i, status_tries, data_tries;
-  
-request_loop:
-  INIT_REQUEST;
-  sti();
-
-  if ((CURRENT==NULL)||(CURRENT->dev<0)) goto err_done;
-  if (CURRENT -> sector == -1) goto err_done;
-  if (CURRENT->cmd != READ)
-    {
-      printk("SBPCD: bad cmd %d\n", CURRENT->cmd);
-      goto err_done;
-    }
-  i = MINOR(CURRENT->dev);
-  if ( (i<0) || (i>=NR_SBPCD) || (DriveStruct[i].drv_id==-1))
-    {
-      printk("SBPCD: do_request: bad device: %04X\n", CURRENT->dev);
-      goto err_done;
-    }
-  switch_drive(i);
-
-  block = CURRENT->sector; /* always numbered as 512-byte-pieces */
-  nsect = CURRENT->nr_sectors; /* always counted as 512-byte-pieces */
-
-  DPRINTF((DBG_BSZ,"SBPCD: read sector %d (%d sectors)\n", block, nsect));
+	u_int block;
+	u_int nsect;
+	int i, status_tries, data_tries;
+	
+ request_loop:
+	INIT_REQUEST;
+	sti();
+	
+	if ((CURRENT==NULL)||(CURRENT->dev<0)) goto err_done;
+	if (CURRENT -> sector == -1) goto err_done;
+	if (CURRENT->cmd != READ)
+	{
+		msg(DBG_INF, "bad cmd %d\n", CURRENT->cmd);
+		goto err_done;
+	}
+	i = MINOR(CURRENT->dev);
+	if ( (i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1))
+	{
+		msg(DBG_INF, "do_request: bad device: %04X\n", CURRENT->dev);
+		goto err_done;
+	}
+	while (busy_audio) sbp_sleep(100); /* wait a bit */
+	busy_data=1;
+	
+	if (D_S[i].audio_state==audio_playing) goto err_done;
+	if (d!=i) switch_drive(i);
+	
+	block = CURRENT->sector; /* always numbered as 512-byte-pieces */
+	nsect = CURRENT->nr_sectors; /* always counted as 512-byte-pieces */
+	
+	msg(DBG_BSZ,"read sector %d (%d sectors)\n", block, nsect);
 #if 0
-  DPRINTF((DBG_MUL,"SBPCD: read LBA %d\n", block/4));
+	msg(DBG_MUL,"read LBA %d\n", block/4);
 #endif
-
-  sbp_transfer();
-  /* if we satisfied the request from the buffer, we're done. */
-  if (CURRENT->nr_sectors == 0)
-    {
-      end_request(1);
-      goto request_loop;
-    }
-
-  i=prepare(0,0); /* at moment not really a hassle check, but ... */
-  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
-  if ((fam0L_drive) && (DriveStruct[d].xa_byte==0x20)) /* XA disk with old drive */
-      {
-	xx_ModeSelect(CD_FRAMESIZE_XA);
-	xx_ModeSense();
-      }
-#endif XA_TEST1
-
-  for (data_tries=n_retries; data_tries > 0; data_tries--)
-    {
-      for (status_tries=3; status_tries > 0; status_tries--)
+	
+	sbp_transfer();
+	/* if we satisfied the request from the buffer, we're done. */
+	if (CURRENT->nr_sectors == 0)
 	{
-	  flags_cmd_out |= f_respo3;
-	  xx_ReadStatus();
-	  if (sbp_status() != 0) break;
-	  if (st_check) xx_ReadError();
-	  sbp_sleep(1);    /* wait a bit, try again */
-	}
-      if (status_tries == 0)
-	{
-	  DPRINTF((DBG_INF,"SBPCD: sbp_status: failed after 3 tries\n"));
-	  break;
+		end_request(1);
+		goto request_loop;
 	}
 
-      sbp_read_cmd();
-      sbp_sleep(0);
-      if (sbp_data() != 0)
+#if FUTURE
+	i=prepare(0,0); /* at moment not really a hassle check, but ... */
+	if (i!=0)
+		msg(DBG_INF,"\"prepare\" tells error %d -- ignored\n", i);
+#endif FUTURE
+	
+	if (!st_spinning) cc_SpinUp();
+	
+	for (data_tries=n_retries; data_tries > 0; data_tries--)
 	{
-	  end_request(1);
-	  goto request_loop;
+		for (status_tries=3; status_tries > 0; status_tries--)
+		{
+			flags_cmd_out |= f_respo3;
+			cc_ReadStatus();
+			if (sbp_status() != 0) break;
+			if (st_check) cc_ReadError();
+			sbp_sleep(1);    /* wait a bit, try again */
+		}
+		if (status_tries == 0)
+		{
+			msg(DBG_INF,"sbp_status: failed after 3 tries\n");
+			break;
+		}
+		
+		sbp_read_cmd();
+		sbp_sleep(0);
+		if (sbp_data() != 0)
+		{
+			end_request(1);
+			goto request_loop;
+		}
 	}
-    }
-  
-err_done:
-  busy_data=0;
-  end_request(0);
-  sbp_sleep(10);    /* wait a bit, try again */
-  goto request_loop;
+	
+ err_done:
+	busy_data=0;
+	end_request(0);
+	sbp_sleep(0);    /* wait a bit, try again */
+	goto request_loop;
 }
 /*==========================================================================*/
 /*
  *  build and send the READ command.
- *  Maybe it would be better to "set mode1" before ...
  */
 static void sbp_read_cmd(void)
 {
-  int i;
-  int block;
+#undef OLD
 
-  DriveStruct[d].sbp_first_frame=DriveStruct[d].sbp_last_frame=-1;      /* purge buffer */
-  block=CURRENT->sector/4;
-  if (block+SBP_BUFFER_FRAMES <= DriveStruct[d].CDsize_frm)
-    DriveStruct[d].sbp_read_frames = SBP_BUFFER_FRAMES;
-  else
-    {
-      DriveStruct[d].sbp_read_frames=DriveStruct[d].CDsize_frm-block;
-                                      /* avoid reading past end of data */
-      if (DriveStruct[d].sbp_read_frames < 1)
-	{
-	  DPRINTF((DBG_INF,"SBPCD: requested frame %d, CD size %d ???\n",
-		        block, DriveStruct[d].CDsize_frm));
-	  DriveStruct[d].sbp_read_frames=1;
+	int i;
+	int block;
+	
+	D_S[d].sbp_first_frame=D_S[d].sbp_last_frame=-1;      /* purge buffer */
+	D_S[d].sbp_current = 0;
+	block=CURRENT->sector/4;
+	if (block+D_S[d].sbp_bufsiz <= D_S[d].CDsize_frm)
+		D_S[d].sbp_read_frames = D_S[d].sbp_bufsiz;
+	else
+	{
+		D_S[d].sbp_read_frames=D_S[d].CDsize_frm-block;
+		/* avoid reading past end of data */
+		if (D_S[d].sbp_read_frames < 1)
+		{
+			msg(DBG_INF,"requested frame %d, CD size %d ???\n",
+			    block, D_S[d].CDsize_frm);
+			D_S[d].sbp_read_frames=1;
+		}
 	}
-    }
-  DriveStruct[d].sbp_current = 0;
-
-  flags_cmd_out = f_putcmd |
-                  f_respo2 |
-                  f_ResponseStatus |
-                  f_obey_p_check;
-
-  if (fam0L_drive)
-    {
-      flags_cmd_out |= f_lopsta | f_getsta | f_bit1;
-      if (DriveStruct[d].xa_byte==0x20)
-	{
-	  cmd_type=READ_M2;
-	  drvcmd[0]=CMD0_READ_XA; /* "read XA frames", old drives */
-	  drvcmd[1]=(block>>16)&0x000000ff;
-	  drvcmd[2]=(block>>8)&0x000000ff;
-	  drvcmd[3]=block&0x000000ff;
-	  drvcmd[4]=0;
-	  drvcmd[5]=DriveStruct[d].sbp_read_frames;
-	  drvcmd[6]=0;
-	}
-      else
-	{
-	  drvcmd[0]=CMD0_READ; /* "read frames", old drives */
-	  
-	  if (DriveStruct[d].drv_type>=drv_201)
-	    {
-	      lba2msf(block,&drvcmd[1]); /* msf-bcd format required */
-	      bin2bcdx(&drvcmd[1]);
-	      bin2bcdx(&drvcmd[2]);
-	      bin2bcdx(&drvcmd[3]);
-	    }
-	  else
-	    {
-	      drvcmd[1]=(block>>16)&0x000000ff;
-	      drvcmd[2]=(block>>8)&0x000000ff;
-	      drvcmd[3]=block&0x000000ff;
-	    }
-	  drvcmd[4]=0;
-	  drvcmd[5]=DriveStruct[d].sbp_read_frames;
-	  drvcmd[6]=(DriveStruct[d].drv_type<drv_201)?0:2; /* flag "lba or msf-bcd format" */
+	
+	flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus | f_obey_p_check;
+	clr_cmdbuf();
+	if (fam0L_drive)
+	{
+		flags_cmd_out |= f_lopsta | f_getsta | f_bit1;
+		if (D_S[d].xa_byte==0x20)
+		{
+			cmd_type=READ_M2;
+			drvcmd[0]=CMD0_READ_XA; /* "read XA frames", old drives */
+			drvcmd[1]=(block>>16)&0x000000ff;
+			drvcmd[2]=(block>>8)&0x000000ff;
+			drvcmd[3]=block&0x000000ff;
+			drvcmd[5]=D_S[d].sbp_read_frames;
+		}
+		else
+		{
+			drvcmd[0]=CMD0_READ; /* "read frames", old drives */
+			if (D_S[d].drv_type>=drv_201)
+			{
+				lba2msf(block,&drvcmd[1]); /* msf-bcd format required */
+				bin2bcdx(&drvcmd[1]);
+				bin2bcdx(&drvcmd[2]);
+				bin2bcdx(&drvcmd[3]);
+			}
+			else
+			{
+				drvcmd[1]=(block>>16)&0x000000ff;
+				drvcmd[2]=(block>>8)&0x000000ff;
+				drvcmd[3]=block&0x000000ff;
+			}
+			drvcmd[5]=D_S[d].sbp_read_frames;
+			drvcmd[6]=(D_S[d].drv_type<drv_201)?0:2; /* flag "lba or msf-bcd format" */
+		}
 	}
-    }
-  else if (fam1_drive)
-    {
-      drvcmd[0]=CMD1_READ;
-      lba2msf(block,&drvcmd[1]); /* msf-bin format required */
-      drvcmd[4]=0;
-      drvcmd[5]=0;
-      drvcmd[6]=DriveStruct[d].sbp_read_frames;
-    }
-  else if (fam2_drive)
-    {
-      drvcmd[0]=CMD2_READ;
-      lba2msf(block,&drvcmd[1]); /* msf-bin format required */
-      drvcmd[4]=0;
-      drvcmd[5]=DriveStruct[d].sbp_read_frames;
-      drvcmd[6]=0x02;
-    }
-  SBPCD_CLI;
-  for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]);
-  SBPCD_STI;
-
-  return;
+	else if (fam1_drive)
+	{
+		drvcmd[0]=CMD1_READ;
+		lba2msf(block,&drvcmd[1]); /* msf-bin format required */
+		drvcmd[6]=D_S[d].sbp_read_frames;
+	}
+	else if (fam2_drive)
+	{
+		drvcmd[0]=CMD2_READ;
+		lba2msf(block,&drvcmd[1]); /* msf-bin format required */
+		drvcmd[5]=D_S[d].sbp_read_frames;
+		drvcmd[6]=0x02;
+	}
+	else if (famT_drive)
+	{
+		drvcmd[0]=CMDT_READ;
+		drvcmd[2]=(block>>24)&0x0ff;
+		drvcmd[3]=(block>>16)&0x0ff;
+		drvcmd[4]=(block>>8)&0x0ff;
+		drvcmd[5]=block&0x0ff;
+		drvcmd[7]=(D_S[d].sbp_read_frames>>8)&0x0ff;
+		drvcmd[8]=D_S[d].sbp_read_frames&0x0ff;
+	}
+#ifdef OLD
+	SBPCD_CLI;
+	for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]);
+	if (famT_drive) for (i=7;i<10;i++) OUT(CDo_command,drvcmd[i]);
+	SBPCD_STI;
+#else
+	flags_cmd_out=f_putcmd;
+	response_count=0;
+	i=cmd_out(); /* immediate return here - read data "ourselves" */
+	if (i<0) msg(DBG_INF,"error giving READ command: %0d\n", i);
+#endif OLD
+	return;
 }
 /*==========================================================================*/
 /*
  *  Check the completion of the read-data command.  On success, read
- *  the SBP_BUFFER_FRAMES * 2048 bytes of data from the disk into buffer.
+ *  the D_S[d].sbp_bufsiz * 2048 bytes of data from the disk into buffer.
  */
 static int sbp_data(void)
 {
-  int i=0, j=0, frame;
-  u_int try=0;
-  u_long timeout;
-  u_char *p;
-  u_int data_tries = 0;
-  u_int data_waits = 0;
-  u_int data_retrying = 0;
-  int error_flag;
-  int xa_count;
-  error_flag=0;
-
-  for (frame=DriveStruct[d].sbp_current;frame<DriveStruct[d].sbp_read_frames&&!error_flag; frame++)
-    {
-      SBPCD_CLI;
-      try=maxtim_data;
+	int i=0, j=0, l, frame;
+	u_int try=0;
+	u_long timeout;
+	u_char *p;
+	u_int data_tries = 0;
+	u_int data_waits = 0;
+	u_int data_retrying = 0;
+	int error_flag;
+	int xa_count;
+	int max_latency;
+	int success;
+	int wait;
+	int duration;
+	
+	error_flag=0;
+	success=0;
 #if LONG_TIMING
-      for (timeout=jiffies+900; ; )
+	max_latency=900;
 #else
-      for (timeout=jiffies+ ( (famL_drive)? 300:100 ); ; )
-#endif
-	{
-	  for ( ; try!=0;try--)
-	    {
-	      j=inb(CDi_status);
-	      if (!(j&s_not_data_ready)) break;
-	      if (!(j&s_not_result_ready)) break;
-	      if (fam0L_drive) if (j&s_attention) break;
-	    }
-	  if (try != 0 || timeout <= jiffies) break;
-	  if (data_retrying == 0) data_waits++;
-	  data_retrying = 1;
-	  sbp_sleep(1);
-	  try = 1;
-	}
-      if (try==0)
-	{
-	  DPRINTF((DBG_INF,"SBPCD: sbp_data: CDi_status timeout.\n"));
-	  error_flag++;
-	  break;
-	}
-
-      if (j&s_not_data_ready)
-	{
-	  if ((DriveStruct[d].ored_ctl_adr&0x40)==0)
-	    printk("SBPCD: CD contains no data tracks.\n");
-	  else printk("SBPCD: sbp_data: DATA_READY timeout.\n");
-	  error_flag++;
-	  break;
-	}
-
-      SBPCD_STI;
-      error_flag=0;
-      p = DriveStruct[d].sbp_buf + frame *  CD_FRAMESIZE;
-
-      if (sbpro_type==1) OUT(CDo_sel_i_d,1);
-      if (cmd_type==READ_M2) READ_DATA(CDi_data, xa_head_buf, CD_XA_HEAD);
-      READ_DATA(CDi_data, p, CD_FRAMESIZE);
-      if (cmd_type==READ_M2) READ_DATA(CDi_data, xa_tail_buf, CD_XA_TAIL);
-      if (sbpro_type==1) OUT(CDo_sel_i_d,0);
-      DriveStruct[d].sbp_current++;
-      if (cmd_type==READ_M2)
-	{
-	  DPRINTF((DBG_XA,"SBPCD: xa_head:"));
-	  for (xa_count=0;xa_count<CD_XA_HEAD;xa_count++)
-	    DPRINTF((DBG_XA," %02X", xa_head_buf[xa_count]));
-	  DPRINTF((DBG_XA,"\n"));
-	}
-      data_tries++;
-      data_retrying = 0;
-      if (data_tries >= 1000)
-	{
-	  DPRINTF((DBG_INF,"SBPCD: info: %d waits in %d frames.\n",
-		        data_waits, data_tries));
-	  data_waits = data_tries = 0;
+	if (D_S[d].f_multisession) max_latency=900;
+	else if (fam0L_drive) max_latency=300;
+	else if (famT_drive) max_latency=300;
+	else max_latency=100;
+#endif
+	msg(DBG_TE2,"beginning to READ\n");
+	duration=jiffies;
+	for (frame=0;frame<D_S[d].sbp_read_frames&&!error_flag; frame++)
+	{
+		SBPCD_CLI;
+		
+		del_timer(&data_timer);
+		data_timer.expires=max_latency;
+		timed_out_data=0;
+		add_timer(&data_timer);
+		while (!timed_out_data) 
+		{
+			if (D_S[d].f_multisession) try=maxtim_data*4;
+			else try=maxtim_data;
+			msg(DBG_000,"sbp_data: CDi_status loop: try=%d.\n",try);
+			for ( ; try!=0;try--)
+			{
+				j=inb(CDi_status);
+				if (!(j&s_not_data_ready)) break;;
+				if (!(j&s_not_result_ready)) break;
+				if (fam0L_drive) if (j&s_attention) break;
+			}
+			if (!(j&s_not_data_ready)) goto data_ready;
+			if (try==0)
+			{
+				if (data_retrying == 0) data_waits++;
+				data_retrying = 1;
+				msg(DBG_000,"sbp_data: CDi_status loop: sleeping.\n");
+				sbp_sleep(1);
+				try = 1;
+			}
+		}
+		msg(DBG_INF,"sbp_data: CDi_status loop expired.\n");
+	data_ready:
+		del_timer(&data_timer);
+
+		if (timed_out_data)
+		{
+			msg(DBG_INF,"sbp_data: CDi_status timeout (timed_out_data) (%02X).\n", j);
+			error_flag++;
+			break;
+		}
+		if (try==0)
+		{
+			msg(DBG_INF,"sbp_data: CDi_status timeout (try=0) (%02X).\n", j);
+			error_flag++;
+			break;
+		}
+		if (!(j&s_not_result_ready))
+		{
+			msg(DBG_INF, "sbp_data: RESULT_READY where DATA_READY awaited (%02X).\n", j);
+			response_count=20;
+			j=ResponseInfo();
+			j=inb(CDi_status);
+		}
+		if (j&s_not_data_ready)
+		{
+			if ((D_S[d].ored_ctl_adr&0x40)==0)
+				msg(DBG_INF, "CD contains no data tracks.\n");
+			else msg(DBG_INF, "sbp_data: DATA_READY timeout (%02X).\n", j);
+			error_flag++;
+			break;
+		}
+		SBPCD_STI;
+		error_flag=0;
+		msg(DBG_000, "sbp_data: beginning to read.\n");
+		p = D_S[d].sbp_buf + frame *  CD_FRAMESIZE;
+		if (sbpro_type==1) OUT(CDo_sel_i_d,1);
+		if (cmd_type==READ_M2) insb(CDi_data, xa_head_buf, CD_XA_HEAD);
+		insb(CDi_data, p, CD_FRAMESIZE);
+		if (cmd_type==READ_M2) insb(CDi_data, xa_tail_buf, CD_XA_TAIL);
+		if (famT_drive)	msg(DBG_TE2, "================frame read=================.\n");
+		D_S[d].sbp_current++;
+		if (sbpro_type==1) OUT(CDo_sel_i_d,0);
+		if (cmd_type==READ_M2)
+		{
+			for (xa_count=0;xa_count<CD_XA_HEAD;xa_count++)
+				sprintf(&msgbuf[xa_count*3], " %02X", xa_head_buf[xa_count]);
+			msgbuf[xa_count*3]=0;
+			msg(DBG_XA1,"xa head:%s\n", msgbuf);
+		}
+		data_retrying = 0;
+		data_tries++;
+		if (data_tries >= 1000)
+		{
+			msg(DBG_INF,"sbp_data() statistics: %d waits in %d frames.\n", data_waits, data_tries);
+			data_waits = data_tries = 0;
+		}
 	}
-    }
-  SBPCD_STI;
-  
-  if (error_flag)    /* must have been spurious D_RDY or (ATTN&&!D_RDY) */
-    {
-      DPRINTF((DBG_INF,"SBPCD: read aborted by drive\n"));
+	duration=jiffies-duration;
+	msg(DBG_TE2,"time to read %d frames: %d jiffies .\n",frame,duration);
+	if (famT_drive)
+	{
+		wait=8;
+		do
+		{
+			sbp_sleep(1);
+			OUT(CDo_sel_i_d,0);
+			i=inb(CDi_status);
+			if (!(i&s_not_data_ready))
+			{
+				OUT(CDo_sel_i_d,1);
+				j=0;
+				do
+				{
+					i=inb(CDi_data);
+					j++;
+					i=inb(CDi_status);
+				}
+				while (!(i&s_not_data_ready));
+				msg(DBG_TEA, "=============too much data (%d bytes)=================.\n", j);
+			}
+			if (!(i&s_not_result_ready))
+			{
+				OUT(CDo_sel_i_d,0);
+				l=0;
+				do
+				{
+					infobuf[l++]=inb(CDi_info);
+					i=inb(CDi_status);
+				}
+				while (!(i&s_not_result_ready));
+				if (infobuf[0]==0x00) success=1;
+#if 1
+				for (j=0;j<l;j++) sprintf(&msgbuf[j*3], " %02X", infobuf[j]);
+				msgbuf[j*3]=0;
+				msg(DBG_TE2,"sbp_data info response:%s\n", msgbuf);
+#endif
+				if (infobuf[0]==0x02)
+				{
+					error_flag++;
+					do
+					{
+						++recursion;
+						if (recursion>1) msg(DBG_TEA,"cmd_out_T READ_ERR recursion (sbp_data): %d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",recursion);
+						else msg(DBG_TEA,"sbp_data: CMDT_READ_ERR necessary.\n");
+						clr_cmdbuf();
+						drvcmd[0]=CMDT_READ_ERR;
+						j=cmd_out_T(); /* !!! recursive here !!! */
+						--recursion;
+						sbp_sleep(1);
+					}
+					while (j<0);
+					D_S[d].error_state=infobuf[2];
+					D_S[d].b3=infobuf[3];
+					D_S[d].b4=infobuf[4];
+				}
+				break;
+			}
+			else
+			{
 #if 0
-      i=DriveReset();                /* ugly fix to prevent a hang */
-#else
-      i=xx_ReadError();
+				msg(DBG_TEA, "============= waiting for result=================.\n");
+				sbp_sleep(1);
 #endif
-      return (0);
-    }
-
-  if (fam0L_drive)
-    {
-      SBPCD_CLI;
-      i=maxtim_data;
-      for (timeout=jiffies+100; timeout > jiffies; timeout--)
-	{
-	  for ( ;i!=0;i--)
-	    {
-	      j=inb(CDi_status);
-	      if (!(j&s_not_data_ready)) break;
-	      if (!(j&s_not_result_ready)) break;
-	      if (j&s_attention) break;
-	    }
-	  if (i != 0 || timeout <= jiffies) break;
-	  sbp_sleep(0);
-	  i = 1;
-	}
-      if (i==0) { DPRINTF((DBG_INF,"SBPCD: STATUS TIMEOUT AFTER READ")); }
-      if (!(j&s_attention))
-	{
-	  DPRINTF((DBG_INF,"SBPCD: sbp_data: timeout waiting DRV_ATTN - retrying\n"));
-	  i=DriveReset();  /* ugly fix to prevent a hang */
-	  SBPCD_STI;
-	  return (0);
+			}
+		}
+		while (wait--);
 	}
-      SBPCD_STI;
-    }
 
-  do
-    {
-      if (fam0L_drive) xx_ReadStatus();
-      i=ResponseStatus();  /* builds status_byte, returns orig. status (old) or faked p_success_old (new) */
-      if (i<0) { DPRINTF((DBG_INF,"SBPCD: xx_ReadStatus error after read: %02X\n",
-			       DriveStruct[d].status_byte));
-		 return (0);
-	       }
-    }
-  while ((fam0L_drive)&&(!st_check)&&(!(i&p_success_old)));
-  if (st_check)
-    {
-      i=xx_ReadError();
-      DPRINTF((DBG_INF,"SBPCD: xx_ReadError was necessary after read: %02X\n",i));
-      return (0);
-    }
-
-  DriveStruct[d].sbp_first_frame = CURRENT -> sector / 4;
-  DriveStruct[d].sbp_last_frame = DriveStruct[d].sbp_first_frame + DriveStruct[d].sbp_read_frames - 1;
-  sbp_transfer();
-  return (1);
+	if (error_flag) /* must have been spurious D_RDY or (ATTN&&!D_RDY) */
+	{
+		msg(DBG_TEA, "================error flag: %d=================.\n", error_flag);
+		msg(DBG_INF,"sbp_data: read aborted by drive.\n");
+#if 1
+		i=cc_DriveReset(); /* ugly fix to prevent a hang */
+#else
+		i=cc_ReadError();
+#endif
+		return (0);
+	}
+	
+	if (fam0L_drive)
+	{
+		SBPCD_CLI;
+		i=maxtim_data;
+		for (timeout=jiffies+100; timeout > jiffies; timeout--)
+		{
+			for ( ;i!=0;i--)
+			{
+				j=inb(CDi_status);
+				if (!(j&s_not_data_ready)) break;
+				if (!(j&s_not_result_ready)) break;
+				if (j&s_attention) break;
+			}
+			if (i != 0 || timeout <= jiffies) break;
+			sbp_sleep(0);
+			i = 1;
+		}
+		if (i==0) msg(DBG_INF,"status timeout after READ.\n");
+		if (!(j&s_attention))
+		{
+			msg(DBG_INF,"sbp_data: timeout waiting DRV_ATTN - retrying.\n");
+			i=cc_DriveReset();  /* ugly fix to prevent a hang */
+			SBPCD_STI;
+			return (0);
+		}
+		SBPCD_STI;
+	}
+	
+#if 0
+	if (!success)
+#endif 0
+		do
+		{
+			if (fam0L_drive) cc_ReadStatus();
+#if 1
+			if (famT_drive) msg(DBG_TE2, "================before ResponseStatus=================.\n", i);
+#endif 1
+			i=ResponseStatus();  /* builds status_bits, returns orig. status (old) or faked p_success (new) */
+#if 1
+			if (famT_drive)	msg(DBG_TE2, "================ResponseStatus: %d=================.\n", i);
+#endif 1
+			if (i<0)
+			{
+				msg(DBG_INF,"bad cc_ReadStatus after read: %02X\n", D_S[d].status_bits);
+				return (0);
+			}
+		}
+		while ((fam0L_drive)&&(!st_check)&&(!(i&p_success)));
+	if (st_check)
+	{
+		i=cc_ReadError();
+		msg(DBG_INF,"cc_ReadError was necessary after read: %d\n",i);
+		return (0);
+	}
+	if (fatal_err)
+	{
+		fatal_err=0;
+		D_S[d].sbp_first_frame=D_S[d].sbp_last_frame=-1;      /* purge buffer */
+		D_S[d].sbp_current = 0;
+		msg(DBG_INF,"sbp_data: fatal_err - retrying.\n");
+		return (0);
+	}
+	
+	D_S[d].sbp_first_frame = CURRENT -> sector / 4;
+	D_S[d].sbp_last_frame = D_S[d].sbp_first_frame + D_S[d].sbp_read_frames - 1;
+	sbp_transfer();
+#if 1
+	if (famT_drive)	msg(DBG_TE2, "================sbp_transfer() done=================.\n");
+#endif 1
+	return (1);
 }
 /*==========================================================================*/
 /*==========================================================================*/
@@ -3934,71 +4802,83 @@
  */
 static int sbpcd_open(struct inode *ip, struct file *fp)
 {
-  int i;
-
-  i = MINOR(ip->i_rdev);
-  if ((i<0) || (i>=NR_SBPCD) || (DriveStruct[i].drv_id==-1))
-    {
-      printk("SBPCD: open: bad device: %04X\n", ip->i_rdev);
-      return (-ENXIO);             /* no such drive */
-    }
-  if (fp->f_mode & 2)
-	  return -EROFS;
-  
-  switch_drive(i);
-
-  flags_cmd_out |= f_respo2;
-  xx_ReadStatus();                         /* command: give 1-byte status */
-  i=ResponseStatus();
-  if (!st_door_closed)
-    {
-      yy_CloseTray();
-      flags_cmd_out |= f_respo2;
-      xx_ReadStatus();
-      i=ResponseStatus();
-    }
-  if (!st_spinning)
-    {
-      xx_SpinUp();
-      flags_cmd_out |= f_respo2;
-      xx_ReadStatus();
-      i=ResponseStatus();
-    }
-  if (i<0)
-    {
-      DPRINTF((DBG_INF,"SBPCD: sbpcd_open: xx_ReadStatus timed out\n"));
-      return (-EIO);                  /* drive doesn't respond */
-    }
-  DPRINTF((DBG_STA,"SBPCD: sbpcd_open: status %02X\n", DriveStruct[d].status_byte));
-  if (!st_door_closed||!st_caddy_in)
-    {
-      printk("SBPCD: sbpcd_open: no disk in drive\n");
+	int i;
+	
+	i = MINOR(ip->i_rdev);
+	if ((i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1))
+	{
+		msg(DBG_INF, "open: bad device: %04X\n", ip->i_rdev);
+		return (-ENXIO);             /* no such drive */
+	}
+	if (fp->f_mode & 2)
+		return -EROFS;
+	
+	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 (i<0)
+	{
+		msg(DBG_INF,"sbpcd_open: ResponseStatus timed out (%d).\n",i);
+		return (-EIO);                  /* drive doesn't respond */
+	}
+	if (famT_drive)	msg(DBG_TE2,"sbpcd_open: ResponseStatus=%02X\n", i);
+	if (!st_door_closed)
+	{
+		if (famT_drive)	msg(DBG_TE2,"sbpcd_open: !st_door_closed.\n");
+		cc_CloseTray();
+		flags_cmd_out |= f_respo2;
+		cc_ReadStatus();
+		i=ResponseStatus();
+	}
+	if (!(famT_drive))
+		if (!st_spinning)
+		{
+			if (famT_drive)	msg(DBG_TE2,"sbpcd_open: !st_spinning.\n");
+			cc_SpinUp();
+			flags_cmd_out |= f_respo2;
+			cc_ReadStatus();
+			i=ResponseStatus();
+		}
+	if (famT_drive)	msg(DBG_TE2,"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;
 #if JUKEBOX
-      do
-	i=yy_LockDoor(0);
-      while (i!=0);
-      if (!fam0_drive) yy_SpinDown(); /* eject tray */
+		if (!fam0_drive)
+		{
+			i=UnLockDoor();
+			cc_SpinDown(); /* eject tray */
+		}
 #endif
-      return (-ENXIO);
-    }
-/*
- * try to keep an "open" counter here and lock the door if 0->1.
- */
-  MOD_INC_USE_COUNT;
-  DPRINTF((DBG_LCK,"SBPCD: open_count: %d -> %d\n",
-	   DriveStruct[d].open_count,DriveStruct[d].open_count+1));
-  if (++DriveStruct[d].open_count==1)
-    {
-      do
-	i=yy_LockDoor(1);
-      while (i!=0);
-    }
-  if (!st_spinning) xx_SpinUp();
-
-  i=DiskInfo();
-  if ((DriveStruct[d].ored_ctl_adr&0x40)==0)
-    DPRINTF((DBG_INF,"SBPCD: CD contains no data tracks.\n"));
-  return (0);
+		return (-ENXIO);
+	}
+	/*
+	 * try to keep an "open" counter here and lock the door if 0->1.
+	 */
+	MOD_INC_USE_COUNT;
+	msg(DBG_LCK,"open_count: %d -> %d\n",
+	    D_S[d].open_count,D_S[d].open_count+1);
+	if (++D_S[d].open_count<=1)
+	{
+		i=LockDoor();
+		D_S[d].open_count=1;
+		if (famT_drive)	msg(DBG_TE2,"sbpcd_open: before i=DiskInfo();.\n");
+		i=DiskInfo();
+		if (famT_drive)	msg(DBG_TE2,"sbpcd_open: after i=DiskInfo();.\n");
+		if ((D_S[d].ored_ctl_adr&0x40)==0)
+			msg(DBG_INF,"CD contains no data tracks.\n");
+	}
+	if (!st_spinning) cc_SpinUp();
+	return (0);
 }
 /*==========================================================================*/
 /*
@@ -4006,37 +4886,37 @@
  */
 static void sbpcd_release(struct inode * ip, struct file * file)
 {
-  int i;
-
-  i = MINOR(ip->i_rdev);
-  if ((i<0) || (i>=NR_SBPCD) || (DriveStruct[i].drv_id==-1))
-    {
-      printk("SBPCD: release: bad device: %04X\n", ip->i_rdev);
-      return;
-    }
-  switch_drive(i);
-
-  DriveStruct[d].sbp_first_frame=DriveStruct[d].sbp_last_frame=-1;
-  sync_dev(ip->i_rdev);                   /* nonsense if read only device? */
-  invalidate_buffers(ip->i_rdev);
-
-/*
- * try to keep an "open" counter here and unlock the door if 1->0.
- */
-  MOD_DEC_USE_COUNT;
-  DPRINTF((DBG_LCK,"SBPCD: open_count: %d -> %d\n",
-	   DriveStruct[d].open_count,DriveStruct[d].open_count-1));
-  if (DriveStruct[d].open_count!=0) /* CDROMEJECT may have been done */
-    {
-      if (--DriveStruct[d].open_count==0) 
-	{
-	  do
-	    i=yy_LockDoor(0);
-	  while (i!=0);
-	  if (DriveStruct[d].f_eject) yy_SpinDown();
-	  DriveStruct[d].diskstate_flags &= ~cd_size_bit;
+	int i;
+	
+	i = MINOR(ip->i_rdev);
+	if ((i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1))
+	{
+		msg(DBG_INF, "release: bad device: %04X\n", ip->i_rdev);
+		return;
+	}
+	switch_drive(i);
+	
+	D_S[d].sbp_first_frame=D_S[d].sbp_last_frame=-1;
+	sync_dev(ip->i_rdev);                   /* nonsense if read only device? */
+	invalidate_buffers(ip->i_rdev);
+	
+	/*
+	 * try to keep an "open" counter here and unlock the door if 1->0.
+	 */
+	MOD_DEC_USE_COUNT;
+	msg(DBG_LCK,"open_count: %d -> %d\n",
+	    D_S[d].open_count,D_S[d].open_count-1);
+	if (D_S[d].open_count>-2) /* CDROMEJECT may have been done */
+	{
+		if (--D_S[d].open_count<=0) 
+		{
+			i=UnLockDoor();
+			if (D_S[d].audio_state!=audio_playing)
+				if (D_S[d].f_eject) cc_SpinDown();
+			D_S[d].diskstate_flags &= ~cd_size_bit;
+			D_S[d].open_count=0; 
+		}
 	}
-    }
 }
 /*==========================================================================*/
 /*
@@ -4044,19 +4924,19 @@
  */
 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,                   /* select */
-  sbpcd_ioctl,            /* ioctl */
-  NULL,                   /* mmap */
-  sbpcd_open,             /* open */
-  sbpcd_release,          /* release */
-  NULL,                   /* fsync */
-  NULL,                   /* fasync */
-  sbpcd_chk_disk_change,  /* media_change */
-  NULL                    /* revalidate */
+	NULL,                   /* lseek - default */
+	block_read,             /* read - general block-dev read */
+	block_write,            /* write - general block-dev write */
+	NULL,                   /* readdir - bad */
+	NULL,                   /* select */
+	sbpcd_ioctl,            /* ioctl */
+	NULL,                   /* mmap */
+	sbpcd_open,             /* open */
+	sbpcd_release,          /* release */
+	NULL,                   /* fsync */
+	NULL,                   /* fasync */
+	sbpcd_chk_disk_change,  /* media_change */
+	NULL                    /* revalidate */
 };
 /*==========================================================================*/
 /*
@@ -4084,82 +4964,80 @@
 #endif
 void sbpcd_setup(char *s, int *p)
 {
-  setup_done++;
-  DPRINTF((DBG_INI,"SBPCD: sbpcd_setup called with %04X,%s\n",p[1], s));
-  sbpro_type=0;
-  if (!strcmp(s,str_sb)) sbpro_type=1;
-  else if (!strcmp(s,str_sb_l)) sbpro_type=1;
-  else if (!strcmp(s,str_sp)) sbpro_type=2;
-  else if (!strcmp(s,str_sp_l)) sbpro_type=2;
-  if (p[0]>0) sbpcd_ioaddr=p[1];
-
-  CDo_command=sbpcd_ioaddr;
-  CDi_info=sbpcd_ioaddr;
-  CDi_status=sbpcd_ioaddr+1;
-  CDo_sel_i_d=sbpcd_ioaddr+1;
-  CDo_reset=sbpcd_ioaddr+2;
-  CDo_enable=sbpcd_ioaddr+3; 
-  if (sbpro_type==1)
-    {
-      MIXER_addr=sbpcd_ioaddr-0x10+0x04;
-      MIXER_data=sbpcd_ioaddr-0x10+0x05;
-      CDi_data=sbpcd_ioaddr;
-    }
-  else CDi_data=sbpcd_ioaddr+2;
+	setup_done++;
+	msg(DBG_INI,"sbpcd_setup called with %04X,%s\n",p[1], s);
+	sbpro_type=0;
+	if (!strcmp(s,str_sb)) sbpro_type=1;
+	else if (!strcmp(s,str_sb_l)) sbpro_type=1;
+	else if (!strcmp(s,str_sp)) sbpro_type=2;
+	else if (!strcmp(s,str_sp_l)) sbpro_type=2;
+	if (p[0]>0) sbpcd_ioaddr=p[1];
+	
+	CDo_command=sbpcd_ioaddr;
+	CDi_info=sbpcd_ioaddr;
+	CDi_status=sbpcd_ioaddr+1;
+	CDo_sel_i_d=sbpcd_ioaddr+1;
+	CDo_reset=sbpcd_ioaddr+2;
+	CDo_enable=sbpcd_ioaddr+3; 
+	if (sbpro_type==1)
+	{
+		MIXER_addr=sbpcd_ioaddr-0x10+0x04;
+		MIXER_data=sbpcd_ioaddr-0x10+0x05;
+		CDi_data=sbpcd_ioaddr;
+	}
+	else CDi_data=sbpcd_ioaddr+2;
 }
 /*==========================================================================*/
 /*
  * Sequoia S-1000 CD-ROM Interface Configuration
  * as used within SPEA Media FX card
- * The SPEA soundcard has to get jumpered for 
+ * The SPEA soundcard has to get configured for 
  *     -> interface type "Matsushita/Panasonic" (not Sony or Mitsumi)
  *     -> I/O base address (0x320, 0x330, 0x340, 0x350)
  */
 static int config_spea(void)
 {
-  int n_ports=0x10; /* 2:0x00, 8:0x10, 16:0x20, 32:0x30 */
-/* What is n_ports? Number of addresses or base address offset? */
-  int irq_number=0; /* 2:0x01, 7:0x03, 12:0x05, 15:0x07, OFF:0x00 */
-  int dma_channel=0; /* 0:0x08, 1:0x18, 3:0x38, 5:0x58, 6:0x68, 7:0x78, OFF: 0x00 */
-  int dack_polarity=0; /* L:0x00, H:0x80 */
-  int drq_polarity=0x40; /* L:0x00, H:0x40 */
-
-  int i;
-
+	int n_ports=0x10; /* 2:0x00, 8:0x10, 16:0x20, 32:0x30 */
+	/* What is n_ports? Number of addresses or base address offset? */
+	int irq_number=0; /* 2:0x01, 7:0x03, 12:0x05, 15:0x07, OFF:0x00 */
+	int dma_channel=0; /* 0:0x08, 1:0x18, 3:0x38, 5:0x58, 6:0x68, 7:0x78, OFF: 0x00 */
+	int dack_polarity=0; /* L:0x00, H:0x80 */
+	int drq_polarity=0x40; /* L:0x00, H:0x40 */
+	
+	int i;
+	
 #define SPEA_REG_1 sbpcd_ioaddr+4
 #define SPEA_REG_2 sbpcd_ioaddr+5
-
-  OUT(SPEA_REG_1,0xFF);
-  i=inb(SPEA_REG_1);
-  if (i!=0x0F)
-    {
-      DPRINTF((DBG_SEQ,"SBPCD: no SPEA interface at %04X present.\n",
-	       sbpcd_ioaddr));
-      return (-1); /* no interface found */
-    }
-  OUT(SPEA_REG_1,0x04);
-  OUT(SPEA_REG_2,0xC0);
-
-  OUT(SPEA_REG_1,0x05);
-  OUT(SPEA_REG_2,0x10|drq_polarity|dack_polarity);
-
+	
+	OUT(SPEA_REG_1,0xFF);
+	i=inb(SPEA_REG_1);
+	if (i!=0x0F)
+	{
+		msg(DBG_SEQ,"no SPEA interface at %04X present.\n", sbpcd_ioaddr);
+		return (-1); /* no interface found */
+	}
+	OUT(SPEA_REG_1,0x04);
+	OUT(SPEA_REG_2,0xC0);
+	
+	OUT(SPEA_REG_1,0x05);
+	OUT(SPEA_REG_2,0x10|drq_polarity|dack_polarity);
+	
 #if 1
 #define SPEA_PATTERN 0x80
 #else
 #define SPEA_PATTERN 0x00
 #endif
-  OUT(SPEA_REG_1,0x06);
-  OUT(SPEA_REG_2,dma_channel|irq_number|SPEA_PATTERN);
-  OUT(SPEA_REG_2,dma_channel|irq_number|SPEA_PATTERN);
-
-  OUT(SPEA_REG_1,0x09);
-  i=(inb(SPEA_REG_2)&0xCF)|n_ports;
-  OUT(SPEA_REG_2,i);
-
-  sbpro_type = 0; /* acts like a LaserMate interface now */
-  DPRINTF((DBG_SEQ,"SBPCD: found SPEA interface at %04X.\n",
-	   sbpcd_ioaddr));
-  return (0);
+	OUT(SPEA_REG_1,0x06);
+	OUT(SPEA_REG_2,dma_channel|irq_number|SPEA_PATTERN);
+	OUT(SPEA_REG_2,dma_channel|irq_number|SPEA_PATTERN);
+	
+	OUT(SPEA_REG_1,0x09);
+	i=(inb(SPEA_REG_2)&0xCF)|n_ports;
+	OUT(SPEA_REG_2,i);
+	
+	sbpro_type = 0; /* acts like a LaserMate interface now */
+	msg(DBG_SEQ,"found SPEA interface at %04X.\n", sbpcd_ioaddr);
+	return (0);
 }
 /*==========================================================================*/
 /*
@@ -4168,261 +5046,261 @@
 #ifdef MODULE
 int init_module(void)
 #else
-unsigned long SBPCD_INIT(u_long mem_start, u_long mem_end)
+	unsigned long SBPCD_INIT(u_long mem_start, u_long mem_end)
 #endif MODULE
 {
-  int i=0, j=0;
-  int addr[2]={1, CDROM_PORT};
-  int port_index;
-   
-  sti(); /* necessary, has consequences for other drivers' init routines */
-
-  DPRINTF((DBG_INF,"SBPCD version %s\n", VERSION));
-
+	int i=0, j=0;
+	int addr[2]={1, CDROM_PORT};
+	int port_index;
+	
+	sti();
+	
+	msg(DBG_INF,"sbpcd.c %s\n", VERSION);
 #ifndef MODULE
-  if (!setup_done)
-    {
-      DPRINTF((DBG_INF,"SBPCD: Looking for Matsushita, Panasonic, CreativeLabs, IBM, Longshine CD-ROM drives\n"));
-      DPRINTF((DBG_WRN,"SBPCD: \n"));
-      DPRINTF((DBG_WRN,"SBPCD: = = = = = = = = = = W A R N I N G = = = = = = = = = =\n"));
-      DPRINTF((DBG_WRN,"SBPCD: Auto-Probing can cause a hang (f.e. touching an ethernet card).\n"));
-      DPRINTF((DBG_WRN,"SBPCD: If that happens, you have to reboot and use the\n"));
-      DPRINTF((DBG_WRN,"SBPCD: LILO (kernel) command line feature like:\n"));
-      DPRINTF((DBG_WRN,"SBPCD: \n"));
-      DPRINTF((DBG_WRN,"SBPCD:    LILO boot: linux sbpcd=0x230,SoundBlaster\n"));
-      DPRINTF((DBG_WRN,"SBPCD: or like:\n"));
-      DPRINTF((DBG_WRN,"SBPCD:    LILO boot: linux sbpcd=0x300,LaserMate\n"));
-      DPRINTF((DBG_WRN,"SBPCD: or like:\n"));
-      DPRINTF((DBG_WRN,"SBPCD:    LILO boot: linux sbpcd=0x330,SPEA\n"));
-      DPRINTF((DBG_WRN,"SBPCD: \n"));
-      DPRINTF((DBG_WRN,"SBPCD: with your REAL address.\n"));
-      DPRINTF((DBG_WRN,"SBPCD: = = = = = = = = = = END of WARNING = = = = = = = = = =\n"));
-      DPRINTF((DBG_WRN,"SBPCD: \n"));
-    }
+#if DISTRIBUTION
+	if (!setup_done)
+	{
+		msg(DBG_INF,"Looking for Matsushita/Panasonic, CreativeLabs, IBM, Longshine, TEAC CD-ROM drives\n");
+		msg(DBG_INF,"\n= = = = = = = = = = W A R N I N G = = = = = = = = = =\n");
+		msg(DBG_INF,"Auto-Probing can cause a hang (f.e. touching an ethernet card).\n");
+		msg(DBG_INF,"If that happens, you have to reboot and use the\n");
+		msg(DBG_INF,"LILO (kernel) command line feature like:\n");
+		msg(DBG_INF,"\n   LILO boot: ... sbpcd=0x230,SoundBlaster\n");
+		msg(DBG_INF,"or like:\n");
+		msg(DBG_INF,"   LILO boot: ... sbpcd=0x300,LaserMate\n");
+		msg(DBG_INF,"or like:\n");
+		msg(DBG_INF,"   LILO boot: ... sbpcd=0x330,SPEA\n");
+		msg(DBG_INF,"\nwith your REAL address.\n");
+		msg(DBG_INF,"= = = = = = = = = = END of WARNING = = = = = = = = = =\n\n");
+	}
+#endif DISTRIBUTION
+	sbpcd[0]=sbpcd_ioaddr; /* possibly changed by kernel command line */
+	sbpcd[1]=sbpro_type; /* possibly changed by kernel command line */
 #endif MODULE
-  sbpcd_probe[0]=sbpcd_ioaddr; /* possibly changed by kernel command line */
-  sbpcd_probe[1]=sbpro_type; /* possibly changed by kernel command line */
-
-  for (port_index=0;port_index<NUM_PROBE;port_index+=2)
-    {
-      addr[1]=sbpcd_probe[port_index];
-      if (addr[1]==0) break;
-      if (check_region(addr[1],4))
-	{
-	  DPRINTF((DBG_INI,"SBPCD: check_region: %03X is not free.\n",addr[1]));
-	  continue;
-	}
-      if (sbpcd_probe[port_index+1]==0) type=str_lm;
-      else if (sbpcd_probe[port_index+1]==1) type=str_sb;
-      else type=str_sp;
-      sbpcd_setup(type, addr);
-      DPRINTF((DBG_INF,"SBPCD: Trying to detect a %s CD-ROM drive at 0x%X.\n", type, CDo_command));
-      DPRINTF((DBG_INF,"SBPCD: - "));
-      if (sbpcd_probe[port_index+1]==2)
-	{
-	  i=config_spea();
-	  if (i<0)
-	    {
-	      DPRINTF((DBG_INF,"\n"));
-	      continue;
-	    }
-	}
-      i=check_drives();
-      DPRINTF((DBG_INI,"SBPCD: check_drives done.\n"));
-      if (i>=0) break; /* drive found */
-      DPRINTF((DBG_INF,"\n"));
-    } /* end of cycling through the set of possible I/O port addresses */
-
-  if (ndrives==0)
-    {
-      printk("SBPCD: No drive found.\n");
-#if PRINTK_BUG
-      sti(); /* to avoid possible "printk" bug */
-#endif
+	
+	for (port_index=0;port_index<NUM_PROBE;port_index+=2)
+	{
+		addr[1]=sbpcd[port_index];
+		if (addr[1]==0) break;
+		if (check_region(addr[1],4))
+		{
+			msg(DBG_INF,"check_region: %03X is not free.\n",addr[1]);
+			continue;
+		}
+		if (sbpcd[port_index+1]==2) type=str_sp;
+		else if (sbpcd[port_index+1]==1) type=str_sb;
+		else type=str_lm;
+		sbpcd_setup(type, addr);
+#if DISTRIBUTION
+		msg(DBG_INF,"Scanning 0x%X (%s)...\n", CDo_command, type);
+#endif DISTRIBUTION
+		if (sbpcd[port_index+1]==2)
+		{
+			i=config_spea();
+			if (i<0) continue;
+		}
+#ifdef PATH_CHECK
+		if (check_card(addr[1])) continue;
+#endif PATH_CHECK
+		i=check_drives();
+		msg(DBG_INI,"check_drives done.\n");
+		if (i>=0) break; /* drive found */
+	} /* end of cycling through the set of possible I/O port addresses */
+	
+	if (ndrives==0)
+	{
+		msg(DBG_INF, "No drive found.\n");
 #ifdef MODULE
-      return -EIO;
+		return -EIO;
 #else
-      goto init_done;
+		goto init_done;
 #endif MODULE
-    }
-
-  if (port_index>0)
-    {
-      printk("SBPCD: You should configure sbpcd.h for your hardware.\n");
-#if PRINTK_BUG
-      sti(); /* to avoid possible "printk" bug */
-#endif
-    }
+	}
+	
+	if (port_index>0)
+		msg(DBG_INF, "You should configure sbpcd.h for your hardware.\n");
+	check_datarate();
+	msg(DBG_INI,"check_datarate done.\n");
+	
+#if 0
+	if (!famL_drive)
+	{
+		OUT(CDo_reset,0);
+		sbp_sleep(100);
+	}
+#endif 0
 
-  printk("SBPCD: %d %s CD-ROM drive(s) at 0x%04X.\n",
-	   ndrives, type, CDo_command);
-#if PRINTK_BUG
-  sti(); /* to avoid possible "printk" bug */
-#endif
-  check_datarate();
-  DPRINTF((DBG_INI,"SBPCD: check_datarate done.\n"));
-
-   if (!famL_drive)
-   {
-     OUT(CDo_reset,0);
-     sbp_sleep(100);
-   }
-
-  for (j=0;j<NR_SBPCD;j++)
-    {
-      if (DriveStruct[j].drv_id==-1) continue;
-      switch_drive(j);
-      if (!famL_drive) xy_DriveReset();
-      if (!st_spinning) xx_SpinUp();
-      DriveStruct[d].sbp_first_frame = -1;  /* First frame in buffer */
-      DriveStruct[d].sbp_last_frame = -1;   /* Last frame in buffer  */
-      DriveStruct[d].sbp_read_frames = 0;   /* Number of frames being read to buffer */
-      DriveStruct[d].sbp_current = 0;       /* Frame being currently read */
-      DriveStruct[d].CD_changed=1;
-      DriveStruct[d].frame_size=CD_FRAMESIZE;
+	for (j=0;j<NR_SBPCD;j++)
+	{
+		if (D_S[j].drv_id==-1) continue;
+		switch_drive(j);
+#if 1
+		if (!famL_drive) cc_DriveReset();
+#endif 0
+		if (!st_spinning) cc_SpinUp();
+		D_S[d].sbp_first_frame = -1;  /* First frame in buffer */
+		D_S[d].sbp_last_frame = -1;   /* Last frame in buffer  */
+		D_S[d].sbp_read_frames = 0;   /* Number of frames being read to buffer */
+		D_S[d].sbp_current = 0;       /* Frame being currently read */
+		D_S[d].CD_changed=1;
+		D_S[d].frame_size=CD_FRAMESIZE;
 #if EJECT
-      if (!fam0_drive) DriveStruct[d].f_eject=1;
-      else DriveStruct[d].f_eject=0;
+		if (!fam0_drive) D_S[d].f_eject=1;
+		else D_S[d].f_eject=0;
 #else
-      DriveStruct[d].f_eject=0;
+		D_S[d].f_eject=0;
 #endif
-
-      xx_ReadStatus();
-      i=ResponseStatus();  /* returns orig. status or p_busy_new */
-      if (i<0)
-	DPRINTF((DBG_INF,"SBPCD: init: ResponseStatus returns %02X\n",i));
-      else
-	{
-	  if (st_check)
-	    {
-	      i=xx_ReadError();
-	      DPRINTF((DBG_INI,"SBPCD: init: xx_ReadError returns %d\n",i));
-	    }
-	}
-      DPRINTF((DBG_INI,"SBPCD: init: first GetStatus: %d\n",i));
-      DPRINTF((DBG_LCS,"SBPCD: init: first GetStatus: error_byte=%d\n",
-	       DriveStruct[d].error_byte));
-      if (DriveStruct[d].error_byte==aud_12)
-	{
-	  do { i=GetStatus();
-	       DPRINTF((DBG_INI,"SBPCD: init: second GetStatus: %02X\n",i));
-	       DPRINTF((DBG_LCS,
-			"SBPCD: init: second GetStatus: error_byte=%d\n",
-			DriveStruct[d].error_byte));
-	       if (i<0) break;
-	       if (!st_caddy_in) break;
-	     }
-	  while (!st_diskok);
+		
+		cc_ReadStatus();
+		i=ResponseStatus();  /* returns orig. status or p_busy_new */
+		if (i<0)
+			msg(DBG_INF,"init: ResponseStatus returns %02X\n",i);
+		else
+		{
+			if (st_check)
+			{
+				i=cc_ReadError();
+				msg(DBG_INI,"init: cc_ReadError returns %d\n",i);
+			}
+		}
+		msg(DBG_INI,"init: first GetStatus: %d\n",i);
+		msg(DBG_LCS,"init: first GetStatus: error_byte=%d\n",
+		    D_S[d].error_byte);
+		if (D_S[d].error_byte==aud_12)
+		{
+			timeout=jiffies+200;
+			do
+			{
+				i=GetStatus();
+				msg(DBG_INI,"init: second GetStatus: %02X\n",i);
+				msg(DBG_LCS,
+				    "init: second GetStatus: error_byte=%d\n",
+				    D_S[d].error_byte);
+				if (i<0) break;
+				if (!st_caddy_in) break;
+				}
+			while ((!st_diskok)||(timeout<jiffies));
+		}
+		i=SetSpeed();
+		if (i>=0) D_S[d].CD_changed=1;
 	}
-      i=SetSpeed();
-      if (i>=0) DriveStruct[d].CD_changed=1;
-    }
-
-/*
- * Turn on the CD audio channels.
- * For "compatible" soundcards (with "SBPRO 0" or "SBPRO 2"), the addresses
- * are obtained from SOUND_BASE (see sbpcd.h).
- */
-  if ((sbpro_type==1) || (SOUND_BASE))
-    {
-      if (sbpro_type!=1)
+	
+	/*
+	 * Turn on the CD audio channels.
+	 * For "compatible" soundcards (with "SBPRO 0" or "SBPRO 2"), the addresses
+	 * are obtained from SOUND_BASE (see sbpcd.h).
+	 */
+	if ((sbpro_type==1) || (SOUND_BASE))
 	{
-	  MIXER_addr=SOUND_BASE+0x04; /* sound card's address register */
-	  MIXER_data=SOUND_BASE+0x05; /* sound card's data register */
+		if (sbpro_type!=1)
+		{
+			MIXER_addr=SOUND_BASE+0x04; /* sound card's address register */
+			MIXER_data=SOUND_BASE+0x05; /* sound card's data register */
+		}
+		OUT(MIXER_addr,MIXER_CD_Volume); /* select SB Pro mixer register */
+		OUT(MIXER_data,0xCC); /* one nibble per channel, max. value: 0xFF */
 	}
-      OUT(MIXER_addr,MIXER_CD_Volume); /* select SB Pro mixer register */
-      OUT(MIXER_data,0xCC); /* one nibble per channel, max. value: 0xFF */
-    }
-
-  if (register_blkdev(MAJOR_NR, major_name, &sbpcd_fops) != 0)
-    {
-      printk("SBPCD: Can't get MAJOR %d for Matsushita CDROM\n", MAJOR_NR);
-#if PRINTK_BUG
-      sti(); /* to avoid possible "printk" bug */
-#endif
+	
+	if (register_blkdev(MAJOR_NR, major_name, &sbpcd_fops) != 0)
+	{
+		msg(DBG_INF, "Can't get MAJOR %d for Matsushita CDROM\n", MAJOR_NR);
 #ifdef MODULE
-      return -EIO;
+		return -EIO;
 #else
-      goto init_done;
+		goto init_done;
 #endif MODULE
-    }
-  blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
-  read_ahead[MAJOR_NR] = SBP_BUFFER_FRAMES * (CD_FRAMESIZE / 512);
-  
-  request_region(CDo_command,4,major_name);
-
-  for (j=0;j<NR_SBPCD;j++)
-    {
-      if (DriveStruct[j].drv_id==-1) continue;
-      switch_drive(j);
-/*
- * allocate memory for the frame buffers
- */
+	}
+	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	read_ahead[MAJOR_NR] = SBP_BUFFER_FRAMES * (CD_FRAMESIZE / 512);
+	
+	request_region(CDo_command,4,major_name);
+	
+	for (j=0;j<NR_SBPCD;j++)
+	{
+		if (D_S[j].drv_id==-1) continue;
+		switch_drive(j);
+		/*
+		 * allocate memory for the frame buffers
+		 */
+		D_S[j].aud_buf=NULL;
+		D_S[j].sbp_audsiz=0;
+		D_S[j].sbp_bufsiz=SBP_BUFFER_FRAMES;
+		if (D_S[j].drv_type&drv_fam1)
+			if (READ_AUDIO>0) D_S[j].sbp_audsiz=READ_AUDIO;
 #ifdef MODULE
-      DriveStruct[j].sbp_buf=(u_char *) kmalloc(SBP_BUFFER_FRAMES*CD_FRAMESIZE, GFP_KERNEL);
-      DriveStruct[j].aud_buf=NULL;
+		D_S[j].sbp_buf=(u_char *) vmalloc(D_S[j].sbp_bufsiz*CD_FRAMESIZE);
+		if (D_S[j].sbp_buf==NULL)
+		{
+			msg(DBG_INF,"data buffer (%d frames) not available.\n",D_S[j].sbp_bufsiz);
+			return -EIO;
+		}
+		msg(DBG_INF,"data buffer size: %d frames.\n",SBP_BUFFER_FRAMES);
+		if (D_S[j].sbp_audsiz>0)
+		{
+			D_S[j].aud_buf=(u_char *) vmalloc(D_S[j].sbp_audsiz*CD_FRAMESIZE_RAW);
+			if (D_S[j].aud_buf==NULL) msg(DBG_INF,"audio buffer (%d frames) not available.\n",D_S[j].sbp_audsiz);
+			else msg(DBG_INF,"audio buffer size: %d frames.\n",D_S[j].sbp_audsiz);
+		}
 #else
-      DriveStruct[j].sbp_buf=(u_char *)mem_start;
-      mem_start += SBP_BUFFER_FRAMES*CD_FRAMESIZE;
-      if ((fam1_drive) && (SBP_BUFFER_AUDIO_FRAMES>0))
-	{
-	  DriveStruct[j].aud_buf=(u_char *)mem_start;
-	  mem_start += SBP_BUFFER_AUDIO_FRAMES*CD_FRAMESIZE_RAW;
-	}
-      else DriveStruct[j].aud_buf=NULL;
+		D_S[j].sbp_buf=(u_char *)mem_start;
+		mem_start += D_S[j].sbp_bufsiz*CD_FRAMESIZE;
+		if (D_S[j].sbp_audsiz>0)
+		{
+			D_S[j].aud_buf=(u_char *)mem_start;
+			mem_start += D_S[j].sbp_audsiz*CD_FRAMESIZE_RAW;
+		}
 #endif MODULE
-/*
- * set the block size
- */
-      sbpcd_blocksizes[j]=CD_FRAMESIZE;
-    }
-  blksize_size[MAJOR_NR]=sbpcd_blocksizes;
-
+		/*
+		 * set the block size
+		 */
+		sbpcd_blocksizes[j]=CD_FRAMESIZE;
+	}
+	blksize_size[MAJOR_NR]=sbpcd_blocksizes;
+	
 #ifdef MODULE
-return (0);
+	return (0);
 #else
-init_done:
+ init_done:
 #if !(SBPCD_ISSUE-1)
 #ifdef CONFIG_SBPCD2
-  mem_start=sbpcd2_init(mem_start, mem_end);
+	mem_start=sbpcd2_init(mem_start, mem_end);
 #endif
 #ifdef CONFIG_SBPCD3
-  mem_start=sbpcd3_init(mem_start, mem_end);
+	mem_start=sbpcd3_init(mem_start, mem_end);
 #endif
 #ifdef CONFIG_SBPCD4
-  mem_start=sbpcd4_init(mem_start, mem_end);
+	mem_start=sbpcd4_init(mem_start, mem_end);
 #endif
 #endif
-#if !(SBPCD_ISSUE-1)
-  DPRINTF((DBG_INF,"SBPCD: init done.\n"));
-#endif
-  return (mem_start);
+	return (mem_start);
 #endif MODULE
 }
 /*==========================================================================*/
 #ifdef MODULE
 void cleanup_module(void)
 {
-  int j;
-
-  if (MOD_IN_USE)
-    {
-      printk("%s module in use - can't remove it.\n", major_name);
-      return;
-    }
-  if ((unregister_blkdev(MAJOR_NR, major_name) == -EINVAL))
-    {
-      printk("What's that: can't unregister %s\n", major_name);
-      return;
-    }
-  release_region(CDo_command,4);
-
-  for (j=0;j<NR_SBPCD;j++)
-    {
-      if (DriveStruct[j].drv_id==-1) continue;
-      kfree_s(DriveStruct[j].sbp_buf, SBP_BUFFER_FRAMES*CD_FRAMESIZE);
-    }
-  printk("%s module released.\n", major_name);
+	int j;
+	
+	if (MOD_IN_USE)
+	{
+		msg(DBG_INF, "%s module in use - can't remove it.\n", major_name);
+		return;
+	}
+	if ((unregister_blkdev(MAJOR_NR, major_name) == -EINVAL))
+	{
+		msg(DBG_INF, "What's that: can't unregister %s.\n", major_name);
+		return;
+	}
+	release_region(CDo_command,4);
+	
+	for (j=0;j<NR_SBPCD;j++)
+	{
+		if (D_S[j].drv_id==-1) continue;
+		vfree(D_S[j].sbp_buf);
+		if (D_S[j].sbp_audsiz>0)
+			vfree(D_S[j].aud_buf);
+	}
+	msg(DBG_INF, "%s module released.\n", major_name);
 }
 #endif MODULE
 /*==========================================================================*/
@@ -4433,53 +5311,70 @@
  */
 static int sbpcd_chk_disk_change(dev_t full_dev)
 {
-  int i, st;
-
-  DPRINTF((DBG_CHK,"SBPCD: media_check (%d) called\n", MINOR(full_dev)));
-  return (0); /* "busy" test necessary before we really can check */
-
-  i=MINOR(full_dev);
-  if ( (i<0) || (i>=NR_SBPCD) || (DriveStruct[i].drv_id==-1) )
-    {
-      printk("SBPCD: media_check: invalid device %04X.\n", full_dev);
-      return (-1);
-    }
-
-  switch_drive(i);
-  
-  xx_ReadStatus();                         /* command: give 1-byte status */
-  st=ResponseStatus();
-  DPRINTF((DBG_CHK,"SBPCD: media_check: %02X\n",DriveStruct[d].status_byte));
-  if (st<0)
-    {
-      DPRINTF((DBG_INF,"SBPCD: media_check: ResponseStatus error.\n"));
-      return (1); /* status not obtainable */
-    }
-  if (DriveStruct[d].CD_changed==0xFF) DPRINTF((DBG_CHK,"SBPCD: media_check: \"changed\" assumed.\n"));
-  if (!st_spinning) DPRINTF((DBG_CHK,"SBPCD: media_check: motor off.\n"));
-  if (!st_door_closed)
-    {
-      DPRINTF((DBG_CHK,"SBPCD: media_check: door open.\n"));
-      DriveStruct[d].CD_changed=0xFF;
-    }
-  if (!st_caddy_in)
-    {
-      DPRINTF((DBG_CHK,"SBPCD: media_check: no disk in drive.\n"));
-      DriveStruct[d].CD_changed=0xFF;
-    }
-  if (!st_diskok) DPRINTF((DBG_CHK,"SBPCD: media_check: !st_diskok.\n"));
-  
+	int i, st;
+	
+	msg(DBG_CHK,"media_check (%d) called\n", MINOR(full_dev));
+	return (0); /* "busy" test necessary before we really can check */
+	
+	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);
+	}
+	
+	switch_drive(i);
+	
+	cc_ReadStatus();                         /* command: give 1-byte status */
+	st=ResponseStatus();
+	msg(DBG_CHK,"media_check: %02X\n",D_S[d].status_bits);
+	if (st<0)
+	{
+		msg(DBG_INF,"media_check: ResponseStatus error.\n");
+		return (1); /* status not obtainable */
+	}
+	if (D_S[d].CD_changed==0xFF) msg(DBG_CHK,"media_check: \"changed\" assumed.\n");
+	if (!st_spinning) msg(DBG_CHK,"media_check: motor off.\n");
+	if (!st_door_closed)
+	{
+		msg(DBG_CHK,"media_check: door open.\n");
+		D_S[d].CD_changed=0xFF;
+	}
+	if (!st_caddy_in)
+	{
+		msg(DBG_CHK,"media_check: no disk in drive.\n");
+		D_S[d].open_count=0;
+		D_S[d].CD_changed=0xFF;
+	}
+	if (!st_diskok) msg(DBG_CHK,"media_check: !st_diskok.\n");
+	
 #if 0000
-  if (DriveStruct[d].CD_changed==0xFF)
-    {
-      DriveStruct[d].CD_changed=1;
-      return (1); /* driver had a change detected before */
-    }
+	if (D_S[d].CD_changed==0xFF)
+	{
+		D_S[d].CD_changed=1;
+		return (1); /* driver had a change detected before */
+	}
 #endif 0000 /* seems to give additional errors at the moment */
-
-  if (!st_diskok) return (1); /* disk not o.k. */
-  if (!st_caddy_in) return (1); /* disk removed */
-  if (!st_door_closed) return (1); /* door open */
-  return (0);
+	
+	if (!st_diskok) return (1); /* disk not o.k. */
+	if (!st_caddy_in) return (1); /* disk removed */
+	if (!st_door_closed) return (1); /* door open */
+	return (0);
 }
 /*==========================================================================*/
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file. 
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff -u --recursive --new-file v1.2.7/linux/drivers/char/ChangeLog linux/drivers/char/ChangeLog
--- v1.2.7/linux/drivers/char/ChangeLog	Sat Apr 29 12:42:21 1995
+++ linux/drivers/char/ChangeLog	Tue May  2 08:38:31 1995
@@ -1,14 +1,36 @@
+Tue May  2 00:53:25 1995    <tytso@rsx-11.mit.edu>
+
+	* tty_io.c (tty_set_ldisc): Wait until the output buffer is
+		drained before closing the old line discipline --- needed
+		in only one case: XON/XOFF processing.
+
+	* n_tty.c (n_tty_close): Don't bother waiting until the output
+		driver is closed; in general, the line discipline
+		shouldn't care if the hardware is finished
+		transmitting before the line discipline terminates.
+
+	* tty_io.c (release_dev): Shutdown the line discipline after
+		decrementing the tty count variable; but set the
+		TTY_CLOSING flag so that we know that this tty structure
+		isn't long for this world.
+
+	* tty_io.c (init_dev): Add sanity code to check to see if
+		TTY_CLOSING is set on a tty structure; if so, something
+		bad has happened (probably a line discipline close blocked
+		when it shouldn't have; so do a kernel printk and then
+		return an error).
+
 Wed Apr 26 10:23:44 1995  Theodore Y. Ts'o  <tytso@localhost>
 
-	* tty_io.c (release_dev): Try to shutdown the line discpline
+	* tty_io.c (release_dev): Try to shutdown the line discipline
 		*before* decrementing the tty count variable; this removes
 		a potential race condition which occurs when the line
-		discpline close blocks, and another process then tries
+		discipline close blocks, and another process then tries
 		open the same serial port.
 
 	* serial.c (rs_hangup): When hanging up, flush the output buffer
-		befure shutting down the UART.  Otherwise the line
-		discpline close blocks waiting for the characters to get
+		before shutting down the UART.  Otherwise the line
+		discipline close blocks waiting for the characters to get
 		flushed, which never happens until the serial port gets reused.
 
 Wed Apr 12 08:06:16 1995  Theodore Y. Ts'o  <tytso@localhost>
diff -u --recursive --new-file v1.2.7/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- v1.2.7/linux/drivers/char/n_tty.c	Mon Feb 20 21:29:52 1995
+++ linux/drivers/char/n_tty.c	Tue May  2 08:33:51 1995
@@ -676,7 +676,6 @@
 
 static void n_tty_close(struct tty_struct *tty)
 {
-	tty_wait_until_sent(tty, 0);
 	n_tty_flush_buffer(tty);
 	if (tty->read_buf) {
 		free_page((unsigned long) tty->read_buf);
diff -u --recursive --new-file v1.2.7/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v1.2.7/linux/drivers/char/tty_io.c	Sat Apr 29 12:42:21 1995
+++ linux/drivers/char/tty_io.c	Tue May  2 08:33:51 1995
@@ -204,6 +204,8 @@
 		return 0;	/* We are already in the desired discipline */
 	o_ldisc = tty->ldisc;
 
+	tty_wait_until_sent(tty, 0);
+	
 	/* Shutdown the current discipline. */
 	if (tty->ldisc.close)
 		(tty->ldisc.close)(tty);
@@ -865,8 +867,15 @@
 			}
 		}
 		tty = NULL;
-	} else
+	} else {
+		if ((*tty_loc)->flags & (1 << TTY_CLOSING)) {
+			printk("Attempt to open closing tty %s.\n",
+			       tty_name(*tty_loc));
+			printk("Ack!!!!  This should never happen!!\n");
+			return -EINVAL;
+		}
 		(*tty_loc)->count++;
+	}
 	if (driver->type == TTY_DRIVER_TYPE_PTY) {
 		if (!*o_tp_loc) {
 			*o_tp_loc = o_tp;
@@ -1006,22 +1015,6 @@
 			tty->link->count = 0;
 		}
 	}
-	if (tty->count <= 1) {
-		/*
-		 * Shutdown the current line discipline, and reset it
-		 * to N_TTY.
-		 */
-		if (tty->ldisc.close)
-			(tty->ldisc.close)(tty);
-		tty->ldisc = ldiscs[N_TTY];
-		tty->termios->c_line = N_TTY;
-		if (o_tty && o_tty->count <= 0) {
-			if (o_tty->ldisc.close)
-				(o_tty->ldisc.close)(o_tty);
-			o_tty->ldisc = ldiscs[N_TTY];
-			o_tty->termios->c_line = N_TTY;
-		}
-	}
 	if (--tty->count < 0) {
 		printk("release_dev: bad tty->count (%d) for %s\n",
 		       tty->count, tty_name(tty));
@@ -1030,6 +1023,9 @@
 	if (tty->count)
 		return;
 
+	/*
+	 * We're committed; at this point, we must not block!
+	 */
 	if (o_tty) {
 		if (o_tty->count)
 			return;
@@ -1041,6 +1037,7 @@
 #ifdef TTY_DEBUG_HANGUP
 	printk("freeing tty structure...");
 #endif
+	tty->flags |= (1 << TTY_CLOSING);
 
 	/*
 	 * Make sure there aren't any processes that still think this
@@ -1055,6 +1052,20 @@
 			(*p)->tty = NULL;
 	}
 
+	/*
+	 * Shutdown the current line discipline, and reset it to
+	 * N_TTY.
+	 */
+	if (tty->ldisc.close)
+		(tty->ldisc.close)(tty);
+	tty->ldisc = ldiscs[N_TTY];
+	tty->termios->c_line = N_TTY;
+	if (o_tty) {
+		if (o_tty->ldisc.close)
+			(o_tty->ldisc.close)(o_tty);
+		o_tty->ldisc = ldiscs[N_TTY];
+	}
+	
 	tty->driver.table[idx] = NULL;
 	if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) {
 		tty->driver.termios[idx] = NULL;
diff -u --recursive --new-file v1.2.7/linux/drivers/net/8390.h linux/drivers/net/8390.h
--- v1.2.7/linux/drivers/net/8390.h	Sat Apr 29 12:42:21 1995
+++ linux/drivers/net/8390.h	Tue May  2 08:01:57 1995
@@ -60,7 +60,7 @@
   struct enet_statistics stat;
 };
 
-/* The maximum number of 8390 interrupt serivce routines called per IRQ. */
+/* The maximum number of 8390 interrupt service routines called per IRQ. */
 #define MAX_SERVICE 12
 
 /* The maximum number of jiffies waited before assuming a Tx failed. */
diff -u --recursive --new-file v1.2.7/linux/drivers/net/CONFIG linux/drivers/net/CONFIG
--- v1.2.7/linux/drivers/net/CONFIG	Sun Feb 12 16:07:22 1995
+++ linux/drivers/net/CONFIG	Tue May  2 07:10:16 1995
@@ -40,10 +40,27 @@
 #       EWRK3_DEBUG	Set the desired debug level
 #
 #  DE4x5		The DIGITAL series of PCI/EISA Ethernet Cards,
-#			DE425, DE434 and DE435
-#       DE4x5_DEBUG	Set the desired debug level
-#	IS_ZYNX         May allow driver to work with Zynx cards - 
+#			DE425, DE434, DE435, DE500
+#     DE4X5_DEBUG	Set the desired debug level
+#     IS_NOT_DEC        May allow driver to work with Zynx & SMC cards - 
 #			see linux/drivers/net/README.de4x5
+#     DE4X5_AUTOSENSE   (Default) auto media/mode selection
+#                       If you want at least one board to not autosense then
+#                       no board can autosense. For a board mix of several
+#	                types, OR the manual values [eg for a DE500 (100M) with
+#	                a DE450 (AUI) use '-DDE4X5_AUTOSENSE=(0x80|0x08)']
+#                       For full auto media/mode selection           = 0x4000
+#                       For manual TP media selection                = 0x01
+#                       For manual TP/Nway media selection (DC21041) = 0x02
+#                       For manual BNC media selection               = 0x04
+#                       For manual AUI media selection               = 0x08
+#                       For manual BNC/AUI media selection (DC21040) = 0x10
+#                       For manual 10Mb/s mode selection   (DC21140) = 0x40
+#                       For manual 100Mb/s mode selection  (DC21140) = 0x80
+#                       The DC21040 will default to TP if TP_NW is specified
+#                       The DC21041 will default to BNC if BNC_AUI is specified
+#                       The DC21140 needs it's speed to be manually set to
+#                       10Mb/s or 100Mb/s (AUTO defaults to 10Mb/s)
 #
 
 # The following options exist, but cannot be set in this file.
@@ -66,4 +83,4 @@
 PLIP_OPTS	=
 DEPCA_OPTS	= -DDEPCA_DEBUG=1
 EWRK3_OPTS	= -DEWRK3_DEBUG=1
-DE4x5_OPTS	= -DDE4x5_DEBUG=1
+DE4X5_OPTS	= -DDE4X5_DEBUG=1 -DDE4X5_AUTOSENSE=0x4000
diff -u --recursive --new-file v1.2.7/linux/drivers/net/README.de4x5 linux/drivers/net/README.de4x5
--- v1.2.7/linux/drivers/net/README.de4x5	Sun Feb 12 16:07:47 1995
+++ linux/drivers/net/README.de4x5	Tue May  2 07:10:16 1995
@@ -1,36 +1,47 @@
-The  de425/de434/de435 driver in this  distribution is designed to work with
-the Digital Equipment Corporation series  of PCI/EISA ethernet cards (DE425,
-DE434, DE435) and with all kernels that support PCI.
+The de425/de434/de435/de500 driver in this distribution  is designed to work
+with  the  Digital Equipment Corporation   series of PCI/EISA ethernet cards
+(DE425, DE434, DE435, DE500) and with all kernels that support PCI.
 
 Auto media detection is provided so that the  media choice isn't compiled in
-and is flexible enough to be able to reconfigure on-the-fly.
+and is  flexible enough to be able  to  reconfigure on-the-fly. This feature
+hasn't been included for the DE500 unfortunately, due  to a potential patent
+dispute. When I get around to implementing the autosense algorithm by myself
+(which could legally be difficult to prove since I'm  part of the group that
+has implemented the patented algorithm) you'll  have an auto speed selection
+for the de500. If you want the auto speed feature yell at Digital. If enough
+of you do things might change.
 
-The ability to  load this  driver as  a loadable  module has been  included,
+The ability to load   this driver as  a loadable  module has been  included,
 although I don't recommend its use with PCI, since PCI dynamically allocates
-where the card will go at boot time.
+where the card will go at boot time (i.e. the  card would have to be present
+in the system at boot time for its address/IRQ to be assigned).
 
-The performance we've achieved  so far has been  measured through the 'ttcp'
-tool at   1.08MB/s.  This measures   the total tcp stack  performance which
-includes  the  card,  so  don't expect   to  get  much  nearer the  1.25MB/s
-theoretical ethernet rate.
-
-    ************************************************************************
-    However there is still a known bug which causes ttcp to hang on transmit
-    (receive  is  OK), although  the  adapter/driver  continues to  function
-    normally for  other applications e.g.  nfs  mounting disks, pinging etc.
-    The cause is under investigation.
-    ************************************************************************
+The performance we've achieved  so far has  been measured through the 'ttcp'
+tool at 1.06MB/s for  TCP  and 1.17MB/s for  UDP.   This measures  the total
+stack performance which  includes the  card, so don't   expect to get   much
+nearer the 1.25MB/s theoretical ethernet rate.
+
+                TCP           UDP
+             TX     RX     TX     RX
+    DE425   1030k  997k   1170k  1128k                 (EISA on a Dell 433DE)
+    DE434   1063k  995k   1170k  1125k                 (PCI: DECpc XL 466d2)
+    DE435   1063k  995k   1170k  1125k                 (PCI: DECpc XL 466d2)
+    DE500   1063k  998k   1170k  1125k  in 10Mb/s mode (PCI: DECpc XL 466d2)
+
+All  values are   typical  (in kBytes/sec) from   a  sample of   4  for each
+measurement. Their error  is approx +/-20k on a  quiet (private) network and
+also depend on what load the CPU has, CPU speed etc.
 
-ZYNX  cards,  which   use  the PCI  DECchip  DC21040,  are  not specifically
+ZYNX and SMC cards, which use the PCI DECchip  DC21040, are not specifically
 supported in this driver because
 
 a) I have  no information on them.   
 b) I cannot test  them with the driver.
 c) Donald Becker's 'tulip.c' driver  works with them....well one person says
-   they do and another doesn't, so take your pick!
+   they do and another says they do not, so take your pick!
 
 This driver can be made to work with the ZYNX  (and may be  the SMC) card by
-setting a compile time flag in linux/drivers/net/CONFIG
+setting a compile time flag (IS_NOT_DEC) in linux/drivers/net/CONFIG
 
 Enjoy!
 
diff -u --recursive --new-file v1.2.7/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v1.2.7/linux/drivers/net/de4x5.c	Sun Feb 12 16:07:22 1995
+++ linux/drivers/net/de4x5.c	Wed May  3 07:17:10 1995
@@ -1,6 +1,6 @@
 /*  de4x5.c: A DIGITAL DE425/DE434/DE435 ethernet driver for linux.
 
-    Copyright 1994 Digital Equipment Corporation.
+    Copyright 1994, 1995 Digital Equipment Corporation.
 
     This software may be used and distributed according to the terms of
     the GNU Public License, incorporated herein by reference.
@@ -11,17 +11,22 @@
 	DE425 TP/COAX EISA
 	DE434 TP PCI
 	DE435 TP/COAX/AUI PCI
+	DE500 10/100 PCI Fasternet
 
-    The driver has been tested on a  relatively busy network using the DE425
-    and DE435 cards and benchmarked with 'ttcp': it  transferred 16M of data
-    at 1.08MB/s (8.6Mb/s) to a DECstation 5000/200.
-
-    ************************************************************************
-    However there is still a known bug which causes ttcp to hang on transmit
-    (receive  is  OK), although  the  adapter/driver  continues to  function
-    normally for  other applications e.g.  nfs  mounting disks, pinging etc.
-    The cause is under investigation.
-    ************************************************************************
+    The driver has been tested on a relatively busy network using the DE425,
+    DE434, DE435 and DE500 cards and benchmarked with 'ttcp': it transferred
+    16M of data to a DECstation 5000/200 as follows:
+
+                TCP           UDP
+             TX     RX     TX     RX
+    DE425   1030k  997k   1170k  1128k
+    DE434   1063k  995k   1170k  1125k
+    DE435   1063k  995k   1170k  1125k
+    DE500   1063k  998k   1170k  1125k  in 10Mb/s mode
+
+    All  values are typical (in   kBytes/sec) from a  sample  of 4 for  each
+    measurement. Their error is +/-20k on a quiet (private) network and also
+    depend on what load the CPU has.
 
     The author may    be  reached as davies@wanton.lkg.dec.com  or   Digital
     Equipment Corporation, 550 King Street, Littleton MA 01460.
@@ -98,9 +103,6 @@
 
     TO DO:
     ------
-    1. Add DC21041 Nway/Autosense support
-    2. Add DC21140 Autosense support
-    3. Add timer support
 
 
     Revision History
@@ -109,18 +111,26 @@
     Version   Date        Description
   
       0.1     17-Nov-94   Initial writing. ALPHA code release.
-      0.2     13-Jan-95   Added PCI support for DE435's
-      0.21    19-Jan-95   Added auto media detection
-      0.22    10-Feb-95   Fix interrupt handler call <chris@cosy.sbg.ac.at>
-                          Fix recognition bug reported by <bkm@star.rl.ac.uk>
-			  Add request/release_region code
-			  Add loadable modules support for PCI
-			  Clean up loadable modules support
+      0.2     13-Jan-95   Added PCI support for DE435's.
+      0.21    19-Jan-95   Added auto media detection.
+      0.22    10-Feb-95   Fix interrupt handler call <chris@cosy.sbg.ac.at>.
+                          Fix recognition bug reported by <bkm@star.rl.ac.uk>.
+			  Add request/release_region code.
+			  Add loadable modules support for PCI.
+			  Clean up loadable modules support.
+      0.23    28-Feb-95   Added DC21041 and DC21140 support. 
+                          Fix missed frame counter value and initialisation.
+			  Fixed EISA probe.
+      0.24    11-Apr-95   Change delay routine to use <linux/udelay>.
+                          Change TX_BUFFS_AVAIL macro.
+			  Change media autodetection to allow manual setting.
+			  Completed DE500 (DC21140) support.
+      0.241   18-Apr-95   Interim release without DE500 Autosense Algorithm.
 
     =========================================================================
 */
 
-static char *version = "de4x5.c:v0.22 2/10/95 davies@wanton.lkg.dec.com\n";
+static char *version = "de4x5.c:v0.241 4/18/95 davies@wanton.lkg.dec.com\n";
 
 #include <linux/config.h>
 #ifdef MODULE
@@ -140,6 +150,7 @@
 #include <linux/ioport.h>
 #include <linux/malloc.h>
 #include <linux/pci.h>
+#include <linux/delay.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -161,6 +172,12 @@
 static int de4x5_debug = 1;
 #endif
 
+#ifdef DE4X5_AUTOSENSE              /* Should be done on a per adapter basis */
+static int de4x5_autosense = DE4X5_AUTOSENSE;
+#else
+static int de4x5_autosense = AUTO;      /* Do auto media/mode sensing */
+#endif
+
 /*
 ** Ethernet PROM defines
 */
@@ -198,79 +215,102 @@
 #define DE4X5_PCI_TOTAL_SIZE 0x80        /* I/O address extent */
 
 /*
-** Timer defines
-*/
-#define TIMER_WIDTH   16
-#define TIMER_PORT    0x43
-#define TIMER_LATCH   0x06
-#define TIMER_READ    0x40
-#define TIMER_TICK    419  /*ns*/
-#define DELAY_QUANT   5    /*us*/
-
-#define LWPAD ((long)(sizeof(long) - 1)) /* for longword alignment */
+** Memory Alignment. Each descriptor is 4 longwords long. To force a
+** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
+** DESC_ALIGN. ALIGN aligns the start address of the private memory area
+** and hence the RX descriptor ring's first entry. 
+*/
+#define ALIGN4      ((u_long)4 - 1)    /* 1 longword align */
+#define ALIGN8      ((u_long)8 - 1)    /* 2 longword align */
+#define ALIGN16     ((u_long)16 - 1)   /* 4 longword align */
+#define ALIGN32     ((u_long)32 - 1)   /* 8 longword align */
+#define ALIGN64     ((u_long)64 - 1)   /* 16 longword align */
+#define ALIGN128    ((u_long)128 - 1)  /* 32 longword align */
+
+#define ALIGN         ALIGN32          /* Keep the DC21040 happy... */
+#define CACHE_ALIGN   CAL_16LONG
+#define DESC_SKIP_LEN DSL_0            /* Must agree with DESC_ALIGN */
+/*#define DESC_ALIGN    u_long dummy[4]; / * Must agree with DESC_SKIP_LEN */
+#define DESC_ALIGN
 
-#ifndef IS_ZYNX                          /* See README.de4x5 for using this */
-static int is_zynx = 0;
+#ifndef IS_NOT_DEC                     /* See README.de4x5 for using this */
+static int is_not_dec = 0;
 #else
-static int is_zynx = 1;
+static int is_not_dec = 1;
 #endif
 
 /*
 ** DE4X5 IRQ ENABLE/DISABLE
 */
-static u_long irq_mask = IMR_RIM | IMR_TIM | IMR_TUM ;
+static u_long irq_mask = IMR_SEM | IMR_RIM | IMR_RUM | IMR_TIM | IMR_TUM ;
 
 static u_long irq_en   = IMR_NIM | IMR_AIM;
 
-#define ENABLE_IRQs \
+#define ENABLE_IRQs { \
     imr |= irq_en;\
-    outl(imr, DE4X5_IMR)                    /* Enable the IRQs */
+    outl(imr, DE4X5_IMR);                   /* Enable the IRQs */\
+}
 
-#define DISABLE_IRQs \
+#define DISABLE_IRQs {\
     imr = inl(DE4X5_IMR);\
     imr &= ~irq_en;\
-    outl(imr, DE4X5_IMR)                    /* Disable the IRQs */
+    outl(imr, DE4X5_IMR);                   /* Disable the IRQs */\
+}
 
-#define UNMASK_IRQs \
+#define UNMASK_IRQs {\
     imr |= irq_mask;\
-    outl(imr, DE4X5_IMR)                    /* Unmask the IRQs */
+    outl(imr, DE4X5_IMR);                   /* Unmask the IRQs */\
+}
 
-#define MASK_IRQs \
+#define MASK_IRQs {\
     imr = inl(DE4X5_IMR);\
     imr &= ~irq_mask;\
-    outl(imr, DE4X5_IMR)                    /* Mask the IRQs */
+    outl(imr, DE4X5_IMR);                   /* Mask the IRQs */\
+}
 
 /*
 ** DE4X5 START/STOP
 */
-#define START_DE4X5 \
+#define START_DE4X5 {\
     omr = inl(DE4X5_OMR);\
     omr |= OMR_ST | OMR_SR;\
-    outl(omr, DE4X5_OMR)                    /* Enable the TX and/or RX */
+    outl(omr, DE4X5_OMR);                   /* Enable the TX and/or RX */\
+}
 
-#define STOP_DE4X5 \
+#define STOP_DE4X5 {\
     omr = inl(DE4X5_OMR);\
     omr &= ~(OMR_ST|OMR_SR);\
-    outl(omr, DE4X5_OMR)                    /* Disable the TX and/or RX */
+    outl(omr, DE4X5_OMR);                   /* Disable the TX and/or RX */ \
+}
 
 /*
 ** DE4X5 SIA RESET
 */
-#define RESET_SIA \
-    outl(SICR_RESET, DE4X5_SICR);           /* Reset SIA connectivity regs */ \
-    outl(STRR_RESET, DE4X5_STRR);           /* Write reset values */ \
-    outl(SIGR_RESET, DE4X5_SIGR)            /* Write reset values */
+#define RESET_SIA outl(0, DE4X5_SICR);      /* Reset SIA connectivity regs */
+
+/*
+** SROM Structure
+*/
+struct de4x5_srom {
+  char reserved[18];
+  char version;
+  char num_adapters;
+  char ieee_addr[6];
+  char info[100];
+  short chksum;
+};
 
 /*
 ** DE4X5 Descriptors. Make sure that all the RX buffers are contiguous
 ** and have sizes of both a power of 2 and a multiple of 4.
 ** A size of 256 bytes for each buffer was chosen because over 90% of
-** all packets in our network are <256 bytes long.
+** all packets in our network are <256 bytes long and 64 longword alignment
+** is possible.
 */
-#define NUM_RX_DESC 64                       /* Number of RX descriptors */
+#define NUM_RX_DESC 8                        /* Number of RX descriptors */
 #define NUM_TX_DESC 8                        /* Number of TX descriptors */
 #define BUFF_ALLOC_RETRIES 10                /* In case of memory shortage */
-#define RX_BUFF_SZ 256                       /* Power of 2 for kmalloc and */
+#define RX_BUFF_SZ 1536                      /* Power of 2 for kmalloc and */
                                              /* Multiple of 4 for DC21040 */
 
 struct de4x5_desc {
@@ -278,6 +318,7 @@
     u_long des1;
     char *buf;
     char *next;
+    DESC_ALIGN
 };
 
 /*
@@ -308,48 +349,76 @@
     char rxRingSize;
     char txRingSize;
     char bus;                                /* EISA or PCI */
+    u_short chipset;                         /* DC21040, DC21041 or DC21140 */
+    long media;                              /* Media (eg TP), mode (eg 100B)*/
+    int  autosense;                          /* Allow/disallow autosensing */
+    int  tx_enable;                          /* Enable descriptor polling */
     char lostMedia;                          /* Possibly lost media */
+    int  setup_f;                            /* Setup frame filtering type */
 };
 
+
+/*
+** The transmit ring full condition is described by the tx_old and tx_new
+** pointers by:
+**    tx_old            = tx_new    Empty ring
+**    tx_old            = tx_new+1  Full ring
+**    tx_old+txRingSize = tx_new+1  Full ring  (wrapped condition)
+*/
 #define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
 			 lp->tx_old+lp->txRingSize-lp->tx_new-1:\
                          lp->tx_old               -lp->tx_new-1)
-#define TX_SUSPENDED   (((sts & STS_TS) ^ TS_SUSP)==0)
+/*#define TX_BUFFS_AVAIL ((lp->tx_ring[lp->tx_new].status)>=0 ? 1 : 0)*/
 
 /*
 ** Public Functions
 */
-static int  de4x5_open(struct device *dev);
-static int  de4x5_queue_pkt(struct sk_buff *skb, struct device *dev);
-static void de4x5_interrupt(int irq, struct pt_regs * regs);
-static int  de4x5_close(struct device *dev);
-static struct enet_statistics *de4x5_get_stats(struct device *dev);
-static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
-static int  de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+static int     de4x5_open(struct device *dev);
+static int     de4x5_queue_pkt(struct sk_buff *skb, struct device *dev);
+static void    de4x5_interrupt(int irq, struct pt_regs *regs);
+static int     de4x5_close(struct device *dev);
+static struct  enet_statistics *de4x5_get_stats(struct device *dev);
+static void    set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+static int     de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd);
 
 /*
 ** Private functions
 */
-static int  de4x5_hw_init(struct device *dev, short iobase);
-static int  de4x5_init(struct device *dev);
-static int  de4x5_rx(struct device *dev);
-static int  de4x5_tx(struct device *dev);
-
-static int  autoconf_media(struct device *dev);
-static void create_packet(struct device *dev, char *frame, int len);
-static u_short dce_get_ticks(void);
-static void dce_us_delay(u_long usec);
-static void dce_ms_delay(u_long msec);
-static void load_packet(struct device *dev, char *buf, u_long flags, struct sk_buff *skb);
-static void EISA_signature(char * name, short iobase);
-static int  DevicePresent(short iobase);
-static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs, char *multicast_table);
-
-static int aprom_crc (struct device *dev);
-
-static void eisa_probe(struct device *dev, short iobase);
-static void pci_probe(struct device *dev, short iobase);
-static struct device *alloc_device(struct device *dev, int iobase);
+static int     de4x5_hw_init(struct device *dev, short iobase);
+static int     de4x5_init(struct device *dev);
+static int     de4x5_rx(struct device *dev);
+static int     de4x5_tx(struct device *dev);
+
+static int     autoconf_media(struct device *dev);
+static void    create_packet(struct device *dev, char *frame, int len);
+static void    dce_us_delay(u_long usec);
+static void    dce_ms_delay(u_long msec);
+static void    load_packet(struct device *dev, char *buf, u_long flags, struct sk_buff *skb);
+static void    dc21040_autoconf(struct device *dev);
+static void    dc21041_autoconf(struct device *dev);
+static void    dc21140_autoconf(struct device *dev);
+static long    test_media(struct device *dev, long irqs, long irq_mask, long csr13, long csr14, long csr15, long msec);
+static long    ping_media(struct device *dev);
+static void    reset_init_sia(struct device *dev, long sicr, long strr, long sigr);
+static int     test_ans(struct device *dev, long irqs, long irq_mask, long msec);
+static void    load_ms_timer(struct device *dev, u_long msec);
+static int     EISA_signature(char *name, long eisa_id);
+static int     DevicePresent(short iobase);
+static short   srom_rd(u_short address, u_char offset);
+static void    srom_latch(u_long command, u_short address);
+static void    srom_command(u_long command, u_short address);
+static void    srom_address(u_long command, u_short address, u_char offset);
+static short   srom_data(u_long command, u_short address);
+/*static void    srom_busy(u_long command, u_short address);*/
+static void    sendto_srom(u_long command, u_short addr);
+static long    getfrom_srom(u_short addr);
+static void    SetMulticastFilter(struct device *dev, int num_addrs, char *addrs);
+static int     aprom_crc (struct device *dev);
+
+static void    eisa_probe(struct device *dev, short iobase);
+static void    pci_probe(struct device *dev, short iobase);
+static struct  device *alloc_device(struct device *dev, int iobase);
+static char    *build_setup_frame(struct device *dev, int mode);
 
 #ifdef MODULE
 int  init_module(void);
@@ -371,6 +440,9 @@
 static struct bus_type {
     int bus;
     int device;
+    int chipset;
+    struct de4x5_srom srom;
+    int autosense;
 } bus;
 
 /*
@@ -382,8 +454,7 @@
     outl(i | BMR_SWR, DE4X5_BMR);\
     outl(i, DE4X5_BMR);\
     for (i=0;i<5;i++) inl(DE4X5_BMR);\
-		   }
-
+}
 
 
 
@@ -409,7 +480,7 @@
     ** Walk the device list to check that at least one device
     ** initialised OK
     */
-    for (; dev->priv == NULL && dev->next != NULL; dev = dev->next);
+    for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next);
 
     if (dev->priv) status = 0;
     if (iobase == 0) autoprobed = 1;
@@ -422,10 +493,16 @@
 de4x5_hw_init(struct device *dev, short iobase)
 {
   struct bus_type *lp = &bus;
-  int tmpbus, i, j, status=0;
+  int tmpbus, tmpchs, i, j, status=0;
   char *tmp;
   u_long nicsr;
 
+  /* Ensure we're not sleeping */
+  if (lp->chipset == DC21041) {
+    outl(0, PCI_CFDA);
+    dce_ms_delay(10);
+  }
+
   RESET_DE4X5;
 
   if (((nicsr=inl(DE4X5_STS)) & (STS_TS | STS_RS)) == 0) {
@@ -433,10 +510,14 @@
     ** Now find out what kind of DC21040/DC21041/DC21140 board we have.
     */
     if (lp->bus == PCI) {
-      if (!is_zynx) {
-	strcpy(name, "DE435");
+      if (!is_not_dec) {
+	if ((lp->chipset == DC21040) || (lp->chipset == DC21041)) {
+	  strcpy(name, "DE435");
+	} else if (lp->chipset == DC21140) {
+	  strcpy(name, "DE500");                /* Must read the SROM here! */
+	}
       } else {
-	strcpy(name, "ZYNX");
+	strcpy(name, "UNKNOWN");
       }
     } else {
       EISA_signature(name, EISA_ID0);
@@ -444,8 +525,6 @@
 
     if (*name != '\0') {                         /* found a board signature */
       dev->base_addr = iobase;
-      request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE :
-			                       DE4X5_EISA_TOTAL_SIZE), name);
       
       if (lp->bus == EISA) {
 	printk("%s: %s at %#3x (EISA slot %d)", 
@@ -462,6 +541,7 @@
       printk("%2.2x,\n", dev->dev_addr[i]);
       
       tmpbus = lp->bus;
+      tmpchs = lp->chipset;
 
       if (status == 0) {
 	struct de4x5_private *lp;
@@ -470,26 +550,50 @@
 	** Reserve a section of kernel memory for the adapter
 	** private area and the TX/RX descriptor rings.
 	*/
-	dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + LWPAD, 
+	dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + ALIGN, 
 				                                   GFP_KERNEL);
 	/*
 	** Align to a longword boundary
 	*/
-	dev->priv = (void *)(((u_long)dev->priv + LWPAD) & ~LWPAD);
+	dev->priv = (void *)(((u_long)dev->priv + ALIGN) & ~ALIGN);
 	lp = (struct de4x5_private *)dev->priv;
 	memset(dev->priv, 0, sizeof(struct de4x5_private));
 	lp->bus = tmpbus;
-	strcpy(lp->adapter_name, name);
+	lp->chipset = tmpchs;
+
+	/*
+	** Choose autosensing
+	*/
+	if (de4x5_autosense & AUTO) {
+	  lp->autosense = AUTO;
+	} else {
+	  if (lp->chipset != DC21140) {
+	    if ((lp->chipset == DC21040) && (de4x5_autosense & TP_NW)) {
+	      de4x5_autosense = TP;
+	    }
+	    if ((lp->chipset == DC21041) && (de4x5_autosense & BNC_AUI)) {
+	      de4x5_autosense = BNC;
+	    }
+	    lp->autosense = de4x5_autosense & 0x001f;
+	  } else {
+	    lp->autosense = de4x5_autosense & 0x00c0;
+	  }
+	}
+
+	sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
+	request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE :
+			                         DE4X5_EISA_TOTAL_SIZE), 
+		                                 lp->adapter_name);
 
 	/*
 	** Allocate contiguous receive buffers, long word aligned. 
 	** This could be a possible memory leak if the private area
 	** is ever hosed.
 	*/
-	for (tmp=NULL, j=0; j<BUFF_ALLOC_RETRIES && tmp==NULL; j++) {
-	  if ((tmp = (void *)kmalloc(RX_BUFF_SZ * NUM_RX_DESC + LWPAD, 
+	for (tmp=NULL, j=0; (j<BUFF_ALLOC_RETRIES) && (tmp==NULL); j++) {
+	  if ((tmp = (void *)kmalloc(RX_BUFF_SZ * NUM_RX_DESC + ALIGN, 
 	       	  		                        GFP_KERNEL)) != NULL) {
-	    tmp = (void *)(((u_long) tmp + LWPAD) & ~LWPAD);
+	    tmp = (char *)(((u_long) tmp + ALIGN) & ~ALIGN);
 	    for (i=0; i<NUM_RX_DESC; i++) {
 	      lp->rx_ring[i].status = 0;
 	      lp->rx_ring[i].des1 = RX_BUFF_SZ;
@@ -508,8 +612,10 @@
 	  lp->tx_ring[lp->txRingSize - 1].des1 |= TD_TER;
 
 	  /* Tell the adapter where the TX/RX rings are located. */
-	  outl((u_long)lp->rx_ring, DE4X5_RRBA);
-	  outl((u_long)lp->tx_ring, DE4X5_TRBA);
+	  outl((long)lp->rx_ring, DE4X5_RRBA);
+	  outl((long)lp->tx_ring, DE4X5_TRBA);
+
+	  lp->tx_enable = TRUE;
 
 	  if (dev->irq < 2) {
 #ifndef MODULE
@@ -526,7 +632,7 @@
 	      printk("      and failed to detect IRQ line.\n");
 	      status = -ENXIO;
 	    } else {
-	      for (dev->irq=0,i=0; i<sizeof(de4x5_irq) && !dev->irq; i++) {
+	      for (dev->irq=0,i=0; (i<sizeof(de4x5_irq)) && (!dev->irq); i++) {
 		if (irqnum == de4x5_irq[i]) {
 		  dev->irq = irqnum;
 		  printk("      and uses IRQ%d.\n", dev->irq);
@@ -550,13 +656,13 @@
 		                                                    dev->name);
 	  status = -ENXIO;
 	}
+	if (status) release_region(iobase, (lp->bus == PCI ? 
+					             DE4X5_PCI_TOTAL_SIZE :
+			                             DE4X5_EISA_TOTAL_SIZE));
       } else {
 	printk("      which has an Ethernet PROM CRC error.\n");
 	status = -ENXIO;
       }
-      if (status) release_region(iobase, (lp->bus == PCI ? 
-					             DE4X5_PCI_TOTAL_SIZE :
-			                             DE4X5_EISA_TOTAL_SIZE));
     } else {
       status = -ENXIO;
     }
@@ -583,13 +689,19 @@
     
     /* Fill in the generic field of the device structure. */
     ether_setup(dev);
+
+    /* Let the adapter sleep to save power */
+    if (lp->chipset == DC21041) {
+      outl(0, DE4X5_SICR);
+      outl(CFDA_PSM, PCI_CFDA);
+    }
   } else {                            /* Incorrectly initialised hardware */
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     if (lp) {
-      kfree_s(lp->rx_ring[0].buf, RX_BUFF_SZ * NUM_RX_DESC + LWPAD);
+      kfree_s(lp->rx_ring[0].buf, RX_BUFF_SZ * NUM_RX_DESC + ALIGN);
     }
     if (dev->priv) {
-      kfree_s(dev->priv, sizeof(struct de4x5_private) + LWPAD);
+      kfree_s(dev->priv, sizeof(struct de4x5_private) + ALIGN);
       dev->priv = NULL;
     }
   }
@@ -604,12 +716,15 @@
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
   short iobase = dev->base_addr;
   int i, status = 0;
-  u_long imr, omr, sts;
+  long imr, omr, sts;
 
   /*
-  ** Stop the TX and RX...
+  ** Wake up the adapter
   */
-  STOP_DE4X5;
+  if (lp->chipset == DC21041) {
+    outl(0, PCI_CFDA);
+    dce_ms_delay(10);
+  }
 
   if (request_irq(dev->irq, (void *)de4x5_interrupt, 0, lp->adapter_name)) {
     printk("de4x5_open(): Requested IRQ%d is busy\n",dev->irq);
@@ -669,21 +784,19 @@
       dev->tbusy = 0;                         
       dev->start = 1;
       dev->interrupt = UNMASK_INTERRUPTS;
-      
-      /*
-      ** Reset any pending interrupts
-      */
-      sts = inl(DE4X5_STS);
-      outl(sts, DE4X5_STS);
+      dev->trans_start = jiffies;
 
-      /*
-      ** Unmask and enable DE4X5 board interrupts
-      */
+      START_DE4X5;
+
+      /* Unmask and enable DE4X5 board interrupts */
       imr = 0;
       UNMASK_IRQs;
-      ENABLE_IRQs;
 
-      START_DE4X5;
+      /* Reset any pending (stale) interrupts */
+      sts = inl(DE4X5_STS);
+      outl(sts, DE4X5_STS);
+
+      ENABLE_IRQs;
     }
     if (de4x5_debug > 1) {
       printk("\tsts:  0x%08x\n", inl(DE4X5_STS));
@@ -703,70 +816,63 @@
 }
 
 /*
-** Initialize the DE4X5 operating conditions
+** Initialize the DE4X5 operating conditions. NB: a chip problem with the
+** DC21140 requires using perfect filtering mode for that chip. Since I can't
+** see why I'd want > 14 multicast addresses, I may change all chips to use
+** the perfect filtering mode. Keep the DMA burst length at 8: there seems
+** to be data corruption problems if it is larger (UDP errors seen from a
+** ttcp source).
 */
 static int
 de4x5_init(struct device *dev)
 {  
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
   short iobase = dev->base_addr;
-  int offset, status = 0;
-  u_long i, j, bmr, omr;
-  char *pa;
+  int status = 0;
+  long i, j, bmr, omr;
+
+  /* Lock out other processes whilst setting up the hardware */
+  set_bit(0, (void *)&dev->tbusy);
 
-  /* Ensure a full reset */
   RESET_DE4X5;
 
-  /* Set up automatic transmit polling every 1.6ms */
   bmr = inl(DE4X5_BMR);
-  bmr |= TAP_1_6MS | CAL_16LONG;
+  bmr |= PBL_8 | DESC_SKIP_LEN | CACHE_ALIGN;
   outl(bmr, DE4X5_BMR);
 
-  /* Set up imperfect filtering mode as default, turn off promiscuous mode */
-  omr = OMR_HP;
-  offset = IMPERF_PA_OFFSET;
-
-  /* Lock out other processes whilst setting up the hardware */
-  set_bit(0, (void *)&dev->tbusy);
-
-  /* Rewrite the descriptor lists' start addresses */
-  outl((u_long)lp->rx_ring, DE4X5_RRBA);  /* Start of RX Descriptor List */
-  outl((u_long)lp->tx_ring, DE4X5_TRBA);  /* Start of TX Descriptor List */
+  if (lp->chipset != DC21140) {
+    omr = TR_96;
+    lp->setup_f = HASH_PERF;
+  } else {
+    omr = OMR_SDP | OMR_SF;
+    lp->setup_f = PERFECT;
+  }
+  outl((long)lp->rx_ring, DE4X5_RRBA);
+  outl((long)lp->tx_ring, DE4X5_TRBA);
 
-  /* Reset the buffer pointers */
   lp->rx_new = lp->rx_old = 0;
   lp->tx_new = lp->tx_old = 0;
 
-  /* Initialize each descriptor ownership in the RX ring */
   for (i = 0; i < lp->rxRingSize; i++) {
     lp->rx_ring[i].status = R_OWN;
   }
 
-  /* Initialize each descriptor ownership in the TX ring */
   for (i = 0; i < lp->txRingSize; i++) {
     lp->tx_ring[i].status = 0;
   }
 
-  /* Initialise the setup frame prior to starting the receive process */
-  memset(lp->setup_frame, 0, SETUP_FRAME_LEN);
+  /* Build the setup frame depending on filtering mode */
+  SetMulticastFilter(dev, 0, NULL);
 
-  /* Insert the physical address */
-  for (pa=lp->setup_frame+offset, j=0; j<ETH_ALEN; j++) {
-    *(pa + j) = dev->dev_addr[j];
-    if (j & 0x01) pa += 2;
+  if (lp->chipset != DC21140) {
+    load_packet(dev, lp->setup_frame, HASH_F|TD_SET|SETUP_FRAME_LEN, NULL);
+  } else {
+    load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, NULL);
   }
-
-  /* Clear the multicast list */
-  set_multicast_list(dev, 0, NULL);
-
-  /* Tell the hardware there's a new packet to be sent */
-  load_packet(dev, lp->setup_frame, HASH_F | TD_SET | SETUP_FRAME_LEN, NULL);
-
-  /* Start the TX process */
   outl(omr|OMR_ST, DE4X5_OMR);
 
   /* Poll for completion of setup frame (interrupts are disabled for now) */
-  for (j=0, i=0;i<100 && j==0;i++) {
+  for (j=0, i=0;(i<100) && (j==0);i++) {
     if (lp->tx_ring[lp->tx_new].status >= 0) j=1;
   }
   outl(omr, DE4X5_OMR);                        /* Stop everything! */
@@ -777,7 +883,6 @@
     status = -EIO;
   }
 
-  /* Update pointers */
   lp->tx_new = (++lp->tx_new) % lp->txRingSize;
   lp->tx_old = lp->tx_new;
 
@@ -807,13 +912,9 @@
   ** The 'lostMedia' threshold accounts for transient errors that
   ** were noticed when switching media.
   */
-  if (dev->tbusy || (lp->lostMedia > 3)) {
+  if (dev->tbusy || (lp->lostMedia > LOST_MEDIA_THRESHOLD)) {
     int tickssofar = jiffies - dev->trans_start;
-    if (tickssofar < 10 && !lp->lostMedia) {
-      /* Check if TX ring is full or not - 'tbusy' cleared if not full. */
-      if ((TX_BUFFS_AVAIL > 0) && dev->tbusy) {
-	dev->tbusy = 0;
-      }
+    if (tickssofar < 10 && (lp->lostMedia <= LOST_MEDIA_THRESHOLD)) {
       status = -1;
     } else {
       printk("%s: transmit timed out, status %08x, tbusy:%d, lostMedia:%d tickssofar:%d, resetting.\n",dev->name, inl(DE4X5_STS), dev->tbusy, lp->lostMedia, tickssofar);
@@ -825,21 +926,21 @@
       /* Unmask DE4X5 board interrupts */
       if (!status) {
 	/* Start here to clean stale interrupts later */
+	dev->interrupt = UNMASK_INTERRUPTS;
+	dev->start = 1;
+	dev->tbusy = 0;                         
 	dev->trans_start = jiffies;
+      
 	START_DE4X5;
 
+	/* Unmask DE4X5 board interrupts */
+	imr = 0;
+	UNMASK_IRQs;
+
 	/* Clear any pending (stale) interrupts */
 	sts = inl(DE4X5_STS);
 	outl(sts, DE4X5_STS);
 
-	/* Unmask DE4X5 board interrupts */
-	imr = 0;
-	UNMASK_IRQs;
-	  
-	dev->interrupt = UNMASK_INTERRUPTS;
-	dev->start = 1;
-	dev->tbusy = 0;                         
-      
 	ENABLE_IRQs;
       } else {
 	printk("%s: hardware initialisation failure, status %08x.\n",
@@ -857,20 +958,18 @@
     if (set_bit(0, (void*)&dev->tbusy) != 0)
       printk("%s: Transmitter access conflict.\n", dev->name);
 
-    if (TX_BUFFS_AVAIL > 0) {                   /* Fill in a Tx ring entry */
-      if (((u_long)skb->data & ~0x03) != (u_long)skb->data) {
-	printk("%s: TX skb buffer alignment prob..\n", dev->name);
-      }
-
+    if (TX_BUFFS_AVAIL) {                       /* Fill in a Tx ring entry */
       load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
-      outl(POLL_DEMAND, DE4X5_TPD);             /* Start the TX */
+      if (lp->tx_enable) {
+	outl(POLL_DEMAND, DE4X5_TPD);           /* Start the TX */
+      }
 
       lp->tx_new = (++lp->tx_new) % lp->txRingSize; /* Ensure a wrap */
 	
       dev->trans_start = jiffies;
     }
 
-    if (TX_BUFFS_AVAIL > 0) {
+    if (TX_BUFFS_AVAIL) {
       dev->tbusy = 0;                           /* Another pkt may be queued */
     }
   }
@@ -882,12 +981,12 @@
 ** The DE4X5 interrupt handler. 
 */
 static void
-de4x5_interrupt(int irq, struct pt_regs * regs)
+de4x5_interrupt(int irq, struct pt_regs *regs)
 {
     struct device *dev = (struct device *)(irq2dev_map[irq]);
     struct de4x5_private *lp;
     int iobase;
-    u_long imr, sts;
+    u_long imr, omr, sts;
 
     if (dev == NULL) {
 	printk ("de4x5_interrupt(): irq %d for unknown device.\n", irq);
@@ -909,19 +1008,22 @@
       sts = inl(DE4X5_STS);
       MASK_IRQs;
 
-      /* 
-      ** Acknowledge the DE4X5 board interrupts
-      */
-      outl(sts, DE4X5_STS);
+      outl(sts, DE4X5_STS);              /* Reset the board interrupts */
 
-      if (sts & STS_RI)	                 /* Rx interrupt (packet[s] arrived) */
+      if (sts & (STS_RI | STS_RU))	 /* Rx interrupt (packet[s] arrived) */
 	de4x5_rx(dev);
 
-      if (sts & STS_TI)                  /* Tx interrupt (packet sent) */
+      if (sts & (STS_TI | STS_TU))       /* Tx interrupt (packet sent) */
 	de4x5_tx(dev); 
 
-      if ((TX_BUFFS_AVAIL > 0) && dev->tbusy) { /* any resources available? */
-	dev->tbusy = 0;                  /* clear TX busy flag */
+      if (sts & STS_SE) {                /* Bus Error */
+	STOP_DE4X5;
+	printk("%s: Fatal bus error occurred, sts=0x%08lx, device stopped.\n", 
+	                                                       dev->name, sts);
+      }
+
+      if (TX_BUFFS_AVAIL && dev->tbusy) {/* Any resources available? */
+	dev->tbusy = 0;                  /* Clear TX busy flag */
 	mark_bh(NET_BH);
       }
 
@@ -941,7 +1043,6 @@
   volatile long status;
   char *buf;
 
-  /* Loop over any new packets for sending up the stack */
   for (entry = lp->rx_new; lp->rx_ring[entry].status >= 0;entry = lp->rx_new) {
     status = lp->rx_ring[entry].status;
 
@@ -957,7 +1058,7 @@
 	if (status & RD_OF)           lp->stats.rx_fifo_errors++;
       } else {                              /* A valid frame received */
 	struct sk_buff *skb;
-	short pkt_len = (short)(lp->rx_ring[entry].status >> 16);
+	short pkt_len = (short)(lp->rx_ring[entry].status >> 16) - 4;
 
 	if ((skb = alloc_skb(pkt_len, GFP_ATOMIC)) != NULL) {
 	  skb->len = pkt_len;
@@ -982,7 +1083,7 @@
 	  */
 	  lp->stats.rx_packets++;
 	  for (i=1; i<DE4X5_PKT_STAT_SZ-1; i++) {
-	    if (pkt_len < i*DE4X5_PKT_BIN_SZ) {
+	    if (pkt_len < (i*DE4X5_PKT_BIN_SZ)) {
 	      lp->pktStats.bins[i]++;
 	      i = DE4X5_PKT_STAT_SZ;
 	    }
@@ -1034,7 +1135,7 @@
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
   int entry, iobase = dev->base_addr;
-  volatile long status;
+  long status;
 
   for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
     status = lp->tx_ring[entry].status;
@@ -1100,6 +1201,12 @@
 
   MOD_DEC_USE_COUNT;
 
+  /* Put the adapter to sleep to save power */
+  if (lp->chipset == DC21041) {
+    outl(0, DE4X5_SICR);
+    outl(CFDA_PSM, PCI_CFDA);
+  }
+
   return 0;
 }
 
@@ -1109,7 +1216,7 @@
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
   int iobase = dev->base_addr;
 
-  lp->stats.rx_missed_errors = (int) inl(DE4X5_MFC);
+  lp->stats.rx_missed_errors = (int) (inl(DE4X5_MFC) & (MFC_OVFL | MFC_CNTR));
     
   return &lp->stats;
 }
@@ -1128,42 +1235,39 @@
 }
 /*
 ** Set or clear the multicast filter for this adaptor.
-** num_addrs == -1	Promiscuous mode, receive all packets
+** num_addrs == -1	Promiscuous mode, receive all packets - not supported.
+**                      Use the ioctls.
 ** num_addrs == 0	Normal mode, clear multicast list
 ** num_addrs > 0	Multicast mode, receive normal and MC packets, and do
 ** 			best-effort filtering.
 ** num_addrs == HASH_TABLE_LEN
-**	                Set all multicast bits
+**	                Set all multicast bits (pass all multicasts).
 */
 static void
 set_multicast_list(struct device *dev, int num_addrs, void *addrs)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
   int iobase = dev->base_addr;
-  u_long omr;
 
   /* First, double check that the adapter is open */
   if (irq2dev_map[dev->irq] != NULL) {
-    omr = inl(DE4X5_OMR);
-
     if (num_addrs >= 0) {
-      SetMulticastFilter(dev, num_addrs, (char *)addrs, lp->setup_frame);
-
-      /* Tell the hardware that there's a new packet to be sent */
-      load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | 
+      SetMulticastFilter(dev, num_addrs, (char *)addrs);
+      if (lp->setup_f == HASH_PERF) {
+	load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | 
+		                                        SETUP_FRAME_LEN, NULL);
+      } else {
+	load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
 		                                        SETUP_FRAME_LEN, NULL);
+      }
+
       lp->tx_new = (++lp->tx_new) % lp->txRingSize;
       outl(POLL_DEMAND, DE4X5_TPD);                /* Start the TX */
-
-      omr &= ~OMR_PR;
-      omr |= OMR_PM;
-      outl(omr, DE4X5_OMR);
-    } else {                             /* set promiscuous mode */
-      omr |= OMR_PR;
-      omr &= ~OMR_PM;
-      outl(omr, DE4X5_OMR);
+      dev->trans_start = jiffies;
     }
   }
+
+  return;
 }
 
 /*
@@ -1171,49 +1275,58 @@
 ** from a list of ethernet multicast addresses.
 ** Little endian crc one liner from Matt Thomas, DEC.
 */
-static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs, char *multicast_table)
+static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs)
 {
-  char j, bit, byte;
-  long *p = (long *) multicast_table;
-  int i;
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  int i, j, bit, byte, iobase = dev->base_addr;
   u_short hashcode;
-  u_long crc, poly = CRC_POLYNOMIAL_LE;
+  u_long crc, omr, poly = CRC_POLYNOMIAL_LE;
+  char *pa;
 
-  if (num_addrs == HASH_TABLE_LEN) {
-    for (i=0; i<(HASH_TABLE_LEN >> 4); i++) {
-      *p++ = 0x0000ffff;
-    }
-  } else {
-    /* Clear the multicast table except for the broadcast bit */
-    memset(multicast_table, 0, (HASH_TABLE_LEN >> 2));
-    *(multicast_table + (HASH_TABLE_LEN >> 3) - 3) = 0x80;
-
-    /* Now update the table */
-    for (i=0;i<num_addrs;i++) {              /* for each address in the list */
-      if ((*addrs & 0x01) == 1) {            /* multicast address? */ 
-	crc = 0xffffffff;                    /* init CRC for each address */
-	for (byte=0;byte<ETH_ALEN;byte++) {  /* for each address byte */
+  omr = inl(DE4X5_OMR);
+  pa = build_setup_frame(dev, ALL);          /* Build the basic frame */
+
+  if (lp->setup_f == HASH_PERF) {
+    if (num_addrs == HASH_TABLE_LEN) {       /* Pass all multicasts */
+      omr |= OMR_PM;
+    } else {
+      omr &= ~OMR_PM;
+                                             /* Now update the MCA table */
+      for (i=0;i<num_addrs;i++) {            /* for each address in the list */
+	if ((*addrs & 0x01) == 1) {          /* multicast address? */ 
+	  crc = 0xffffffff;                  /* init CRC for each address */
+	  for (byte=0;byte<ETH_ALEN;byte++) {/* for each address byte */
 	                                     /* process each address bit */ 
-	  for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
-	    crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0);
+	    for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
+	      crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0);
+	    }
 	  }
-	}
-	hashcode = crc & ((1 << 9) - 1);     /* hashcode is 9 LSb of CRC */
+	  hashcode = crc & HASH_BITS;        /* hashcode is 9 LSb of CRC */
 
-	byte = hashcode >> 3;                /* bit[3-8] -> byte in filter */
-	bit = 1 << (hashcode & 0x07);        /* bit[0-2] -> bit in byte */
+	  byte = hashcode >> 3;              /* bit[3-8] -> byte in filter */
+	  bit = 1 << (hashcode & 0x07);      /* bit[0-2] -> bit in byte */
 
-	byte <<= 1;                          /* calc offset into setup frame */
-	if (byte & 0x02) {
-	  byte -= 1;
+	  byte <<= 1;                        /* calc offset into setup frame */
+	  if (byte & 0x02) {
+	    byte -= 1;
+	  }
+	  lp->setup_frame[byte] |= bit;
+	  
+	} else {                             /* skip this address */
+	  addrs += ETH_ALEN;
 	}
-	multicast_table[byte] |= bit;
-
-      } else {                               /* skip this address */
-	addrs += ETH_ALEN;
+      }
+    }
+  } else {                                   /* Perfect filtering */
+    omr &= ~OMR_PM;
+    for (j=0; j<num_addrs; j++) {
+      for (i=0; i<ETH_ALEN; i++) { 
+	*(pa + (i&1)) = *addrs++;
+	if (i & 0x01) pa += 4;
       }
     }
   }
+  outl(omr, DE4X5_OMR);
 
   return;
 }
@@ -1226,8 +1339,10 @@
 {
   int i, maxSlots;
   int status;
-  u_short iobase;
+  u_short vendor, device, iobase;
   struct bus_type *lp = &bus;
+  char name[DE4X5_STRLEN];
+  long cfid;
 
   if (!ioaddr && autoprobed) return ;            /* Been here before ! */
   if ((ioaddr < 0x1000) && (ioaddr > 0)) return; /* PCI MODULE special */
@@ -1244,17 +1359,30 @@
     maxSlots = i + 1;
   }
 
-  for (status = -ENODEV; i<maxSlots && dev!=NULL; i++, iobase+=EISA_SLOT_INC) {
-    if ((DevicePresent(EISA_APROM) == 0) || is_zynx) { 
-      if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) {
-	if ((dev = alloc_device(dev, iobase)) != NULL) {
-	  if ((status = de4x5_hw_init(dev, iobase)) == 0) {
-	    num_de4x5s++;
-	  }
+  for (status = -ENODEV; (i<maxSlots) && (dev!=NULL); i++, iobase+=EISA_SLOT_INC) {
+    if (EISA_signature(name, EISA_ID)) {
+      cfid = inl(PCI_CFID);
+      device = (u_short)(cfid >> 16);
+      vendor = (u_short) cfid;
+
+      lp->bus = EISA;
+      lp->chipset = device;
+      if (DevicePresent(EISA_APROM) == 0) { 
+	/* Write the PCI Configuration Registers */
+	outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
+	outl(0x00004000, PCI_CFLT);
+	outl((u_long)iobase, PCI_CBIO);
+
+	if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) {
+	  if ((dev = alloc_device(dev, iobase)) != NULL) {
+	    if ((status = de4x5_hw_init(dev, iobase)) == 0) {
+	      num_de4x5s++;
+	    }
 	  num_eth++;
+	  }
+	} else if (autoprobed) {
+	  printk("%s: region already allocated at 0x%04x.\n", dev->name, iobase);
 	}
-      } else if (autoprobed) {
-	printk("%s: region already allocated at 0x%04x.\n", dev->name, iobase);
       }
     }
   }
@@ -1295,15 +1423,18 @@
       dev_last = PCI_LAST_DEV;
     }
 
-    for (; dev_num < dev_last && dev != NULL; dev_num++) {
+    for (; (dev_num < dev_last) && (dev != NULL); dev_num++) {
       pcibios_read_config_dword(pb, PCI_DEVICE, PCI_CLASS_REVISION, &class);
       if (class != 0xffffffff) {
 	pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
 	pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &device);
-	if ((vendor == DC21040_VID) && (device == DC21040_DID)) {
+	if (is_DC21040 || is_DC21041 || is_DC21140) {
 	  /* Set the device number information */
 	  lp->device = dev_num;
 
+	  /* Set the chipset information */
+	  lp->chipset = device;
+
 	  /* Get the board I/O address */
 	  pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &iobase);
 	  iobase &= CBIO_MASK;
@@ -1317,7 +1448,7 @@
 	  pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
 
 	  /* If there is a device and I/O region is open, initialise dev. */
-	  if ((DevicePresent(DE4X5_APROM) == 0) || is_zynx) {
+	  if ((DevicePresent(DE4X5_APROM) == 0) || is_not_dec) {
 	    if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
 	      if ((dev = alloc_device(dev, iobase)) != NULL) {
 		dev->irq = irq;
@@ -1457,120 +1588,322 @@
 static int autoconf_media(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int media, entry, iobase = dev->base_addr;
-  char frame[64];
-  u_long i, omr, sisr, linkBad;
-/*  u_long t_330ms = 920000;*/
-  u_long t_3s    = 8000000;
+  int iobase = dev->base_addr;
 
-  /* Set up for TP port, with LEDs */
-  media = TP;
-  RESET_SIA;
-  outl(SICR_OE57 | SICR_SEL | SICR_SRL, DE4X5_SICR);
+  if (lp->chipset == DC21040) {
+    lp->media = (lp->autosense == AUTO ? TP : lp->autosense);
+    dc21040_autoconf(dev);
+  } else if (lp->chipset == DC21041) {
+    lp->media = (lp->autosense == AUTO ? TP_NW : lp->autosense);
+    dc21041_autoconf(dev);
+  } else if (lp->chipset == DC21140) {
+    /* Force 10Mb/s (_100Mb for 100Mb/s) */
+    lp->media = (lp->autosense == AUTO ? _10Mb : lp->autosense);
+    dc21140_autoconf(dev);
+  }
+
+  if (de4x5_debug >= 1 ) {
+    if (lp->chipset != DC21140) {
+      printk("%s: Media is %s\n",dev->name,
+	                                (lp->media == NC  ? "unconnected!" :
+					(lp->media == TP  ? "TP." :
+					(lp->media == ANS ? "TP/Nway." :
+					(lp->media == BNC ? "BNC." : 
+					(lp->media == AUI ? "AUI." : 
+                                                            "BNC/AUI."
+					))))));
+    } else {
+      printk("%s: Mode is forced to %s\n",dev->name,
+	                                (lp->media == NC      ? "link down.":
+					(lp->media == _100Mb  ? "100Mb/s." :
+					(lp->media == _10Mb   ? "10Mb/s." :
+					                        "\?\?\?"
+					))));
+    }
+  }
 
-  /* Test the TP port */
-  for (linkBad=1,i=0;i<t_3s && linkBad;i++) {
-    if (((sisr = inl(DE4X5_SISR)) & SISR_LKF) == 0) linkBad = 0;
-    if (sisr & SISR_NCR) break;
+  if (lp->media) {
+    lp->lostMedia = 0;
+    inl(DE4X5_MFC);                         /* Zero the lost frames counter */
   }
-    
-  if (linkBad) {
-    /* Set up for BNC (Thinwire) port, with LEDs */
-    media = BNC;
-    RESET_SIA;
-    outl(SIGR_JCK | SIGR_HUJ, DE4X5_SIGR);
-    outl(STRR_CLD | STRR_CSQ | STRR_RSQ | STRR_DREN | STRR_ECEN, DE4X5_STRR);
-    outl(SICR_OE57| SICR_OE24 | SICR_OE13 | SICR_SEL |
- 	                                    SICR_AUI | SICR_SRL, DE4X5_SICR);
+  dce_ms_delay(10);
+
+  return (lp->media);
+}
+
+static void dc21040_autoconf(struct device *dev)
+{
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  int iobase = dev->base_addr;
+  u_long i, sisr = 0, linkBad;
+  u_long t_3s    = 3000;
+
+  switch (lp->media) {
+  case TP:
+    reset_init_sia(dev, 0x8f01, 0xffff, 0x0000);
+    for (linkBad=1,i=0;(i<t_3s) && linkBad && !(sisr & SISR_NCR);i++) {
+      if (((sisr = inl(DE4X5_SISR)) & SISR_LKF) == 0) linkBad = 0;
+      dce_ms_delay(1);
+    }
+    if (linkBad && (lp->autosense == AUTO)) {
+      lp->media = BNC_AUI;
+      dc21040_autoconf(dev);
+    }
+    break;
 
-    /* Wait 330ms */
+  case BNC:
+  case AUI:
+  case BNC_AUI:
+    reset_init_sia(dev, 0x8f09, 0x0705, 0x0006);
     dce_ms_delay(330);
-/*    for (i=0; i<t_330ms; i++) {
-      sisr = inl(DE4X5_SISR);
+    linkBad = ping_media(dev);
+    if (linkBad && (lp->autosense == AUTO)) {
+      lp->media = NC;
+      dc21040_autoconf(dev);
     }
+    break;
+
+  case NC:
+    reset_init_sia(dev, 0x8f01, 0xffff, 0x0000);
+    break;
+  }
+
+  return;
+}
+
+/*
+** Autoconfigure the media when using the DC21041. AUI needs to be tested
+** before BNC, because the BNC port will indicate activity if it's not
+** terminated correctly. The only way to test for that is to place a loopback
+** packet onto the network and watch for errors.
 */
-    /* Make up a dummy packet with CRC error */
-    create_packet(dev, frame, sizeof(frame));
+static void dc21041_autoconf(struct device *dev)
+{
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  int iobase = dev->base_addr;
+  u_long sts, irqs, irq_mask, omr;
 
-    /* Setup the packet descriptor */
-    entry = lp->tx_new;                        /* Remember the ring position */
-    load_packet(dev, frame, TD_LS | TD_FS | TD_AC | sizeof(frame), NULL);
+  switch (lp->media) {
+  case TP_NW:
+    omr = inl(DE4X5_OMR);        /* Set up full duplex for the autonegotiate */
+    outl(omr | OMR_FD, DE4X5_OMR);
+    irqs = STS_LNF | STS_LNP;
+    irq_mask = IMR_LFM | IMR_LPM;
+    sts = test_media(dev, irqs, irq_mask, 0xef01, 0xffff, 0x0008, 2400);
+    if (sts & STS_LNP) {
+      lp->media = ANS;
+    } else {
+      lp->media = AUI;
+    }
+    dc21041_autoconf(dev);
+    break;
 
-    /* Start the TX process */
-    omr = inl(DE4X5_OMR);
-    outl(omr|OMR_ST, DE4X5_OMR);
+  case ANS:
+    irqs = STS_LNP;
+    irq_mask = IMR_LPM;
+    sts = test_ans(dev, irqs, irq_mask, 3000);
+    if (!(sts & STS_LNP) && (lp->autosense == AUTO)) {
+      lp->media = TP;
+      dc21041_autoconf(dev);
+    }
+    break;
 
-    /* Update pointers */
-    lp->tx_new = (++lp->tx_new) % lp->txRingSize;
-    lp->tx_old = lp->tx_new;
+  case TP:
+    omr = inl(DE4X5_OMR);                      /* Set up half duplex for TP */
+    outl(omr & ~OMR_FD, DE4X5_OMR);
+    irqs = STS_LNF | STS_LNP;
+    irq_mask = IMR_LFM | IMR_LPM;
+    sts = test_media(dev, irqs, irq_mask, 0xef01, 0xff3f, 0x0008, 2400);
+    if (!(sts & STS_LNP) && (lp->autosense == AUTO)) {
+      if (inl(DE4X5_SISR) & SISR_NRA) {    /* Non selected port activity */
+	lp->media = AUI;
+      } else {
+	lp->media = BNC;
+      }
+      dc21041_autoconf(dev);
+    }
+    break;
 
-    /* 
-    ** Poll for completion of frame (interrupts are disabled for now)...
-    ** Allow upto 3 seconds to complete.
-    */
-    for (linkBad=1,i=0;i<t_3s && linkBad;i++) {
-      if ((inl(DE4X5_SISR) & SISR_NCR) == 1) break;
-      if (lp->tx_ring[entry].status >= 0) linkBad=0;
+  case AUI:
+    omr = inl(DE4X5_OMR);                      /* Set up half duplex for AUI */
+    outl(omr & ~OMR_FD, DE4X5_OMR);
+    irqs = 0;
+    irq_mask = 0;
+    sts = test_media(dev, irqs, irq_mask, 0xef09, 0xf7fd, 0x000e, 1000);
+    if (!(inl(DE4X5_SISR) & SISR_SRA) && (lp->autosense == AUTO)) {
+      lp->media = BNC;
+      dc21041_autoconf(dev);
     }
-    
-    outl(omr, DE4X5_OMR);                        /* Stop everything! */
+    break;
 
-    if (linkBad || (lp->tx_ring[entry].status & TD_ES)) {
-      /* Set up for AUI (Thickwire) port, with LEDs */
-      media = AUI;
-      RESET_SIA;
-      outl(SIGR_JCK | SIGR_HUJ, DE4X5_SIGR);
-      outl(STRR_CLD | STRR_CSQ | STRR_RSQ | STRR_DREN | STRR_ECEN, DE4X5_STRR);
-      outl(SICR_OE57| SICR_SEL | SICR_AUI | SICR_SRL, DE4X5_SICR);
-      
-      /* Wait 330ms */
-      dce_ms_delay(330);
+  case BNC:
+    omr = inl(DE4X5_OMR);                      /* Set up half duplex for BNC */
+    outl(omr & ~OMR_FD, DE4X5_OMR);
+    irqs = 0;
+    irq_mask = 0;
+    sts = test_media(dev, irqs, irq_mask, 0xef09, 0xf7fd, 0x0006, 1000);
+    if (!(inl(DE4X5_SISR) & SISR_SRA) && (lp->autosense == AUTO)) {
+      lp->media = NC;
+    } else {                                   /* Ensure media connected */
+      if (ping_media(dev)) lp->media = NC;
+    }
+    break;
 
-      /* Setup the packet descriptor */
-      entry = lp->tx_new;                      /* Remember the ring position */
-      load_packet(dev, frame, TD_LS | TD_FS | TD_AC | sizeof(frame), NULL);
-      
-      /* Start the TX process */
-      omr = inl(DE4X5_OMR);
-      outl(omr|OMR_ST, DE4X5_OMR);
+  case NC:
+    omr = inl(DE4X5_OMR);        /* Set up full duplex for the autonegotiate */
+    outl(omr | OMR_FD, DE4X5_OMR);
+    reset_init_sia(dev, 0xef01, 0xffff, 0x0008);/* Initialise the SIA */
+    break;
+  }
 
-      /* Update pointers */
-      lp->tx_new = (++lp->tx_new) % lp->txRingSize;
-      lp->tx_old = lp->tx_new;
+  return;
+}
 
-      /* 
-      ** Poll for completion of frame (interrupts are disabled for now)...
-      ** Allow 3 seconds to complete.
-      */
-      for (linkBad=1,i=0;i<t_3s && linkBad;i++) {
-	if ((inl(DE4X5_SISR) & SISR_NCR) == 1) break;
-	if (lp->tx_ring[entry].status >= 0) linkBad=0;
-      }
-    
-      outl(omr, DE4X5_OMR);                        /* Stop everything! */
+/*
+** Reduced feature version (temporary I hope)
+*/
+static void dc21140_autoconf(struct device *dev)
+{
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  int iobase = dev->base_addr;
+  u_long omr;
 
-      if (linkBad || (lp->tx_ring[entry].status & TD_ES)) {
-	/* Reset the SIA */
-	outl(SICR_RESET, DE4X5_SICR);        /* Reset SIA connectivity regs */
-	outl(STRR_RESET, DE4X5_STRR);        /* Write reset values */
-	outl(SIGR_RESET, DE4X5_SIGR);        /* Write reset values */
+  switch(lp->media) {
+  case _100Mb:      /* Set 100Mb/s, MII Port with PCS Function and Scrambler */
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));
+    outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);
+    outl(GEP_FDXD | GEP_MODE, DE4X5_GEP);
+    break;
 
-	media = NC;
-      }
-    } 
+  case _10Mb:       /* Set conventional 10Mb/s ENDEC interface */
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));
+    outl(omr | OMR_TTM, DE4X5_OMR);
+    outl(GEP_FDXD, DE4X5_GEP);
+    break;
   }
 
-  if (de4x5_debug >= 1 ) {
-    printk("%s: Media is %s.\n",dev->name, 
-                                 (media == NC  ? "unconnected to this device" :
-                                 (media == TP  ? "TP" :
-                                 (media == BNC ? "BNC" : 
-                                                 "AUI"))));
+  return;
+}
+
+static long test_media(struct device *dev, long irqs, long irq_mask, long csr13, long csr14, long csr15, long msec)
+{
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  int iobase = dev->base_addr;
+  long sts, time, csr12;
+
+  reset_init_sia(dev, csr13, csr14, csr15);
+
+  /* Set link_fail_inhibit_timer */
+  load_ms_timer(dev, msec);
+
+  /* clear all pending interrupts */
+  sts = inl(DE4X5_STS);
+  outl(sts, DE4X5_STS);
+
+  /* clear csr12 NRA and SRA bits */
+  csr12 = inl(DE4X5_SISR);
+  outl(csr12, DE4X5_SISR);
+
+  /* Poll for timeout - timer interrupt doesn't work correctly */
+  do {
+    time = inl(DE4X5_GPT) & GPT_VAL;
+    sts = inl(DE4X5_STS);
+  } while ((time != 0) && !(sts & irqs));
+
+  sts = inl(DE4X5_STS);
+
+  return sts;
+}
+
+/*
+** Send a packet onto the media and watch for send errors that indicate the
+** media is bad or unconnected.
+*/
+static long ping_media(struct device *dev)
+{
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  int entry, iobase = dev->base_addr;
+  char frame[64];
+  long i, linkBad, omr;
+  u_long t_3s    = 3000;
+
+  create_packet(dev, frame, sizeof(frame));
+
+  entry = lp->tx_new;                        /* Remember the ring position */
+  load_packet(dev, frame, TD_LS | TD_FS | sizeof(frame),NULL);
+
+  omr = inl(DE4X5_OMR);
+  outl(omr|OMR_ST, DE4X5_OMR);
+
+  lp->tx_new = (++lp->tx_new) % lp->txRingSize;
+  lp->tx_old = lp->tx_new;
+
+  /* Poll for completion of frame (interrupts are disabled for now)... */
+  for (linkBad=1,i=0;(i<t_3s) && linkBad;i++) {
+    if ((inl(DE4X5_SISR) & SISR_NCR) == 1) break;
+    if (lp->tx_ring[entry].status >= 0) linkBad=0;
+    dce_ms_delay(1);
   }
+  outl(omr, DE4X5_OMR); 
+
+  return ((linkBad || (lp->tx_ring[entry].status & TD_ES)) ? 1 : 0);
+}
+
+/*
+** Check the Auto Negotiation State. Return OK when a link pass interrupt
+** is received and the auto-negotiation status is NWAY OK.
+*/
+static int test_ans(struct device *dev, long irqs, long irq_mask, long msec)
+{
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  int iobase = dev->base_addr;
+  long sts, ans;
+
+  outl(irq_mask, DE4X5_IMR);
+
+  /* Set timeout limit */
+  load_ms_timer(dev, msec);
+
+  /* clear all pending interrupts */
+  sts = inl(DE4X5_STS);
+  outl(sts, DE4X5_STS);
+
+  /* Poll for interrupts */
+  do {
+    ans = inl(DE4X5_SISR) & SISR_ANS;
+    sts = inl(DE4X5_STS);
+  } while (!(sts & irqs) && (ans ^ ANS_NWOK) != 0);
+
+  return ((sts & STS_LNP) && ((ans ^ ANS_NWOK) == 0) ? STS_LNP : 0);
+}
+
+/*
+**
+*/
+static void reset_init_sia(struct device *dev, long sicr, long strr, long sigr)
+{
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  int iobase = dev->base_addr;
+
+  RESET_SIA;
+  outl(sigr, DE4X5_SIGR);
+  outl(strr, DE4X5_STRR);
+  outl(sicr, DE4X5_SICR);
+
+  return;
+}
+
+/*
+** Load the timer on the DC21041 and 21140. Max time is 13.42 secs.
+*/
+static void load_ms_timer(struct device *dev, u_long msec)
+{
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  int iobase = dev->base_addr;
 
-  if (media) lp->lostMedia = 0;
+  outl((long)(msec * 10000)/2048, DE4X5_GPT);
 
-  return media;
+  return;
 }
 
 /*
@@ -1578,7 +1911,7 @@
 */
 static void create_packet(struct device *dev, char *frame, int len)
 {
-  int i, j;
+  int i;
   char *buf = frame;
 
   for (i=0; i<ETH_ALEN; i++) {             /* Use this source address */
@@ -1587,58 +1920,25 @@
   for (i=0; i<ETH_ALEN; i++) {             /* Use this destination address */
     *buf++ = dev->dev_addr[i];
   }
-  for (j=1; j>=0; j--) {                   /* Packet length (2 bytes) */
-    *buf++ = (char) ((len >> 8*j) & 0xff);
-  }
-  *buf++ = 0;                              /* Data */
 
-  for (i=len-4; i<len; i++) {              /* CRC */
-    buf[i] = 0;
-  }
+  *buf++ = 0;                              /* Packet length (2 bytes) */
+  *buf++ = 1;
   
   return;
 }
 
 /*
-** Get the timer ticks from the PIT
-*/
-static u_short dce_get_ticks(void)
-{
-  u_short ticks = 0;
-  
-  /* Command 8254 to latch T0's count */
-  outb(TIMER_PORT, TIMER_LATCH);
-  
-  /* Read the counter */
-  ticks = inb(TIMER_READ);
-  ticks |= (inb(TIMER_READ) << 8);
-  
-  return ticks;
-}
-
-/*
 ** Known delay in microseconds
 */
 static void dce_us_delay(u_long usec)
 {
-  u_long i, start, now, quant=(DELAY_QUANT*1000)/TIMER_TICK+1;
-  
-  for (i=0; i<usec/DELAY_QUANT; i++) {
-    start=dce_get_ticks();  
-    for (now=start; (start-now)<quant;) {
-      now=dce_get_ticks();
-      if (now > start) {         /* Wrapped counter counting down */
-	quant -= start;
-	start = (1 << TIMER_WIDTH);
-      }
-    }
-  }
+  udelay(usec);
 
   return;
 }
 
 /*
-** Known delay in milliseconds
+** Known delay in milliseconds, in millisecond steps.
 */
 static void dce_ms_delay(u_long msec)
 {
@@ -1655,18 +1955,19 @@
 /*
 ** Look for a particular board name in the EISA configuration space
 */
-static void EISA_signature(char *name, short iobase)
+int EISA_signature(char *name, long eisa_id)
 {
   unsigned long i;
   char *signatures[] = DE4X5_SIGNATURE;
-  char ManCode[8];
+  char ManCode[DE4X5_STRLEN];
   union {
-    u_long ID;
-    u_char Id[4];
+    long ID;
+    char Id[4];
   } Eisa;
+  int status = 0;
 
-  strcpy(name, "");
-  Eisa.ID = inl(iobase);
+  *name = '\0';
+  Eisa.ID = inl(eisa_id);
 
   ManCode[0]=(((Eisa.Id[0]>>2)&0x1f)+0x40);
   ManCode[1]=(((Eisa.Id[1]&0xe0)>>5)+((Eisa.Id[0]&0x03)<<3)+0x40);
@@ -1675,13 +1976,14 @@
   ManCode[4]=(((Eisa.Id[3]>>4)&0x0f)+0x30);
   ManCode[5]='\0';
 
-  for (i=0;*signatures[i] != '\0' && *name == '\0';i++) {
+  for (i=0;(*signatures[i] != '\0') && (*name == '\0');i++) {
     if (strstr(ManCode, signatures[i]) != NULL) {
       strcpy(name,ManCode);
+      status = 1;
     }
   }
-  
-  return;                                   /* return the device name string */
+
+  return status;                           /* return the device name string */
 }
 
 /*
@@ -1715,26 +2017,34 @@
   dev.llsig.b = ETH_PROM_SIG;
   sigLength = sizeof(long) << 1;
 
-  for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) {
-    if (lp->bus == PCI) {
-      while ((tmp = inl(aprom_addr)) < 0);
-      data = (char)tmp;
-    } else {
-      data = inb(aprom_addr);
-    }
-    if (dev.Sig[j] == data) {   /* track signature */
-      j++;
-    } else {                    /* lost signature; begin search again */
-      if (data == dev.Sig[0]) {
-	j=1;
+  if (lp->chipset == DC21040) {
+    for (i=0,j=0;(j<sigLength) && (i<PROBE_LENGTH+sigLength-1);i++) {
+      if (lp->bus == PCI) {
+	while ((tmp = inl(aprom_addr)) < 0);
+	data = (char)tmp;
       } else {
-	j=0;
+	data = inb(aprom_addr);
+      }
+      if (dev.Sig[j] == data) {   /* track signature */
+	j++;
+      } else {                    /* lost signature; begin search again */
+	if (data == dev.Sig[0]) {
+	  j=1;
+	} else {
+	  j=0;
+	}
       }
     }
-  }
 
-  if (j!=sigLength) {
-    status = -ENODEV;           /* search failed */
+    if (j!=sigLength) {
+      status = -ENODEV;           /* search failed */
+    }
+
+  } else {                        /* use new srom */
+    short *p = (short *)&lp->srom;
+    for (i=0; i<(sizeof(struct de4x5_srom)>>1); i++) {
+      *p++ = srom_rd(aprom_addr, i);
+    }
   }
 
   return status;
@@ -1753,12 +2063,17 @@
     if (k > 0xffff) k-=0xffff;
 
     if (lp->bus == PCI) {
-      while ((tmp = inl(DE4X5_APROM)) < 0);
-      k += (u_char) tmp;
-      dev->dev_addr[i++] = (u_char) tmp;
-      while ((tmp = inl(DE4X5_APROM)) < 0);
-      k += (u_short) (tmp << 8);
-      dev->dev_addr[i++] = (u_char) tmp;
+      if (lp->chipset == DC21040) {
+	while ((tmp = inl(DE4X5_APROM)) < 0);
+	k += (u_char) tmp;
+	dev->dev_addr[i++] = (u_char) tmp;
+	while ((tmp = inl(DE4X5_APROM)) < 0);
+	k += (u_short) (tmp << 8);
+	dev->dev_addr[i++] = (u_char) tmp;
+      } else {
+	dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; i++;
+	dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; i++;
+      }
     } else {
       k += (u_char) (tmp = inb(EISA_APROM));
       dev->dev_addr[i++] = (u_char) tmp;
@@ -1771,21 +2086,158 @@
   if (k == 0xffff) k=0;
 
   if (lp->bus == PCI) {
-    while ((tmp = inl(DE4X5_APROM)) < 0);
-    chksum = (u_char) tmp;
-    while ((tmp = inl(DE4X5_APROM)) < 0);
-    chksum |= (u_short) (tmp << 8);
+    if (lp->chipset == DC21040) {
+      while ((tmp = inl(DE4X5_APROM)) < 0);
+      chksum = (u_char) tmp;
+      while ((tmp = inl(DE4X5_APROM)) < 0);
+      chksum |= (u_short) (tmp << 8);
+      if (k != chksum) status = -1;
+    }
   } else {
     chksum = (u_char) inb(EISA_APROM);
     chksum |= (u_short) (inb(EISA_APROM) << 8);
+    if (k != chksum) status = -1;
   }
 
-  if (k != chksum) status = -1;
 
   return status;
 }
 
 /*
+** SROM Read
+*/
+static short srom_rd(u_short addr, u_char offset)
+{
+  sendto_srom(SROM_RD | SROM_SR, addr);
+
+  srom_latch(SROM_RD | SROM_SR | DT_CS, addr);
+  srom_command(SROM_RD | SROM_SR | DT_IN | DT_CS, addr);
+  srom_address(SROM_RD | SROM_SR | DT_CS, addr, offset);
+
+  return srom_data(SROM_RD | SROM_SR | DT_CS, addr);
+}
+
+static void srom_latch(u_long command, u_short addr)
+{
+  sendto_srom(command, addr);
+  sendto_srom(command | DT_CLK, addr);
+  sendto_srom(command, addr);
+
+  return;
+}
+
+static void srom_command(u_long command, u_short addr)
+{
+  srom_latch(command, addr);
+  srom_latch(command, addr);
+  srom_latch((command & 0x0000ff00) | DT_CS, addr);
+
+  return;
+}
+
+static void srom_address(u_long command, u_short addr, u_char offset)
+{
+  long i;
+  char a;
+
+  a = (char)(offset << 2);
+  for (i=0; i<6; i++, a <<= 1) {
+    srom_latch(command | ((a < 0) ? DT_IN : 0), addr);
+  }
+  dce_us_delay(1);
+
+  i = (getfrom_srom(addr) >> 3) & 0x01;
+  if (i != 0) {
+    printk("Bad SROM address phase.....\n");
+  }
+
+  return;
+}
+
+static short srom_data(u_long command, u_short addr)
+{
+  int i;
+  short word = 0;
+  long tmp;
+
+  for (i=0; i<16; i++) {
+    sendto_srom(command  | DT_CLK, addr);
+    tmp = getfrom_srom(addr);
+    sendto_srom(command, addr);
+
+    word = (word << 1) | ((tmp >> 3) & 0x01);
+  }
+
+  sendto_srom(command & 0x0000ff00, addr);
+
+  return word;
+}
+
+/*
+static void srom_busy(u_long command, u_short addr)
+{
+  sendto_srom((command & 0x0000ff00) | DT_CS, addr);
+
+  while (!((getfrom_srom(addr) >> 3) & 0x01)) {
+    dce_ms_delay(1);
+  }
+
+  sendto_srom(command & 0x0000ff00, addr);
+
+  return;
+}
+*/
+
+static void sendto_srom(u_long command, u_short addr)
+{
+  outl(command, addr);
+  dce_us_delay(1);
+
+  return;
+}
+
+static long getfrom_srom(u_short addr)
+{
+  long tmp;
+
+  tmp = inl(addr);
+  dce_us_delay(1);
+
+  return tmp;
+}
+
+static char *build_setup_frame(struct device *dev, int mode)
+{
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  int i;
+  char *pa = lp->setup_frame;
+
+  /* Initialise the setup frame */
+  if (mode == ALL) {
+    memset(lp->setup_frame, 0, SETUP_FRAME_LEN);
+  }
+
+  if (lp->setup_f == HASH_PERF) {
+    for (pa=lp->setup_frame+IMPERF_PA_OFFSET, i=0; i<ETH_ALEN; i++) {
+      *(pa + i) = dev->dev_addr[i];                 /* Host address */
+      if (i & 0x01) pa += 2;
+    }
+    *(lp->setup_frame + (HASH_TABLE_LEN >> 3) - 3) = 0x80; /* B'cast address */
+  } else {
+    for (i=0; i<ETH_ALEN; i++) { /* Host address */
+      *(pa + (i&1)) = dev->dev_addr[i];
+      if (i & 0x01) pa += 4;
+    }
+    for (i=0; i<ETH_ALEN; i++) { /* Broadcast address */
+      *(pa + (i&1)) = (char) 0xff;
+      if (i & 0x01) pa += 4;
+    }
+  }
+
+  return pa;                     /* Points to the next entry */
+}
+
+/*
 ** Perform IOCTL call functions here. Some are privileged operations and the
 ** effective uid is checked in those cases.
 */
@@ -1812,29 +2264,20 @@
     break;
   case DE4X5_SET_HWADDR:             /* Set the hardware address */
     if (suser()) {
-      int offset;
-      char *pa;
-      u_long omr;
-
       memcpy_fromfs(tmp.addr,ioc->data,ETH_ALEN);
       for (i=0; i<ETH_ALEN; i++) {
 	dev->dev_addr[i] = tmp.addr[i];
       }
-      omr = inl(DE4X5_OMR);
-      if (omr & OMR_HP) {
-	offset = IMPERF_PA_OFFSET;
-      } else {
-	offset = PERF_PA_OFFSET;
-      }
-      /* Insert the physical address */
-      for (pa=lp->setup_frame+offset, i=0; i<ETH_ALEN; i++) {
-	*(pa + i) = dev->dev_addr[i];
-	if (i & 0x01) pa += 2;
-      }
+      build_setup_frame(dev, PHYS_ADDR_ONLY);
       /* Set up the descriptor and give ownership to the card */
       while (set_bit(0, (void *)&dev->tbusy) != 0); /* Wait for lock to free */
-      load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | 
+      if (lp->setup_f == HASH_PERF) {
+	load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | 
+		                                        SETUP_FRAME_LEN, NULL);
+      } else {
+	load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
 		                                        SETUP_FRAME_LEN, NULL);
+      }
       lp->tx_new = (++lp->tx_new) % lp->txRingSize;
       outl(POLL_DEMAND, DE4X5_TPD);                /* Start the TX */
       dev->tbusy = 0;                              /* Unlock the TX ring */
@@ -1848,7 +2291,6 @@
     if (suser()) {
       omr = inl(DE4X5_OMR);
       omr |= OMR_PR;
-      omr &= ~OMR_PM;
       outl(omr, DE4X5_OMR);
     } else {
       status = -EPERM;
@@ -1893,11 +2335,10 @@
     }
 
     break;
-  case DE4X5_MCA_EN:                 /* Enable multicast addressing */
+  case DE4X5_MCA_EN:                 /* Enable pass all multicast addressing */
     if (suser()) {
       omr = inl(DE4X5_OMR);
       omr |= OMR_PM;
-      omr &= ~OMR_PR;
       outl(omr, DE4X5_OMR);
     } else {
       status = -EPERM;
@@ -2049,9 +2490,9 @@
 					             DE4X5_PCI_TOTAL_SIZE :
 			                             DE4X5_EISA_TOTAL_SIZE));
     if (lp) {
-      kfree_s(lp->rx_ring[0].buf, RX_BUFF_SZ * NUM_RX_DESC + LWPAD);
+      kfree_s(lp->rx_ring[0].buf, RX_BUFF_SZ * NUM_RX_DESC + ALIGN);
     }
-    kfree_s(thisDE4X5.priv, sizeof(struct de4x5_private) + LWPAD);
+    kfree_s(thisDE4X5.priv, sizeof(struct de4x5_private) + ALIGN);
     thisDE4X5.priv = NULL;
 
     unregister_netdev(&thisDE4X5);
diff -u --recursive --new-file v1.2.7/linux/drivers/net/de4x5.h linux/drivers/net/de4x5.h
--- v1.2.7/linux/drivers/net/de4x5.h	Tue Jan 31 09:39:01 1995
+++ linux/drivers/net/de4x5.h	Wed May  3 07:17:10 1995
@@ -23,8 +23,12 @@
 #define DE4X5_IMR    iobase+(0x038 << lp->bus)  /* Interrupt Mask Register */
 #define DE4X5_MFC    iobase+(0x040 << lp->bus)  /* Missed Frame Counter */
 #define DE4X5_APROM  iobase+(0x048 << lp->bus)  /* Ethernet Address PROM */
+#define DE4X5_BROM   iobase+(0x048 << lp->bus)  /* Boot ROM Register */
+#define DE4X5_SROM   iobase+(0x048 << lp->bus)  /* Serial ROM Register */
 #define DE4X5_DDR    iobase+(0x050 << lp->bus)  /* Data Diagnostic Register */
 #define DE4X5_FDR    iobase+(0x058 << lp->bus)  /* Full Duplex Register */
+#define DE4X5_GPT    iobase+(0x058 << lp->bus)  /* General Purpose Timer Reg.*/
+#define DE4X5_GEP    iobase+(0x060 << lp->bus)  /* General Purpose Register */
 #define DE4X5_SISR   iobase+(0x060 << lp->bus)  /* SIA Status Register */
 #define DE4X5_SICR   iobase+(0x068 << lp->bus)  /* SIA Connectivity Register */
 #define DE4X5_STRR   iobase+(0x070 << lp->bus)  /* SIA TX/RX Register */
@@ -54,7 +58,9 @@
 #define PCI_CFLT     iobase+0x001c   /* PCI Latency Timer Register */
 #define PCI_CBIO     iobase+0x0028   /* PCI Base I/O Register */
 #define PCI_CBMA     iobase+0x002c   /* PCI Base Memory Address Register */
-#define PCI_CFIT     iobase+0x0038   /* PCI Configuration Interrupt Register */
+#define PCI_CBER     iobase+0x0030   /* PCI Expansion ROM Base Address Reg. */
+#define PCI_CFIT     iobase+0x003c   /* PCI Configuration Interrupt Register */
+#define PCI_CFDA     iobase+0x0040   /* PCI Driver Area Register */
 
 /*
 ** EISA Configuration Register 0 bit definitions
@@ -94,6 +100,21 @@
 #define CFID_VID    0x00ff           /* Vendor ID */
 #define DC21040_DID 0x0002           /* Unique Device ID # */
 #define DC21040_VID 0x1011           /* DC21040 Manufacturer */
+#define DC21041_DID 0x0014           /* Unique Device ID # */
+#define DC21041_VID 0x1011           /* DC21041 Manufacturer */
+#define DC21140_DID 0x0009           /* Unique Device ID # */
+#define DC21140_VID 0x1011           /* DC21140 Manufacturer */
+
+/*
+** Chipset defines
+*/
+#define DC21040     DC21040_DID
+#define DC21041     DC21041_DID
+#define DC21140     DC21140_DID
+
+#define is_DC21040 ((vendor == DC21040_VID) && (device == DC21040_DID))
+#define is_DC21041 ((vendor == DC21041_VID) && (device == DC21041_DID))
+#define is_DC21140 ((vendor == DC21140_VID) && (device == DC21140_DID))
 
 /*
 ** PCI Configuration Command/Status Register (PCI_CFCS)
@@ -136,9 +157,21 @@
 #define CBIO_IOSI   0x00000001       /* I/O Space Indicator (RO, value is 1) */
 
 /*
+** PCI Configuration Expansion ROM Base Address Register (PCI_CBER)
+*/
+#define CBER_MASK   0xfffffc00       /* Expansion ROM Base Address Mask */
+#define CBER_ROME   0x00000001       /* ROM Enable */
+
+/*
+** PCI Configuration Driver Area Register (PCI_CFDA)
+*/
+#define CFDA_PSM    0x80000000       /* Power Saving Mode */
+
+/*
 ** DC21040 Bus Mode Register (DE4X5_BMR)
 */
-#define BMR_TAP    0x00060000       /* Transmit Automatic Polling */
+#define BMR_DBO    0x00100000       /* Descriptor Byte Ordering (Endian) */
+#define BMR_TAP    0x000e0000       /* Transmit Automatic Polling */
 #define BMR_DAS    0x00010000       /* Diagnostic Address Space */
 #define BMR_CAL    0x0000c000       /* Cache Alignment */
 #define BMR_PBL    0x00003f00       /* Programmable Burst Length */
@@ -151,6 +184,10 @@
 #define TAP_200US  0x00020000       /* TX automatic polling every 200us */
 #define TAP_800US  0x00040000       /* TX automatic polling every 800us */
 #define TAP_1_6MS  0x00060000       /* TX automatic polling every 1.6ms */
+#define TAP_12_8US 0x00080000       /* TX automatic polling every 12.8us */
+#define TAP_25_6US 0x000a0000       /* TX automatic polling every 25.6us */
+#define TAP_51_2US 0x000c0000       /* TX automatic polling every 51.2us */
+#define TAP_102_4US 0x000e0000      /* TX automatic polling every 102.4us */
 
 #define CAL_NOUSE  0x00000000       /* Not used */
 #define CAL_8LONG  0x00004000       /* 8-longword alignment */
@@ -165,6 +202,7 @@
 #define PBL_16     0x00001000       /* 16 longwords DMA burst length */
 #define PBL_32     0x00002000       /* 32 longwords DMA burst length */
 
+#define DSL_0      0x00000000       /*  0 longword  / descriptor */
 #define DSL_1      0x00000004       /*  1 longword  / descriptor */
 #define DSL_2      0x00000008       /*  2 longwords / descriptor */
 #define DSL_4      0x00000010       /*  4 longwords / descriptor */
@@ -195,20 +233,23 @@
 /*
 ** DC21040 Status Register (DE4X5_STS)
 */
-#define STS_EB     0x03800000       /* Error Bits */
+#define STS_BE     0x03800000       /* Bus Error Bits */
 #define STS_TS     0x00700000       /* Transmit Process State */
 #define STS_RS     0x000e0000       /* Receive Process State */
 #define STS_NIS    0x00010000       /* Normal Interrupt Summary */
 #define STS_AIS    0x00008000       /* Abnormal Interrupt Summary */
+#define STS_ER     0x00004000       /* Early Receive */
 #define STS_SE     0x00002000       /* System Error */
 #define STS_LNF    0x00001000       /* Link Fail */
 #define STS_FD     0x00000800       /* Full-Duplex Short Frame Received */
+#define STS_TM     0x00000800       /* Timer Expired (DC21041) */
 #define STS_AT     0x00000400       /* AUI/TP Pin */
 #define STS_RWT    0x00000200       /* Receive Watchdog Time-Out */
 #define STS_RPS    0x00000100       /* Receive Process Stopped */
 #define STS_RU     0x00000080       /* Receive Buffer Unavailable */
 #define STS_RI     0x00000040       /* Receive Interrupt */
 #define STS_UNF    0x00000020       /* Transmit Underflow */
+#define STS_LNP    0x00000010       /* Link Pass */
 #define STS_TJT    0x00000008       /* Transmit Jabber Time-Out */
 #define STS_TU     0x00000004       /* Transmit Buffer Unavailable */
 #define STS_TPS    0x00000002       /* Transmit Process Stopped */
@@ -243,6 +284,13 @@
 /*
 ** DC21040 Operation Mode Register (DE4X5_OMR)
 */
+#define OMR_SDP    0x02000000       /* SD Polarity - MUST BE ASSERTED */
+#define OMR_SCR    0x01000000       /* Scrambler Mode */
+#define OMR_PCS    0x00800000       /* PCS Function */
+#define OMR_TTM    0x00400000       /* Transmit Threshold Mode */
+#define OMR_SF     0x00200000       /* Store and Forward */
+#define OMR_HBD    0x00080000       /* HeartBeat Disable */
+#define OMR_PS     0x00040000       /* Port Select */
 #define OMR_CA     0x00020000       /* Capture Effect Enable */
 #define OMR_BP     0x00010000       /* Back Pressure */
 #define OMR_TR     0x0000c000       /* Threshold Control Bits */
@@ -270,15 +318,18 @@
 */
 #define IMR_NIM    0x00010000       /* Normal Interrupt Summary Mask */
 #define IMR_AIM    0x00008000       /* Abnormal Interrupt Summary Mask */
+#define IMR_ERM    0x00004000       /* Early Receive Mask */
 #define IMR_SEM    0x00002000       /* System Error Mask */
 #define IMR_LFM    0x00001000       /* Link Fail Mask */
-#define IMR_FDM    0x00000800       /* Full-Duplex Mask */
+#define IMR_FDM    0x00000800       /* Full-Duplex (Short Frame) Mask */
+#define IMR_TMM    0x00000800       /* Timer Expired Mask (DC21041) */
 #define IMR_ATM    0x00000400       /* AUI/TP Switch Mask */
 #define IMR_RWM    0x00000200       /* Receive Watchdog Time-Out Mask */
 #define IMR_RSM    0x00000100       /* Receive Stopped Mask */
 #define IMR_RUM    0x00000080       /* Receive Buffer Unavailable Mask */
 #define IMR_RIM    0x00000040       /* Receive Interrupt Mask */
 #define IMR_UNM    0x00000020       /* Underflow Interrupt Mask */
+#define IMR_LPM    0x00000010       /* Link Pass */
 #define IMR_TJM    0x00000008       /* Transmit Time-Out Jabber Mask */
 #define IMR_TUM    0x00000004       /* Transmit Buffer Unavailable Mask */
 #define IMR_TSM    0x00000002       /* Transmission Stopped Mask */
@@ -297,27 +348,89 @@
 #define APROM_DT   0x000000ff       /* Address Byte */
 
 /*
+** DC21041 Boot/Ethernet Address ROM (DE4X5_BROM)
+*/
+#define BROM_MODE 0x00008000       /* MODE_1: 0,  MODE_0: 1  (read only) */
+#define BROM_RD   0x00004000       /* Read from Boot ROM */
+#define BROM_WR   0x00002000       /* Write to Boot ROM */
+#define BROM_BR   0x00001000       /* Select Boot ROM when set */
+#define BROM_SR   0x00000800       /* Select Serial ROM when set */
+#define BROM_REG  0x00000400       /* External Register Select */
+#define BROM_DT   0x000000ff       /* Data Byte */
+
+/*
+** DC21041 Serial/Ethernet Address ROM (DE4X5_SROM)
+*/
+#define SROM_MODE 0x00008000       /* MODE_1: 0,  MODE_0: 1  (read only) */
+#define SROM_RD   0x00004000       /* Read from Boot ROM */
+#define SROM_WR   0x00002000       /* Write to Boot ROM */
+#define SROM_BR   0x00001000       /* Select Boot ROM when set */
+#define SROM_SR   0x00000800       /* Select Serial ROM when set */
+#define SROM_REG  0x00000400       /* External Register Select */
+#define SROM_DT   0x000000ff       /* Data Byte */
+
+#define DT_OUT    0x00000008       /* Serial Data Out */
+#define DT_IN     0x00000004       /* Serial Data In */
+#define DT_CLK    0x00000002       /* Serial ROM Clock */
+#define DT_CS     0x00000001       /* Serial ROM Chip Select */
+
+/*
 ** DC21040 Full Duplex Register (DE4X5_FDR)
 */
-#define FDR_FDACV  0x0000ffff       /* Full Duplex Auto Configuration Value */
+#define FDR_FDACV  0x0000ffff      /* Full Duplex Auto Configuration Value */
 
 /*
-** DC21040 SIA Status Register (DE4X5_SISR)
+** DC21041 General Purpose Timer Register (DE4X5_GPT)
 */
-#define SISR_DAO   0x00000080       /* PLL All One */
-#define SISR_DAZ   0x00000040       /* PLL All Zero */
-#define SISR_DSP   0x00000020       /* PLL Self-Test Pass */
-#define SISR_DSD   0x00000010       /* PLL Self-Test Done */
-#define SISR_APS   0x00000008       /* Auto Polarity State */
-#define SISR_LKF   0x00000004       /* Link Fail Status */
-#define SISR_NCR   0x00000002       /* Network Connection Error */
-#define SISR_PAUI  0x00000001       /* AUI_TP Indication */
+#define GPT_CON  0x00010000        /* One shot: 0,  Continuous: 1 */
+#define GPT_VAL  0x0000ffff        /* Timer Value */
+
+/*
+** DC21140 General Purpose Register (DE4X5_GEP) (hardware dependent bits)
+*/
+/* Valid ONLY for DE500 hardware */
+#define GEP_LNP  0x00000080        /* Link Pass               (input) */
+#define GEP_SLNK 0x00000040        /* SYM LINK                (input) */
+#define GEP_SDET 0x00000020        /* Signal Detect           (input) */
+#define GEP_FDXD 0x00000008        /* Full Duplex Disable     (output) */
+#define GEP_PHYL 0x00000004        /* PHY Loopback            (output) */
+#define GEP_FLED 0x00000002        /* Force Activity LED on   (output) */
+#define GEP_MODE 0x00000001        /* 0: 10Mb/s,  1: 100Mb/s           */
+#define GEP_INIT 0x0000010f        /* Setup inputs (0) and outputs (1) */
 
-#define SIA_RESET  0x00000000       /* SIA Reset */
+
+/*
+** DC21040 SIA Status Register (DE4X5_SISR)
+*/
+#define SISR_LPC   0xffff0000      /* Link Partner's Code Word */
+#define SISR_LPN   0x00008000      /* Link Partner Negotiable */
+#define SISR_ANS   0x00007000      /* Auto Negotiation Arbitration State */
+#define SISR_NSN   0x00000800      /* Non Stable NLPs Detected */
+#define SISR_ANR_FDS 0x00000400    /* Auto Negotiate Restart/Full Duplex Sel.*/
+#define SISR_NRA   0x00000200      /* Non Selected Port Receive Activity */
+#define SISR_SRA   0x00000100      /* Selected Port Receive Activity */
+#define SISR_DAO   0x00000080      /* PLL All One */
+#define SISR_DAZ   0x00000040      /* PLL All Zero */
+#define SISR_DSP   0x00000020      /* PLL Self-Test Pass */
+#define SISR_DSD   0x00000010      /* PLL Self-Test Done */
+#define SISR_APS   0x00000008      /* Auto Polarity State */
+#define SISR_LKF   0x00000004      /* Link Fail Status */
+#define SISR_NCR   0x00000002      /* Network Connection Error */
+#define SISR_PAUI  0x00000001      /* AUI_TP Indication */
+#define SIA_RESET  0x00000000      /* SIA Reset */
+
+#define ANS_NDIS   0x00000000      /* Nway disable */
+#define ANS_TDIS   0x00001000      /* Transmit Disable */
+#define ANS_ADET   0x00002000      /* Ability Detect */
+#define ANS_ACK    0x00003000      /* Acknowledge */
+#define ANS_CACK   0x00004000      /* Complete Acknowledge */
+#define ANS_NWOK   0x00005000      /* Nway OK - FLP Link Good */
+#define ANS_LCHK   0x00006000      /* Link Check */
 
 /*
 ** DC21040 SIA Connectivity Register (DE4X5_SICR)
 */
+#define SICR_SDM   0xffff0000       /* SIA Diagnostics Mode */
 #define SICR_OE57  0x00008000       /* Output Enable 5 6 7 */
 #define SICR_OE24  0x00004000       /* Output Enable 2 4 */
 #define SICR_OE13  0x00002000       /* Output Enable 1 3 */
@@ -343,6 +456,7 @@
 /*
 ** DC21040 SIA Transmit and Receive Register (DE4X5_STRR)
 */
+#define STRR_TAS   0x00008000       /* 10Base-T/AUI Autosensing Enable */
 #define STRR_SPP   0x00004000       /* Set Polarity Plus */
 #define STRR_APE   0x00002000       /* Auto Polarity Enable */
 #define STRR_LTE   0x00001000       /* Link Test Enable */
@@ -350,6 +464,8 @@
 #define STRR_CLD   0x00000400       /* Collision Detect Enable */
 #define STRR_CSQ   0x00000200       /* Collision Squelch Enable */
 #define STRR_RSQ   0x00000100       /* Receive Squelch Enable */
+#define STRR_ANE   0x00000080       /* Auto Negotiate Enable */
+#define STRR_HDE   0x00000040       /* Half Duplex Enable */
 #define STRR_CPEN  0x00000030       /* Compensation Enable */
 #define STRR_LSE   0x00000008       /* Link Pulse Send Enable */
 #define STRR_DREN  0x00000004       /* Driver Enable */
@@ -360,13 +476,19 @@
 /*
 ** DC21040 SIA General Register (DE4X5_SIGR)
 */
+#define SIGR_LV2   0x00008000       /* General Purpose LED2 value */
+#define SIGR_LE2   0x00004000       /* General Purpose LED2 enable */
 #define SIGR_FRL   0x00002000       /* Force Receiver Low */
 #define SIGR_DPST  0x00001000       /* PLL Self Test Start */
+#define SIGR_LSD   0x00000800       /* LED Stretch Disable */
 #define SIGR_FLF   0x00000400       /* Force Link Fail */
 #define SIGR_FUSQ  0x00000200       /* Force Unsquelch */
 #define SIGR_TSCK  0x00000100       /* Test Clock */
+#define SIGR_LV1   0x00000080       /* General Purpose LED1 value */
+#define SIGR_LE1   0x00000040       /* General Purpose LED1 enable */
 #define SIGR_RWR   0x00000020       /* Receive Watchdog Release */
 #define SIGR_RWD   0x00000010       /* Receive Watchdog Disable */
+#define SIGR_ABM   0x00000008       /* BNC: 0,  AUI:1 */
 #define SIGR_JCK   0x00000004       /* Jabber Clock */
 #define SIGR_HUJ   0x00000002       /* Host Unjab */
 #define SIGR_JBD   0x00000001       /* Jabber Disable */
@@ -432,26 +554,63 @@
 #define HASH_O_F   TD_FT1| TD_F0
 
 /*
+** Media / mode state machine definitions
+*/
+#define NC         0x0000          /* No Connection */
+#define TP         0x0001          /* 10Base-T */
+#define TP_NW      0x0002          /* 10Base-T with Nway */
+#define BNC        0x0004          /* Thinwire */
+#define AUI        0x0008          /* Thickwire */
+#define BNC_AUI    0x0010          /* BNC/AUI on DC21040 indistinguishable */
+#define ANS        0x0020          /* Intermediate AutoNegotiation State */
+
+#define _10Mb      0x0040          /* 10Mb/s Ethernet */
+#define _100Mb     0x0080          /* 100Mb/s Ethernet */
+#define SYM_WAIT   0x0100          /* Wait for SYM_LINK */
+#define INIT       0x0200          /* Initial state */
+
+#define AUTO       0x4000          /* Auto sense the media or speed */
+
+/*
 ** Miscellaneous
 */
 #define PCI  0
 #define EISA 1
 
-#define NC         0               /* No Connection */
-#define TP         1               /* 10Base-T */
-#define BNC        2               /* Thinwire */
-#define AUI        3               /* Thickwire */
-  
 #define HASH_TABLE_LEN   512       /* Bits */
+#define HASH_BITS        0x01ff    /* 9 LS bits */
 
 #define SETUP_FRAME_LEN  192       /* Bytes */
-#define PERF_PA_OFFSET   180       /* Bytes */
 #define IMPERF_PA_OFFSET 156       /* Bytes */
 
-#define POLL_DEMAND       1
+#define POLL_DEMAND          1
+
+#define LOST_MEDIA_THRESHOLD 3
+
+#define MASK_INTERRUPTS      1
+#define UNMASK_INTERRUPTS    0
+
+#define DE4X5_STRLEN         8
+
+/*
+** Address Filtering Modes
+*/
+#define PERFECT              0     /* 16 perfect physical addresses */
+#define HASH_PERF            1     /* 1 perfect, 512 multicast addresses */
+#define PERFECT_REJ          2     /* Reject 16 perfect physical addresses */
+#define ALL_HASH             3     /* Hashes all physical & multicast addrs */
+
+#define ALL                  0     /* Clear out all the setup frame */
+#define PHYS_ADDR_ONLY       1     /* Update the physical address only */
+
+/*
+** Booleans
+*/
+#define NO                   0
+#define FALSE                0
 
-#define MASK_INTERRUPTS   1
-#define UNMASK_INTERRUPTS 0
+#define YES                  !0
+#define TRUE                 !0
 
 /*
 ** Include the IOCTL stuff
diff -u --recursive --new-file v1.2.7/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v1.2.7/linux/drivers/net/lance.c	Fri Apr 28 11:10:53 1995
+++ linux/drivers/net/lance.c	Tue May  2 08:06:18 1995
@@ -608,7 +608,7 @@
 	outw(((int)&lp->init_block) >> 16, ioaddr+LANCE_DATA);
 
 	outw(0x0004, ioaddr+LANCE_ADDR);
-	outw(0x0d15, ioaddr+LANCE_DATA);
+	outw(0x0915, ioaddr+LANCE_DATA);
 
 	outw(0x0000, ioaddr+LANCE_ADDR);
 	outw(0x0001, ioaddr+LANCE_DATA);
diff -u --recursive --new-file v1.2.7/linux/drivers/net/ne.c linux/drivers/net/ne.c
--- v1.2.7/linux/drivers/net/ne.c	Sat Apr 29 12:42:21 1995
+++ linux/drivers/net/ne.c	Tue May  2 08:02:12 1995
@@ -50,7 +50,7 @@
 /* Do we implement the read before write bugfix ? */
 /* #define CONFIG_NE_RW_BUGFIX */
 
-/* ---- No user-servicable parts below ---- */
+/* ---- No user-serviceable parts below ---- */
 
 extern struct device *init_etherdev(struct device *dev, int sizeof_private,
 				    unsigned long *mem_startp);
@@ -86,7 +86,7 @@
 #define NESM_START_PG	0x40	/* First page of TX buffer */
 #define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
 
-#define NE_RDC_TIMEOUT	0x03	/* Max wait in jiffies for Tx RDC */
+#define NE_RDC_TIMEOUT	0x02	/* Max wait in jiffies for Tx RDC */
 
 int ne_probe(struct device *dev);
 static int ne_probe1(struct device *dev, int ioaddr);
@@ -462,7 +462,6 @@
     SLOW_DOWN_IO;
 #endif  /* rw_bugfix */
 
-    dma_start = jiffies;
     outb_p(ENISR_RDC, nic_base + EN0_ISR);
 
    /* Now the normal output. */
@@ -477,6 +476,8 @@
     } else {
 	outsb(NE_BASE + NE_DATAPORT, buf, count);
     }
+
+    dma_start = jiffies;
 
 #ifdef CONFIG_NE_SANITY
     /* This was for the ALPHA version only, but enough people have
diff -u --recursive --new-file v1.2.7/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v1.2.7/linux/drivers/net/ppp.c	Thu Feb 23 13:19:17 1995
+++ linux/drivers/net/ppp.c	Tue May  2 08:02:13 1995
@@ -31,6 +31,7 @@
 /* #define NET02D				-* */
 #define NEW_TTY_DRIVERS				/* */
 #define OPTIMIZE_FLAG_TIME  ((HZ * 3)/2)	/* */
+#define CHECK_CHARACTERS
 
 #ifdef MODULE
 #include <linux/module.h>
@@ -469,8 +470,8 @@
 #endif
 
   if (ppp->dev) {
-    ppp->dev->flags &= ~IFF_UP; /* down the device */
-    ppp->dev->flags |= IFF_POINTOPOINT;
+    dev_close (ppp->dev);
+    ppp->dev->flags = 0;
   }
 
   kfree (ppp->xbuff);
@@ -953,14 +954,14 @@
 
 #ifdef CHECK_CHARACTERS
     if (c & 0x80)
-	sc->sc_flags |= SC_RCV_B7_1;
+	ppp->flags |= SC_RCV_B7_1;
     else
-	sc->sc_flags |= SC_RCV_B7_0;
+	ppp->flags |= SC_RCV_B7_0;
 
     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
-	sc->sc_flags |= SC_RCV_ODDP;
+	ppp->flags |= SC_RCV_ODDP;
     else
-	sc->sc_flags |= SC_RCV_EVNP;
+	ppp->flags |= SC_RCV_EVNP;
 #endif
 
     switch (c) {
@@ -1005,6 +1006,7 @@
   if (ppp->toss) {
     PRINTKN (1, (KERN_WARNING "ppp_toss: tossing frame, reason = %d\n",
 		 ppp->toss));
+    slhc_toss (ppp->slcomp);
     ppp->stats.rerrors++;
     return;
   }
@@ -1018,6 +1020,7 @@
 
   if (count < 4) {
     PRINTKN (1,(KERN_WARNING "ppp: got runt ppp frame, %d chars\n", count));
+    slhc_toss (ppp->slcomp);
     ppp->stats.runts++;
     return;
   }
@@ -1025,6 +1028,7 @@
   /* check PPP error detection field */
   if (!ppp_check_fcs(ppp)) {
     PRINTKN (1,(KERN_WARNING "ppp: frame with bad fcs\n"));
+    slhc_toss (ppp->slcomp);
     ppp->stats.rerrors++;
     return;
   }
@@ -1067,6 +1071,7 @@
   /* couldn't cope. */
   PRINTKN (1,(KERN_WARNING
 	      "ppp: dropping packet on the floor: nobody could take it.\n"));
+  slhc_toss (ppp->slcomp);
   ppp->stats.tossed++;
 }
 
@@ -1109,6 +1114,7 @@
       PRINTKN (1,(KERN_NOTICE
 		  "ppp: no space to decompress VJ compressed TCP header.\n"));
       ppp->stats.roverrun++;
+      slhc_toss (ppp->slcomp);
       return 1;
     }
 
@@ -1116,6 +1122,7 @@
     if (count <= 0) {
       ppp->stats.rerrors++;
       PRINTKN (1,(KERN_NOTICE "ppp: error in VJ decompression\n"));
+      slhc_toss (ppp->slcomp);
       return 1;
     }
     ppp->stats.rcomp++;
@@ -1126,6 +1133,7 @@
     if (slhc_remember(ppp->slcomp, c, count) <= 0) {
       ppp->stats.rerrors++;
       PRINTKN (1,(KERN_NOTICE "ppp: error in VJ memorizing\n"));
+      slhc_toss (ppp->slcomp);
       return 1;
     }
     ppp->stats.runcomp++;
@@ -1709,7 +1717,12 @@
   PRINTKN(4,(KERN_DEBUG "ppp_xmit [%s]: skb %lX busy %d\n", dev->name, 
 	     (unsigned long int) skb, ppp->sending));
 
-  CHECK_PPP(0);
+  /* avoid race conditions when the link fails */
+  if (!ppp->inuse) {
+    dev_kfree_skb(skb, FREE_WRITE);
+    dev_close (dev);
+    return 0;
+  }
 
   if (tty == NULL) {
     PRINTKN(1,(KERN_ERR "ppp_xmit: %s not connected to a TTY!\n", dev->name));
@@ -1726,7 +1739,7 @@
   /* get length from IP header as per Alan Cox bugfix for slip.c */
   if (len < sizeof(struct iphdr)) {
     PRINTKN(0,(KERN_ERR "ppp_xmit: given runt packet, ignoring\n"));
-    return 1;
+    goto done;
   }
   len = ntohs( ((struct iphdr *)(skb->data)) -> tot_len );
 
@@ -1750,8 +1763,8 @@
 
   /* try to compress, if VJ compression mode is on */
   if (ppp->flags & SC_COMP_TCP) {
-    /* NOTE: last 0 argument says never to compress connection ID */
-    len = slhc_compress(ppp->slcomp, p, len, ppp->cbuff, &p, 0);
+    len = slhc_compress(ppp->slcomp, p, len, ppp->cbuff, &p, 
+			!(ppp->flags & SC_NO_TCP_CCID));
     if (p[0] & SL_TYPE_COMPRESSED_TCP)
       proto = PROTO_VJCOMP;
     else {
@@ -2055,10 +2068,25 @@
 		0, 0, 0, 0,	/* memory */
 		0, 0,		/* base, irq */
 		0, 0, 0, NULL, ppp_init,
-	},
-	{ "ppp1" , 0, 0, 0, 0,  1, 0, 0, 0, 0, NULL, ppp_init },
-	{ "ppp2" , 0, 0, 0, 0,  2, 0, 0, 0, 0, NULL, ppp_init },
-	{ "ppp3" , 0, 0, 0, 0,  3, 0, 0, 0, 0, NULL, ppp_init },
+	}
+	, { "ppp1" , 0, 0, 0, 0,  1, 0, 0, 0, 0, NULL, ppp_init }
+	, { "ppp2" , 0, 0, 0, 0,  2, 0, 0, 0, 0, NULL, ppp_init }
+	, { "ppp3" , 0, 0, 0, 0,  3, 0, 0, 0, 0, NULL, ppp_init }
+
+#ifdef PPP_PPP_LOTS
+	, { "ppp4" , 0, 0, 0, 0,  4, 0, 0, 0, 0, NULL, ppp_init }
+	, { "ppp5" , 0, 0, 0, 0,  5, 0, 0, 0, 0, NULL, ppp_init }
+	, { "ppp6" , 0, 0, 0, 0,  6, 0, 0, 0, 0, NULL, ppp_init }
+	, { "ppp7" , 0, 0, 0, 0,  7, 0, 0, 0, 0, NULL, ppp_init }
+	, { "ppp8" , 0, 0, 0, 0,  8, 0, 0, 0, 0, NULL, ppp_init }
+	, { "ppp9" , 0, 0, 0, 0,  9, 0, 0, 0, 0, NULL, ppp_init }
+	, { "ppp10" , 0, 0, 0, 0, 10, 0, 0, 0, 0, NULL, ppp_init }
+	, { "ppp11" , 0, 0, 0, 0, 11, 0, 0, 0, 0, NULL, ppp_init }
+	, { "ppp12" , 0, 0, 0, 0, 12, 0, 0, 0, 0, NULL, ppp_init }
+	, { "ppp13" , 0, 0, 0, 0, 13, 0, 0, 0, 0, NULL, ppp_init }
+	, { "ppp14" , 0, 0, 0, 0, 14, 0, 0, 0, 0, NULL, ppp_init }
+	, { "ppp15" , 0, 0, 0, 0, 15, 0, 0, 0, 0, NULL, ppp_init }
+#endif
 };
 
 int
diff -u --recursive --new-file v1.2.7/linux/drivers/net/slip.c linux/drivers/net/slip.c
--- v1.2.7/linux/drivers/net/slip.c	Thu Feb 23 13:27:11 1995
+++ linux/drivers/net/slip.c	Sat Apr 29 12:41:33 1995
@@ -1046,6 +1046,13 @@
 	}
 }
 
+static int sl_open_dev(struct device *dev)
+{
+	struct slip *sl = &sl_ctrl[dev->base_addr];
+	if(sl->tty==NULL)
+		return -ENODEV;
+	return 0;
+}
 
 /* Initialize the SLIP driver.  Called by DDI. */
 int
@@ -1103,7 +1110,7 @@
 	/* Finish setting up the DEVICE info. */
 	dev->mtu		= SL_MTU;
 	dev->hard_start_xmit	= sl_xmit;
-	dev->open		= sl_open;
+	dev->open		= sl_open_dev;
 	dev->stop		= sl_close;
 	dev->hard_header	= sl_header;
 	dev->type_trans	        = sl_type_trans;
diff -u --recursive --new-file v1.2.7/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c
--- v1.2.7/linux/drivers/scsi/53c7,8xx.c	Sat Apr 29 12:42:22 1995
+++ linux/drivers/scsi/53c7,8xx.c	Tue May  2 07:28:31 1995
@@ -1242,7 +1242,8 @@
 	sti();
 
 	timeout = jiffies + 50;	/* arbitrary */
-	while ((hostdata->test_completed == -1) && jiffies < timeout);
+	while ((hostdata->test_completed == -1) && jiffies < timeout)
+		barrier();
 
 	failed = 1;
 	if (hostdata->test_completed == -1)
@@ -1330,7 +1331,8 @@
 	    sti();
 
 	    timeout = jiffies + 500;	/* arbitrary */
-	    while ((hostdata->test_completed == -1) && jiffies < timeout);
+	    while ((hostdata->test_completed == -1) && jiffies < timeout)
+	    	barrier();
 	    NCR53c7x0_write32 (DSA_REG, 0);
 
 	    if (hostdata->test_completed == 2) {
diff -u --recursive --new-file v1.2.7/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c
--- v1.2.7/linux/drivers/scsi/NCR5380.c	Wed Mar 29 06:52:58 1995
+++ linux/drivers/scsi/NCR5380.c	Tue May  2 07:30:44 1995
@@ -636,7 +636,8 @@
     NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | 
 	ICR_ASSERT_SEL);
 
-    while (probe_irq == IRQ_NONE && jiffies < timeout);
+    while (probe_irq == IRQ_NONE && jiffies < timeout)
+    	barrier();
 
     NCR5380_write(SELECT_ENABLE_REG, 0);
     NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
@@ -2147,8 +2148,8 @@
 		     */
 		    NCR5380_write(TARGET_COMMAND_REG, 0);
 		    
-		    while ((NCR5380_read(STATUS_REG) & SR_BSY) && 
-			!hostdata->connected);
+		    while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+			barrier();
 		    return;
 		case MESSAGE_REJECT:
 		    /* Accept message by clearing ACK */
@@ -2187,8 +2188,8 @@
 		    /* Enable reselect interrupts */
 		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 		    /* Wait for bus free to avoid nasty timeouts */
-		    while ((NCR5380_read(STATUS_REG) & SR_BSY) && 
-			!hostdata->connected);
+		    while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+		    	barrier();
 		    return;
 		/* 
 		 * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
diff -u --recursive --new-file v1.2.7/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- v1.2.7/linux/drivers/scsi/aha152x.c	Tue Apr  4 09:05:34 1995
+++ linux/drivers/scsi/aha152x.c	Tue May  2 07:31:26 1995
@@ -968,7 +968,7 @@
   
         /* sleep until the abortion is complete */
         while(!abortion_complete)
-	  ;
+	  barrier();
         aborting=0;
         return abort_result;
       }
diff -u --recursive --new-file v1.2.7/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c
--- v1.2.7/linux/drivers/scsi/aha1542.c	Mon Jan 23 10:38:29 1995
+++ linux/drivers/scsi/aha1542.c	Tue May  2 07:33:59 1995
@@ -681,7 +681,8 @@
     aha1542_queuecommand(SCpnt, internal_done);
 
     SCpnt->SCp.Status = 0;
-    while (!SCpnt->SCp.Status);
+    while (!SCpnt->SCp.Status)
+    	barrier();
     return SCpnt->result;
 }
 
diff -u --recursive --new-file v1.2.7/linux/drivers/scsi/buslogic.c linux/drivers/scsi/buslogic.c
--- v1.2.7/linux/drivers/scsi/buslogic.c	Fri Apr 28 11:10:55 1995
+++ linux/drivers/scsi/buslogic.c	Tue May  2 07:47:13 1995
@@ -788,7 +788,7 @@
 
     scpnt->SCp.Status = 0;
     while (!scpnt->SCp.Status)
-	continue;
+	barrier();
     return scpnt->result;
 }
 #endif
diff -u --recursive --new-file v1.2.7/linux/drivers/scsi/in2000.c linux/drivers/scsi/in2000.c
--- v1.2.7/linux/drivers/scsi/in2000.c	Thu Mar  9 20:37:34 1995
+++ linux/drivers/scsi/in2000.c	Tue May  2 07:34:38 1995
@@ -462,7 +462,8 @@
     if ( in2000_SCptr )
     {
 	printk("in2000_queue_command waiting for free command block!\n");
-	while ( in2000_SCptr );
+	while ( in2000_SCptr )
+	    barrier();
     }
     for ( timeout = jiffies + 5; timeout > jiffies; )
     {
diff -u --recursive --new-file v1.2.7/linux/drivers/scsi/qlogic.c linux/drivers/scsi/qlogic.c
--- v1.2.7/linux/drivers/scsi/qlogic.c	Thu Mar  9 20:37:35 1995
+++ linux/drivers/scsi/qlogic.c	Tue May  2 08:01:57 1995
@@ -18,7 +18,7 @@
    Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994
    (you can reference it, but it is incomplete and inaccurate in places)
 
-   Version 0.41
+   Version 0.43 4/6/95 - kernel 1.2.0+, pcmcia 2.5.4+
 
    Functions as standalone, loadable, and PCMCIA driver, the latter from
    Dave Hind's PCMCIA package.
@@ -29,6 +29,11 @@
 /*----------------------------------------------------------------*/
 /* Configuration */
 
+/* Set the following to 2 to use normal interrupt (active high/totempole-
+   tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
+   drain */
+#define QL_INT_ACTIVE_HIGH 2
+
 /* Set the following to 1 to enable the use of interrupts.  Note that 0 tends
    to be more stable, but slower (or ties up the system more) */
 #define QL_USE_IRQ 1
@@ -100,6 +105,8 @@
 
 /*----------------------------------------------------------------*/
 #ifdef PCMCIA
+#undef QL_INT_ACTIVE_HIGH
+#define QL_INT_ACTIVE_HIGH 0
 #define MODULE
 #endif 
 
@@ -143,7 +150,7 @@
 /*----------------------------------------------------------------*/
 /* The qlogic card uses two register maps - These macros select which one */
 #define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd ))
-#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb6 , qbase + 0xd ))
+#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd ))
 
 /* following is watchdog timeout in microseconds */
 #define WATCHDOG 5000000
@@ -262,8 +269,10 @@
 static int	ql_wai(void)
 {
 int	i,k;
+	k = 0;
 	i = jiffies + WATCHDOG;
-	while ( i > jiffies && !qabort && !((k = inb(qbase + 4)) & 0xe0));
+	while ( i > jiffies && !qabort && !((k = inb(qbase + 4)) & 0xe0))
+		barrier();
 	if (i <= jiffies)
 		return (DID_TIME_OUT);
 	if (qabort)
@@ -420,8 +429,10 @@
 		return (k << 16);
 /* should get bus service interrupt and disconnect interrupt */
 	i = inb(qbase + 5);	/* should be bus service */
-	while (!qabort && ((i & 0x20) != 0x20))
+	while (!qabort && ((i & 0x20) != 0x20)) {
+		barrier();
 		i |= inb(qbase + 5);
+	}
 rtrc(0)
 	if (qabort)
 		return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
@@ -493,7 +504,8 @@
 
 	cmd->scsi_done = done;
 /* wait for the last command's interrupt to finish */
-	while (qlcmd != NULL);
+	while (qlcmd != NULL)
+		barrier();
 	ql_icmd(cmd);
 	return 0;
 }
@@ -556,7 +568,6 @@
 	outb(0x40 | qlcfg8 | qinitid, qbase + 8);	/* (ini) bus id, disable scsi rst */
 	outb(qlcfg5, qbase + 5);		/* select timer */
 	outb(qlcfg9, qbase + 9);			/* prescaler */
-	qlirq = -1;
 #if QL_RESET_AT_START
 	outb( 3 , qbase + 3 );
 	REG1;
@@ -565,6 +576,7 @@
 #endif
 #if QL_USE_IRQ
 /* IRQ probe - toggle pin and check request pending */
+
 	if( qlirq == -1 ) {
 		save_flags( flags );
 		cli();
@@ -575,21 +587,24 @@
 		outb(10, 0x20); /* access pending interrupt map */
 		outb(10, 0xa0);
 		while (j--) {
-			outb(0xb2 , qbase + 0xd);		/* int pin off */
+			outb(0xb0 | QL_INT_ACTIVE_HIGH , qbase + 0xd);	/* int pin off */
 			i &= ~(inb(0x20) | (inb(0xa0) << 8));	/* find IRQ off */
-			outb(0xb6 , qbase + 0xd);		/* int pin on */
+			outb(0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd);	/* int pin on */
 			i &= inb(0x20) | (inb(0xa0) << 8);	/* find IRQ on */
 		}
 		REG0;
 		while (inb(qbase + 5)); 			/* purge int */
+		j = -1;
 		while (i)					/* find on bit */
-			i >>= 1, qlirq++;	/* should check for exactly 1 on */
-		if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogic"))
-			host->can_queue = 1;
+			i >>= 1, j++;	/* should check for exactly 1 on */
+		qlirq = j;
 		restore_flags( flags );
 	}
 	else
-		printk( "Ql: Using preset IRQ of %d\n", qlirq );
+		printk( "Ql: Using preset IRQ %d\n", qlirq );
+
+	if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogic"))
+		host->can_queue = 1;
 #endif
 	request_region( qbase , 0x10 ,"qlogic");
 	hreg = scsi_register( host , 0 );	/* no host data */
@@ -599,7 +614,7 @@
 	if( qlirq != -1 )
 		hreg->irq = qlirq;
 
-	sprintf(qinfo, "Qlogic Driver version 0.41, chip %02X at %03X, IRQ %d, TPdma:%d",
+	sprintf(qinfo, "Qlogic Driver version 0.43, chip %02X at %03X, IRQ %d, TPdma:%d",
 	    qltyp, qbase, qlirq, QL_TURBO_PDMA );
 	host->name = qinfo;
 
diff -u --recursive --new-file v1.2.7/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.2.7/linux/drivers/scsi/scsi.c	Fri Apr 14 12:02:42 1995
+++ linux/drivers/scsi/scsi.c	Tue May  2 07:38:40 1995
@@ -369,7 +369,7 @@
 	     do it right and use a mutex */
 
 	  if (current == task[0])
-	      while (SCpnt->request.dev != 0xfffe);
+	      while (SCpnt->request.dev != 0xfffe) barrier();
 	  else if (SCpnt->request.dev != 0xfffe) {
 	      struct semaphore sem = MUTEX_LOCKED;
 
@@ -421,7 +421,7 @@
 		       256,  scan_scsis_done, SCSI_TIMEOUT, 3);
 
 	  if (current == task[0])
-	      while (SCpnt->request.dev != 0xfffe);
+	      while (SCpnt->request.dev != 0xfffe) barrier();
 	  else if (SCpnt->request.dev != 0xfffe) {
 	      struct semaphore sem = MUTEX_LOCKED;
 
@@ -584,7 +584,7 @@
 				 SCSI_TIMEOUT, 3);
 
 		    if (current == task[0])
-			while (SCpnt->request.dev != 0xfffe);
+			while (SCpnt->request.dev != 0xfffe) barrier();
 		    else if (SCpnt->request.dev != 0xfffe) {
 			struct semaphore sem = MUTEX_LOCKED;
 
@@ -1551,7 +1551,8 @@
 		if (SCpnt->internal_timeout & IN_ABORT)
 			{
 			restore_flags(flags);
-			while (SCpnt->internal_timeout & IN_ABORT);
+			while (SCpnt->internal_timeout & IN_ABORT)
+				barrier();
 			}
 		else
 			{
@@ -1644,7 +1645,8 @@
 		if (SCpnt->internal_timeout & IN_RESET)
 			{
 			restore_flags(flags);
-			while (SCpnt->internal_timeout & IN_RESET);
+			while (SCpnt->internal_timeout & IN_RESET)
+				barrier();
 			}
 		else
 			{
diff -u --recursive --new-file v1.2.7/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v1.2.7/linux/drivers/scsi/sd.c	Fri Apr 14 12:02:42 1995
+++ linux/drivers/scsi/sd.c	Tue May  2 07:39:45 1995
@@ -89,7 +89,8 @@
 /* Make sure that only one process can do a check_change_disk at one time.
  This is also used to lock out further access when the partition table is being re-read. */
 
-	while (rscsi_disks[target].device->busy);
+	while (rscsi_disks[target].device->busy)
+	  barrier();
 
 	if(rscsi_disks[target].device->removable) {
 	  check_disk_change(inode->i_rdev);
@@ -879,7 +880,7 @@
 		   512, sd_init_done,  SD_TIMEOUT,
 		   MAX_RETRIES);
       
-      while(SCpnt->request.dev != 0xfffe);
+      while(SCpnt->request.dev != 0xfffe) barrier();
       
       the_result = SCpnt->result;
       
@@ -905,7 +906,7 @@
 		       512, sd_init_done,  SD_TIMEOUT,
 		       MAX_RETRIES);
 	  
-	  while(SCpnt->request.dev != 0xfffe);
+	  while(SCpnt->request.dev != 0xfffe) barrier();
 
 	  spintime = jiffies;
 	};
@@ -941,7 +942,7 @@
 		 MAX_RETRIES);
     
     if (current == task[0])
-      while(SCpnt->request.dev != 0xfffe);
+      while(SCpnt->request.dev != 0xfffe) barrier();
     else
       if (SCpnt->request.dev != 0xfffe){
       	struct semaphore sem = MUTEX_LOCKED;
diff -u --recursive --new-file v1.2.7/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v1.2.7/linux/drivers/scsi/sr.c	Wed Mar 29 06:52:59 1995
+++ linux/drivers/scsi/sr.c	Tue May  2 07:40:03 1995
@@ -926,7 +926,7 @@
 		 MAX_RETRIES);
     
     if (current == task[0])
-      while(SCpnt->request.dev != 0xfffe);
+      while(SCpnt->request.dev != 0xfffe) barrier();
     else
       if (SCpnt->request.dev != 0xfffe){
       	struct semaphore sem = MUTEX_LOCKED;
diff -u --recursive --new-file v1.2.7/linux/drivers/scsi/t128.c linux/drivers/scsi/t128.c
--- v1.2.7/linux/drivers/scsi/t128.c	Tue Nov 29 10:07:11 1994
+++ linux/drivers/scsi/t128.c	Tue May  2 07:41:02 1995
@@ -320,9 +320,9 @@
 
 #if 0
     for (; i; --i) {
-	while (!(instance->base[T_STATUS_REG_OFFSET]) & T_ST_RDY);
+	while (!(instance->base[T_STATUS_REG_OFFSET]) & T_ST_RDY) barrier();
 #else
-    while (!(instance->base[T_STATUS_REG_OFFSET]) & T_ST_RDY);
+    while (!(instance->base[T_STATUS_REG_OFFSET]) & T_ST_RDY) barrier();
     for (; i; --i) {
 #endif
 	*d++ = *reg;
@@ -363,9 +363,9 @@
 
 #if 0
     for (; i; --i) {
-	while (!(instance->base[T_STATUS_REG_OFFSET]) & T_ST_RDY);
+	while (!(instance->base[T_STATUS_REG_OFFSET]) & T_ST_RDY) barrier();
 #else
-    while (!(instance->base[T_STATUS_REG_OFFSET]) & T_ST_RDY);
+    while (!(instance->base[T_STATUS_REG_OFFSET]) & T_ST_RDY) barrier();
     for (; i; --i) {
 #endif
 	*reg = *s++;
diff -u --recursive --new-file v1.2.7/linux/drivers/scsi/ultrastor.c linux/drivers/scsi/ultrastor.c
--- v1.2.7/linux/drivers/scsi/ultrastor.c	Mon Jan 16 16:48:19 1995
+++ linux/drivers/scsi/ultrastor.c	Tue May  2 07:42:04 1995
@@ -733,13 +733,13 @@
   retry:
     if (config.slot)
 	while (inb(config.ogm_address - 1) != 0 &&
-	       config.aborted[mscp_index] == 0xff);
+	       config.aborted[mscp_index] == 0xff) barrier();
 
     /* else??? */
 
     while ((inb(LCL_DOORBELL_INTR(config.doorbell_address)) & 
 	    (config.slot ? 2 : 1)) 
-	   && config.aborted[mscp_index] == 0xff);
+	   && config.aborted[mscp_index] == 0xff) barrier();
 
     /* To avoid race conditions, make the code to write to the adapter
        atomic.  This simplifies the abort code.  */
diff -u --recursive --new-file v1.2.7/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c
--- v1.2.7/linux/drivers/scsi/wd7000.c	Mon Jan 16 07:17:37 1995
+++ linux/drivers/scsi/wd7000.c	Tue May  2 07:43:45 1995
@@ -941,7 +941,7 @@
 {
     wd7000_queuecommand(SCpnt, wd7000_scsi_done);
 
-    while (SCpnt->SCp.phase > 0);  /* phase counts scbs down to 0 */
+    while (SCpnt->SCp.phase > 0) barrier();  /* phase counts scbs down to 0 */
 
     return SCpnt->result;
 }
@@ -964,7 +964,8 @@
      */
     mail_out(host, (struct scb *) &icb);
     timeout = jiffies + WAITnexttimeout;  /* wait up to 2 seconds */
-    while (icb.phase && jiffies < timeout) /* wait for completion */;
+    while (icb.phase && jiffies < timeout)
+    	barrier(); /* wait for completion */
 
     if (icb.phase)  {
         printk("wd7000_diagnostics: timed out.\n");
@@ -1074,7 +1075,8 @@
      * which in turn means that scatter/gather will be disabled.
      */
     mail_out(host, (struct scb *) &icb);
-    while (icb.phase) /* wait for completion */;
+    while (icb.phase)
+    	barrier(); /* wait for completion */
     host->rev1 = icb.primary;
     host->rev2 = icb.secondary;
 }
diff -u --recursive --new-file v1.2.7/linux/include/linux/sbpcd.h linux/include/linux/sbpcd.h
--- v1.2.7/linux/include/linux/sbpcd.h	Sat Mar 18 12:45:46 1995
+++ linux/include/linux/sbpcd.h	Mon May  1 21:45:40 1995
@@ -3,7 +3,10 @@
  */
 
 /*
- * the definitions for the first controller can get overridden by
+ * Attention! This file contains user-serviceable parts!
+ * I recommend to make use of it...
+ *
+ * The definitions for the first controller can get overridden by
  * the kernel command line ("lilo boot option").
  * Examples:
  *                                 sbpcd=0x230,SoundBlaster
@@ -12,64 +15,97 @@
  *                             or
  *                                 sbpcd=0x330,SPEA
  *
- * These strings are case sensitive !!!
+ * If sbpcd gets used as a module, you can load it with
+ *     insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x230,1
+ * or
+ *     insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x300,0
+ * or
+ *     insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x330,2
+ * respective to override the configured address and type.
  */
 
 /*
- * put your CDROM port base address into CDROM_PORT
- * and specify the type of your interface in SBPRO.
+ * define your CDROM port base address as CDROM_PORT
+ * and specify the type of your interface card as SBPRO.
  *
- * SBPRO addresses typically are 0x0230 (=0x220+0x10), 0x0250, ...
- * LASERMATE (CI-101P, WDH-7001C) addresses typically are 0x0300, 0x0310, ...
- * SPEA addresses are 0x320, 0x330, 0x340, 0x350
- * there are some soundcards on the market with 0x0630, 0x0650, ...
+ * Read linux/drivers/block/README.sbpcd if you are in doubt about the
+ * type of your interface card (you should do that anyway).
  *
- * example: if your SBPRO audio address is 0x220, specify 0x230.
+ * address:
+ * ========
+ * SBPRO type addresses typically are 0x0230 (=0x220+0x10), 0x0250, ...
+ * LASERMATE type (CI-101P, WDH-7001C) addresses typically are 0x0300, ...
+ * SPEA addresses are from the LASERMATE type and range.
+ * There are some soundcards on the market with 0x0630, 0x0650, ...; their
+ * type is not obvious (both types are possible).
  *
+ * example: if your SBPRO audio address is 0x220, specify 0x230 and SBPRO 1.
+ *          if your soundcard has its CDROM port above 0x300, specify
+ *          that address and try SBPRO 0 first.
  *
+ * interface type:
+ * ===============
  * set SBPRO to 1 for "true" SoundBlaster card
- * set SBPRO to 0 for "poor" (no sound) interface cards
- *                and for "compatible" soundcards.
+ * set SBPRO to 0 for "compatible" soundcards and
+ *                for "poor" (no sound) interface cards.
  * set SBPRO to 2 for the SPEA Media FX card
  *
- * most "compatible" sound boards like Galaxy need to set SBPRO to 0 !!!
- * if SBPRO gets set wrong, the drive will get found - but any
+ * Almost all "compatible" sound boards need to set SBPRO to 0.
+ * If SBPRO is set wrong, the drives will get found - but any
  * data access will give errors (audio access will work).
- * The OmniCD interface card from CreativeLabs needs SBPRO 1.
+ * The "OmniCD" no-sound interface card from CreativeLabs needs SBPRO 1.
  *
- * mail to emoenke@gwdg.de if your "compatible" card needs SBPRO 1
- * (currently I do not know any "compatible" with SBPRO 1)
- * then I can include better information with the next release.
- */
-#if !(SBPCD_ISSUE-1) /* first (or if you have only one) interface board: */
-#define CDROM_PORT 0x0340
-#define SBPRO     0
-#endif
-
-/*
- * If you have a "compatible" soundcard of type "SBPRO 0" or "SBPRO 2",
- * enter your sound card's base address here if you want sbpcd to turn
- * the CD sound channels on.
+ * mail to emoenke@gwdg.de if you have a "compatible" sound card which
+ * in fact needs to set SBPRO to 1 (not any known at time).
+ *
+ * sound base:
+ * ===========
+ * The SOUND_BASE definition tells if we should try to turn the CD sound
+ * channels on. It will only be of use regarding soundcards with a SbPro
+ * compatible mixer.
  *
  * Example: #define SOUND_BASE 0x220 enables the sound card's CD channels
  *          #define SOUND_BASE 0     leaves the soundcard untouched
  */
-#define SOUND_BASE 0x220
-
-/* ignore the rest if you have only one interface board & driver */
-
-#if !(SBPCD_ISSUE-2) /* second interface board: */
-#define CDROM_PORT 0x0320
-#define SBPRO     0
+#if !(SBPCD_ISSUE-1)     /* first (or if you have only one) interface board: */
+#define CDROM_PORT 0x340 /* <-----------<< port address                      */
+#define SBPRO      0     /* <-----------<< interface type                    */
+#define SOUND_BASE 0x220 /* <-----------<< sound address of this card or 0   */
 #endif
-#if !(SBPCD_ISSUE-3) /* third interface board: */
-#define CDROM_PORT 0x0630
-#define SBPRO     1
+#if !(SBPCD_ISSUE-2)     /* ==================== second interface board: === */
+#define CDROM_PORT 0x344 /* <-----------<< port address                      */
+#define SBPRO      0     /* <-----------<< interface type                    */
+#define SOUND_BASE 0x000 /* <-----------<< sound address of this card or 0   */
 #endif
-#if !(SBPCD_ISSUE-4) /* fourth interface board: */
-#define CDROM_PORT 0x0634
-#define SBPRO     0
+#if !(SBPCD_ISSUE-3)     /* ===================== third interface board: === */
+#define CDROM_PORT 0x634 /* <-----------<< port address                      */
+#define SBPRO      1     /* <-----------<< interface type                    */
+#define SOUND_BASE 0x240 /* <-----------<< sound address of this card or 0   */
 #endif
+#if !(SBPCD_ISSUE-4)     /* ==================== fourth interface board: === */
+#define CDROM_PORT 0x634 /* <-----------<< port address                      */
+#define SBPRO      0     /* <-----------<< interface type                    */
+#define SOUND_BASE 0x000 /* <-----------<< sound address of this card or 0   */
+#endif
+
+/*
+ * some more or less user dependent definitions - service them!
+ */
+
+/* Set this to 0 after you have configured your interface definitions right. */
+#define DISTRIBUTION 1
+
+/* max. number of audio frames to read with one     */
+/* request (allocates n* 2352 bytes kernel memory!) */
+/* may be freely adjusted, f.e. 75 (= 1 sec.), at   */
+/* runtime by use of the CDROMAUDIOBUFSIZ ioctl.    */
+#define READ_AUDIO 0 
+
+/* tray control: eject tray if no disk is in (0 or 1) */
+#define JUKEBOX 1
+
+/* tray control: eject tray after last use (0 or 1) */
+#define EJECT 1
 
 /*==========================================================================*/
 /*==========================================================================*/
@@ -79,49 +115,65 @@
 #ifndef _LINUX_SBPCD_H
 
 #define _LINUX_SBPCD_H
-
 /*==========================================================================*/
 /*==========================================================================*/
+#define LONG_TIMING 0 /* test against timeouts with "gold" CDs on CR-521 */
+#undef  FUTURE
+
+#define TEST_UPC 0
+#define SPEA_TEST 0
+#define TEST_STI 0
+#undef PATH_CHECK
+/*==========================================================================*/
 /*
  * DDI interface definitions
  * "invented" by Fred N. van Kempen..
  */
 #define DDIOCSDBG	0x9000
-#define DPRINTF(x)	sbpcd_dprintf x
+
+/*==========================================================================*/
+/*
+ * "private" IOCTL functions
+ */
+#define CDROMRESET		0x5380 /* hard-rest the drive */
+#define CDROMVOLREAD		0x5381 /* let the drive tell its volume settings */
+#define CDROMAUDIOBUFSIZ	0x5382 /* set the audio buffer size */
 
 /*==========================================================================*/
 /*
  * Debug output levels
  */
-#define DBG_INF		1	/* necessary information */
-#define DBG_BSZ		2	/* BLOCK_SIZE trace */
-#define DBG_REA		3	/* "read" status trace */
-#define DBG_CHK		4	/* "media check" trace */
-#define DBG_TIM		5	/* datarate timer test */
-#define DBG_INI		6	/* initialization trace */
-#define DBG_TOC		7	/* tell TocEntry values */
-#define DBG_IOC         8	/* ioctl trace */
-#define DBG_STA		9	/* "ResponseStatus" trace */
-#define DBG_ERR		10	/* "xx_ReadError" trace */
-#define DBG_CMD		11	/* "cmd_out" trace */
-#define DBG_WRN		12	/* give explanation before auto-probing */
-#define DBG_MUL         13      /* multi session code test */
-#define DBG_ID		14	/* "drive_id !=0" test code */
-#define DBG_IOX		15	/* some special information */
-#define DBG_DID		16	/* drive ID test */
-#define DBG_RES		17	/* drive reset info */
-#define DBG_SPI		18	/* SpinUp test */
-#define DBG_IOS		19	/* ioctl trace: "subchannel" */
-#define DBG_IO2		20	/* ioctl trace: general */
-#define DBG_UPC		21	/* show UPC information */
-#define DBG_XA 		22	/* XA mode debugging */
-#define DBG_LCK		23	/* door (un)lock info */
-#define DBG_SQ 		24	/* dump SubQ frame */
-#define DBG_AUD		25      /* "read audio" debugging */
-#define DBG_SEQ		26      /* Sequoia interface configuration trace */
-#define DBG_LCS		27      /* Longshine LCS-7260 debugging trace */
-#define DBG_CD2		28      /* MKE CD200 debugging trace */
-#define DBG_000		29      /* unnecessary information */
+#define DBG_INF	1	/* necessary information */
+#define DBG_BSZ	2	/* BLOCK_SIZE trace */
+#define DBG_REA	3	/* READ status trace */
+#define DBG_CHK	4	/* MEDIA CHECK trace */
+#define DBG_TIM	5	/* datarate timer test */
+#define DBG_INI	6	/* initialization trace */
+#define DBG_TOC	7	/* tell TocEntry values */
+#define DBG_IOC	8	/* ioctl trace */
+#define DBG_STA	9	/* ResponseStatus() trace */
+#define DBG_ERR	10	/* cc_ReadError() trace */
+#define DBG_CMD	11	/* cmd_out() trace */
+#define DBG_WRN	12	/* give explanation before auto-probing */
+#define DBG_MUL	13	/* multi session code test */
+#define DBG_IDX	14	/* test code for drive_id !=0 */
+#define DBG_IOX	15	/* some special information */
+#define DBG_DID	16	/* drive ID test */
+#define DBG_RES	17	/* drive reset info */
+#define DBG_SPI	18	/* SpinUp test */
+#define DBG_IOS	19	/* ioctl trace: subchannel functions */
+#define DBG_IO2	20	/* ioctl trace: general */
+#define DBG_UPC	21	/* show UPC information */
+#define DBG_XA1	22	/* XA mode debugging */
+#define DBG_LCK	23	/* door (un)lock info */
+#define DBG_SQ1	24	/* dump SubQ frame */
+#define DBG_AUD	25	/* READ AUDIO debugging */
+#define DBG_SEQ	26	/* Sequoia interface configuration trace */
+#define DBG_LCS	27	/* Longshine LCS-7260 debugging trace */
+#define DBG_CD2	28	/* MKE CD200 debugging trace */
+#define DBG_TEA	29	/* TEAC CD-55A debugging trace */
+#define DBG_TE2	30	/* TEAC CD-55A 2nd debugging level */
+#define DBG_000	31	/* unnecessary information */
 
 /*==========================================================================*/
 /*==========================================================================*/
@@ -154,35 +206,41 @@
 /*
  * disk states (bits of diskstate_flags):
  */
-#define upc_valid (DriveStruct[d].diskstate_flags&upc_bit)
-#define volume_valid (DriveStruct[d].diskstate_flags&volume_bit)
-#define toc_valid (DriveStruct[d].diskstate_flags&toc_bit)
-#define cd_size_valid (DriveStruct[d].diskstate_flags&cd_size_bit)
-#define subq_valid (DriveStruct[d].diskstate_flags&subq_bit)
-#define frame_size_valid (DriveStruct[d].diskstate_flags&frame_size_bit)
-
-/*
- * bits of the status_byte (result of xx_ReadStatus):
- */
-#define p_door_closed 0x80
-#define p_caddy_in 0x40
-#define p_spinning 0x20
-#define p_check 0x10
-#define p_busy_new 0x08
-#define p_door_locked 0x04
-#define p_bit_1 0x02 /* hopefully unused now */
-#define p_lcs_door_locked 0x02 /* new use of old bit */
-#define p_disk_ok 0x01
-#define p_lcs_door_closed 0x01 /* new use of old bit */
-/*
- * "old" drives status result bits:
- */
-#define p_caddin_old 0x40
-#define p_success_old 0x08
-#define p_busy_old 0x04
+#define upc_valid		(D_S[d].diskstate_flags&upc_bit)
+#define volume_valid		(D_S[d].diskstate_flags&volume_bit)
+#define toc_valid		(D_S[d].diskstate_flags&toc_bit)
+#define cd_size_valid		(D_S[d].diskstate_flags&cd_size_bit)
+#define subq_valid		(D_S[d].diskstate_flags&subq_bit)
+#define frame_size_valid	(D_S[d].diskstate_flags&frame_size_bit)
 
 /*
- * "generation specific" defs of the status_byte:
+ * the status_bits variable
+ */
+#define p_success	0x100
+#define p_door_closed	0x80
+#define p_caddy_in	0x40
+#define p_spinning	0x20
+#define p_check		0x10
+#define p_busy_new	0x08
+#define p_door_locked	0x04
+#define p_disk_ok	0x01
+
+/*
+ * LCS-7260 special status result bits:
+ */
+#define p_lcs_door_locked	0x02
+#define p_lcs_door_closed	0x01
+
+/*
+ * CR-52x special status result bits:
+ */
+#define p_caddin_old	0x40
+#define p_success_old	0x08
+#define p_busy_old	0x04
+#define p_bit_1		0x02	/* hopefully unused now */
+
+/*
+ * "generation specific" defs of the status result bits:
  */
 #define p0_door_closed	0x80
 #define p0_caddy_in	0x40
@@ -193,6 +251,14 @@
 #define p0_bit_1	0x02 /* unused */
 #define p0_disk_ok	0x01
 
+#define pL_disk_in	0x40
+#define pL_spinning	0x20
+#define pL_check	0x10
+#define pL_success	0x08 /* unused ?? */
+#define pL_busy		0x04
+#define pL_door_locked	0x02
+#define pL_door_closed	0x01
+
 #define p1_door_closed	0x80
 #define p1_disk_in	0x40
 #define p1_spinning	0x20
@@ -214,60 +280,66 @@
 /*
  * used drive states:
  */
-#define st_door_closed (DriveStruct[d].status_byte&p_door_closed)
-#define st_caddy_in (DriveStruct[d].status_byte&p_caddy_in)
-#define st_spinning (DriveStruct[d].status_byte&p_spinning)
-#define st_check (DriveStruct[d].status_byte&p_check)
-#define st_busy (DriveStruct[d].status_byte&p_busy_new)
-#define st_door_locked (DriveStruct[d].status_byte&p_door_locked)
-#define st_diskok (DriveStruct[d].status_byte&p_disk_ok)
+#define st_door_closed	(D_S[d].status_bits&p_door_closed)
+#define st_caddy_in	(D_S[d].status_bits&p_caddy_in)
+#define st_spinning	(D_S[d].status_bits&p_spinning)
+#define st_check	(D_S[d].status_bits&p_check)
+#define st_busy		(D_S[d].status_bits&p_busy_new)
+#define st_door_locked	(D_S[d].status_bits&p_door_locked)
+#define st_diskok	(D_S[d].status_bits&p_disk_ok)
 
 /*
  * bits of the CDi_status register:
  */
-#define s_not_result_ready 0x04  /* 0: "result ready" */
-#define s_not_data_ready 0x02    /* 0: "data ready"   */
-#define s_attention 0x01         /* 1: "attention required" */
+#define s_not_result_ready	0x04 /* 0: "result ready" */
+#define s_not_data_ready	0x02 /* 0: "data ready"   */
+#define s_attention		0x01 /* 1: "attention required" */
 /*
  * usable as:
  */
-#define DRV_ATTN               ((inb(CDi_status)&s_attention)!=0)
-#define DATA_READY             ((inb(CDi_status)&s_not_data_ready)==0)
-#define RESULT_READY           ((inb(CDi_status)&s_not_result_ready)==0)
+#define DRV_ATTN	((inb(CDi_status)&s_attention)!=0)
+#define DATA_READY	((inb(CDi_status)&s_not_data_ready)==0)
+#define RESULT_READY	((inb(CDi_status)&s_not_result_ready)==0)
 
 /*
  * drive types (firmware versions):
  */
-#define drv_fam0 0x08   /* CR-52x family */
-#define drv_199 (drv_fam0+0x01)    /* <200 */
-#define drv_200 (drv_fam0+0x02)    /* <201 */
-#define drv_201 (drv_fam0+0x03)    /* <210 */
-#define drv_210 (drv_fam0+0x04)    /* <211 */
-#define drv_211 (drv_fam0+0x05)    /* <300 */
-#define drv_300 (drv_fam0+0x06)    /* >=300 */
-
-#define drv_famL 0x10    /* Longshine family */
-#define drv_260 (drv_famL+0x01)    /* LCS-7260 */
-
-#define drv_fam1 0x20    /* CR-56x family */
-#define drv_099 (drv_fam1+0x01)    /* <100 */
-#define drv_100 (drv_fam1+0x02)    /* >=100 */
-
-#define drv_fam2 0x80    /* CD200 family */
-
-#define fam0_drive (DriveStruct[d].drv_type&drv_fam0)
-#define famL_drive (DriveStruct[d].drv_type&drv_famL)
-#define fam1_drive (DriveStruct[d].drv_type&drv_fam1)
-#define fam2_drive (DriveStruct[d].drv_type&drv_fam2)
-#define fam0L_drive (DriveStruct[d].drv_type&(drv_fam0|drv_famL))
-#define fam1L_drive (DriveStruct[d].drv_type&(drv_fam1|drv_famL))
-#define fam01_drive (DriveStruct[d].drv_type&(drv_fam0|drv_fam1))
+#define drv_fam0	0x08		/* CR-52x family */
+#define drv_199		(drv_fam0+0x01)	/* <200 */
+#define drv_200		(drv_fam0+0x02)	/* <201 */
+#define drv_201		(drv_fam0+0x03)	/* <210 */
+#define drv_210		(drv_fam0+0x04)	/* <211 */
+#define drv_211		(drv_fam0+0x05)	/* <300 */
+#define drv_300		(drv_fam0+0x06)	/* >=300 */
+
+#define drv_famL	0x10		/* Longshine family */
+#define drv_260		(drv_famL+0x01)	/* LCS-7260 */
+#define drv_e1		(drv_famL+0x01)	/* LCS-7260, firmware "A E1" */
+#define drv_f4		(drv_famL+0x02)	/* LCS-7260, firmware "A4F4" */
+
+#define drv_fam1	0x20		/* CR-56x family */
+#define drv_099		(drv_fam1+0x01)	/* <100 */
+#define drv_100		(drv_fam1+0x02)	/* >=100, only 5.00 known here */
+
+#define drv_famT	0x40		/* TEAC CD-55A */
+#define drv_fam2	0x80		/* CD200 family */
+
+#define fam0_drive	(D_S[d].drv_type&drv_fam0)
+#define famL_drive	(D_S[d].drv_type&drv_famL)
+#define fam1_drive	(D_S[d].drv_type&drv_fam1)
+#define fam2_drive	(D_S[d].drv_type&drv_fam2)
+#define famT_drive	(D_S[d].drv_type&drv_famT)
+#define fam0L_drive	(D_S[d].drv_type&(drv_fam0|drv_famL))
+#define fam1L_drive	(D_S[d].drv_type&(drv_fam1|drv_famL))
+#define fam01_drive	(D_S[d].drv_type&(drv_fam0|drv_fam1))
+#define fam12_drive	(D_S[d].drv_type&(drv_fam1|drv_fam2))
+#define fam2T_drive	(D_S[d].drv_type&(drv_fam2|drv_famT))
 
 /*
  * audio states:
  */
-#define audio_playing 2
-#define audio_pausing 1
+#define audio_playing	2
+#define audio_pausing	1
 
 /*
  * drv_pattern, drv_options:
@@ -280,10 +352,10 @@
 /*
  * values of cmd_type (0 else):
  */
-#define READ_M1  0x01 /* "data mode 1": 2048 bytes per frame */
-#define READ_M2  0x02 /* "data mode 2": 12+2048+280 bytes per frame */
-#define READ_SC  0x04 /* "subchannel info": 96 bytes per frame */
-#define READ_AU  0x08 /* "audio frame": 2352 bytes per frame */
+#define READ_M1	0x01	/* "data mode 1": 2048 bytes per frame */
+#define READ_M2	0x02	/* "data mode 2": 12+2048+280 bytes per frame */
+#define READ_SC	0x04	/* "subchannel info": 96 bytes per frame */
+#define READ_AU	0x08	/* "audio frame": 2352 bytes per frame */
 
 /*
  * sense_byte:
@@ -314,32 +386,27 @@
 /*
  * highest allowed drive number (MINOR+1)
  */
-#define NR_SBPCD 4
+#define NR_SBPCD	4
 
 /*
  * we try to never disable interrupts - seems to work
  */
-#define SBPCD_DIS_IRQ 0
+#define SBPCD_DIS_IRQ	0
 
 /*
  * "write byte to port"
  */
-#define OUT(x,y) outb(y,x)
-
-/*
- * use "REP INSB" for strobing the data in:
- */
-#define READ_DATA(port, buf, nr) insb(port, buf, nr)
+#define OUT(x,y)	outb(y,x)
 
 /*==========================================================================*/
 
-#define MIXER_CD_Volume	0x28 /* internal SB Pro register address */
+#define MIXER_CD_Volume	0x28	/* internal SB Pro register address */
 
 /*==========================================================================*/
 /*
  * Creative Labs Programmers did this:
  */
-#define MAX_TRACKS	120 /* why more than 99? */
+#define MAX_TRACKS	120	/* why more than 99? */
 
 /*==========================================================================*/
 /*
@@ -347,17 +414,15 @@
  */
 typedef union _msf
 {
-  u_int n;
-  u_char c[4];
-}
-MSF;
+	u_int n;
+	u_char c[4];
+} MSF;
 
 typedef union _blk
 {
-  u_int n;
-  u_char c[4];
-}
-BLK;
+	u_int n;
+	u_char c[4];
+} BLK;
 
 /*==========================================================================*/
 
@@ -519,111 +584,177 @@
  * CR-56x:      CMD1_
  * CD200:       CMD2_
  * LCS-7260:    CMDL_
+ * TEAC CD-55A: CMDT_
  */
 #define CMD1_RESET	0x0a
 #define CMD2_RESET	0x01
+#define CMDT_RESET	0xc0
+
 #define CMD1_LOCK_CTL	0x0c
 #define CMD2_LOCK_CTL	0x1e
+#define CMDT_LOCK_CTL	CMD2_LOCK_CTL
 #define CMDL_LOCK_CTL	0x0e
+
 #define CMD1_TRAY_CTL	0x07
 #define CMD2_TRAY_CTL	0x1b
+#define CMDT_TRAY_CTL	CMD2_TRAY_CTL
 #define CMDL_TRAY_CTL	0x0d
+
 #define CMD1_MULTISESS	0x8d
 #define CMDL_MULTISESS	0x8c
+
 #define CMD1_SUBCHANINF	0x11
-#define CMD2_SUBCHANINF	0x
+#define CMD2_SUBCHANINF	0x??
+
 #define CMD2_x02	0x02
 #define CMD1_x08	0x08
 #define CMD2_x08	0x08
+#define CMDT_x08	0x08
+
 #define CMD2_SETSPEED	0xda
 
 #define CMD0_PATH_CHECK	0x00
-#define CMD1_PATH_CHECK	0x00
-#define CMD2_PATH_CHECK	0x
-#define CMDL_PATH_CHECK	0x00
+#define CMD1_PATH_CHECK	0x???
+#define CMD2_PATH_CHECK	0x???
+#define CMDT_PATH_CHECK	0x???
+#define CMDL_PATH_CHECK	CMD0_PATH_CHECK
+
 #define CMD0_SEEK	0x01
-#define CMD1_SEEK	0x01
+#define CMD1_SEEK	CMD0_SEEK
 #define CMD2_SEEK	0x2b
-#define CMDL_SEEK	0x01
+#define CMDT_SEEK	CMD2_SEEK
+#define CMDL_SEEK	CMD0_SEEK
+
 #define CMD0_READ	0x02
 #define CMD1_READ	0x10
 #define CMD2_READ	0x28
-#define CMDL_READ	0x02
+#define CMDT_READ	CMD2_READ
+#define CMDL_READ	CMD0_READ
+
 #define CMD0_READ_XA	0x03
 #define CMD2_READ_XA	0xd4
-#define CMDL_READ_XA	0x03 /* really ?? */
+#define CMDL_READ_XA	CMD0_READ_XA /* really ?? */
+
 #define CMD0_READ_HEAD	0x04
+
 #define CMD0_SPINUP	0x05
 #define CMD1_SPINUP	0x02
 #define CMD2_SPINUP	CMD2_TRAY_CTL
-#define CMDL_SPINUP	0x05
+#define CMDL_SPINUP	CMD0_SPINUP
+
 #define CMD0_SPINDOWN	0x06 /* really??? */
 #define CMD1_SPINDOWN	0x06
 #define CMD2_SPINDOWN	CMD2_TRAY_CTL
 #define CMDL_SPINDOWN	0x0d
+
 #define CMD0_DIAG	0x07
+
 #define CMD0_READ_UPC	0x08
 #define CMD1_READ_UPC	0x88
-#define CMD2_READ_UPC	0x
-#define CMDL_READ_UPC	0x08
+#define CMD2_READ_UPC	0x???
+#define CMDL_READ_UPC	CMD0_READ_UPC
+
 #define CMD0_READ_ISRC	0x09
+
 #define CMD0_PLAY	0x0a
-#define CMD1_PLAY	0x
-#define CMD2_PLAY	0x
-#define CMDL_PLAY	0x0a
+#define CMD1_PLAY	0x???
+#define CMD2_PLAY	0x???
+#define CMDL_PLAY	CMD0_PLAY
+
 #define CMD0_PLAY_MSF	0x0b
 #define CMD1_PLAY_MSF	0x0e
 #define CMD2_PLAY_MSF	0x47
-#define CMDL_PLAY_MSF	0x
+#define CMDT_PLAY_MSF	CMD2_PLAY_MSF
+#define CMDL_PLAY_MSF	0x???
+
 #define CMD0_PLAY_TI	0x0c
+
 #define CMD0_STATUS	0x81
 #define CMD1_STATUS	0x05
 #define CMD2_STATUS	0x00
-#define CMDL_STATUS	0x81
+#define CMDT_STATUS	CMD2_STATUS
+#define CMDL_STATUS	CMD0_STATUS
+
 #define CMD0_READ_ERR	0x82
-#define CMD1_READ_ERR	0x82
+#define CMD1_READ_ERR	CMD0_READ_ERR
 #define CMD2_READ_ERR	0x03
-#define CMDL_READ_ERR	0x82
+#define CMDT_READ_ERR	CMD2_READ_ERR /* get audio status */
+#define CMDL_READ_ERR	CMD0_READ_ERR
+
 #define CMD0_READ_VER	0x83
-#define CMD1_READ_VER	0x83
+#define CMD1_READ_VER	CMD0_READ_VER
 #define CMD2_READ_VER	0x12
-#define CMDL_READ_VER	0x83
+#define CMDT_READ_VER	CMD2_READ_VER /* really ?? */
+#define CMDL_READ_VER	CMD0_READ_VER
+
 #define CMD0_SETMODE	0x84
 #define CMD1_SETMODE	0x09
 #define CMD2_SETMODE	0x55
-#define CMDL_SETMODE	0x84
+#define CMDT_SETMODE	CMD2_SETMODE
+#define CMDL_SETMODE	CMD0_SETMODE
+
 #define CMD0_GETMODE	0x85
 #define CMD1_GETMODE	0x84
 #define CMD2_GETMODE	0x5a
-#define CMDL_GETMODE	0x85
+#define CMDT_GETMODE	CMD2_GETMODE
+#define CMDL_GETMODE	CMD0_GETMODE
+
 #define CMD0_SET_XA	0x86
+
 #define CMD0_GET_XA	0x87
+
 #define CMD0_CAPACITY	0x88
 #define CMD1_CAPACITY	0x85
 #define CMD2_CAPACITY	0x25
-#define CMDL_CAPACITY	0x88
+#define CMDL_CAPACITY	CMD0_CAPACITY /* missing in some firmware versions */
+
 #define CMD0_READSUBQ	0x89
 #define CMD1_READSUBQ	0x87
 #define CMD2_READSUBQ	0x42
-#define CMDL_READSUBQ	0x89
+#define CMDT_READSUBQ	CMD2_READSUBQ
+#define CMDL_READSUBQ	CMD0_READSUBQ
+
 #define CMD0_DISKCODE	0x8a
+
 #define CMD0_DISKINFO	0x8b
-#define CMD1_DISKINFO	0x8b
+#define CMD1_DISKINFO	CMD0_DISKINFO
 #define CMD2_DISKINFO	0x43
-#define CMDL_DISKINFO	0x8b
+#define CMDT_DISKINFO	CMD2_DISKINFO
+#define CMDL_DISKINFO	CMD0_DISKINFO
+
 #define CMD0_READTOC	0x8c
-#define CMD1_READTOC	0x8c
-#define CMD2_READTOC	0x
-#define CMDL_READTOC	0x8c
+#define CMD1_READTOC	CMD0_READTOC
+#define CMD2_READTOC	0x???
+#define CMDL_READTOC	CMD0_READTOC
+
 #define CMD0_PAU_RES	0x8d
 #define CMD1_PAU_RES	0x0d
 #define CMD2_PAU_RES	0x4b
-#define CMDL_PAU_RES	0x8d
+#define CMDT_PAUSE	CMD2_PAU_RES
+#define CMDL_PAU_RES	CMD0_PAU_RES
+
 #define CMD0_PACKET	0x8e
-#define CMD1_PACKET	0x8e
-#define CMD2_PACKET	0x
-#define CMDL_PACKET	0x8e
+#define CMD1_PACKET	CMD0_PACKET
+#define CMD2_PACKET	0x???
+#define CMDL_PACKET	CMD0_PACKET
 
 /*==========================================================================*/
 /*==========================================================================*/
 #endif _LINUX_SBPCD_H
+/*==========================================================================*/
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file. 
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff -u --recursive --new-file v1.2.7/linux/include/linux/sched.h linux/include/linux/sched.h
--- v1.2.7/linux/include/linux/sched.h	Sun Apr  9 11:59:57 1995
+++ linux/include/linux/sched.h	Tue May  2 07:22:23 1995
@@ -77,6 +77,8 @@
 
 #ifdef __KERNEL__
 
+#define barrier() __asm__("": : :"memory")
+
 extern void sched_init(void);
 extern void show_state(void);
 extern void trap_init(void);
diff -u --recursive --new-file v1.2.7/linux/include/linux/tty.h linux/include/linux/tty.h
--- v1.2.7/linux/include/linux/tty.h	Sun Feb 26 16:45:26 1995
+++ linux/include/linux/tty.h	Tue May  2 08:33:51 1995
@@ -255,6 +255,7 @@
 #define TTY_DEBUG 4
 #define TTY_DO_WRITE_WAKEUP 5
 #define TTY_PUSH 6
+#define TTY_CLOSING 7
 
 #define TTY_WRITE_FLUSH(tty) tty_write_flush((tty))
 
diff -u --recursive --new-file v1.2.7/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.2.7/linux/kernel/ksyms.c	Fri Apr 28 11:10:56 1995
+++ linux/kernel/ksyms.c	Tue May  2 08:05:05 1995
@@ -321,7 +321,6 @@
 	X(n_tty_ioctl),
 	X(tty_register_ldisc),
 	X(kill_fasync),
-	X(tty_hung_up_p),
 #endif
 #ifdef CONFIG_SCSI
 	/* Supports loadable scsi drivers */
diff -u --recursive --new-file v1.2.7/linux/net/inet/datagram.c linux/net/inet/datagram.c
--- v1.2.7/linux/net/inet/datagram.c	Thu Mar  9 20:37:36 1995
+++ linux/net/inet/datagram.c	Tue May  2 18:58:07 1995
@@ -15,6 +15,7 @@
  *					AX.25 now works right, and SPX is feasible.
  *		Alan Cox	:	Fixed write select of non IP protocol crash.
  *		Florian  La Roche:	Changed for my new skbuff handling.
+ *		Darryl Miles	:	Fixed non-blocking SOCK_SEQPACKET.
  *
  *	Note:
  *		A lot of this will change when the protocol/socket separation
@@ -191,6 +192,11 @@
 			return(0);
 
 		case SEL_OUT:
+			if (sk->type==SOCK_SEQPACKET && sk->state==TCP_SYN_SENT)
+			{
+				/* Connection still in progress */
+				return(0);
+			}
 			if (sk->prot && sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
 			{
 				return(1);
diff -u --recursive --new-file v1.2.7/linux/net/inet/tcp.c linux/net/inet/tcp.c
--- v1.2.7/linux/net/inet/tcp.c	Wed Mar 29 06:53:01 1995
+++ linux/net/inet/tcp.c	Tue May  2 18:57:03 1995
@@ -2854,7 +2854,7 @@
 	buff = newsk->prot->wmalloc(newsk, MAX_SYN_SIZE, 1, GFP_ATOMIC);
 	if (buff == NULL) 
 	{
-		sk->err = -ENOMEM;
+		sk->err = ENOMEM;
 		newsk->dead = 1;
 		newsk->state = TCP_CLOSE;
 		/* And this will destroy it */
