Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 22 Sep 1995 00:59:11 +0400 (MSD)
From:      "Serge V.Vakulenko" <vak@crox.net.kiae.su>
To:        current@freebsd.org
Subject:   [patch] version 1.5 of ATAPI CD-ROM driver
Message-ID:  <Pine.BSF.3.91.950922005032.286A-100000@crox.net.kiae.su>

next in thread | raw e-mail | index | archive | help

This version fixes the following bugs:
-- drq type was incorrectly printed
-- support for drives which identify itself as direct-type
   (instead of type CDROM) added
-- model string for NEC and Mitsumi drives was printed
   with incorrect byte order
-- data underrun/overrun bug fixed
-- NEC 260 i/o phase incompatibility fixed

New features added:
-- The drive revision number is printed during attach.

Serge

--- atapi-c.c	Fri Sep 22 00:45:18 1995
+++ atapi.c	Fri Sep 22 00:45:18 1995
@@ -11,7 +11,7 @@
  * or modify this software as long as this message is kept with the software,
  * all derivative works or modified versions.
  *
- * Version 1.3, Mon Aug 28 21:44:01 MSD 1995
+ * Version 1.5, Thu Sep 21 23:08:11 MSD 1995
  */
 
 /*
@@ -129,6 +129,7 @@
 #define PHASE_DATAIN    (ARS_DRQ | ARI_IN)
 #define PHASE_DATAOUT   ARS_DRQ
 #define PHASE_COMPLETED (ARI_IN | ARI_CMD)
+#define PHASE_ABORTED   0                       /* nonstandard - for NEC 260 */
 
 struct atapicmd {                       /* ATAPI command block */
 	struct atapicmd *next;          /* next command in queue */
@@ -172,6 +173,7 @@
 	struct atapi *ata = atapitab + ctlr;
 	struct atapi_params *ap;
 	char buf [sizeof(ap->model) + 1];
+	char revbuf [sizeof(ap->revision) + 1];
 	struct atapicmd *ac;
 
 	print (("atapi%d.%d at 0x%x: attach called\n", ctlr, unit, port));
@@ -181,7 +183,11 @@
 
 	bcopy (ap->model, buf, sizeof(buf)-1);
 	buf[sizeof(buf)-1] = 0;
-	printf ("wdc%d: unit %d (atapi): <%s>", ctlr, unit, buf);
+
+	bcopy (ap->revision, revbuf, sizeof(revbuf)-1);
+	revbuf[sizeof(revbuf)-1] = 0;
+
+	printf ("wdc%d: unit %d (atapi): <%s/%s>", ctlr, unit, buf, revbuf);
 
 	/* device is removable */
 	if (ap->removable)
@@ -199,7 +205,7 @@
 	case AT_DRQT_MPROC: ata->slow = 1; break;
 	case AT_DRQT_INTR:  printf (", intr"); ata->intrcmd = 1; break;
 	case AT_DRQT_ACCEL: printf (", accel"); break;
-	default:            printf (", drq%d", ap->cmdsz);
+	default:            printf (", drq%d", ap->drqtype);
 	}
 
 	/* overlap operation supported */
@@ -242,22 +248,16 @@
 		return;
 	}
 	switch (ap->devtype) {
-	default: 			/* unknown ATAPI device */
-		printf ("wdc%d: unit %d: unknown ATAPI device type=%d\n",
+	default:
+		/* unknown ATAPI device */
+		printf ("wdc%d: unit %d: unknown ATAPI type=%d\n",
 			ctlr, unit, ap->devtype);
 		break;
 
-	case AT_TYPE_DIRECT:            /* direct-access (magnetic disk) */
-#if NWHD > 0
-		/* Add your driver here */
-#else
-		printf ("wdc%d: ATAPI hard disks not supported\n", ctlr);
-		printf ("wdc%d: Could be old ATAPI CDROM, trying...\n", ctlr);
-		break;
-#endif
-
+	case AT_TYPE_DIRECT:            /* direct-access */
 	case AT_TYPE_CDROM:             /* CD-ROM device */
 #if NWCD > 0
+		/* ATAPI CD-ROM */
 		{
 			int wcdattach (struct atapi*, int, struct atapi_params*,
 				int, struct kern_devconf*);
@@ -275,7 +275,7 @@
 #if NWMT > 0
 		/* Add your driver here */
 #else
-		printf ("wdc%d: ATAPI streaming tapes not supported\n", ctlr);
+		printf ("wdc%d: ATAPI streaming tapes not supported yet\n", ctlr);
 		break;
 #endif
 
@@ -283,7 +283,7 @@
 #if NWMD > 0
 		/* Add your driver here */
 #else
-		printf ("wdc%d: ATAPI optical disks not supported\n", ctlr);
+		printf ("wdc%d: ATAPI optical disks not supported yet\n", ctlr);
 		break;
 #endif
 	}
@@ -291,6 +291,25 @@
 	free (ap, M_TEMP);
 }
 
+static void bswap (char *buf, int len)
+{
+	u_short *p = (u_short*) (buf + len);
+	while (--p >= (u_short*) buf)
+		*p = ntohs (*p);
+}
+
+static void btrim (char *buf, int len)
+{
+	char *p;
+
+	/* Remove the trailing spaces. */
+	for (p=buf; p<buf+len; ++p)
+		if (! *p)
+			*p = ' ';
+	for (p=buf+len-1; p>=buf && *p==' '; --p)
+		*p = 0;
+}
+
 /*
  * Issue IDENTIFY command to ATAPI drive to ask it what it is.
  */
@@ -298,11 +317,10 @@
 {
 	struct atapi_params *ap;
 	char tb [DEV_BSIZE];
-	int i;
 
 	/* Wait for controller not busy. */
 	if (atapi_wait (port, 0) < 0) {
-		print (("atapi.%d at 0x%x: controller busy, status=%b\n",
+		print (("atapiX.%d at 0x%x: controller busy, status=%b\n",
 			unit, port, inb (port + AR_STATUS), ARS_BITS));
 		return (0);
 	}
@@ -313,7 +331,7 @@
 
 	/* Check that device is present. */
 	if (inb (port + AR_STATUS) == 0xff) {
-		print (("atapi.%d at 0x%x: no device\n", unit, port));
+		print (("atapiX.%d at 0x%x: no device\n", unit, port));
 		if (unit == 1)
 			/* Select unit 0. */
 			outb (port + AR_DRIVE, ARD_DRIVE0);
@@ -322,7 +340,7 @@
 
 	/* Wait for data ready. */
 	if (atapi_wait (port, ARS_DRQ) != 0) {
-		print (("atapi.%d at 0x%x: identify not ready, status=%b\n",
+		print (("atapiX.%d at 0x%x: identify not ready, status=%b\n",
 			unit, port, inb (port + AR_STATUS), ARS_BITS));
 		if (unit == 1)
 			/* Select unit 0. */
@@ -344,18 +362,15 @@
 	 */
 	if (! ((ap->model[0] == 'N' && ap->model[1] == 'E') ||
 	    (ap->model[0] == 'F' && ap->model[1] == 'X'))) {
-		u_short *p = (u_short*) (ap->model + sizeof(ap->model));
-		while (--p >= (u_short*) ap->model)
-			*p = ntohs (*p);
+		bswap (ap->model, sizeof(ap->model));
+		bswap (ap->serial, sizeof(ap->serial));
+		bswap (ap->revision, sizeof(ap->revision));
 	}
 
-	/* Clean up the model by converting nulls to spaces, and
-	 * then removing the trailing spaces. */
-	for (i=0; i < sizeof(ap->model); i++)
-		if (! ap->model[i])
-			ap->model[i] = ' ';
-	for (i=sizeof(ap->model)-1; i>=0 && ap->model[i]==' '; i--)
-		ap->model[i] = 0;
+	/* Clean up the model name, serial and revision numbers. */
+	btrim (ap->model, sizeof(ap->model));
+	btrim (ap->serial, sizeof(ap->serial));
+	btrim (ap->revision, sizeof(ap->revision));
 	return (ap);
 }
 
@@ -585,7 +600,7 @@
 int atapi_io (struct atapi *ata, struct atapicmd *ac)
 {
 	u_char ireason;
-	u_short len;
+	u_short len, i;
 
 	if (atapi_wait (ata->port, 0) < 0) {
 		ac->result.status = inb (ata->port + AR_STATUS);
@@ -635,12 +650,16 @@
 			break;
 		}
 		if (-ac->count < len) {
-			printf ("atapi%d.%d: send data underrun, %d bytes left\n",
-				ata->ctrlr, ac->unit, -ac->count);
+			print (("atapi%d.%d: send data underrun, %d bytes left\n",
+				ata->ctrlr, ac->unit, -ac->count));
 			ac->result.code = RES_UNDERRUN;
-			break;
-		}
-		outsw (ata->port + AR_DATA, ac->addr, len / sizeof(short));
+			outsw (ata->port + AR_DATA, ac->addr,
+				-ac->count / sizeof(short));
+			for (i= -ac->count; i<len; i+=sizeof(short))
+				outw (ata->port + AR_DATA, 0);
+		} else
+			outsw (ata->port + AR_DATA, ac->addr,
+				len / sizeof(short));
 		ac->addr += len;
 		ac->count += len;
 		return (1);
@@ -654,34 +673,35 @@
 			break;
 		}
 		if (ac->count < len) {
-			printf ("atapi%d.%d: recv data overrun, %d bytes left\n",
-				ata->ctrlr, ac->unit, ac->count);
+			print (("atapi%d.%d: recv data overrun, %d bytes left\n",
+				ata->ctrlr, ac->unit, ac->count));
 			ac->result.code = RES_OVERRUN;
-			break;
-		}
-		insw (ata->port + AR_DATA, ac->addr, len / sizeof(short));
+			insw (ata->port + AR_DATA, ac->addr,
+				ac->count / sizeof(short));
+			for (i=ac->count; i<len; i+=sizeof(short))
+				inw (ata->port + AR_DATA);
+		} else
+			insw (ata->port + AR_DATA, ac->addr,
+				len / sizeof(short));
 		ac->addr += len;
 		ac->count -= len;
 		return (1);
 
+	case PHASE_ABORTED:
 	case PHASE_COMPLETED:
-		if (ac->result.status & (ARS_CHECK | ARS_DF)) {
+		if (ac->result.status & (ARS_CHECK | ARS_DF))
 			ac->result.code = RES_ERR;
-			break;
-		}
-		if (ac->count < 0) {
-			printf ("atapi%d.%d: send data overrun, %d bytes left\n",
-				ata->ctrlr, ac->unit, -ac->count);
+		else if (ac->count < 0) {
+			print (("atapi%d.%d: send data overrun, %d bytes left\n",
+				ata->ctrlr, ac->unit, -ac->count));
 			ac->result.code = RES_OVERRUN;
-			break;
-		}
-		if (ac->count > 0) {
-			printf ("atapi%d.%d: recv data underrun, %d bytes left\n",
-				ata->ctrlr, ac->unit, ac->count);
+		} else if (ac->count > 0) {
+			print (("atapi%d.%d: recv data underrun, %d bytes left\n",
+				ata->ctrlr, ac->unit, ac->count));
 			ac->result.code = RES_UNDERRUN;
-			break;
-		}
-		ac->result.code = RES_OK;
+			bzero (ac->addr, ac->count);
+		} else
+			ac->result.code = RES_OK;
 		break;
 	}
 	return (0);
@@ -817,6 +837,12 @@
 	if (atapi_start_cmd (ata, ac) >= 0 && atapi_wait_cmd (ata, ac) >= 0) {
 		/* Send packet command. */
 		atapi_send_cmd (ata, ac);
+
+		/* Wait for data i/o phase. */
+		for (cnt=20000; cnt>0; --cnt)
+			if (((inb (ata->port + AR_IREASON) & (ARI_CMD | ARI_IN)) |
+			    (inb (ata->port + AR_STATUS) & ARS_DRQ)) != PHASE_CMDOUT)
+				break;
 
 		/* Do all needed i/o. */
 		while (atapi_io (ata, ac))
--- atapi-c.h	Fri Sep 22 00:45:18 1995
+++ atapi.h	Fri Sep 22 00:45:18 1995
@@ -11,7 +11,7 @@
  * or modify this software as long as this message is kept with the software,
  * all derivative works or modified versions.
  *
- * Version 1.1, Mon Jul 10 21:55:11 MSD 1995
+ * Version 1.4, Tue Sep  5 20:59:48 MSD 1995
  */
 
 /*
@@ -112,21 +112,21 @@
  */
 struct atapi_params {
 	unsigned        cmdsz : 2;      /* packet command size */
-#define AT_PSIZE_12     0
-#define AT_PSIZE_16     1
+#define AT_PSIZE_12     0               /* 12 bytes */
+#define AT_PSIZE_16     1               /* 16 bytes */
 	unsigned : 3;
 	unsigned        drqtype : 2;    /* DRQ type */
 #define AT_DRQT_MPROC   0               /* microprocessor DRQ - 3 msec delay */
 #define AT_DRQT_INTR    1               /* interrupt DRQ - 10 msec delay */
 #define AT_DRQT_ACCEL   2               /* accelerated DRQ - 50 usec delay */
 	unsigned        removable : 1;  /* device is removable */
-	unsigned        devtype : 5;    /* packet command size */
+	unsigned        devtype : 5;    /* device type */
 #define AT_TYPE_DIRECT  0               /* direct-access (magnetic disk) */
 #define AT_TYPE_TAPE    1               /* streaming tape (QIC-121 model) */
 #define AT_TYPE_CDROM   5               /* CD-ROM device */
 #define AT_TYPE_OPTICAL 7               /* optical disk */
 	unsigned : 1;
-	unsigned        proto : 2;      /* packet command size */
+	unsigned        proto : 2;      /* command protocol */
 #define AT_PROTO_ATAPI  2
 	short reserved1[9];
 	char            serial[20];     /* serial number - optional */
@@ -146,7 +146,7 @@
 	short reserved4;
 	u_short         pio_timing;     /* PIO cycle timing */
 	u_short         dma_timing;     /* DMA cycle timing */
-	u_short         flags;          /* flags */
+	u_short         flags;
 #define AT_FLAG_54_58   1               /* words 54-58 valid */
 #define AT_FLAG_64_70   2               /* words 64-70 valid */
 	short reserved5[8];
--- wcd-c.c	Fri Sep 22 00:45:18 1995
+++ wcd.c	Fri Sep 22 00:48:50 1995
@@ -12,12 +12,9 @@
  * or modify this software as long as this message is kept with the software,
  * all derivative works or modified versions.
  *
- * Version 1.2, Mon Jul 24 17:21:25 MSD 1995
+ * Version 1.5, Thu Sep 21 23:08:11 MSD 1995
  */
 
-/*
- * The driver was tested on Toshiba XM-5302TA drive. (vak)
- */
 #include "wdc.h"
 #include "wcd.h"
 #if NWCD > 0 && NWDC > 0 && defined (ATAPI)
@@ -166,6 +163,19 @@
 	u_short max_vol_levels;         /* number of discrete volume levels */
 	u_short buf_size;               /* internal buffer size in bytes/1024 */
 	u_short cur_speed;              /* current data rate in bytes/1000  */
+
+	/* Digital drive output format description (optional?) */
+	u_char  reserved3;
+	u_char  bckf : 1;               /* data valid on failing edge of BCK */
+	u_char  rch : 1;                /* high LRCK indicates left channel */
+	u_char  lsbf : 1;               /* set if LSB first */
+	u_char  dlen: 2;
+#define DLEN_32         0               /* 32 BCKs */
+#define DLEN_16         1               /* 16 BCKs */
+#define DLEN_24         2               /* 24 BCKs */
+#define DLEN_24_I2S     3               /* 24 BCKs (I2S) */
+	u_char  : 3;
+	u_char  reserved4[2];
 };
 
 struct wcd {
@@ -262,16 +272,22 @@
 	}
 
 	/* Get drive capabilities. */
-	/* Do it twice to avoid the stale media changed state. */
 	result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
 		0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8, sizeof (t->cap),
 		0, 0, 0, 0, 0, 0, 0, (char*) &t->cap, sizeof (t->cap));
 
-	if (result.code == RES_ERR && result.error == AER_SK_UNIT_ATTENTION)
+	/* Do it twice to avoid the stale media changed state. */
+	if (result.code == RES_ERR &&
+	    (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)
 		result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
 			0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8,
 			sizeof (t->cap), 0, 0, 0, 0, 0, 0, 0,
 			(char*) &t->cap, sizeof (t->cap));
+
+	/* Some drives have shorter capabilities page. */
+	if (result.code == RES_UNDERRUN)
+		result.code = 0;
+
 	if (result.code == 0) {
 		wcd_describe (t);
 		if (t->flags & F_DEBUG)
@@ -302,7 +318,7 @@
 	printf ("wcd%d: ", t->lun);
 	if (t->cap.cur_speed != t->cap.max_speed)
 		printf ("%d/", t->cap.cur_speed * 1000 / 1024);
-	printf ("%dKb/sec", t->cap.max_speed * 1000 / 1024, t->cap.buf_size);
+	printf ("%dKb/sec", t->cap.max_speed * 1000 / 1024);
 	if (t->cap.buf_size)
 		printf (", %dKb cache", t->cap.buf_size);
 
@@ -373,7 +389,8 @@
 	result = atapi_request_wait (t->ata, t->unit, ATAPI_TEST_UNIT_READY,
 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 
-	if (result.code == RES_ERR && result.error == AER_SK_UNIT_ATTENTION) {
+	if (result.code == RES_ERR &&
+	    (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION) {
 		t->flags |= F_MEDIA_CHANGED;
 		result = atapi_request_wait (t->ata, t->unit,
 			ATAPI_TEST_UNIT_READY, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -394,6 +411,9 @@
 		return (EIO);
 	t->info.volsize = ntohl (t->info.volsize);
 	t->info.blksize = ntohl (t->info.blksize);
+
+	/* Print the disc description string on every disc change.
+	 * It would help to track the history of disc changes. */
 	if (t->flags & (F_MEDIA_CHANGED | F_DEBUG)) {
 		printf ("wcd%d: ", t->lun);
 		if (t->toc.tab[0].control & 4)
@@ -538,37 +558,34 @@
 {
 	if (result.code != RES_ERR)
 		return;
-	switch (result.error) {
+	switch (result.error & AER_SKEY) {
 	case AER_SK_NOT_READY:
+		if (result.error & ~AER_SKEY) {
+			/* Audio disc. */
+			printf ("wcd%d: cannot read audio disc\n", t->lun);
+			return;
+		}
 		/* Tray open. */
 		if (! (t->flags & F_MEDIA_CHANGED))
 			printf ("wcd%d: tray open\n", t->lun);
 		t->flags |= F_MEDIA_CHANGED;
-		break;
+		return;
 
 	case AER_SK_UNIT_ATTENTION:
 		/* Media changed. */
 		if (! (t->flags & F_MEDIA_CHANGED))
 			printf ("wcd%d: media changed\n", t->lun);
 		t->flags |= F_MEDIA_CHANGED;
-		break;
-
-	case AER_SK_NOT_READY | AER_ILI | AER_EOM:
-		/* Audio disc. */
-		printf ("wcd%d: cannot read audio disc\n", t->lun);
-		break;
+		return;
 
 	case AER_SK_ILLEGAL_REQUEST:
 		/* Unknown command or invalid command arguments. */
 		if (t->flags & F_DEBUG)
 			printf ("wcd%d: invalid command\n", t->lun);
-		break;
-
-	default:
-		printf ("wcd%d: i/o error, status=%b, error=%b\n", t->lun,
-			result.status, ARS_BITS, result.error, AER_BITS);
-		break;
+		return;
 	}
+	printf ("wcd%d: i/o error, status=%b, error=%b\n", t->lun,
+		result.status, ARS_BITS, result.error, AER_BITS);
 }
 
 static int wcd_request_wait (struct wcd *t, u_char cmd, u_char a1, u_char a2,
@@ -617,11 +634,15 @@
 		return (ENOTTY);
 
 	case CDIOCSETDEBUG:
+		if (p->p_cred->pc_ucred->cr_uid)
+			return (EPERM);
 		t->flags |= F_DEBUG;
 		atapi_debug (t->ata, 1);
 		return 0;
 
 	case CDIOCCLRDEBUG:
+		if (p->p_cred->pc_ucred->cr_uid)
+			return (EPERM);
 		t->flags &= ~F_DEBUG;
 		atapi_debug (t->ata, 0);
 		return 0;
@@ -651,6 +672,8 @@
 			0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
 
 	case CDIOCRESET:
+		if (p->p_cred->pc_ucred->cr_uid)
+			return (EPERM);
 		return wcd_request_wait (t, ATAPI_TEST_UNIT_READY,
 			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 

---
Serge Vakulenko                 <vak@cronyx.msk.su>
Cronyx Ltd., Moscow             Unix consulting and custom programming
phone: +7 (095) 939-23-23       FreeBSD support
fax:   +7 (095) 939-03-00       Relcom network development




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.3.91.950922005032.286A-100000>