patch-1.3.71 linux/drivers/cdrom/mcdx.c

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

diff -u --recursive --new-file v1.3.70/linux/drivers/cdrom/mcdx.c linux/drivers/cdrom/mcdx.c
@@ -1,7 +1,7 @@
 /*
  * The Mitsumi CDROM interface
  * Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
- * VERSION: 1.5a
+ * VERSION: 1.7
  * 
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -27,6 +27,7 @@
  *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
  *  Gerd Knorr (he lent me his PhotoCD)
  *  Nils Faerber and Roger E. Wolff (extensivly tested the LU portion)
+ *  Andreas Kies (testing the mysterious hang up's)
  *  ... somebody forgotten?
  *  
  */
@@ -34,14 +35,13 @@
 
 #if RCS
 static const char *mcdx_c_version
-		= "mcdx.c,v 1.19.2.1 1996/01/13 21:25:55 heiko Exp";
+		= "mcdx.c,v 1.31 1996/03/02 00:21:18 heiko Exp";
 #endif
 
 #include <linux/version.h>
 #include <linux/module.h>
 
 #include <linux/errno.h>
-#include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/fs.h>
@@ -77,14 +77,13 @@
 enum datamodes { MODE0, MODE1, MODE2 };
 enum resetmodes { SOFT, HARD };
 
-const int SINGLE = 0x01;
-const int DOUBLE = 0x02;
-const int DOOR   = 0x04;
-const int MULTI  = 0x08;
-const int READY  = 0x70;
+const int SINGLE = 0x01;		/* single speed drive (FX001S, LU) */
+const int DOUBLE = 0x02;		/* double speed drive (FX001D, ..? */
+const int DOOR   = 0x04;		/* door locking capability */
+const int MULTI  = 0x08;		/* multi session capability */
 
-const unsigned char READSSPEED = 0xc0;
-const unsigned char READDSPEED = 0xc1;
+const unsigned char READ1X = 0xc0;
+const unsigned char READ2X = 0xc1;
 
 
 /* DECLARATIONS ****************************************************/ 
@@ -161,14 +160,15 @@
     int irq;			/* irq used by this drive */
     int minor;			/* minor number of this drive */
     int present;	    /* drive present and its capabilities */
-    char readcmd;		/* read cmd depends on single/double speed */
-    char playcmd;       /* play should always be single speed */
-    unsigned long changed;	/* last jiff the media was changed */
-    unsigned long xxx;      /* last jiff it was asked for media change */
+    unsigned char readcmd;	/* read cmd depends on single/double speed */
+    unsigned char playcmd;  /* play should always be single speed */
+    unsigned int xxx;      /* set if changed, reset while open */
+    unsigned int yyy;      /* set if changed, reset by media_changed */
     unsigned long ejected;  /* time we called the eject function */
     int users;				/* keeps track of open/close */
     int lastsector;			/* last block accessible */
-    int errno;				/* last operation's error */
+    int status;				/* last operation's error / status */
+	int readerrs;			/* # of blocks read w/o error */
 };
 
 
@@ -211,6 +211,7 @@
 static int irq(int*);
 static void mcdx_delay(struct s_drive_stuff*, long jifs);
 static int mcdx_transfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);
+static int mcdx_xfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);
 
 static int mcdx_config(struct s_drive_stuff*, int);
 static int mcdx_closedoor(struct s_drive_stuff*, int);
@@ -238,6 +239,7 @@
 
 /* static variables ************************************************/
 
+static int mcdx_blocksizes[MCDX_NDRIVES];
 static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
 static struct s_drive_stuff* mcdx_stuffp[MCDX_NDRIVES];
 static struct s_drive_stuff* mcdx_irq_map[16] =
@@ -468,7 +470,7 @@
 				ms.addr.lba = msf2log(&stuffp->multi.msf_last);
 			else
 				return -EINVAL;
-			ms.xa_flag = stuffp->xa;
+			ms.xa_flag = !!stuffp->multi.multi;
 
 			if (0 != (ans = verify_area(VERIFY_WRITE, (void*) arg,
 					sizeof(struct cdrom_multisession))))
@@ -571,7 +573,7 @@
 	  break;
 
       case READ:
-	  stuffp->errno = 0;
+	  stuffp->status = 0;
 	  while (CURRENT->nr_sectors) {
 	      int i;
 
@@ -580,12 +582,13 @@
 				      CURRENT->buffer,
 				      CURRENT->sector,
 				      CURRENT->nr_sectors))) {
-              WARN(("do_request() read error\n"));
-              if (stuffp->errno == MCDX_EOM) {
+              INFO(("do_request() read error\n"));
+              if (stuffp->status & MCDX_ST_EOM) {
                   CURRENT->sector += CURRENT->nr_sectors;
                   CURRENT->nr_sectors = 0;
-              }
+              } 
               end_request(0);
+			  /* return; */
               goto again;
 	      }
 	      CURRENT->sector += i;
@@ -627,38 +630,36 @@
 	if (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_DOOR) {
         if (jiffies - stuffp->ejected < ACLOSE_INHIBIT) return -EIO;
         if (stuffp->autoclose) mcdx_closedoor(stuffp, 1);
-        else return -EIO;
+		else return -EIO;
     }
 
 	/* if the media changed we will have to do a little more */
-	if (stuffp->xxx < stuffp->changed) {
+	if (stuffp->xxx) {
 
 		TRACE((OPENCLOSE, "open() media changed\n"));
         /* but wait - the time of media change will be set at the 
-        very last of this block - it seems, some of the following
-        talk() will detect a media change ... (I think, config()
-        is the reason. */
+           very last of this block - it seems, some of the following
+           talk() will detect a media change ... (I think, config()
+           is the reason. */
 
         stuffp->audiostatus = CDROM_AUDIO_INVALID;
 
 		/* get the multisession information */
-		{
-            int ans;
-
-			TRACE((OPENCLOSE, "open() Request multisession info\n"));
-            ans = mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6);
-            if (ans == -1) {
-                stuffp->autoclose = 0;
-                mcdx_eject(stuffp, 1);
-                return -EIO;
-            }
-
-            /* we succeeded, so on next open(2) we could try auto close
-            again */
-            stuffp->autoclose = 1;
+		TRACE((OPENCLOSE, "open() Request multisession info\n"));
+		if (-1 == mcdx_requestmultidiskinfo(
+				stuffp, &stuffp->multi, 6)) {
+			INFO(("No multidiskinfo\n"));
+			stuffp->autoclose = 0;
+		} else {
+			/* we succeeded, so on next open(2) we could try auto close
+			again */
+			stuffp->autoclose = 1;
 		
+#if !MCDX_QUIET
 			if (stuffp->multi.multi > 2)
-				WARN(("open() unknown multisession value (%d)\n", stuffp->multi.multi));
+				INFO(("open() unknown multisession value (%d)\n", 
+						stuffp->multi.multi));
+#endif
 
 			/* multisession ? */
 			if (!stuffp->multi.multi)
@@ -669,38 +670,54 @@
 					stuffp->multi.msf_last.minute,
 					stuffp->multi.msf_last.second,
 					stuffp->multi.msf_last.frame));
+
 		} /* got multisession information */
 
 		/* request the disks table of contents (aka diskinfo) */
-		if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) return -EIO;
+		if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
 
-		stuffp->lastsector = (CD_FRAMESIZE / 512) 
-                * msf2log(&stuffp->di.msf_leadout) - 1;
+			stuffp->lastsector = -1;
+
+		} else {
 
-		TRACE((OPENCLOSE, "open() start %d (%02x:%02x.%02x) %d\n",
-				stuffp->di.n_first,
-				stuffp->di.msf_first.minute,
-				stuffp->di.msf_first.second,
-				stuffp->di.msf_first.frame,
-				msf2log(&stuffp->di.msf_first)));
-		TRACE((OPENCLOSE, "open() last %d (%02x:%02x.%02x) %d\n",
-				stuffp->di.n_last,
-				stuffp->di.msf_leadout.minute,
-				stuffp->di.msf_leadout.second,
-				stuffp->di.msf_leadout.frame,
-				msf2log(&stuffp->di.msf_leadout)));
+			stuffp->lastsector = (CD_FRAMESIZE / 512) 
+					* msf2log(&stuffp->di.msf_leadout) - 1;
+
+			TRACE((OPENCLOSE, "open() start %d (%02x:%02x.%02x) %d\n",
+					stuffp->di.n_first,
+					stuffp->di.msf_first.minute,
+					stuffp->di.msf_first.second,
+					stuffp->di.msf_first.frame,
+					msf2log(&stuffp->di.msf_first)));
+			TRACE((OPENCLOSE, "open() last %d (%02x:%02x.%02x) %d\n",
+					stuffp->di.n_last,
+					stuffp->di.msf_leadout.minute,
+					stuffp->di.msf_leadout.second,
+					stuffp->di.msf_leadout.frame,
+					msf2log(&stuffp->di.msf_leadout)));
+		}
 
 		if (stuffp->toc) {
-			TRACE((MALLOC, "open() free toc @ %p\n", stuffp->toc));
+			TRACE((MALLOC, "open() free old toc @ %p\n", stuffp->toc));
 			kfree(stuffp->toc);
+		
+			stuffp->toc = NULL;
 		}
-		stuffp->toc = NULL;
 
 		TRACE((OPENCLOSE, "open() init irq generation\n"));
 		if (-1 == mcdx_config(stuffp, 1)) return -EIO;
 
-		/* try to get the first sector ... */
-		{
+#if FALLBACK
+		/* Set the read speed */
+		WARN(("AAA %x AAA\n", stuffp->readcmd));
+		if (stuffp->readerrs) stuffp->readcmd = READ1X;
+		else stuffp->readcmd = 
+				stuffp->present | SINGLE ? READ1X : READ2X;
+		WARN(("XXX %x XXX\n", stuffp->readcmd));
+#endif
+
+		/* try to get the first sector, iff any ... */
+		if (stuffp->lastsector >= 0) {
 			char buf[512];
 			int ans;
 			int tries;
@@ -709,13 +726,19 @@
 			stuffp->audio = 0;
 
 			for (tries = 6; tries; tries--) {
+
+				stuffp->introk = 1;
+
 				TRACE((OPENCLOSE, "open() try as %s\n",
 					stuffp->xa ? "XA" : "normal"));
 
 				/* set data mode */
 				if (-1 == (ans = mcdx_setdatamode(stuffp, 
-						stuffp->xa ? MODE2 : MODE1, 1)))
-					return -EIO;
+						stuffp->xa ? MODE2 : MODE1, 1))) {
+					/* return -EIO; */
+					stuffp->xa = 0;
+					break;
+				}
 
 				if ((stuffp->audio = e_audio(ans))) break; 
 
@@ -725,7 +748,7 @@
 				if (ans == 1) break;
 				stuffp->xa = !stuffp->xa; 
 			}
-			if (!tries) return -EIO;
+			/* if (!tries) return -EIO; */
 		}
 
 		/* xa disks will be read in raw mode, others not */
@@ -735,13 +758,13 @@
 
 		if (stuffp->audio) {
 			INFO(("open() audio disk found\n"));
-		} else {
+		} else if (stuffp->lastsector >= 0) {
 			INFO(("open() %s%s disk found\n",
 					stuffp->xa ? "XA / " : "",
 					stuffp->multi.multi ? "Multi Session" : "Single Session"));
-		}
+		} 
 
-        stuffp->xxx = jiffies;
+        stuffp->xxx = 0;
 	}
 
     /* lock the door if not already done */
@@ -768,9 +791,12 @@
 		/* invalidate_inodes(ip->i_rdev); */
 		invalidate_buffers(ip->i_rdev);
 
+
 #if !MCDX_QUIET
 		if (-1 == mcdx_lockdoor(stuffp, 0, 3))
 				INFO(("close() Cannot unlock the door\n"));
+#else
+		mcdx_lockdoor(stuffp, 0, 3);
 #endif
 
         /* eject if wished */
@@ -783,15 +809,25 @@
 }
 
 int check_mcdx_media_change(kdev_t full_dev)
-/*	Return: 1 if media changed since last call to 
-			  this function
-			0 else
-	Setting flag to 0 resets the changed state. */
-
+/*	Return: 1 if media changed since last call to this function
+			0 otherwise */
 {
+    struct s_drive_stuff *stuffp; 
+
     INFO(("check_mcdx_media_change called for device %s\n",
 	  kdevname(full_dev)));
-    return 0;
+
+	stuffp = mcdx_stuffp[MINOR(full_dev)];
+	mcdx_getstatus(stuffp, 1);
+
+	if (stuffp->yyy == 0) {
+		INFO((" ... not changed\n"));
+		return 0;
+	}
+
+	INFO((" ... changed\n"));
+	stuffp->yyy = 0;
+	return 1;
 }
 
 void mcdx_setup(char *str, int *pi)
@@ -803,22 +839,15 @@
 /* DIRTY PART ******************************************************/ 
 
 static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
-/*	This routine is used for sleeping while initialisation - it seems that
- 	there are no other means available. May be we could use a simple count
- 	loop w/ jumps to itself, but I wanna make this independend of cpu
- 	speed. [1 jiffie is 1/HZ sec */
+/*	This routine is used for sleeping.
+	May be we could use a simple count loop w/ jumps to itself, but 
+	I wanna make this independend of cpu speed. [1 jiffie is 1/HZ] sec */
 {
     unsigned long tout = jiffies + jifs;
 
-    TRACE((INIT, "mcdx_delay %d\n", jifs));
-    if (jifs < 0) return;
+    /* TRACE((INIT, "mcdx_delay %d\n", jifs)); */
+    if (jifs <= 0) return;
 
-#if 1
-    while (jiffies < tout) {
-        current->timeout = jiffies;
-        schedule();
-    }
-#else
     if (current->pid == 0) {        /* no sleep allowed */
 		while (jiffies < tout) {
             current->timeout = jiffies;
@@ -826,37 +855,50 @@
         }
     } else {                        /* sleeping is allowed */
         current->timeout = tout;
-        current->state = TASK_INTERRUPTIBLE;
+        /* current->state = TASK_INTERRUPTIBLE; */
+		/* And perhaps we should remove the while() { ... } */
         while (current->timeout) {
             interruptible_sleep_on(&stuff->sleepq);
+			TRACE((SLEEP, "delay: to is %d\n", current->timeout));
         }
     }
-#endif
 }
 
 static void 
 mcdx_intr(int irq, void *dev_id, struct pt_regs* regs)
 {
     struct s_drive_stuff *stuffp;
-	unsigned char x;
+	unsigned char b;
 
     stuffp = mcdx_irq_map[irq];
 
-    if (stuffp == NULL || !stuffp->busy) {
-		TRACE((IRQ, "intr() unexpected interrupt @ irq %d\n", irq));
+    if (stuffp == NULL ) {
+		WARN(("mcdx: no device for intr %d\n", irq));
 		return;
     }
 
-	/* if not ok read the next byte as the drives status */
-	if (0 == (stuffp->introk = 
-			(~(x = inb((unsigned int) stuffp->rreg_status)) & MCDX_RBIT_DTEN))) 
-		TRACE((IRQ, "intr() irq %d failed, status %02x %02x\n",
-				irq, x, inb((unsigned int) stuffp->rreg_data)));
-	else
-	  {
-	    TRACE((IRQ, "irq() irq %d ok, status %02x\n", irq, x));
+	/* get the interrupt status */
+	b = inb((unsigned int) stuffp->rreg_status);
+	stuffp->introk = ~b & MCDX_RBIT_DTEN;
+
+	/* NOTE: We only should get interrupts if data were requested.
+	   But the drive seems to generate ``asynchronous'' interrupts
+	   on several error conditions too.  (Despite the err int enable
+	   setting during initialisation) */
+
+	/* if not ok, read the next byte as the drives status */
+	if (!stuffp->introk) {
+		TRACE((IRQ, "intr() irq %d hw status 0x%02x\n", irq, b));
+		if (~b & MCDX_RBIT_STEN) {
+			INFO((  "intr() irq %d    status 0x%02x\n", 
+					irq, inb((unsigned int) stuffp->rreg_data)));
+		} else {
+			INFO((  "intr() irq %d ambigous hw status\n", irq));
+		}
+	} else {
+		TRACE((IRQ, "irq() irq %d ok, status %02x\n", irq, b));
+    }
 
-	  }
     stuffp->busy = 0;
     wake_up_interruptible(&stuffp->busyq);
 }
@@ -881,13 +923,11 @@
 
     if ((disgard = (buffer == NULL))) buffer = &c;
 
-    while (stuffp->lock)
-		interruptible_sleep_on(&stuffp->lockq);
-
-    if (current->signal && ~current->blocked) {
-        WARN(("talk() got signal %d\n", current->signal));
-        return -1;
-    }
+    while (stuffp->lock) {
+		interruptible_sleep_on(&stuffp->lockq); 
+		TRACE((SLEEP, "talk: lock = %d\n",
+				stuffp->lock));
+	}
 
     stuffp->lock = 1;
     stuffp->valid = 0;	
@@ -906,8 +946,8 @@
      *  st != -1 (good) */
 	for (st = -1; st == -1 && tries; tries--) {
 
-        size_t sz = size;
-        char* bp = buffer;
+		char *bp = (char*) buffer;
+		size_t sz = size;
 
 		outsb((unsigned int) stuffp->wreg_data, cmd, cmdlen);
         TRACE((TALK, "talk() command sent\n"));
@@ -930,7 +970,7 @@
                     cmd[0], cmdlen > 1 ? "..." : ""));
             st = -1;
             continue;
-        }
+		}
 
         /* audio status? */
         if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
@@ -943,7 +983,7 @@
         /* media change? */
         if (e_changed(st)) {
             INFO(("talk() media changed\n"));
-            stuffp->changed = jiffies;
+            stuffp->xxx = stuffp->yyy = 1;
         }
 
         /* now actually get the data */
@@ -958,7 +998,9 @@
         }
     }
 
-    if (!tries && st == -1) WARN(("talk() giving up\n"));
+#if !MCDX_QUIET
+    if (!tries && st == -1) INFO(("talk() giving up\n"));
+#endif
 
     stuffp->lock = 0;
     wake_up_interruptible(&stuffp->lockq);
@@ -995,7 +1037,7 @@
 {
     int i;
 
-	WARN(("cleanup_module called\n"));
+	INFO(("cleanup_module called\n"));
 	
     for (i = 0; i < MCDX_NDRIVES; i++) {
 		struct s_drive_stuff *stuffp;
@@ -1012,9 +1054,12 @@
 		kfree(stuffp);
     }
 
-    if (unregister_blkdev(MAJOR_NR, DEVICE_NAME) != 0) 
+    if (unregister_blkdev(MAJOR_NR, DEVICE_NAME) != 0) {
         WARN(("cleanup() unregister_blkdev() failed\n"));
-    else INFO(("cleanup() succeeded\n"));
+    } 
+#if !MCDX_QUIET
+	else INFO(("cleanup() succeeded\n"));
+#endif
 }
 
 #endif MODULE
@@ -1046,15 +1091,12 @@
 	va_end(args);
 }
 
-
 int mcdx_init(void)
 {
 	int drive;
 
-	WARN(("Version 1.5a "
-			"mcdx.c,v 1.19.2.1 1996/01/13 21:25:55 heiko Exp\n"));
-	INFO((": Version 1.5a "
-			"mcdx.c,v 1.19.2.1 1996/01/13 21:25:55 heiko Exp\n"));
+	WARN(("Version 1.7 for %s\n", kernel_version));
+	WARN(("mcdx.c,v 1.31 1996/03/02 00:21:18 heiko Exp\n"));
 
 	/* zero the pointer array */
 	for (drive = 0; drive < MCDX_NDRIVES; drive++)
@@ -1066,6 +1108,8 @@
 		struct s_drive_stuff* stuffp;
         int size;
 
+		mcdx_blocksizes[drive] = 0;
+
         size = sizeof(*stuffp);
 		
 		TRACE((INIT, "init() try drive %d\n", drive));
@@ -1085,7 +1129,6 @@
 
 		stuffp->present = 0;		/* this should be 0 already */
 		stuffp->toc = NULL;			/* this should be NULL already */
-		stuffp->changed = jiffies;
 
 		/* setup our irq and i/o addresses */
 		stuffp->irq = irq(mcdx_drive_map[drive]);
@@ -1096,9 +1139,8 @@
 
 		/* check if i/o addresses are available */
 		if (0 != check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) {
-            WARN(("%s=0x%3p,%d: "
-                    "Init failed. I/O ports (0x%3p..0x3p) already in use.\n"
-                    MCDX, 
+            WARN(("0x%3p,%d: "
+                    "Init failed. I/O ports (0x%3p..0x%3p) already in use.\n",
                     stuffp->wreg_data, stuffp->irq,
                     stuffp->wreg_data, 
                     stuffp->wreg_data + MCDX_IO_SIZE - 1));
@@ -1127,22 +1169,22 @@
 
 		switch (version.code) {
 		case 'D': 
-                stuffp->readcmd = READDSPEED; 
+                stuffp->readcmd = READ2X; 
                 stuffp->present = DOUBLE | DOOR | MULTI; 
                 break;
 		case 'F': 
-                stuffp->readcmd = READSSPEED; 
+                stuffp->readcmd = READ1X; 
                 stuffp->present = SINGLE | DOOR | MULTI;
                 break;
 		case 'M': 
-                stuffp->readcmd = READSSPEED;
+                stuffp->readcmd = READ1X;
                 stuffp->present = SINGLE;
                 break;
 		default: 
                 stuffp->present = 0; break;
 		}
 
-        stuffp->playcmd = READSSPEED;
+        stuffp->playcmd = READ1X;
 
 
 		if (!stuffp->present) {
@@ -1164,9 +1206,7 @@
 		blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 		read_ahead[MAJOR_NR] = READ_AHEAD;
 
-#if WE_KNOW_WHY
-		 blksize_size[MAJOR_NR] = BLKSIZES;
-#endif
+		blksize_size[MAJOR_NR] = mcdx_blocksizes;
 
 		TRACE((INIT, "init() subscribe irq and i/o\n"));
 		mcdx_irq_map[stuffp->irq] = stuffp;
@@ -1210,8 +1250,38 @@
 	return 0;
 }
 
+static int 
+mcdx_transfer(struct s_drive_stuff *stuffp,
+		char *p, int sector, int nr_sectors)
+/*	This seems to do the actually transfer.  But it does more.  It
+	keeps track of errors ocurred and will (if possible) fall back
+	to single speed on error. 
+	Return:	-1 on timeout or other error
+			else status byte (as in stuff->st) */
+{
+	int ans;
+
+	ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
+	return ans;
+#if FALLBACK
+	if (-1 == ans) stuffp->readerrs++;
+	else return ans;
 
-static int mcdx_transfer(struct s_drive_stuff *stuffp,
+	if (stuffp->readerrs && stuffp->readcmd == READ1X) {
+		WARN(("XXX Alrady reading 1x -- no chance\n"));
+		return -1;
+	}
+
+	WARN(("XXX Fallback to 1x\n"));
+
+	stuffp->readcmd = READ1X;
+	return mcdx_transfer(stuffp, p, sector, nr_sectors);
+#endif
+	
+}
+
+
+static int mcdx_xfer(struct s_drive_stuff *stuffp,
 		char *p, int sector, int nr_sectors)
 /*	This does actually the transfer from the drive.
 	Return:	-1 on timeout or other error
@@ -1228,11 +1298,11 @@
 		return -1;
 	}
 
-    while (stuffp->lock)
+    while (stuffp->lock) {
 		interruptible_sleep_on(&stuffp->lockq);
-    if (current->signal && ~current->blocked) {
-        WARN(("talk() got signal %d\n", current->signal));
-    }
+		TRACE((SLEEP, "xfer: lock = %d\n",
+			stuffp->lock));
+	}
 
     if (stuffp->valid
 			&& (sector >= stuffp->pending)
@@ -1245,29 +1315,32 @@
 	stuffp->lock = current->pid;
 
 	do {
-	    /* int sig = 0; */
-	    int to = 0;
+		/* wait for the drive become idle, but first
+		   check for possible occured errors --- the drive
+		   seems to report them asynchronously */
 
-		/* wait for the drive become idle */
-	    current->timeout = jiffies + 5*HZ;
-	    while (stuffp->busy) {
+	    current->timeout = jiffies + 5 * HZ;
+	    while (stuffp->introk && stuffp->busy && current->timeout) {
 			interruptible_sleep_on(&stuffp->busyq);
+			TRACE((SLEEP, "request: busy = %d, timeout = %d\n",
+				stuffp->busy, current->timeout));
 		}
 
-	    current->timeout = 0;
-
 		/* test for possible errors */
-	    if (((stuffp->busy == 0) && !stuffp->introk)
-				|| to) {
-			if ((stuffp->busy == 0) && !stuffp->introk)
-                WARN(("mcdx_transfer() failure in data request\n"));
-			else if (to)
-                WARN(("mcdx_transfer(): timeout\n"));
+		if (current->timeout == 0 || !stuffp->introk) {
+			if (current->timeout == 0)  {
+				WARN(("mcdx_transfer() timeout\n"));
+			} else if (!stuffp->introk) { 
+				WARN(("mcdx_transfer() error via irq reported\n"));
+			} else {
+				WARN(("mcdx_transfer() unknown failure in data request\n"));
+			}
+
 			stuffp->lock = 0;
 			stuffp->busy = 0;
+			stuffp->valid = 0;
+
 			wake_up_interruptible(&stuffp->lockq);
-			wake_up_interruptible(&stuffp->busyq);
-			stuffp->errno = MCDX_E;
 			TRACE((TRANSFER, "transfer() done (-1)\n"));
 			return -1;
 	    }
@@ -1301,8 +1374,7 @@
 			done++;
 			sector++;
 	    }
-	}
-	while (++(stuffp->pending) < off);
+	} while (++(stuffp->pending) < off);
 
 	stuffp->lock = 0;
 	wake_up_interruptible(&stuffp->lockq);
@@ -1325,7 +1397,8 @@
 		if (stuffp->pending > stuffp->lastsector) {
 			WARN(("transfer() sector %d from nirvana requested.\n",
 				stuffp->pending));
-			stuffp->errno = MCDX_EOM;
+			stuffp->status = MCDX_ST_EOM;
+			stuffp->valid = 0;
 			TRACE((TRANSFER, "transfer() done (-1)\n"));
 			return -1;
 		}
@@ -1507,7 +1580,7 @@
 
     outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
 
-    if (-1 == mcdx_getval(stuffp, 3*HZ, 0, NULL)) {
+    if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
         WARN(("playmsf() timeout\n")); 
         return -1;
     }
@@ -1550,25 +1623,25 @@
 mcdx_closedoor(struct s_drive_stuff *stuffp, int tries)
 {
 	if (stuffp->present & DOOR)
-		return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5*HZ, tries);
+		return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, tries);
 	else
 		return 0;
 }
 
 static int 
 mcdx_stop(struct s_drive_stuff *stuffp, int tries)
-{ return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2*HZ, tries); }
+{ return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries); }
 
 static int
 mcdx_hold(struct s_drive_stuff *stuffp, int tries)
-{ return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2*HZ, tries); }
+{ return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries); }
 
 static int
 mcdx_eject(struct s_drive_stuff *stuffp, int tries)
 {
 	if (stuffp->present & DOOR) {
         stuffp->ejected = jiffies;
-		return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5*HZ, tries);
+		return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, tries);
     } else return 0;
 }
 
@@ -1582,7 +1655,7 @@
 
 	if (-1 == (ans = mcdx_talk(
             stuffp, "\x20", 1, buf, sizeof(buf),
-            2*HZ, tries))) 
+            2 * HZ, tries))) 
         return -1;
 	sub->control = buf[1];
 	sub->tno = buf[2];
@@ -1604,8 +1677,8 @@
 	int ans;
 
     if (stuffp->present & MULTI) {
-        ans = mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2*HZ, tries);
-        multi->multi = buf[1];
+		ans = mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 1 * HZ, tries);
+		multi->multi = buf[1];
         multi->msf_last.minute = buf[2];
         multi->msf_last.second = buf[3];
         multi->msf_last.frame = buf[4];
@@ -1621,15 +1694,20 @@
 {
 	char buf[9];
 	int ans;
-	ans = mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2*HZ, tries);
-	info->n_first = bcd2uint(buf[1]);
-	info->n_last = bcd2uint(buf[2]);
-	info->msf_leadout.minute = buf[3];
-	info->msf_leadout.second = buf[4];
-	info->msf_leadout.frame = buf[5];
-	info->msf_first.minute = buf[6];
-	info->msf_first.second = buf[7];
-	info->msf_first.frame = buf[8];
+	ans = mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 1 * HZ, tries);
+	if (ans == -1) {
+		info->n_first = 0;
+		info->n_last = 0;
+	} else {
+		info->n_first = bcd2uint(buf[1]);
+		info->n_last = bcd2uint(buf[2]);
+		info->msf_leadout.minute = buf[3];
+		info->msf_leadout.second = buf[4];
+		info->msf_leadout.frame = buf[5];
+		info->msf_first.minute = buf[6];
+		info->msf_first.second = buf[7];
+		info->msf_first.frame = buf[8];
+	}
 	return ans;
 }
 
@@ -1641,7 +1719,7 @@
 
 	TRACE((HW, "setdrivemode() %d\n", mode));
 
-	if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5*HZ, tries)))
+	if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
 		return -1;
 
 	switch (mode) {
@@ -1652,10 +1730,9 @@
 	  default: break;
 	}
 	cmd[0] = 0x50;
-	return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5*HZ, tries);
+	return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
 }
 
-
 static int
 mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode, int tries)
 {
@@ -1667,7 +1744,7 @@
 	  case MODE2: cmd[1] = 0x02; break;
 	  default: return -EINVAL;
 	}
-	return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5*HZ, tries);
+	return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
 }
 
 static int
@@ -1682,13 +1759,13 @@
 	cmd[1] = 0x10;		/* irq enable */
 	cmd[2] = 0x05;		/* pre, err irq enable */
 
-	if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1*HZ, tries))
+	if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
 		return -1;
 
 	cmd[1] = 0x02;		/* dma select */
 	cmd[2] = 0x00;		/* no dma */
 
-	return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1*HZ, tries);
+	return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
 }
 
 static int
@@ -1697,7 +1774,8 @@
 	char buf[3];
 	int ans;
 
-	if (-1 == (ans = mcdx_talk(stuffp, "\xdc", 1, buf, sizeof(buf), 2*HZ, tries)))
+	if (-1 == (ans = mcdx_talk(stuffp, "\xdc", 
+			1, buf, sizeof(buf), 1 * HZ, tries)))
 		return ans;
 
 	ver->code = buf[1];
@@ -1713,7 +1791,7 @@
 		outb(0, (unsigned int) stuffp->wreg_chn);		/* no dma, no irq -> hardware */
 		outb(0, (unsigned int) stuffp->wreg_reset);		/* hw reset */
 		return 0;
-	} else return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5*HZ, tries);
+	} else return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
 }
 
 static int
@@ -1722,14 +1800,13 @@
 	char cmd[2] = { 0xfe };
     if (stuffp->present & DOOR) {
         cmd[1] = lock ? 0x01 : 0x00;
-        return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5*HZ, tries);
-    } else 
-        return 0;
+        return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, tries);
+    } else return 0;
 }
 
 static int
 mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
-{ return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5*HZ, tries); }
+{ return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries); }
 
 static int
 mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char* buf)
@@ -1765,3 +1842,4 @@
     return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
 }
 
+/* ex:set ts=4 sw=4: */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this