summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/i386/i386/conf.c24
-rw-r--r--sys/i386/isa/atapi.c284
-rw-r--r--sys/i386/isa/atapi.h58
-rw-r--r--sys/i386/isa/wcd.c435
-rw-r--r--sys/i386/isa/wd.c54
-rw-r--r--sys/pc98/pc98/atapi.h58
6 files changed, 703 insertions, 210 deletions
diff --git a/sys/i386/i386/conf.c b/sys/i386/i386/conf.c
index 312b5f4..f2ca17f 100644
--- a/sys/i386/i386/conf.c
+++ b/sys/i386/i386/conf.c
@@ -42,7 +42,7 @@
* SUCH DAMAGE.
*
* from: @(#)conf.c 5.8 (Berkeley) 5/12/91
- * $Id: conf.c,v 1.100 1995/10/12 23:28:41 bde Exp $
+ * $Id: conf.c,v 1.101 1995/10/14 05:25:45 bde Exp $
*/
#include <sys/param.h>
@@ -305,13 +305,17 @@ d_psize_t atasize;
#include "wcd.h"
#if NWCD > 0
-d_open_t wcdopen;
-d_close_t wcdclose;
+d_open_t wcdbopen;
+d_open_t wcdropen;
+d_close_t wcdbclose;
+d_close_t wcdrclose;
d_strategy_t wcdstrategy;
d_ioctl_t wcdioctl;
#else
-#define wcdopen nxopen
-#define wcdclose nxclose
+#define wcdbopen nxopen
+#define wcdropen nxopen
+#define wcdbclose nxclose
+#define wcdrclose nxclose
#define wcdstrategy nxstrategy
#define wcdioctl nxioctl
#endif
@@ -445,8 +449,8 @@ struct bdevsw bdevsw[] =
matcddump, matcdsize, 0 },
{ ataopen, ataclose, atastrategy, ataioctl, /*18*/
atadump, atasize, 0 },
- { wcdopen, wcdclose, wcdstrategy, wcdioctl, /*19*/
- nxdump, zerosize, 0 },
+ { wcdbopen, wcdbclose, wcdstrategy, wcdioctl, /*19*/
+ nxdump, zerosize, 0 },
{ odopen, odclose, odstrategy, odioctl, /*20*/
oddump, odsize, 0 },
@@ -1291,9 +1295,9 @@ struct cdevsw cdevsw[] =
{ siopen, siclose, siread, siwrite, /*68*/
siioctl, sistop, sireset, sidevtotty,/* slxos */
ttselect, nxmmap, NULL },
- { wcdopen, wcdclose, rawread, nowrite, /*69*/
- wcdioctl, nostop, nullreset, nodevtotty,/* atapi */
- seltrue, nommap, wcdstrategy },
+ { wcdropen, wcdrclose, rawread, nowrite, /*69*/
+ wcdioctl, nostop, nullreset, nodevtotty,/* atapi */
+ seltrue, nommap, wcdstrategy },
{ odopen, odclose, rawread, rawwrite, /*70*/
odioctl, nostop, nullreset, nodevtotty,/* od */
seltrue, nommap, odstrategy },
diff --git a/sys/i386/isa/atapi.c b/sys/i386/isa/atapi.c
index 540c2bd..6d608fb 100644
--- a/sys/i386/isa/atapi.c
+++ b/sys/i386/isa/atapi.c
@@ -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.5, Thu Sep 21 23:08:11 MSD 1995
+ * Version 1.9, Mon Oct 9 22:34:47 MSK 1995
*/
/*
@@ -112,16 +112,40 @@
#include <sys/malloc.h>
#include <i386/include/cpufunc.h>
#include <i386/include/clock.h>
+
+#ifdef ATAPI_MODULE
+# define ATAPI_STATIC
+#endif
+
#include <i386/isa/atapi.h>
+#ifndef ATAPI_STATIC
+/*
+ * In the case of loadable ATAPI driver we need to store
+ * the probe info for delayed attaching.
+ */
+struct atapidrv atapi_drvtab[4];
+int atapi_ndrv;
+struct atapi *atapi_tab;
+
+int atapi_attach (int ctlr, int unit, int port, struct kern_devconf *parent)
+{
+ atapi_drvtab[atapi_ndrv].ctlr = ctlr;
+ atapi_drvtab[atapi_ndrv].unit = unit;
+ atapi_drvtab[atapi_ndrv].port = port;
+ atapi_drvtab[atapi_ndrv].parent = parent;
+ atapi_drvtab[atapi_ndrv].attached = 0;
+ ++atapi_ndrv;
+ return (1);
+}
+#else /* ATAPI_STATIC */
+
#ifdef DEBUG
# define print(s) printf s
#else
# define print(s) {/*void*/}
#endif
-#define MAXCMD (8*NWDC)
-
/*
* ATAPI packet command phase.
*/
@@ -131,32 +155,6 @@
#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 */
- int busy; /* busy flag */
- u_char cmd[16]; /* command and args */
- int unit; /* drive unit number */
- int count; /* byte count, >0 - read, <0 - write */
- char *addr; /* data to transfer */
- void (*callback) (); /* call when done */
- void *cbarg1; /* callback arg 1 */
- void *cbarg2; /* callback arg 1 */
- struct atapires result; /* resulting error code */
-};
-
-struct atapi { /* ATAPI controller data */
- u_short port; /* i/o port base */
- u_char ctrlr; /* physical controller number */
- u_char debug : 1; /* trace enable flag */
- u_char cmd16 : 1; /* 16-byte command flag */
- u_char intrcmd : 1; /* interrupt before cmd flag */
- u_char slow : 1; /* slow reaction device */
- struct atapicmd *queue; /* queue of commands to perform */
- struct atapicmd *tail; /* tail of queue */
- struct atapicmd *free; /* queue of free command blocks */
- struct atapicmd cmdrq[MAXCMD]; /* pool of command requests */
-};
-
struct atapi atapitab[NWDC];
static struct atapi_params *atapi_probe (int port, int unit);
@@ -167,8 +165,16 @@ static int atapi_start_cmd (struct atapi *ata, struct atapicmd *ac);
static int atapi_wait_cmd (struct atapi *ata, struct atapicmd *ac);
extern int wdstart (int ctrlr);
+extern int wcdattach(struct atapi*, int, struct atapi_params*, int, struct kern_devconf*);
-void atapi_attach (int ctlr, int unit, int port, struct kern_devconf *parent)
+/*
+ * Probe the ATAPI device at IDE controller `ctlr', drive `unit'.
+ * Called at splbio().
+ */
+#ifdef ATAPI_MODULE
+static
+#endif
+int atapi_attach (int ctlr, int unit, int port, struct kern_devconf *parent)
{
struct atapi *ata = atapitab + ctlr;
struct atapi_params *ap;
@@ -179,7 +185,7 @@ void atapi_attach (int ctlr, int unit, int port, struct kern_devconf *parent)
print (("atapi%d.%d at 0x%x: attach called\n", ctlr, unit, port));
ap = atapi_probe (port, unit);
if (! ap)
- return;
+ return (0);
bcopy (ap->model, buf, sizeof(buf)-1);
buf[sizeof(buf)-1] = 0;
@@ -230,14 +236,16 @@ void atapi_attach (int ctlr, int unit, int port, struct kern_devconf *parent)
ata->port = port;
ata->ctrlr = ctlr;
+ ata->parent = parent;
+ ata->attached[unit] = 0;
#ifdef DEBUG
ata->debug = 1;
#else
ata->debug = 0;
#endif
/* Initialize free queue. */
- ata->cmdrq[MAXCMD-1].next = 0;
- for (ac = ata->cmdrq+MAXCMD-2; ac >= ata->cmdrq; --ac)
+ ata->cmdrq[15].next = 0;
+ for (ac = ata->cmdrq+14; ac >= ata->cmdrq; --ac)
ac->next = ac+1;
ata->free = ata->cmdrq;
@@ -245,8 +253,12 @@ void atapi_attach (int ctlr, int unit, int port, struct kern_devconf *parent)
printf ("wdc%d: unit %d: unknown ATAPI protocol=%d\n",
ctlr, unit, ap->proto);
free (ap, M_TEMP);
- return;
+ return (0);
}
+#ifdef ATAPI_MODULE
+ ata->params[unit] = ap;
+ return (1);
+#else
switch (ap->devtype) {
default:
/* unknown ATAPI device */
@@ -258,14 +270,11 @@ void atapi_attach (int ctlr, int unit, int port, struct kern_devconf *parent)
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*);
- if (wcdattach (ata, unit, ap, ata->debug, parent) < 0)
- break;
- }
+ if (wcdattach (ata, unit, ap, ata->debug, parent) < 0)
+ break;
/* Device attached successfully. */
- return;
+ ata->attached[unit] = 1;
+ return (1);
#else
printf ("wdc%d: ATAPI CD-ROMs not configured\n", ctlr);
break;
@@ -276,19 +285,46 @@ void atapi_attach (int ctlr, int unit, int port, struct kern_devconf *parent)
/* Add your driver here */
#else
printf ("wdc%d: ATAPI streaming tapes not supported yet\n", ctlr);
- break;
#endif
+ break;
case AT_TYPE_OPTICAL: /* optical disk */
#if NWMD > 0
/* Add your driver here */
#else
printf ("wdc%d: ATAPI optical disks not supported yet\n", ctlr);
- break;
#endif
+ break;
}
/* Attach failed. */
free (ap, M_TEMP);
+ return (0);
+#endif /* ATAPI_MODULE */
+}
+
+static char *cmdname (u_char cmd)
+{
+ static char buf[8];
+
+ switch (cmd) {
+ case 0x00: return ("TEST_UNIT_READY");
+ case 0x03: return ("REQUEST_SENSE");
+ case 0x1b: return ("START_STOP");
+ case 0x1e: return ("PREVENT_ALLOW");
+ case 0x25: return ("READ_CAPACITY");
+ case 0x28: return ("READ_BIG");
+ case 0x43: return ("READ_TOC");
+ case 0x42: return ("READ_SUBCHANNEL");
+ case 0x55: return ("MODE_SELECT_BIG");
+ case 0x5a: return ("MODE_SENSE");
+ case 0xb4: return ("PLAY_CD");
+ case 0x47: return ("PLAY_MSF");
+ case 0x4b: return ("PAUSE");
+ case 0x48: return ("PLAY_TRACK");
+ case 0xa5: return ("PLAY_BIG");
+ }
+ sprintf (buf, "[0x%x]", cmd);
+ return (buf);
}
static void bswap (char *buf, int len)
@@ -319,6 +355,7 @@ static struct atapi_params *atapi_probe (int port, int unit)
char tb [DEV_BSIZE];
/* Wait for controller not busy. */
+ outb (port + AR_DRIVE, unit ? ARD_DRIVE1 : ARD_DRIVE0);
if (atapi_wait (port, 0) < 0) {
print (("atapiX.%d at 0x%x: controller busy, status=%b\n",
unit, port, inb (port + AR_STATUS), ARS_BITS));
@@ -361,11 +398,10 @@ static struct atapi_params *atapi_probe (int port, int unit)
* Mitsumi and NEC drives don't need this.
*/
if (! ((ap->model[0] == 'N' && ap->model[1] == 'E') ||
- (ap->model[0] == 'F' && ap->model[1] == 'X'))) {
+ (ap->model[0] == 'F' && ap->model[1] == 'X')))
bswap (ap->model, sizeof(ap->model));
- bswap (ap->serial, sizeof(ap->serial));
- bswap (ap->revision, sizeof(ap->revision));
- }
+ bswap (ap->serial, sizeof(ap->serial));
+ bswap (ap->revision, sizeof(ap->revision));
/* Clean up the model name, serial and revision numbers. */
btrim (ap->model, sizeof(ap->model));
@@ -537,17 +573,26 @@ int atapi_wait_cmd (struct atapi *ata, struct atapicmd *ac)
{
/* Wait for DRQ from 50 usec to 3 msec for slow devices */
int cnt = ata->intrcmd ? 10000 : ata->slow ? 3000 : 50;
+ int ireason = 0, phase = 0;
+ /* Wait for command phase. */
for (; cnt>0; cnt-=10) {
+ ireason = inb (ata->port + AR_IREASON);
ac->result.status = inb (ata->port + AR_STATUS);
- if (ac->result.status & ARS_DRQ)
+ phase = (ireason & (ARI_CMD | ARI_IN)) |
+ (ac->result.status & ARS_DRQ);
+ if (phase == PHASE_CMDOUT)
break;
DELAY (10);
}
- if (! (ac->result.status & ARS_DRQ)) {
- printf ("atapi%d.%d: no cmd drq\n", ata->ctrlr, ac->unit);
+
+ if (phase != PHASE_CMDOUT) {
ac->result.code = RES_NODRQ;
ac->result.error = inb (ata->port + AR_ERROR);
+ printf ("atapi%d.%d: invalid command phase, ireason=0x%x, status=%b, error=%b\n",
+ ata->ctrlr, ac->unit, ireason,
+ ac->result.status, ARS_BITS,
+ ac->result.error, AER_BITS);
return (-1);
}
return (0);
@@ -560,11 +605,11 @@ void atapi_send_cmd (struct atapi *ata, struct atapicmd *ac)
{
outsw (ata->port + AR_DATA, ac->cmd, ata->cmd16 ? 8 : 6);
if (ata->debug)
- printf ("atapi%d.%d: send cmd %x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x\n",
- ata->ctrlr, ac->unit, ac->cmd[0], ac->cmd[1],
- ac->cmd[2], ac->cmd[3], ac->cmd[4], ac->cmd[5],
- ac->cmd[6], ac->cmd[7], ac->cmd[8], ac->cmd[9],
- ac->cmd[10], ac->cmd[11], ac->cmd[12],
+ printf ("atapi%d.%d: send cmd %s %x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x\n",
+ ata->ctrlr, ac->unit, cmdname (ac->cmd[0]), ac->cmd[0],
+ ac->cmd[1], ac->cmd[2], ac->cmd[3], ac->cmd[4],
+ ac->cmd[5], ac->cmd[6], ac->cmd[7], ac->cmd[8],
+ ac->cmd[9], ac->cmd[10], ac->cmd[11], ac->cmd[12],
ac->cmd[13], ac->cmd[14], ac->cmd[15]);
}
@@ -853,4 +898,133 @@ struct atapires atapi_request_immediate (struct atapi *ata, int unit,
}
return (ac->result);
}
+#endif /* ATAPI_STATIC */
+
+#ifdef ATAPI_MODULE
+/*
+ * ATAPI loadable driver stubs.
+ */
+#include <sys/exec.h>
+#include <sys/conf.h>
+#include <sys/sysent.h>
+#include <sys/lkm.h>
+
+extern int (*atapi_start_ptr) (int ctrlr);
+extern int (*atapi_intr_ptr) (int ctrlr);
+extern void (*atapi_debug_ptr) (struct atapi *ata, int on);
+extern struct atapires (*atapi_request_wait_ptr) (struct atapi *ata, int unit,
+ u_char cmd, u_char a1, u_char a2, u_char a3, u_char a4,
+ u_char a5, u_char a6, u_char a7, u_char a8, u_char a9,
+ u_char a10, u_char a11, u_char a12, u_char a13, u_char a14, u_char a15,
+ char *addr, int count);
+extern void (*atapi_request_callback_ptr) (struct atapi *ata, int unit,
+ u_char cmd, u_char a1, u_char a2, u_char a3, u_char a4,
+ u_char a5, u_char a6, u_char a7, u_char a8, u_char a9,
+ u_char a10, u_char a11, u_char a12, u_char a13, u_char a14, u_char a15,
+ char *addr, int count, void (*done)(), void *x, void *y);
+extern struct atapires (*atapi_request_immediate_ptr) (struct atapi *ata, int unit,
+ u_char cmd, u_char a1, u_char a2, u_char a3, u_char a4,
+ u_char a5, u_char a6, u_char a7, u_char a8, u_char a9,
+ u_char a10, u_char a11, u_char a12, u_char a13, u_char a14, u_char a15,
+ char *addr, int count);
+
+extern void wdintr (int);
+
+/*
+ * Construct lkm_misc structure (see lkm.h).
+ */
+MOD_MISC("atapi")
+
+int atapi_locked;
+
+int atapi_lock (int ctlr)
+{
+ atapi_locked = 1;
+ wakeup (&atapi_locked);
+ return (1);
+}
+
+/*
+ * Function called when loading the driver.
+ */
+int atapi_load (struct lkm_table *lkmtp, int cmd)
+{
+ struct atapidrv *d;
+ int n, x;
+
+ /*
+ * Probe all free IDE units, searching for ATAPI drives.
+ */
+ n = 0;
+ for (d=atapi_drvtab; d<atapi_drvtab+atapi_ndrv && d->port; ++d) {
+ /* Lock the controller. */
+ x = splbio ();
+ atapi_locked = 0;
+ atapi_start_ptr = atapi_lock;
+ wdstart (d->ctlr);
+ while (! atapi_locked)
+ tsleep (&atapi_locked, PRIBIO, "atach", 0);
+
+ /* Probe the drive. */
+ if (atapi_attach (d->ctlr, d->unit, d->port, d->parent)) {
+ d->attached = 1;
+ ++n;
+ }
+
+ /* Unlock the controller. */
+ atapi_start_ptr = 0;
+ wdintr (d->ctlr);
+ splx (x);
+ }
+ if (! n)
+ return ENXIO;
+ atapi_start_ptr = atapi_start;
+ atapi_intr_ptr = atapi_intr;
+ atapi_debug_ptr = atapi_debug;
+ atapi_request_wait_ptr = atapi_request_wait;
+ atapi_request_callback_ptr = atapi_request_callback;
+ atapi_request_immediate_ptr = atapi_request_immediate;
+ atapi_tab = atapitab;
+ return 0;
+}
+
+/*
+ * Function called when unloading the driver.
+ */
+int atapi_unload (struct lkm_table *lkmtp, int cmd)
+{
+ struct atapi *ata;
+ int u;
+
+ for (ata=atapi_tab; ata<atapi_tab+2; ++ata)
+ if (ata->port)
+ for (u=0; u<2; ++u)
+ if (ata->attached[u])
+ return EBUSY;
+ for (ata=atapi_tab; ata<atapi_tab+2; ++ata)
+ if (ata->port)
+ for (u=0; u<2; ++u)
+ if (ata->params[u]) {
+ free (ata->params[u], M_TEMP);
+ ata->params[u] = 0;
+ }
+ atapi_start_ptr = 0;
+ atapi_intr_ptr = 0;
+ atapi_debug_ptr = 0;
+ atapi_request_wait_ptr = 0;
+ atapi_request_callback_ptr = 0;
+ atapi_request_immediate_ptr = 0;
+ atapi_tab = 0;
+ return 0;
+}
+
+/*
+ * Dispatcher function for the module (load/unload/stat).
+ */
+int atapi (struct lkm_table *lkmtp, int cmd, int ver)
+{
+ DISPATCH (lkmtp, cmd, ver, atapi_load, atapi_unload, nosys);
+}
+#endif /* ATAPI_MODULE */
+
#endif /* NWDC && ATAPI */
diff --git a/sys/i386/isa/atapi.h b/sys/i386/isa/atapi.h
index cb46dcc..f22a5a2 100644
--- a/sys/i386/isa/atapi.h
+++ b/sys/i386/isa/atapi.h
@@ -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.8, Thu Sep 28 20:24:38 MSK 1995
+ * Version 1.9, Thu Oct 12 15:53:50 MSK 1995
*/
/*
@@ -190,10 +190,64 @@ struct atapires {
u_char error; /* error register contents */
};
+struct atapidrv { /* delayed attach info */
+ int ctlr; /* IDE controller, 0/1 */
+ int unit; /* drive unit, 0/1 */
+ int port; /* controller base port */
+ int attached; /* the drive is attached */
+ struct kern_devconf *parent; /* the devconf info pattern */
+};
+
+struct atapicmd { /* ATAPI command block */
+ struct atapicmd *next; /* next command in queue */
+ int busy; /* busy flag */
+ u_char cmd[16]; /* command and args */
+ int unit; /* drive unit number */
+ int count; /* byte count, >0 - read, <0 - write */
+ char *addr; /* data to transfer */
+ void (*callback) (); /* call when done */
+ void *cbarg1; /* callback arg 1 */
+ void *cbarg2; /* callback arg 1 */
+ struct atapires result; /* resulting error code */
+};
+
+struct atapi { /* ATAPI controller data */
+ u_short port; /* i/o port base */
+ u_char ctrlr; /* physical controller number */
+ u_char debug : 1; /* trace enable flag */
+ u_char cmd16 : 1; /* 16-byte command flag */
+ u_char intrcmd : 1; /* interrupt before cmd flag */
+ u_char slow : 1; /* slow reaction device */
+ u_char attached[2]; /* units are attached to subdrivers */
+ struct atapi_params *params[2]; /* params for units 0,1 */
+ struct kern_devconf *parent; /* parent configuration pattern */
+ struct atapicmd *queue; /* queue of commands to perform */
+ struct atapicmd *tail; /* tail of queue */
+ struct atapicmd *free; /* queue of free command blocks */
+ struct atapicmd cmdrq[16]; /* pool of command requests */
+};
+
#ifdef KERNEL
struct atapi;
struct kern_devconf;
-void atapi_attach (int ctlr, int unit, int port, struct kern_devconf*);
+
+extern struct atapidrv atapi_drvtab[4]; /* delayed attach info */
+extern int atapi_ndrv; /* the number of potential drives */
+extern struct atapi *atapi_tab; /* the table of atapi controllers */
+
+#ifndef ATAPI_STATIC
+# define atapi_start (*atapi_start_ptr)
+# define atapi_intr (*atapi_intr_ptr)
+# define atapi_debug (*atapi_debug_ptr)
+# define atapi_request_wait (*atapi_request_wait_ptr)
+# define atapi_request_callback (*atapi_request_callback_ptr)
+# define atapi_request_immediate (*atapi_request_immediate_ptr)
+#endif
+
+#ifndef ATAPI_MODULE
+int atapi_attach (int ctlr, int unit, int port, struct kern_devconf*);
+#endif
+
int atapi_start (int ctrlr);
int atapi_intr (int ctrlr);
void atapi_debug (struct atapi *ata, int on);
diff --git a/sys/i386/isa/wcd.c b/sys/i386/isa/wcd.c
index a5a2dff..a64953a 100644
--- a/sys/i386/isa/wcd.c
+++ b/sys/i386/isa/wcd.c
@@ -12,7 +12,7 @@
* or modify this software as long as this message is kept with the software,
* all derivative works or modified versions.
*
- * Version 1.8, Thu Sep 28 21:04:16 MSK 1995
+ * Version 1.9, Mon Oct 9 20:27:42 MSK 1995
*/
#include "wdc.h"
@@ -36,10 +36,9 @@
#define UNIT(d) ((minor(d) >> 3) & 3) /* Unit part of minor device number */
#define SECSIZE 2048 /* CD-ROM sector size in bytes */
-#define F_OPEN 0x0001 /* The drive os opened */
+#define F_BOPEN 0x0001 /* The block device is opened */
#define F_MEDIA_CHANGED 0x0002 /* The media have changed since open */
-#define F_DEBUG 0x0004 /* The media have changed since open */
-#define F_NOPLAYCD 0x0008 /* The PLAY_CD op not supported */
+#define F_DEBUG 0x0004 /* Print debug info */
/*
* Disc table of contents.
@@ -184,6 +183,7 @@ struct wcd {
int unit; /* IDE bus drive unit */
int lun; /* Logical device unit */
int flags; /* Device state flags */
+ int refcnt; /* The number of raw opens */
struct buf queue; /* Queue of i/o requests */
struct atapi_params *param; /* Drive parameters table */
struct toc toc; /* Table of disc contents */
@@ -212,6 +212,7 @@ static int wcd_goaway (struct kern_devconf *kdc, int force);
static void wcd_describe (struct wcd *t);
static int wcd_setchan (struct wcd *t,
u_char c0, u_char c1, u_char c2, u_char c3);
+static int wcd_eject (struct wcd *t);
static struct kern_devconf cftemplate = {
0, 0, 0, "wcd", 0, { MDDT_DISK, 0 },
@@ -244,7 +245,7 @@ static int wcd_goaway (struct kern_devconf *kdc, int force)
return 0;
}
-void wcdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug,
+int wcdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug,
struct kern_devconf *parent)
{
struct wcd *t;
@@ -252,12 +253,12 @@ void wcdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug,
if (wcdnlun >= NUNIT) {
printf ("wcd: too many units\n");
- return;
+ return (0);
}
t = malloc (sizeof (struct wcd), M_TEMP, M_NOWAIT);
if (! t) {
printf ("wcd: out of memory\n");
- return;
+ return (0);
}
wcdtab[wcdnlun] = t;
bzero (t, sizeof (struct wcd));
@@ -266,6 +267,7 @@ void wcdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug,
t->lun = wcdnlun++;
t->param = ap;
t->flags = F_MEDIA_CHANGED;
+ t->refcnt = 0;
if (debug) {
t->flags |= F_DEBUG;
/* Print params. */
@@ -305,6 +307,7 @@ void wcdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug,
strncpy (t->description + strlen(t->description),
ap->model, sizeof(ap->model));
dev_attach (&t->cf);
+ return (1);
}
void wcd_describe (struct wcd *t)
@@ -365,89 +368,72 @@ void wcd_describe (struct wcd *t)
printf ("\n");
}
-int wcdopen (dev_t dev, int flags, int fmt, struct proc *p)
+int wcd_open (dev_t dev, int rawflag)
{
int lun = UNIT(dev);
struct wcd *t;
struct atapires result;
- /* Check the unit is legal. */
- if (lun >= wcdnlun)
+ /* Check that the device number is legal
+ * and the ATAPI driver is loaded. */
+ if (lun >= wcdnlun || ! atapi_request_immediate)
return (ENXIO);
t = wcdtab[lun];
- /* If already opened, that's all. */
- if (t->flags & F_OPEN) {
- /* If it's been invalidated, forbid re-entry.
- * (may have changed media) */
- if (t->flags & F_MEDIA_CHANGED)
- return (ENXIO);
- return (0);
- }
-
- /* On the first open: check for the media.
- * Do it twice to avoid the stale media changed state. */
- 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);
+ /* On the first open, read the table of contents. */
+ if (! (t->flags & F_BOPEN) && ! t->refcnt) {
+ /* Read table of contents. */
+ if (wcd_read_toc (t) < 0)
+ return (EIO);
- 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,
- 0, 0, 0, 0, 0, 0, 0, 0, 0);
- }
- if (result.code) {
- wcd_error (t, result);
- return (ENXIO);
+ /* Lock the media. */
+ wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
}
+ if (rawflag)
+ ++t->refcnt;
+ else
+ t->flags |= F_BOPEN;
+ return (0);
+}
- /* Read table of contents. */
- if (wcd_read_toc (t) != 0)
- bzero (&t->toc, sizeof (t->toc));
-
- /* Read disc capacity. */
- if (wcd_request_wait (t, ATAPI_READ_CAPACITY, 0, 0, 0, 0, 0, 0,
- 0, sizeof(t->info), 0, (char*)&t->info, sizeof(t->info)) != 0)
- bzero (&t->info, sizeof (t->info));
- 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->info.volsize && t->toc.hdr.ending_track &&
- (t->flags & F_MEDIA_CHANGED) && (t->flags & F_DEBUG)) {
- printf ("wcd%d: ", t->lun);
- if (t->toc.tab[0].control & 4)
- printf ("%ldMB ", t->info.volsize / 512);
- else
- printf ("%ld:%ld audio ", t->info.volsize/75/60,
- t->info.volsize/75%60);
- printf ("(%ld sectors), %d tracks\n", t->info.volsize,
- t->toc.hdr.ending_track - t->toc.hdr.starting_track + 1);
- }
- /* Lock the media. */
- wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
- 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
+int wcdbopen (dev_t dev, int flags, int fmt, struct proc *p)
+{
+ return wcd_open (dev, 0);
+}
- t->flags &= ~F_MEDIA_CHANGED;
- t->flags |= F_OPEN;
- return (0);
+int wcdropen (dev_t dev, int flags, int fmt, struct proc *p)
+{
+ return wcd_open (dev, 1);
}
/*
* Close the device. Only called if we are the LAST
* occurence of an open device.
*/
-int wcdclose (dev_t dev, int flags, int fmt, struct proc *p)
+int wcdbclose (dev_t dev, int flags, int fmt, struct proc *p)
{
int lun = UNIT(dev);
struct wcd *t = wcdtab[lun];
/* If we were the last open of the entire device, release it. */
- wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
- t->flags &= ~F_OPEN;
+ if (! t->refcnt)
+ wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ t->flags &= ~F_BOPEN;
+ return (0);
+}
+
+int wcdrclose (dev_t dev, int flags, int fmt, struct proc *p)
+{
+ int lun = UNIT(dev);
+ struct wcd *t = wcdtab[lun];
+
+ /* If we were the last open of the entire device, release it. */
+ if (! (t->flags & F_BOPEN) && t->refcnt == 1)
+ wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ --t->refcnt;
return (0);
}
@@ -462,15 +448,6 @@ void wcdstrategy (struct buf *bp)
struct wcd *t = wcdtab[lun];
int x;
- /* If the device has been made invalid, error out
- * maybe the media changed. */
- if (t->flags & F_MEDIA_CHANGED) {
- bp->b_error = EIO;
- bp->b_flags |= B_ERROR;
- biodone (bp);
- return;
- }
-
/* Can't ever write to a CD. */
if (! (bp->b_flags & B_READ)) {
bp->b_error = EROFS;
@@ -608,34 +585,6 @@ static int wcd_request_wait (struct wcd *t, u_char cmd, u_char a1, u_char a2,
return (0);
}
-static int wcd_play (struct wcd *t, u_char cmd, u_char a1, u_char a2,
- u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
- u_char a9, char *addr, int count)
-{
- struct atapires result;
-
- if (! (t->flags & F_NOPLAYCD)) {
- t->cf.kdc_state = DC_BUSY;
- result = atapi_request_wait (t->ata, t->unit, ATAPI_PLAY_CD,
- cmd == ATAPI_PLAY_MSF ? 2 : 0, a2, a3, a4, a5, a6,
- a7, a8, a9, 0, 0, 0, 0, 0, 0, addr, count);
- t->cf.kdc_state = DC_IDLE;
- if (result.code == RES_ERR &&
- (result.error & AER_SKEY) == AER_SK_ILLEGAL_REQUEST) {
- /* Some drives don't support a PLAY_CD command.
- * Remember this and use PLAY_MSF instead. */
- t->flags |= F_NOPLAYCD;
- result.code = 0;
- }
- if (result.code) {
- wcd_error (t, result);
- return (EIO);
- }
- }
- return wcd_request_wait (t, cmd, a1, a2, a3, a4, a5, a6,
- a7, a8, a9, addr, count);
-}
-
static inline void lba2msf (int lba, u_char *m, u_char *s, u_char *f)
{
lba += 150; /* offset of first logical frame */
@@ -650,15 +599,29 @@ static inline void lba2msf (int lba, u_char *m, u_char *s, u_char *f)
* Perform special action on behalf of the user.
* Knows about the internals of this device
*/
-int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p)
+int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
{
int lun = UNIT(dev);
struct wcd *t = wcdtab[lun];
+ struct atapires result;
int error = 0;
- /* If the device is not valid.. abandon ship. */
if (t->flags & F_MEDIA_CHANGED)
- return (EIO);
+ switch (cmd) {
+ case CDIOCSETDEBUG:
+ case CDIOCCLRDEBUG:
+ case CDIOCRESET:
+ /* These ops are media change transparent. */
+ break;
+ default:
+ /* Read table of contents. */
+ wcd_read_toc (t);
+
+ /* Lock the media. */
+ wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
+ break;
+ }
switch (cmd) {
default:
return (ENOTTY);
@@ -708,21 +671,15 @@ int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p)
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
case CDIOCEJECT:
- /* Stop the disc. */
- error = wcd_request_wait (t, ATAPI_START_STOP,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
- if (error)
- return (error);
- /* Give it some time to stop spinning. */
- tsleep ((caddr_t)&lbolt, PRIBIO, "wcdejct", 0);
- tsleep ((caddr_t)&lbolt, PRIBIO, "wcdejct", 0);
- /* Eject. */
- return wcd_request_wait (t, ATAPI_START_STOP,
- 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0);
+ /* Don't allow eject if the device is opened
+ * by somebody (not us) in block mode. */
+ if ((t->flags & F_BOPEN) && t->refcnt)
+ return (EBUSY);
+ return wcd_eject (t);
case CDIOREADTOCHEADER:
if (! t->toc.hdr.ending_track)
- return (ENODEV);
+ return (EIO);
bcopy (&t->toc.hdr, addr, sizeof t->toc.hdr);
break;
@@ -734,7 +691,7 @@ int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p)
u_long len;
if (! t->toc.hdr.ending_track)
- return (ENODEV);
+ return (EIO);
if (te->starting_track < toc->hdr.starting_track ||
te->starting_track > toc->hdr.ending_track)
return (EINVAL);
@@ -808,14 +765,14 @@ int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p)
case CDIOCPLAYMSF: {
struct ioc_play_msf *args = (struct ioc_play_msf*) addr;
- return wcd_play (t, ATAPI_PLAY_MSF, 0, 0,
+ return wcd_request_wait (t, ATAPI_PLAY_MSF, 0, 0,
args->start_m, args->start_s, args->start_f,
args->end_m, args->end_s, args->end_f, 0, 0, 0);
}
case CDIOCPLAYBLOCKS: {
struct ioc_play_blocks *args = (struct ioc_play_blocks*) addr;
- return wcd_play (t, ATAPI_PLAY_BIG, 0,
+ return wcd_request_wait (t, ATAPI_PLAY_BIG, 0,
args->blk >> 24 & 0xff, args->blk >> 16 & 0xff,
args->blk >> 8 & 0xff, args->blk & 0xff,
args->len >> 24 & 0xff, args->len >> 16 & 0xff,
@@ -827,7 +784,7 @@ int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p)
int t1, t2;
if (! t->toc.hdr.ending_track)
- return (ENODEV);
+ return (EIO);
/* Ignore index fields,
* play from start_track to end_track inclusive. */
@@ -842,7 +799,7 @@ int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p)
start = t->toc.tab[t1].addr.lba;
len = t->toc.tab[t2].addr.lba - start;
- return wcd_play (t, ATAPI_PLAY_BIG, 0,
+ return wcd_request_wait (t, ATAPI_PLAY_BIG, 0,
start >> 24 & 0xff, start >> 16 & 0xff,
start >> 8 & 0xff, start & 0xff,
len >> 24 & 0xff, len >> 16 & 0xff,
@@ -888,6 +845,9 @@ int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p)
if (t->flags & F_DEBUG)
wcd_dump (t->lun, "mask", &t->aumask, sizeof t->aumask);
+ /* Sony-55E requires the data length field to be zeroed. */
+ t->au.data_length = 0;
+
t->au.port[0].channels = CHANNEL_0;
t->au.port[1].channels = CHANNEL_1;
t->au.port[0].volume = arg->vol[0] & t->aumask.port[0].volume;
@@ -929,16 +889,40 @@ int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p)
static int wcd_read_toc (struct wcd *t)
{
int ntracks, len, i;
+ struct atapires result;
+
+ bzero (&t->toc, sizeof (t->toc));
+ bzero (&t->info, sizeof (t->info));
+
+ /* Check for the media.
+ * Do it twice to avoid the stale media changed state. */
+ 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_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,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ }
+ if (result.code) {
+ wcd_error (t, result);
+ return (EIO);
+ }
+ t->flags &= ~F_MEDIA_CHANGED;
/* First read just the header, so we know how long the TOC is. */
len = sizeof(struct ioc_toc_header) + sizeof(struct cd_toc_entry);
if (wcd_request_wait (t, ATAPI_READ_TOC, 0, 0, 0, 0, 0, 0,
- len >> 8, len & 0xff, 0, (char*)&t->toc, len) != 0)
- return (EIO);
+ len >> 8, len & 0xff, 0, (char*)&t->toc, len) != 0) {
+err: bzero (&t->toc, sizeof (t->toc));
+ return (0);
+ }
ntracks = t->toc.hdr.ending_track - t->toc.hdr.starting_track + 1;
if (ntracks <= 0)
- return (EIO);
+ goto err;
if (ntracks > MAXTRK)
ntracks = MAXTRK;
@@ -947,11 +931,36 @@ static int wcd_read_toc (struct wcd *t)
(ntracks+1) * sizeof(struct cd_toc_entry);
if (wcd_request_wait (t, ATAPI_READ_TOC, 0, 0, 0, 0, 0, 0,
len >> 8, len & 0xff, 0, (char*)&t->toc, len) & 0xff)
- return (EIO);
+ goto err;
t->toc.hdr.len = ntohs (t->toc.hdr.len);
for (i=0; i<=ntracks; i++)
t->toc.tab[i].addr.lba = ntohl (t->toc.tab[i].addr.lba);
+
+ /* Decrement the total length of the disc.
+ * Some drives (e.g. Sony-55E) have this value too big. */
+ --t->toc.tab[ntracks].addr.lba;
+
+ /* Read disc capacity. */
+ if (wcd_request_wait (t, ATAPI_READ_CAPACITY, 0, 0, 0, 0, 0, 0,
+ 0, sizeof(t->info), 0, (char*)&t->info, sizeof(t->info)) != 0)
+ bzero (&t->info, sizeof (t->info));
+ 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->info.volsize && t->toc.hdr.ending_track &&
+ (t->flags & F_MEDIA_CHANGED) && (t->flags & F_DEBUG)) {
+ printf ("wcd%d: ", t->lun);
+ if (t->toc.tab[0].control & 4)
+ printf ("%ldMB ", t->info.volsize / 512);
+ else
+ printf ("%ld:%ld audio ", t->info.volsize/75/60,
+ t->info.volsize/75%60);
+ printf ("(%ld sectors), %d tracks\n", t->info.volsize,
+ t->toc.hdr.ending_track - t->toc.hdr.starting_track + 1);
+ }
return (0);
}
@@ -973,6 +982,9 @@ static int wcd_setchan (struct wcd *t,
if (t->au.page_code != AUDIO_PAGE)
return (EIO);
+ /* Sony-55E requires the data length field to be zeroed. */
+ t->au.data_length = 0;
+
t->au.port[0].channels = c0;
t->au.port[1].channels = c1;
t->au.port[2].channels = c2;
@@ -981,4 +993,171 @@ static int wcd_setchan (struct wcd *t,
0, 0, 0, 0, 0, sizeof (t->au) >> 8, sizeof (t->au),
0, (char*) &t->au, - sizeof (t->au));
}
+
+static int wcd_eject (struct wcd *t)
+{
+ struct atapires result;
+
+ /* Try to stop the disc. */
+ t->cf.kdc_state = DC_BUSY;
+ result = atapi_request_wait (t->ata, t->unit, ATAPI_START_STOP,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ t->cf.kdc_state = DC_IDLE;
+
+ if (result.code == RES_ERR &&
+ ((result.error & AER_SKEY) == AER_SK_NOT_READY ||
+ (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)) {
+ /*
+ * The disc was unloaded.
+ * Load it (close tray).
+ * Read the table of contents.
+ */
+ int err = wcd_request_wait (t, ATAPI_START_STOP,
+ 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0);
+ if (err)
+ return (err);
+
+ /* Read table of contents. */
+ wcd_read_toc (t);
+
+ /* Lock the media. */
+ wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
+
+ return (0);
+ }
+
+ if (result.code) {
+ wcd_error (t, result);
+ return (EIO);
+ }
+
+ /* Give it some time to stop spinning. */
+ tsleep ((caddr_t)&lbolt, PRIBIO, "wcdej1", 0);
+ tsleep ((caddr_t)&lbolt, PRIBIO, "wcdej2", 0);
+
+ /* Unlock. */
+ wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ /* Eject. */
+ t->flags |= F_MEDIA_CHANGED;
+ return wcd_request_wait (t, ATAPI_START_STOP,
+ 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0);
+}
+
+#ifdef WCD_MODULE
+/*
+ * Loadable ATAPI CD-ROM driver stubs.
+ */
+#include <sys/exec.h>
+#include <sys/sysent.h>
+#include <sys/lkm.h>
+
+/*
+ * Device table entries.
+ * These get copied at modload time into the kernels
+ * lkm dummy device driver entries (see sys/i386/i386/conf.c).
+ */
+#define NOSTOP (d_stop_t*) enodev
+#define NOWRITE (d_rdwr_t*) enodev
+#define NORESET (d_reset_t*) nullop
+#define NODEVTOTTY (d_ttycv_t*) nullop
+#define NOMMAP (d_mmap_t*) enodev
+#define NODUMP (d_dump_t*) enxio
+#define ZEROSIZE (d_psize_t*) 0
+d_rdwr_t rawread;
+struct bdevsw dev_wcd = { wcdbopen, wcdbclose, wcdstrategy, wcdioctl,
+ NODUMP, ZEROSIZE, 0 };
+struct cdevsw dev_rwcd = { wcdropen, wcdrclose, rawread, NOWRITE, wcdioctl,
+ NOSTOP, NORESET, NODEVTOTTY, seltrue, NOMMAP,
+ wcdstrategy };
+/*
+ * Construct lkm_dev structures (see lkm.h).
+ * Our bdevsw/cdevsw slot numbers are 19/69.
+ */
+static struct lkm_dev wcd_module = {
+ LM_DEV, LKM_VERSION, "wcd", 19, LM_DT_BLOCK, { (void*) &dev_wcd } };
+static struct lkm_dev rwcd_module = {
+ LM_DEV, LKM_VERSION, "rwcd", 69, LM_DT_CHAR, { (void*) &dev_rwcd } };
+
+/*
+ * Function called when loading the driver.
+ */
+int wcd_load (struct lkm_table *lkmtp, int cmd)
+{
+ struct atapi *ata;
+ int n, u;
+
+ if (! atapi_start)
+ /* No ATAPI driver available. */
+ return EPROTONOSUPPORT;
+ n = 0;
+ for (ata=atapi_tab; ata<atapi_tab+2; ++ata)
+ if (ata->port)
+ for (u=0; u<2; ++u)
+ /* Probing controller ata->ctrlr, unit u. */
+ if (ata->params[u] && ! ata->attached[u] &&
+ wcdattach (ata, u, ata->params[u],
+ ata->debug, ata->parent) >= 0)
+ {
+ /* Drive found. */
+ ata->attached[u] = 1;
+ ++n;
+ }
+ if (! n)
+ /* No IDE CD-ROMs found. */
+ return ENXIO;
+ return 0;
+}
+
+/*
+ * Function called when unloading the driver.
+ */
+int wcd_unload (struct lkm_table *lkmtp, int cmd)
+{
+ struct wcd **t;
+
+ for (t=wcdtab; t<wcdtab+wcdnlun; ++t)
+ if (((*t)->flags & F_BOPEN) || (*t)->refcnt)
+ /* The device is opened, cannot unload the driver. */
+ return EBUSY;
+ for (t=wcdtab; t<wcdtab+wcdnlun; ++t) {
+ (*t)->ata->attached[(*t)->unit] = 0;
+ free (*t, M_TEMP);
+ }
+ wcdnlun = 0;
+ bzero (wcdtab, sizeof(wcdtab));
+ return 0;
+}
+
+/*
+ * Dispatcher function for the module (load/unload/stat).
+ */
+int wcd (struct lkm_table *lkmtp, int cmd, int ver)
+{
+ int err = 0;
+
+ if (ver != LKM_VERSION)
+ return EINVAL;
+
+ if (cmd == LKM_E_LOAD)
+ err = wcd_load (lkmtp, cmd);
+ else if (cmd == LKM_E_UNLOAD)
+ err = wcd_unload (lkmtp, cmd);
+ if (err)
+ return err;
+
+ /* Register the cdevsw entry. */
+ lkmtp->private.lkm_dev = &rwcd_module;
+ err = lkmdispatch (lkmtp, cmd);
+ if (err)
+ return err;
+
+ /* Register the bdevsw entry. */
+ lkmtp->private.lkm_dev = &wcd_module;
+ return lkmdispatch (lkmtp, cmd);
+}
+#endif /* WCD_MODULE */
+
#endif /* NWCD && NWDC && ATAPI */
diff --git a/sys/i386/isa/wd.c b/sys/i386/isa/wd.c
index 115f275..d3c8ec3 100644
--- a/sys/i386/isa/wd.c
+++ b/sys/i386/isa/wd.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)wd.c 7.2 (Berkeley) 5/9/91
- * $Id: wd.c,v 1.85 1995/09/30 00:11:19 jkh Exp $
+ * $Id: wd.c,v 1.86 1995/09/30 15:19:44 davidg Exp $
*/
/* TODO:
@@ -301,11 +301,34 @@ wdprobe(struct isa_device *dvp)
/* check if we have registers that work */
outb(du->dk_port + wd_sdh, WDSD_IBM); /* set unit 0 */
outb(du->dk_port + wd_cyl_lo, 0xa5); /* wd_cyl_lo is read/write */
- if (inb(du->dk_port + wd_cyl_lo) == 0xff) /* XXX too weak */
- goto nodevice;
+ if (inb(du->dk_port + wd_cyl_lo) == 0xff) { /* XXX too weak */
+#ifdef ATAPI
+ /* There is no master, try the ATAPI slave. */
+ outb(du->dk_port + wd_sdh, WDSD_IBM | 0x10);
+ outb(du->dk_port + wd_cyl_lo, 0xa5);
+ if (inb(du->dk_port + wd_cyl_lo) == 0xff)
+#endif
+ goto nodevice;
+ }
- if (wdreset(du) != 0 && (DELAY(RECOVERYTIME), wdreset(du)) != 0)
+ if (wdreset(du) == 0)
+ goto reset_ok;
+#ifdef ATAPI
+ /* test for ATAPI signature */
+ outb(du->dk_port + wd_sdh, WDSD_IBM); /* master */
+ if (inb(du->dk_port + wd_cyl_lo) == 0x14 &&
+ inb(du->dk_port + wd_cyl_hi) == 0xeb)
+ goto reset_ok;
+ du->dk_unit = 1;
+ outb(du->dk_port + wd_sdh, WDSD_IBM | 0x10); /* slave */
+ if (inb(du->dk_port + wd_cyl_lo) == 0x14 &&
+ inb(du->dk_port + wd_cyl_hi) == 0xeb)
+ goto reset_ok;
+#endif
+ DELAY(RECOVERYTIME);
+ if (wdreset(du) != 0)
goto nodevice;
+reset_ok:
/* execute a controller only command */
if (wdcommand(du, 0, 0, 0, 0, WDCC_DIAGNOSE) != 0
@@ -657,7 +680,7 @@ loop:
bp = wdtab[ctrlr].b_actf;
if (bp == NULL) {
#ifdef ATAPI
- if (atapi_start (ctrlr))
+ if (atapi_start && atapi_start (ctrlr))
/* mark controller active in ATAPI mode */
wdtab[ctrlr].b_active = 3;
#endif
@@ -891,7 +914,7 @@ wdintr(int unit)
#ifdef ATAPI
if (wdtab[unit].b_active == 3) {
/* process an ATAPI interrupt */
- if (atapi_intr (unit))
+ if (atapi_intr && atapi_intr (unit))
/* ATAPI op continues */
return;
/* controller is free, start new op */
@@ -1916,13 +1939,6 @@ wdreset(struct disk *du)
du->dk_error = inb(wdc + wd_error);
if (du->dk_error != 0x01)
err = 1; /* the drive is incompatible */
- if (err) {
- /* no IDE drive, test for ATAPI signature */
- int lo = inb(wdc + wd_cyl_lo);
- int hi = inb(wdc + wd_cyl_hi);
- if (lo == 0x14 && hi == 0xeb)
- err = 0; /* ATAPI drive detected */
- }
#else
if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0
|| (du->dk_error = inb(wdc + wd_error)) != 0x01)
@@ -2042,6 +2058,18 @@ wdwait(struct disk *du, u_char bits_wanted, int timeout)
min_retries[du->dk_ctrlr] = timeout;
#endif
du->dk_status = status = inb(wdc + wd_status);
+#ifdef ATAPI
+ /*
+ * Atapi drives have a very interesting feature, when attached
+ * as a slave on the IDE bus, and there is no master.
+ * They release the bus after getting the command.
+ * We should reselect the drive here to get the status.
+ */
+ if (status == 0xff) {
+ outb(wdc + wd_sdh, WDSD_IBM | du->dk_unit << 4);
+ du->dk_status = status = inb(wdc + wd_status);
+ }
+#endif
if (!(status & WDCS_BUSY)) {
if (status & WDCS_ERR) {
du->dk_error = inb(wdc + wd_error);
diff --git a/sys/pc98/pc98/atapi.h b/sys/pc98/pc98/atapi.h
index cb46dcc..f22a5a2 100644
--- a/sys/pc98/pc98/atapi.h
+++ b/sys/pc98/pc98/atapi.h
@@ -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.8, Thu Sep 28 20:24:38 MSK 1995
+ * Version 1.9, Thu Oct 12 15:53:50 MSK 1995
*/
/*
@@ -190,10 +190,64 @@ struct atapires {
u_char error; /* error register contents */
};
+struct atapidrv { /* delayed attach info */
+ int ctlr; /* IDE controller, 0/1 */
+ int unit; /* drive unit, 0/1 */
+ int port; /* controller base port */
+ int attached; /* the drive is attached */
+ struct kern_devconf *parent; /* the devconf info pattern */
+};
+
+struct atapicmd { /* ATAPI command block */
+ struct atapicmd *next; /* next command in queue */
+ int busy; /* busy flag */
+ u_char cmd[16]; /* command and args */
+ int unit; /* drive unit number */
+ int count; /* byte count, >0 - read, <0 - write */
+ char *addr; /* data to transfer */
+ void (*callback) (); /* call when done */
+ void *cbarg1; /* callback arg 1 */
+ void *cbarg2; /* callback arg 1 */
+ struct atapires result; /* resulting error code */
+};
+
+struct atapi { /* ATAPI controller data */
+ u_short port; /* i/o port base */
+ u_char ctrlr; /* physical controller number */
+ u_char debug : 1; /* trace enable flag */
+ u_char cmd16 : 1; /* 16-byte command flag */
+ u_char intrcmd : 1; /* interrupt before cmd flag */
+ u_char slow : 1; /* slow reaction device */
+ u_char attached[2]; /* units are attached to subdrivers */
+ struct atapi_params *params[2]; /* params for units 0,1 */
+ struct kern_devconf *parent; /* parent configuration pattern */
+ struct atapicmd *queue; /* queue of commands to perform */
+ struct atapicmd *tail; /* tail of queue */
+ struct atapicmd *free; /* queue of free command blocks */
+ struct atapicmd cmdrq[16]; /* pool of command requests */
+};
+
#ifdef KERNEL
struct atapi;
struct kern_devconf;
-void atapi_attach (int ctlr, int unit, int port, struct kern_devconf*);
+
+extern struct atapidrv atapi_drvtab[4]; /* delayed attach info */
+extern int atapi_ndrv; /* the number of potential drives */
+extern struct atapi *atapi_tab; /* the table of atapi controllers */
+
+#ifndef ATAPI_STATIC
+# define atapi_start (*atapi_start_ptr)
+# define atapi_intr (*atapi_intr_ptr)
+# define atapi_debug (*atapi_debug_ptr)
+# define atapi_request_wait (*atapi_request_wait_ptr)
+# define atapi_request_callback (*atapi_request_callback_ptr)
+# define atapi_request_immediate (*atapi_request_immediate_ptr)
+#endif
+
+#ifndef ATAPI_MODULE
+int atapi_attach (int ctlr, int unit, int port, struct kern_devconf*);
+#endif
+
int atapi_start (int ctrlr);
int atapi_intr (int ctrlr);
void atapi_debug (struct atapi *ata, int on);
OpenPOWER on IntegriCloud