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>
