kern/158086: [patch] Update digi(4) to work with TTYng

Peter Jeremy Peter.Jeremy at alcatel-lucent.com
Tue Jun 21 04:50:08 UTC 2011


>Number:         158086
>Category:       kern
>Synopsis:       [patch] Update digi(4) to work with TTYng
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Jun 21 04:50:08 UTC 2011
>Closed-Date:
>Last-Modified:
>Originator:     Peter Jeremy
>Release:        FreeBSD 9.0-CURRENT amd64
>Organization:
Alcatel-Lucent Australia Limited
>Environment:
System: FreeBSD C2B0004103.au.alcatel-lucent.com 9.0-CURRENT FreeBSD 9.0-CURRENT #0: Tue Jun 21 12:53:47 EST 2011 root at C2B0004103.au.alcatel-lucent.com:/var/obj/usr/src/sys/pjdesk amd64

>Description:
	The digi(4) driver needs updating to work with TTYng.  The patch
	below does this.  The code has also been cross-checked against
	the Linux driver (dgap-1.3) available from Digi.

	Notes:
	- kern/152254 must be committed before this PR
	- Only PCI DigiBoards are supported.  Additional locking would
	  be required to support ISA cards and I do not have access to
	  any for testing.
	- The code still handles firmware loading/unloading itself
	  rather than using firmware(9) because each card needs two
	  or three firmware images and the current approach allows
	  one kld per card, rather than one kld per image.
	- Interrupt or polling mode can be selected at compile time.
	- Giant is no longer used.
	- The softc has been rototilled to reduce the amount of padding
	- If compiled with debugging, a sysctl is available to control
	  verbosity.
	- This patch still includes debugging code.

>How-To-Repeat:
	Try to compile digi(4) on 8.0 or later.

>Fix:

Index: sys/conf/files
===================================================================
RCS file: /usr/ncvs/src/sys/conf/files,v
retrieving revision 1.1606
diff -u -r1.1606 files
--- sys/conf/files	10 Jun 2011 22:38:31 -0000	1.1606
+++ sys/conf/files	20 Jun 2011 22:43:01 -0000
@@ -942,7 +942,7 @@
 dev/digi/Xem.c			optional digi_Xem
 dev/digi/Xr.c			optional digi_Xr
 dev/digi/digi.c			optional digi
-dev/digi/digi_isa.c		optional digi isa
+#dev/digi/digi_isa.c		optional digi isa
 dev/digi/digi_pci.c		optional digi pci
 dev/dpt/dpt_eisa.c		optional dpt eisa
 dev/dpt/dpt_pci.c		optional dpt pci
Index: sys/dev/digi/CX.c
===================================================================
RCS file: /usr/ncvs/src/sys/dev/digi/CX.c,v
retrieving revision 1.3
diff -u -r1.3 CX.c
--- sys/dev/digi/CX.c	24 Aug 2003 17:46:03 -0000	1.3
+++ sys/dev/digi/CX.c	20 Jun 2011 22:43:50 -0000
@@ -44,5 +44,18 @@
 	{ NULL, 0 }
 };
 
+static int
+digi_fw_load(module_t mod, int cmd, void *arg)
+{
+
+	switch (cmd) {
+	case MOD_LOAD:
+	case MOD_UNLOAD:
+		return (0);
+	default:
+		return (EOPNOTSUPP);
+	}
+}
+
 MODULE_VERSION(digi_CX, 1);
-DEV_MODULE(digi_CX, 0, 0);
+DEV_MODULE(digi_CX, digi_fw_load, 0);
Index: sys/dev/digi/CX_PCI.c
===================================================================
RCS file: /usr/ncvs/src/sys/dev/digi/CX_PCI.c,v
retrieving revision 1.3
diff -u -r1.3 CX_PCI.c
--- sys/dev/digi/CX_PCI.c	24 Aug 2003 17:46:03 -0000	1.3
+++ sys/dev/digi/CX_PCI.c	20 Jun 2011 22:43:50 -0000
@@ -44,5 +44,18 @@
 	{ NULL, 0 }
 };
 
+static int
+digi_fw_load(module_t mod, int cmd, void *arg)
+{
+
+	switch (cmd) {
+	case MOD_LOAD:
+	case MOD_UNLOAD:
+		return (0);
+	default:
+		return (EOPNOTSUPP);
+	}
+}
+
 MODULE_VERSION(digi_CX_PCI, 1);
-DEV_MODULE(digi_CX_PCI, 0, 0);
+DEV_MODULE(digi_CX_PCI, digi_fw_load, 0);
Index: sys/dev/digi/EPCX.c
===================================================================
RCS file: /usr/ncvs/src/sys/dev/digi/EPCX.c,v
retrieving revision 1.3
diff -u -r1.3 EPCX.c
--- sys/dev/digi/EPCX.c	24 Aug 2003 17:46:03 -0000	1.3
+++ sys/dev/digi/EPCX.c	20 Jun 2011 22:43:50 -0000
@@ -44,5 +44,18 @@
 	{ NULL, 0 }
 };
 
+static int
+digi_fw_load(module_t mod, int cmd, void *arg)
+{
+
+	switch (cmd) {
+	case MOD_LOAD:
+	case MOD_UNLOAD:
+		return (0);
+	default:
+		return (EOPNOTSUPP);
+	}
+}
+
 MODULE_VERSION(digi_EPCX, 1);
-DEV_MODULE(digi_EPCX, 0, 0);
+DEV_MODULE(digi_EPCX, digi_fw_load, 0);
Index: sys/dev/digi/EPCX_PCI.c
===================================================================
RCS file: /usr/ncvs/src/sys/dev/digi/EPCX_PCI.c,v
retrieving revision 1.3
diff -u -r1.3 EPCX_PCI.c
--- sys/dev/digi/EPCX_PCI.c	24 Aug 2003 17:46:03 -0000	1.3
+++ sys/dev/digi/EPCX_PCI.c	20 Jun 2011 22:43:50 -0000
@@ -44,5 +44,18 @@
 	{ NULL, 0 }
 };
 
+static int
+digi_fw_load(module_t mod, int cmd, void *arg)
+{
+
+	switch (cmd) {
+	case MOD_LOAD:
+	case MOD_UNLOAD:
+		return (0);
+	default:
+		return (EOPNOTSUPP);
+	}
+}
+
 MODULE_VERSION(digi_EPCX_PCI, 1);
-DEV_MODULE(digi_EPCX_PCI, 0, 0);
+DEV_MODULE(digi_EPCX_PCI, digi_fw_load, 0);
Index: sys/dev/digi/Xe.c
===================================================================
RCS file: /usr/ncvs/src/sys/dev/digi/Xe.c,v
retrieving revision 1.3
diff -u -r1.3 Xe.c
--- sys/dev/digi/Xe.c	24 Aug 2003 17:46:03 -0000	1.3
+++ sys/dev/digi/Xe.c	20 Jun 2011 22:43:50 -0000
@@ -44,5 +44,18 @@
 	{ NULL, 0 }
 };
 
+static int
+digi_fw_load(module_t mod, int cmd, void *arg)
+{
+
+	switch (cmd) {
+	case MOD_LOAD:
+	case MOD_UNLOAD:
+		return (0);
+	default:
+		return (EOPNOTSUPP);
+	}
+}
+
 MODULE_VERSION(digi_Xe, 1);
-DEV_MODULE(digi_Xe, 0, 0);
+DEV_MODULE(digi_Xe, digi_fw_load, 0);
Index: sys/dev/digi/Xem.c
===================================================================
RCS file: /usr/ncvs/src/sys/dev/digi/Xem.c,v
retrieving revision 1.3
diff -u -r1.3 Xem.c
--- sys/dev/digi/Xem.c	24 Aug 2003 17:46:03 -0000	1.3
+++ sys/dev/digi/Xem.c	20 Jun 2011 22:43:50 -0000
@@ -44,5 +44,18 @@
 	{ NULL, 0 }
 };
 
+static int
+digi_fw_load(module_t mod, int cmd, void *arg)
+{
+
+	switch (cmd) {
+	case MOD_LOAD:
+	case MOD_UNLOAD:
+		return (0);
+	default:
+		return (EOPNOTSUPP);
+	}
+}
+
 MODULE_VERSION(digi_Xem, 1);
-DEV_MODULE(digi_Xem, 0, 0);
+DEV_MODULE(digi_Xem, digi_fw_load, 0);
Index: sys/dev/digi/Xr.c
===================================================================
RCS file: /usr/ncvs/src/sys/dev/digi/Xr.c,v
retrieving revision 1.3
diff -u -r1.3 Xr.c
--- sys/dev/digi/Xr.c	24 Aug 2003 17:46:03 -0000	1.3
+++ sys/dev/digi/Xr.c	20 Jun 2011 22:43:50 -0000
@@ -44,5 +44,18 @@
 	{ NULL, 0 }
 };
 
+static int
+digi_fw_load(module_t mod, int cmd, void *arg)
+{
+
+	switch (cmd) {
+	case MOD_LOAD:
+	case MOD_UNLOAD:
+		return (0);
+	default:
+		return (EOPNOTSUPP);
+	}
+}
+
 MODULE_VERSION(digi_Xr, 1);
-DEV_MODULE(digi_Xr, 0, 0);
+DEV_MODULE(digi_Xr, digi_fw_load, 0);
Index: sys/dev/digi/digi.c
===================================================================
RCS file: /usr/ncvs/src/sys/dev/digi/digi.c,v
retrieving revision 1.63
diff -u -r1.63 digi.c
--- sys/dev/digi/digi.c	27 Sep 2006 19:56:58 -0000	1.63
+++ sys/dev/digi/digi.c	20 Jun 2011 22:43:51 -0000
@@ -42,12 +42,15 @@
 #include <sys/proc.h>
 #include <sys/conf.h>
 #include <sys/linker.h>
+#include <sys/lock.h>
 #include <sys/kernel.h>
 #include <sys/mbuf.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
-#include <sys/tty.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
 #include <sys/syslog.h>
+#include <sys/tty.h>
 #include <sys/fcntl.h>
 #include <sys/serial.h>
 #include <sys/bus.h>
@@ -59,25 +62,39 @@
 #include <dev/digi/digi_mod.h>
 #include <dev/digi/digi_pci.h>
 
-static t_open_t		digiopen;
+static tsw_open_t digiopen;
+static tsw_close_t digiclose;
+static tsw_outwakeup_t digioutwakeup;
+static tsw_inwakeup_t digiinwakeup;
+static tsw_ioctl_t digiioctl;
+static tsw_param_t digiparam;
+static tsw_modem_t digimodem;
+static tsw_pktnotify_t diginotify;
+static tsw_free_t digifree;
+static tsw_cioctl_t digisioctl;
+
+static struct ttydevsw digi_class = {
+	.tsw_flags	= TF_INITLOCK | TF_CALLOUT,
+	.tsw_open	= digiopen,
+	.tsw_close	= digiclose,
+	.tsw_outwakeup	= digioutwakeup,
+	.tsw_inwakeup	= digiinwakeup,
+	.tsw_ioctl	= digiioctl,
+	.tsw_param	= digiparam,
+	.tsw_modem	= digimodem,
+	.tsw_pktnotify	= diginotify,
+	.tsw_free	= digifree,
+	.tsw_cioctl	= digisioctl,
+};
+
 static d_open_t		digicopen;
 static d_close_t	digicclose;
-static t_ioctl_t	digiioctl;
-static d_ioctl_t	digisioctl;
 static d_ioctl_t	digicioctl;
 
-static void	digistop(struct tty *tp, int rw);
-static void	digibreak(struct tty *tp, int brk);
-static int	digimodem(struct tty *tp, int sigon, int sigoff);
 static void	digi_poll(void *ptr);
-static void	digi_freemoduledata(struct digi_softc *);
 static void	fepcmd(struct digi_p *port, int cmd, int op, int ncmds);
-static void	digistart(struct tty *tp);
-static int	digiparam(struct tty *tp, struct termios *t);
-static void	digiclose(struct tty *tp);
-static void	digi_intr(void *);
 static int	digi_init(struct digi_softc *_sc);
-static int	digi_loadmoduledata(struct digi_softc *);
+static int	digi_loadmoduledata(struct digi_softc *, struct digi_mod **, linker_file_t *);
 static int	digi_inuse(struct digi_softc *);
 static void	digi_free_state(struct digi_softc *);
 
@@ -85,18 +102,25 @@
 	fepcmd(port, cmd, (op2 << 8) | op1, ncmds)
 #define	fepcmd_w	fepcmd
 
-struct con_bios {
-	struct con_bios *next;
-	u_char *bios;
-	size_t size;
-};
-
-static struct con_bios *con_bios_list;
 devclass_t	 digi_devclass;
 static char	 driver_name[] = "digi";
-unsigned 	 digi_debug = 0;
 
-static struct speedtab digispeedtab[] = {
+#ifdef DEBUG
+unsigned long	 digi_debug = 1;
+
+SYSCTL_ULONG(_debug, OID_AUTO, digi_debug, CTLFLAG_RW, &digi_debug, 0,
+	"digi(4) debug flags");
+TUNABLE_ULONG("debug.digi_debug", &digi_debug);
+#endif
+
+/* digi(4) uses the old SysV-style Bx codes to control line speed.
+ * (The Linux driver suggests some Digi variants can handle direct
+ * baud-rate programming but that would be a more invasive change)
+ */
+static const struct {
+	int	sp_speed;	/* Actual line rate in BPS */
+	int	sp_code;	/* Code for Digi */
+} digispeedtab[] = {
 	{ 0,		0},			/* old (sysV-like) Bx codes */
 	{ 50,		1},
 	{ 75,		2},
@@ -134,7 +158,7 @@
 	.d_close =	digicclose,
 	.d_ioctl =	digicioctl,
 	.d_name =	driver_name,
-	.d_flags =	D_TTY | D_NEEDGIANT,
+	.d_flags =	D_TTY,
 };
 
 static void
@@ -143,9 +167,12 @@
 	struct digi_softc *sc;
 
 	sc = (struct digi_softc *)ptr;
-	callout_handle_init(&sc->callout);
+	mtx_assert(&sc->dg_mutex, MA_OWNED);
+
+	if (callout_pending(&sc->callout) || callout_active(&sc->callout) == 0)
+		return;
 	digi_intr(sc);
-	sc->callout = timeout(digi_poll, sc, (hz >= 200) ? hz / 100 : 1);
+	callout_schedule(&sc->callout, (hz >= 200) ? hz / 100 : 1);
 }
 
 static void
@@ -153,36 +180,22 @@
 {
 	struct digi_softc *sc = v;
 
-	callout_handle_init(&sc->inttest);
+	mtx_assert(&sc->dg_mutex, MA_OWNED);
+	if (callout_pending(&sc->callout) || !callout_active(&sc->callout))
+		return;
 #ifdef DIGI_INTERRUPT
-	if (sc->intr_timestamp.tv_sec || sc->intr_timestamp.tv_usec) {
+	if (sc->interrupt_seen) {
+		callout_deactivate(&sc->callout);
 		/* interrupt OK! */
 		return;
 	}
-	log(LOG_ERR, "digi%d: Interrupt didn't work, use polled mode\n", unit);
+	log(LOG_ERR, "digi%d: Interrupt didn't work, use polled mode\n", sc->res.unit);
 #endif
-	sc->callout = timeout(digi_poll, sc, (hz >= 200) ? hz / 100 : 1);
-}
-
-static void
-digi_freemoduledata(struct digi_softc *sc)
-{
-	if (sc->fep.data != NULL) {
-		free(sc->fep.data, M_TTYS);
-		sc->fep.data = NULL;
-	}
-	if (sc->link.data != NULL) {
-		free(sc->link.data, M_TTYS);
-		sc->link.data = NULL;
-	}
-	if (sc->bios.data != NULL) {
-		free(sc->bios.data, M_TTYS);
-		sc->bios.data = NULL;
-	}
+	callout_reset(&sc->callout, (hz >= 200) ? hz / 100 : 1, digi_poll, sc);
 }
 
 static int
-digi_bcopy(const void *vfrom, void *vto, size_t sz)
+digi_bcopy(const void *vfrom, void volatile *vto, size_t sz)
 {
 	volatile const char *from = (volatile const char *)vfrom;
 	volatile char *to = (volatile char *)vto;
@@ -204,6 +217,8 @@
 {
 	if (cold)
 		DELAY(timo * 1000000 / hz);
+	else if (mtx_owned(&sc->dg_mutex))
+		mtx_sleep(sc, &sc->dg_mutex, PUSER | PCATCH, txt, timo);
 	else
 		tsleep(sc, PUSER | PCATCH, txt, timo);
 }
@@ -212,62 +227,78 @@
 digi_init(struct digi_softc *sc)
 {
 	int i, cnt, resp;
-	u_char *ptr;
+	int error;
+	u_char volatile *ptr;
+	u_char *cptr;
 	int lowwater;
 	struct digi_p *port;
 	volatile struct board_chan *bc;
 	struct tty *tp;
+	struct digi_mod *dm;
+	linker_file_t lf;
+	enum digi_board_status old_state;
 
+	mtx_assert(&sc->dg_mutex, MA_OWNED);
 	ptr = NULL;
 
-	if (sc->status == DIGI_STATUS_DISABLED) {
-		log(LOG_ERR, "digi%d: Cannot init a disabled card\n",
+	if (sc->status == DIGI_STATUS_DISABLED ||
+	    sc->status == DIGI_STATUS_STARTING) {
+		log(LOG_ERR, "digi%d: Card [de]initialisation in progress\n",
 		    sc->res.unit);
 		return (EIO);
 	}
-	if (sc->bios.data == NULL) {
-		log(LOG_ERR, "digi%d: Cannot init without BIOS\n",
-		    sc->res.unit);
-		return (EIO);
-	}
-#if 0
-	if (sc->link.data == NULL && sc->model >= PCCX) {
-		log(LOG_ERR, "digi%d: Cannot init without link info\n",
-		    sc->res.unit);
-		return (EIO);
-	}
-#endif
-	if (sc->fep.data == NULL) {
-		log(LOG_ERR, "digi%d: Cannot init without fep code\n",
-		    sc->res.unit);
-		return (EIO);
+	old_state = sc->status;
+	sc->status = DIGI_STATUS_STARTING;
+
+	/* Status now protects against unwanted re-entrancy
+	 * release mutex to load firmware */
+	mtx_unlock(&sc->dg_mutex);
+
+	/* Load required firmware image */
+	error = digi_loadmoduledata(sc, &dm, &lf);
+	if (error) {
+		mtx_lock(&sc->dg_mutex);
+		sc->status = old_state;
+		return (error);
 	}
-	sc->status = DIGI_STATUS_NOTINIT;
 
 	if (sc->numports) {
+		mtx_lock(&sc->dg_mutex);
 		/*
 		 * We're re-initialising - maybe because someone's attached
 		 * another port module.  For now, we just re-initialise
 		 * everything.
 		 */
-		if (digi_inuse(sc))
+		if (digi_inuse(sc)) {
+			linker_release_module(NULL, NULL, lf);
+			sc->status = old_state;
 			return (EBUSY);
+		}
 
 		digi_free_state(sc);
+		sc->status = DIGI_STATUS_STARTING;
+		mtx_unlock(&sc->dg_mutex);
+
 	}
 
-	ptr = sc->setwin(sc, MISCGLOBAL);
+	ptr = digi_setwin(sc, MISCGLOBAL);
 	for (i = 0; i < 16; i += 2)
 		vW(ptr + i) = 0;
 
+	error = EIO;		/* default error if initialisation fails */
+
 	switch (sc->model) {
+	default:
+		goto init_failed;
+
+#ifdef DIGI_ISA
 	case PCXEVE:
 		outb(sc->wport, 0xff);		/* window 7 */
 		ptr = sc->vmem + (BIOSCODE & 0x1fff);
 
-		if (!digi_bcopy(sc->bios.data, ptr, sc->bios.size)) {
+		if (!digi_bcopy(dm->dm_bios.data, ptr, dm->dm_bios.size)) {
 			device_printf(sc->dev, "BIOS upload failed\n");
-			return (EIO);
+			goto init_failed;
 		}
 
 		outb(sc->port, FEPCLR);
@@ -275,136 +306,143 @@
 
 	case PCXE:
 	case PCXI:
+#endif
+
 	case PCCX:
-		ptr = sc->setwin(sc, BIOSCODE + ((0xf000 - sc->mem_seg) << 4));
-		if (!digi_bcopy(sc->bios.data, ptr, sc->bios.size)) {
+		ptr = digi_setwin(sc, BIOSCODE + ((0xf000 - MEM_SEG(sc)) << 4));
+		if (!digi_bcopy(dm->dm_bios.data, ptr, dm->dm_bios.size)) {
 			device_printf(sc->dev, "BIOS upload failed\n");
-			return (EIO);
+			goto init_failed;
 		}
 		break;
 
 	case PCXEM:
 	case PCIEPCX:
 	case PCIXR:
-		if (sc->pcibus)
-			PCIPORT = FEPRST;
-		else
-			outb(sc->port, FEPRST | FEPMEM);
+		digi_outportmem(sc, FEPRST);
 
-		for (i = 0; ((sc->pcibus ? PCIPORT : inb(sc->port)) &
-		    FEPMASK) != FEPRST; i++) {
+		for (i = 0; (digi_inport(sc) & FEPMASK) != FEPRST; i++) {
 			if (i > hz) {
 				log(LOG_ERR, "digi%d: %s init reset failed\n",
 				    sc->res.unit, sc->name);
-				return (EIO);
+				goto init_failed;
 			}
 			digi_delay(sc, "digiinit0", 5);
 		}
-		DLOG(DIGIDB_INIT, (sc->dev, "Got init reset after %d us\n", i));
+		DLOG(DIGIDB_INIT, (sc->dev,
+			"Got init reset after %d iterations\n", i));
+
+		/* Clear POST area */
+		ptr = digi_setwin(sc, MISCGLOBAL);
+		for (i = 0; i < 16; i++)
+			*(uint8_t volatile *)(ptr + i) = 0;
 
 		/* Now upload the BIOS */
-		cnt = (sc->bios.size < sc->win_size - BIOSOFFSET) ?
-		    sc->bios.size : sc->win_size - BIOSOFFSET;
+		cnt = (dm->dm_bios.size < sc->win_size - BIOSOFFSET) ?
+		    dm->dm_bios.size : sc->win_size - BIOSOFFSET;
 
-		ptr = sc->setwin(sc, BIOSOFFSET);
-		if (!digi_bcopy(sc->bios.data, ptr, cnt)) {
+		ptr = digi_setwin(sc, BIOSOFFSET);
+		if (!digi_bcopy(dm->dm_bios.data, ptr, cnt)) {
 			device_printf(sc->dev, "BIOS upload (1) failed\n");
-			return (EIO);
+			goto init_failed;
 		}
 
-		if (cnt != sc->bios.size) {
+		if (cnt != dm->dm_bios.size) {
 			/* and the second part */
-			ptr = sc->setwin(sc, sc->win_size);
-			if (!digi_bcopy(sc->bios.data + cnt, ptr,
-			    sc->bios.size - cnt)) {
+			ptr = digi_setwin(sc, sc->win_size);
+			if (!digi_bcopy(dm->dm_bios.data + cnt, ptr,
+			    dm->dm_bios.size - cnt)) {
 				device_printf(sc->dev, "BIOS upload failed\n");
-				return (EIO);
+				goto init_failed;
 			}
 		}
 
-		ptr = sc->setwin(sc, 0);
-		vW(ptr + 0) = 0x0401;
-		vW(ptr + 2) = 0x0bf0;
-		vW(ptr + 4) = 0x0000;
-		vW(ptr + 6) = 0x0000;
+		ptr = digi_setwin(sc, 0);
+		vD(ptr + 0) = 0x0bf00401;
+		vD(ptr + 4) = 0x00000000;
 
 		break;
 	}
 
 	DLOG(DIGIDB_INIT, (sc->dev, "BIOS uploaded\n"));
 
-	ptr = sc->setwin(sc, MISCGLOBAL);
-	W(ptr) = 0;
+	ptr = digi_setwin(sc, MISCGLOBAL);
+	vW(ptr) = 0;
 
-	if (sc->pcibus) {
-		PCIPORT = FEPCLR;
-		resp = FEPRST;
-	} else if (sc->model == PCXEVE) {
-		outb(sc->port, FEPCLR);
+	digi_outportmem(sc, FEPRST);
+#ifdef DIGI_ISA
+	if (sc->pcibus || sc->model == PCXEVE) {
+		digi_outport(sc, FEPCLR);
 		resp = FEPRST;
 	} else {
 		outb(sc->port, FEPCLR | FEPMEM);
 		resp = FEPRST | FEPMEM;
 	}
-
-	for (i = 0; ((sc->pcibus ? PCIPORT : inb(sc->port)) & FEPMASK)
-	    == resp; i++) {
+#else
+	digi_outport(sc, FEPCLR);
+	resp = FEPRST;
+#endif
+	for (i = 0; (digi_inport(sc) & FEPMASK) == resp; i++) {
 		if (i > hz) {
 			log(LOG_ERR, "digi%d: BIOS start failed\n",
 			    sc->res.unit);
-			return (EIO);
+			goto init_failed;
 		}
 		digi_delay(sc, "digibios0", 5);
 	}
 
-	DLOG(DIGIDB_INIT, (sc->dev, "BIOS started after %d us\n", i));
+	DLOG(DIGIDB_INIT, (sc->dev, "BIOS started after %d iterations\n", i));
 
 	for (i = 0; vW(ptr) != *(u_short *)"GD"; i++) {
 		if (i > 5*hz) {
 			log(LOG_ERR, "digi%d: BIOS boot failed "
 			    "(0x%02x != 0x%02x)\n",
 			    sc->res.unit, vW(ptr), *(u_short *)"GD");
-			return (EIO);
+			goto init_failed;
 		}
 		digi_delay(sc, "digibios1", 5);
 	}
 
 	DLOG(DIGIDB_INIT, (sc->dev, "BIOS booted after %d iterations\n", i));
 
-	if (sc->link.data != NULL) {
+	if (dm->dm_link.data != NULL) {
 		DLOG(DIGIDB_INIT, (sc->dev, "Loading link data\n"));
-		ptr = sc->setwin(sc, 0xcd0);
-		digi_bcopy(sc->link.data, ptr, 21);	/* XXX 21 ? */
+		ptr = digi_setwin(sc, 0xcd0);
+		digi_bcopy(dm->dm_link.data, ptr, 21);	/* XXX 21 ? */
 	}
 
 	/* load FEP/OS */
 
 	switch (sc->model) {
+	default:
+		goto init_failed;
+
+#ifdef DIGI_ISA
 	case PCXE:
 	case PCXEVE:
 	case PCXI:
-		ptr = sc->setwin(sc, sc->model == PCXI ? 0x2000 : 0x0);
-		digi_bcopy(sc->fep.data, ptr, sc->fep.size);
+		ptr = digi_setwin(sc, sc->model == PCXI ? 0x2000 : 0x0);
+		digi_bcopy(dm->dm_fep.data, ptr, dm->dm_fep.size);
 
 		/* A BIOS request to move our data to 0x2000 */
-		ptr = sc->setwin(sc, MBOX);
+		ptr = digi_setwin(sc, MBOX);
 		vW(ptr + 0) = 2;
-		vW(ptr + 2) = sc->mem_seg + FEPCODESEG;
+		vW(ptr + 2) = MEM_SEG(sc) + FEPCODESEG;
 		vW(ptr + 4) = 0;
 		vW(ptr + 6) = FEPCODESEG;
 		vW(ptr + 8) = 0;
-		vW(ptr + 10) = sc->fep.size;
+		vW(ptr + 10) = dm->dm_fep.size;
 
 		/* Run the BIOS request */
 		outb(sc->port, FEPREQ | FEPMEM);
 		outb(sc->port, FEPCLR | FEPMEM);
 
-		for (i = 0; W(ptr); i++) {
+		for (i = 0; vW(ptr); i++) {
 			if (i > hz) {
 				log(LOG_ERR, "digi%d: FEP/OS move failed\n",
 				    sc->res.unit);
-				sc->hidewin(sc);
-				return (EIO);
+				digi_hidewin(sc);
+				goto init_failed;
 			}
 			digi_delay(sc, "digifep0", 5);
 		}
@@ -412,11 +450,11 @@
 		    (sc->dev, "FEP/OS moved after %d iterations\n", i));
 
 		/* Clear the confirm word */
-		ptr = sc->setwin(sc, FEPSTAT);
+		ptr = digi_setwin(sc, FEPSTAT);
 		vW(ptr + 0) = 0;
 
 		/* A BIOS request to execute the FEP/OS */
-		ptr = sc->setwin(sc, MBOX);
+		ptr = digi_setwin(sc, MBOX);
 		vW(ptr + 0) = 0x01;
 		vW(ptr + 2) = FEPCODESEG;
 		vW(ptr + 4) = 0x04;
@@ -425,71 +463,76 @@
 		outb(sc->port, FEPREQ);
 		outb(sc->port, FEPCLR);
 
-		ptr = sc->setwin(sc, FEPSTAT);
+		ptr = digi_setwin(sc, FEPSTAT);
 
 		break;
-
+#endif
 	case PCXEM:
 	case PCIEPCX:
 	case PCIXR:
 		DLOG(DIGIDB_INIT, (sc->dev, "Loading FEP/OS\n"));
 
-		cnt = (sc->fep.size < sc->win_size - BIOSOFFSET) ?
-		    sc->fep.size : sc->win_size - BIOSOFFSET;
+		cnt = (dm->dm_fep.size < sc->win_size - BIOSOFFSET) ?
+		    dm->dm_fep.size : sc->win_size - BIOSOFFSET;
 
-		ptr = sc->setwin(sc, BIOSOFFSET);
-		digi_bcopy(sc->fep.data, ptr, cnt);
+		ptr = digi_setwin(sc, BIOSOFFSET);
+		digi_bcopy(dm->dm_fep.data, ptr, cnt);
 
-		if (cnt != sc->fep.size) {
-			ptr = sc->setwin(sc, BIOSOFFSET + cnt);
-			digi_bcopy(sc->fep.data + cnt, ptr,
-			    sc->fep.size - cnt);
+		if (cnt != dm->dm_fep.size) {
+			ptr = digi_setwin(sc, BIOSOFFSET + cnt);
+			digi_bcopy(dm->dm_fep.data + cnt, ptr,
+			    dm->dm_fep.size - cnt);
 		}
 
 		DLOG(DIGIDB_INIT, (sc->dev, "FEP/OS loaded\n"));
 
-		ptr = sc->setwin(sc, 0xc30);
-		W(ptr + 4) = 0x1004;
-		W(ptr + 6) = 0xbfc0;
-		W(ptr + 0) = 0x03;
-		W(ptr + 2) = 0x00;
+		ptr = digi_setwin(sc, 0xc30);
+		vD(ptr + 4) = 0xbfc01004;
+		vD(ptr + 0) = 0x00000003;
 
 		/* Clear the confirm word */
-		ptr = sc->setwin(sc, FEPSTAT);
-		W(ptr + 0) = 0;
-
+		ptr = digi_setwin(sc, FEPSTAT);
+		vW(ptr + 0) = 0;
+#ifdef DIGI_ISA
 		if (sc->port)
 			outb(sc->port, 0);		/* XXX necessary ? */
-
+#endif
 		break;
 
+#ifdef NEEDS_PORTING
 	case PCCX:
-		ptr = sc->setwin(sc, 0xd000);
-		digi_bcopy(sc->fep.data, ptr, sc->fep.size);
+		ptr = digi_setwin(sc, 0xd000);
+		digi_bcopy(dm->dm_fep.data, ptr, dm->dm_fep.size);
 
 		/* A BIOS request to execute the FEP/OS */
-		ptr = sc->setwin(sc, 0xc40);
-		W(ptr + 0) = 1;
-		W(ptr + 2) = FEPCODE >> 4;
-		W(ptr + 4) = 4;
+		ptr = digi_setwin(sc, 0xc40);
+		vW(ptr + 0) = 1;
+		vW(ptr + 2) = FEPCODE >> 4;
+		vW(ptr + 4) = 4;
 
 		/* Clear the confirm word */
-		ptr = sc->setwin(sc, FEPSTAT);
-		W(ptr + 0) = 0;
+		ptr = digi_setwin(sc, FEPSTAT);
+		vW(ptr + 0) = 0;
 
 		/* Run the BIOS request */
 		outb(sc->port, FEPREQ | FEPMEM); /* send interrupt to BIOS */
 		outb(sc->port, FEPCLR | FEPMEM);
 		break;
+#endif
 	}
 
+	/* Release the firmware image */
+	i = linker_release_module(NULL, NULL, lf);
+	DLOG(DIGIDB_INIT, (sc->dev, "linker_release_module(%p)=%d\n", lf, i));
+
 	/* Now wait 'till the FEP/OS has booted */
 	for (i = 0; vW(ptr) != *(u_short *)"OS"; i++) {
 		if (i > 2*hz) {
 			log(LOG_ERR, "digi%d: FEP/OS start failed "
 			    "(0x%02x != 0x%02x)\n",
 			    sc->res.unit, vW(ptr), *(u_short *)"OS");
-			sc->hidewin(sc);
+			digi_hidewin(sc);
+			sc->status = DIGI_STATUS_NOTINIT;
 			return (EIO);
 		}
 		digi_delay(sc, "digifep1", 5);
@@ -498,34 +541,40 @@
 	DLOG(DIGIDB_INIT, (sc->dev, "FEP/OS started after %d iterations\n", i));
 
 	if (sc->model >= PCXEM) {
-		ptr = sc->setwin(sc, 0xe04);
-		vW(ptr) = 2;
-		ptr = sc->setwin(sc, 0xc02);
+		/* Interrupt configuration */
+		ptr = digi_setwin(sc, 0xe04);
+#ifdef DIGI_INTERRUPT
+		vW(ptr) = 1;	/* From dgap driver */
+#else
+		vW(ptr) = 2;	/* ???? */
+#endif
+		/* Read number of ports */
+		ptr = digi_setwin(sc, 0xc02);
 		sc->numports = vW(ptr);
 	} else {
-		ptr = sc->setwin(sc, 0xc22);
+		ptr = digi_setwin(sc, 0xc22);
 		sc->numports = vW(ptr);
 	}
 
+	device_printf(sc->dev, "%s, %d ports found\n", sc->name, sc->numports);
+
 	if (sc->numports == 0) {
-		device_printf(sc->dev, "%s, 0 ports found\n", sc->name);
-		sc->hidewin(sc);
+		digi_hidewin(sc);
+		sc->status = DIGI_STATUS_NOTINIT;
 		return (0);
 	}
 
-	device_printf(sc->dev, "%s, %d ports found\n", sc->name, sc->numports);
-
 	if (sc->ports)
-		free(sc->ports, M_TTYS);
+		free(sc->ports, M_DEVBUF);
 	sc->ports = malloc(sizeof(struct digi_p) * sc->numports,
-	    M_TTYS, M_WAITOK | M_ZERO);
+	    M_DEVBUF, M_WAITOK | M_ZERO);
 
 	/*
 	 * XXX Should read port 0xc90 for an array of 2byte values, 1 per
 	 * port.  If the value is 0, the port is broken....
 	 */
 
-	ptr = sc->setwin(sc, 0);
+	ptr = digi_setwin(sc, 0);
 
 	/* We should now init per-port structures */
 	bc = (volatile struct board_chan *)(ptr + CHANSTRUCT);
@@ -540,38 +589,31 @@
 		port->sc = sc;
 		port->status = ENABLED;
 		port->bc = bc;
-		tp = port->tp = ttyalloc();
-		tp->t_oproc = digistart;
-		tp->t_param = digiparam;
-		tp->t_modem = digimodem;
-		tp->t_break = digibreak;
-		tp->t_stop = digistop;
-		tp->t_cioctl = digisioctl;
-		tp->t_ioctl = digiioctl;
-		tp->t_open = digiopen;
-		tp->t_close = digiclose;
-		tp->t_sc = port;
+		/* Normally tty_alloc() is passed the softc but for digi, we
+		 * need to pass the digi_p associated with the current port */
+		tp = port->tp = tty_alloc(&digi_class, port);
+		cptr = (u_char *)(intptr_t)ptr;
 
 		if (sc->model == PCXEVE) {
-			port->txbuf = ptr +
-			    (((bc->tseg - sc->mem_seg) << 4) & 0x1fff);
-			port->rxbuf = ptr +
-			    (((bc->rseg - sc->mem_seg) << 4) & 0x1fff);
-			port->txwin = FEPWIN | ((bc->tseg - sc->mem_seg) >> 9);
-			port->rxwin = FEPWIN | ((bc->rseg - sc->mem_seg) >> 9);
+			port->txbuf = cptr +
+			    (((bc->tseg - MEM_SEG(sc)) << 4) & 0x1fff);
+			port->rxbuf = cptr +
+			    (((bc->rseg - MEM_SEG(sc)) << 4) & 0x1fff);
+			port->txwin = FEPWIN | ((bc->tseg - MEM_SEG(sc)) >> 9);
+			port->rxwin = FEPWIN | ((bc->rseg - MEM_SEG(sc)) >> 9);
 		} else if (sc->model == PCXI || sc->model == PCXE) {
-			port->txbuf = ptr + ((bc->tseg - sc->mem_seg) << 4);
-			port->rxbuf = ptr + ((bc->rseg - sc->mem_seg) << 4);
+			port->txbuf = cptr + ((bc->tseg - MEM_SEG(sc)) << 4);
+			port->rxbuf = cptr + ((bc->rseg - MEM_SEG(sc)) << 4);
 			port->txwin = port->rxwin = 0;
 		} else {
-			port->txbuf = ptr +
-			    (((bc->tseg - sc->mem_seg) << 4) % sc->win_size);
-			port->rxbuf = ptr +
-			    (((bc->rseg - sc->mem_seg) << 4) % sc->win_size);
+			port->txbuf = cptr +
+			    (((bc->tseg - MEM_SEG(sc)) << 4) % sc->win_size);
+			port->rxbuf = cptr +
+			    (((bc->rseg - MEM_SEG(sc)) << 4) % sc->win_size);
 			port->txwin = FEPWIN |
-			    (((bc->tseg - sc->mem_seg) << 4) / sc->win_size);
+			    (((bc->tseg - MEM_SEG(sc)) << 4) / sc->win_size);
 			port->rxwin = FEPWIN |
-			    (((bc->rseg - sc->mem_seg) << 4) / sc->win_size);
+			    (((bc->rseg - MEM_SEG(sc)) << 4) / sc->win_size);
 		}
 		port->txbufsize = bc->tmax + 1;
 		port->rxbufsize = bc->rmax + 1;
@@ -579,24 +621,31 @@
 		lowwater = port->txbufsize >> 2;
 		if (lowwater > 1024)
 			lowwater = 1024;
-		sc->setwin(sc, 0);
 		fepcmd_w(port, STXLWATER, lowwater, 10);
 		fepcmd_w(port, SRXLWATER, port->rxbufsize >> 2, 10);
 		fepcmd_w(port, SRXHWATER, (3 * port->rxbufsize) >> 2, 10);
 
-		bc->edelay = 100;
+		bc->edelay = 100;	/*XXX Use 0 if interrupts enabled */
+		bc->idata = 1;
 
-		ttyinitmode(tp, 0, 0);
 		port->send_ring = 1;	/* Default action on signal RI */
-		ttycreate(tp, TS_CALLOUT, "D%r%r", sc->res.unit, i);
+		tty_makedev(tp, NULL, "D%r%r", sc->res.unit, i);
 	}
 
-	sc->hidewin(sc);
-	sc->inttest = timeout(digi_int_test, sc, hz);
+	mtx_lock(&sc->dg_mutex);
+	digi_hidewin(sc);
+	callout_reset(&sc->callout, hz, digi_int_test, sc);
 	/* fepcmd_w(&sc->ports[0], 0xff, 0, 0); */
 	sc->status = DIGI_STATUS_ENABLED;
 
 	return (0);
+
+init_failed:
+	linker_release_module(NULL, NULL, lf);
+	mtx_lock(&sc->dg_mutex);
+	sc->status = DIGI_STATUS_NOTINIT;
+	return (error);
+
 }
 
 static int
@@ -606,24 +655,24 @@
 	struct digi_p *port;
 	int bitand, bitor, mstat;
 
-	port = tp->t_sc;
+	port = tty_softc(tp);
 	sc = port->sc;
 
 	if (sigon == 0 && sigoff == 0) {
-		port->sc->setwin(port->sc, 0);
+		digi_setwin(sc, 0);
 		mstat = port->bc->mstat;
-		port->sc->hidewin(port->sc);
-		if (mstat & port->sc->csigs->rts)
+		digi_hidewin(sc);
+		if (mstat & sc->csigs->rts)
 			sigon |= SER_RTS;
 		if (mstat & port->cd)
 			sigon |= SER_DCD;
 		if (mstat & port->dsr)
 			sigon |= SER_DSR;
-		if (mstat & port->sc->csigs->cts)
+		if (mstat & sc->csigs->cts)
 			sigon |= SER_CTS;
-		if (mstat & port->sc->csigs->ri)
+		if (mstat & sc->csigs->ri)
 			sigon |= SER_RI;
-		if (mstat & port->sc->csigs->dtr)
+		if (mstat & sc->csigs->dtr)
 			sigon |= SER_DTR;
 		return (sigon);
 	}
@@ -632,13 +681,13 @@
 	bitor = 0;
 
 	if (sigoff & SER_DTR)
-		bitand |= port->sc->csigs->dtr;
+		bitand |= sc->csigs->dtr;
 	if (sigoff & SER_RTS)
-		bitand |= port->sc->csigs->rts;
+		bitand |= sc->csigs->rts;
 	if (sigon & SER_DTR)
-		bitor |= port->sc->csigs->dtr;
+		bitor |= sc->csigs->dtr;
 	if (sigon & SER_RTS)
-		bitor |= port->sc->csigs->rts;
+		bitor |= sc->csigs->rts;
 	fepcmd_b(port, SETMODEM, bitor, ~bitand, 0);
 	return (0);
 }
@@ -649,26 +698,32 @@
 	struct digi_softc *sc;
 
 	sc = dev->si_drv1;
+	mtx_lock(&sc->dg_mutex);
 	if (sc->status != DIGI_STATUS_ENABLED) {
+		mtx_unlock(&sc->dg_mutex);
 		DLOG(DIGIDB_OPEN, (sc->dev, "Cannot open a disabled card\n"));
 		return (ENXIO);
 	}
 	sc->opencnt++;
+	mtx_unlock(&sc->dg_mutex);
 	return (0);
 }
 
 static int
-digiopen(struct tty *tp, struct cdev *dev)
+digiopen(struct tty *tp)
 {
-	int error;
 	struct digi_softc *sc;
 	struct digi_p *port;
 	volatile struct board_chan *bc;
 
-	port = tp->t_sc;
+	port = tty_softc(tp);
 	sc = port->sc;
 
+	/* device lock needed to protect against detach or reninit during open */
+	mtx_lock(&sc->dg_mutex);
+
 	if (sc->status != DIGI_STATUS_ENABLED) {
+		mtx_unlock(&sc->dg_mutex);
 		DLOG(DIGIDB_OPEN, (sc->dev, "Cannot open a disabled card\n"));
 		return (ENXIO);
 	}
@@ -680,13 +735,13 @@
 	 * cases: to preempt sleeping callin opens if we are callout,
 	 * and to complete a callin open after DCD rises.
 	 */
-	sc->setwin(sc, 0);
+	digi_setwin(sc, 0);
 
 	bc->rout = bc->rin;	/* clear input queue */
 	bc->idata = 1;
 	bc->iempty = 1;
 	bc->ilow = 1;
-	bc->mint = port->cd | port->sc->csigs->ri;
+	bc->mint = port->cd | sc->csigs->ri;  /*XXX cf m_int on dgap */
 	bc->tin = bc->tout;
 	if (port->ialtpin) {
 		port->cd = sc->csigs->dsr;
@@ -695,11 +750,11 @@
 		port->cd = sc->csigs->cd;
 		port->dsr = sc->csigs->dsr;
 	}
-	tp->t_wopeners++;			/* XXX required ? */
-	error = digiparam(tp, &tp->t_termios);
-	tp->t_wopeners--;
 
-	return (error);
+	port->status |= DG_OPENED;
+	mtx_unlock(&sc->dg_mutex);
+
+	return (0);
 }
 
 static int
@@ -708,93 +763,69 @@
 	struct digi_softc *sc;
 
 	sc = dev->si_drv1;
+	/*XXX Is the mutex really needed here */
+	mtx_lock(&sc->dg_mutex);
 	sc->opencnt--;
+	mtx_unlock(&sc->dg_mutex);
 	return (0);
 }
 
 static void
-digidtrwakeup(void *chan)
-{
-	struct digi_p *port = chan;
-
-	port->status &= ~DIGI_DTR_OFF;
-	wakeup(&port->tp->t_dtr_wait);
-	port->tp->t_wopeners--;
-}
-
-static void
 digiclose(struct tty *tp)
 {
 	volatile struct board_chan *bc;
 	struct digi_p *port;
-	int s;
 
-	port = tp->t_sc;
+	port = tty_softc(tp);
 	bc = port->bc;
 
-	s = spltty();
-	port->sc->setwin(port->sc, 0);
+	digi_setwin(port->sc, 0);
 	bc->idata = 0;
 	bc->iempty = 0;
 	bc->ilow = 0;
 	bc->mint = 0;
-	if ((tp->t_cflag & HUPCL) ||
-	    (!tp->t_actout && !(bc->mstat & port->cd) &&
-	    !(tp->t_init_in.c_cflag & CLOCAL)) ||
-	    !(tp->t_state & TS_ISOPEN)) {
+	if (port->p_hupcl ||
+//XXXXX	    (!tp->t_actout && !(bc->mstat & port->cd) && !port->p_clocal) ||
+	    !tty_opened(tp)) {
 		digimodem(tp, 0, SER_DTR | SER_RTS);
-		if (tp->t_dtr_wait != 0) {
-			/* Schedule a wakeup of any callin devices */
-			tp->t_wopeners++;
-			timeout(&digidtrwakeup, port, tp->t_dtr_wait);
-			port->status |= DIGI_DTR_OFF;
-		}
 	}
-	tp->t_actout = FALSE;
-	wakeup(&tp->t_actout);
-	wakeup(TSA_CARR_ON(tp));
-	splx(s);
+	port->status &= ~DG_OPENED;
 }
 
 /*
  * Load module "digi_<mod>.ko" and look for a symbol called digi_mod_<mod>.
  *
- * Populate sc->bios, sc->fep, and sc->link from this data.
- *
- * sc->fep.data, sc->bios.data and sc->link.data are malloc()d according
- * to their respective sizes.
- *
- * The module is unloaded when we're done.
+ * Returns 0 if no error - in which case, the pointer to the digi_mod
+ * structure has been initialised and the linker file must be freed by
+ * the caller.
  */
 static int
-digi_loadmoduledata(struct digi_softc *sc)
+digi_loadmoduledata(struct digi_softc *sc, struct digi_mod **mod, linker_file_t *lfp)
 {
 	struct digi_mod *digi_mod;
 	linker_file_t lf;
-	char *modfile, *sym;
+	char *name;
 	caddr_t symptr;
 	int modlen, res;
 
-	KASSERT(sc->bios.data == NULL, ("Uninitialised BIOS variable"));
-	KASSERT(sc->fep.data == NULL, ("Uninitialised FEP variable"));
-	KASSERT(sc->link.data == NULL, ("Uninitialised LINK variable"));
 	KASSERT(sc->module != NULL, ("Uninitialised module name"));
 
 	modlen = strlen(sc->module);
-	modfile = malloc(modlen + 6, M_TEMP, M_WAITOK);
-	snprintf(modfile, modlen + 6, "digi_%s", sc->module);
-	if ((res = linker_reference_module(modfile, NULL, &lf)) != 0)
-		printf("%s: Failed %d to autoload module\n", modfile, res);
-	free(modfile, M_TEMP);
-	if (res != 0)
+	name = malloc(modlen + 10, M_TEMP, M_WAITOK);
+
+	snprintf(name, modlen + 10, "digi_%s", sc->module);
+	if ((res = linker_reference_module(name, NULL, &lf)) != 0)
+		printf("%s: Failed %d to autoload module\n", name, res);
+	if (res != 0) {
+		free(name, M_TEMP);
 		return (res);
+	}
 
-	sym = malloc(modlen + 10, M_TEMP, M_WAITOK);
-	snprintf(sym, modlen + 10, "digi_mod_%s", sc->module);
-	symptr = linker_file_lookup_symbol(lf, sym, 0);
-	free(sym, M_TEMP);
+	snprintf(name, modlen + 10, "digi_mod_%s", sc->module);
+	symptr = linker_file_lookup_symbol(lf, name, 0);
+	free(name, M_TEMP);
 	if (symptr == NULL) {
-		printf("digi_%s.ko: Symbol `%s' not found\n", sc->module, sym);
+		printf("digi_%s.ko: Symbol `%s' not found\n", sc->module, name);
 		linker_release_module(NULL, NULL, lf);
 		return (EINVAL);
 	}
@@ -807,56 +838,39 @@
 		return (EINVAL);
 	}
 
-	sc->bios.size = digi_mod->dm_bios.size;
-	if (sc->bios.size != 0 && digi_mod->dm_bios.data != NULL) {
-		sc->bios.data = malloc(sc->bios.size, M_TTYS, M_WAITOK);
-		bcopy(digi_mod->dm_bios.data, sc->bios.data, sc->bios.size);
-	}
-
-	sc->fep.size = digi_mod->dm_fep.size;
-	if (sc->fep.size != 0 && digi_mod->dm_fep.data != NULL) {
-		sc->fep.data = malloc(sc->fep.size, M_TTYS, M_WAITOK);
-		bcopy(digi_mod->dm_fep.data, sc->fep.data, sc->fep.size);
-	}
-
-	sc->link.size = digi_mod->dm_link.size;
-	if (sc->link.size != 0 && digi_mod->dm_link.data != NULL) {
-		sc->link.data = malloc(sc->link.size, M_TTYS, M_WAITOK);
-		bcopy(digi_mod->dm_link.data, sc->link.data, sc->link.size);
-	}
-
-	linker_release_module(NULL, NULL, lf);
+	*mod = digi_mod;
+	*lfp = lf;
 
 	return (0);
 }
 
 static int
-digisioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
+digisioctl(struct tty *tp, int unit, u_long cmd, caddr_t data, struct thread *td)
 {
 	struct digi_p *port;
 	struct digi_softc *sc;
 
-	port = dev->si_drv1;
+	port = tty_softc(tp);
 	sc = port->sc;
 
 	switch (cmd) {
 	case DIGIIO_GETALTPIN:
-		if (ISINIT(dev))
+	    if (unit & TTYUNIT_INIT)
 			*(int *)data = port->ialtpin;
-		else if (ISLOCK(dev))
+		else if (unit & TTYUNIT_LOCK)
 			*(int *)data = port->laltpin;
 		else
 			return (ENOTTY);
 		break;
 	case DIGIIO_SETALTPIN:
-		if (ISINIT(dev)) {
+		if (unit & TTYUNIT_INIT) {
 			if (!port->laltpin) {
 				port->ialtpin = !!*(int *)data;
 				DLOG(DIGIDB_SET, (sc->dev,
 				    "port%d: initial ALTPIN %s\n", port->pnum,
 				    port->ialtpin ? "set" : "cleared"));
 			}
-		} else if (ISLOCK(dev)) {
+		} else if (unit & TTYUNIT_LOCK) {
 			port->laltpin = !!*(int *)data;
 			DLOG(DIGIDB_SET, (sc->dev,
 			    "port%d: ALTPIN %slocked\n",
@@ -865,7 +879,7 @@
 			return (ENOTTY);
 		break;
 	default:
-		return (ENOTTY);
+		return (ENOIOCTL);
 	}
 	return (0);
 }
@@ -877,39 +891,52 @@
 	struct digi_softc *sc;
 
 	sc = dev->si_drv1;
+	mtx_lock(&sc->dg_mutex);
 
-	if (sc->status == DIGI_STATUS_DISABLED)
+	if (sc->status == DIGI_STATUS_DISABLED ||
+	    sc->status == DIGI_STATUS_STARTING) {
+		mtx_unlock(&sc->dg_mutex);
 		return (ENXIO);
+	}
 
+	error = 0;
 	switch (cmd) {
 	case DIGIIO_DEBUG:
 #ifdef DEBUG
 		digi_debug = *(int *)data;
-		return (0);
 #else
 		device_printf(sc->dev, "DEBUG not defined\n");
-		return (ENXIO);
+		error = ENXIO;
 #endif
+		break;
+
 	case DIGIIO_REINIT:
-		digi_loadmoduledata(sc);
+		/* don't count this open for "in-use" checks */
+		sc->opencnt--;
 		error = digi_init(sc);
-		digi_freemoduledata(sc);
-		return (error);
+		sc->opencnt++;
+		break;
 
 	case DIGIIO_MODEL:
 		*(enum digi_model *)data = sc->model;
-		return (0);
+		break;
 
 	case DIGIIO_IDENT:
-		return (copyout(sc->name, *(char **)data,
-		    strlen(sc->name) + 1));
+		error = copyout(sc->name, *(char **)data,
+		    strlen(sc->name) + 1);
+		break;
+
 	default:
-		return (ENOIOCTL);
+		error = ENOIOCTL;
+		break;
 	}
+
+	mtx_unlock(&sc->dg_mutex);
+	return (error);
 }
 
 static int
-digiioctl(struct tty *tp, u_long cmd, void *data, int flag, struct thread *td)
+digiioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
 {
 	struct digi_softc *sc;
 	struct digi_p *port;
@@ -918,9 +945,9 @@
 	int ival;
 #endif
 
-	port = tp->t_sc;
+	port = tty_softc(tp);
 	sc = port->sc;
-	if (sc->status == DIGI_STATUS_DISABLED)
+	if (sc->status != DIGI_STATUS_ENABLED)
 		return (ENXIO);
 
 	if (!(port->status & ENABLED))
@@ -950,31 +977,30 @@
     defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
 	case _IO('e', 'C'):
 		ival = IOCPARM_IVAL(data);
-		data = &ival;
+		data = (caddr_t)&ival;
 		/* FALLTHROUGH */
 #endif
 	case DIGIIO_RING:
 		port->send_ring = (u_char)*(int *)data;
 		break;
-	default:
-		return (ENOTTY);
-	}
-	return (0);
-}
-
-static void
-digibreak(struct tty *tp, int brk)
-{
-	struct digi_p *port;
 
-	port = tp->t_sc;
+	case TIOCCBRK:
+	    	/* There's no support for turning break state on/off
+		 * arbitrarily so TIOCCBRK is a no-op and TIOCSBRK sends
+		 * a fixed 400msec break */
+		break;
 
-	/*
-	 * now it sends 400 millisecond break because I don't know
-	 * how to send an infinite break
-	 */
-	if (brk)
+	case TIOCSBRK:
+	    	/* There's no support for turning break state on/off
+		 * arbitrarily so TIOCCBRK is a no-op and TIOCSBRK sends
+		 * a fixed 400msec break */
 		fepcmd_w(port, SENDBREAK, 400, 10);
+		break;
+
+	default:
+		return (ENOIOCTL);
+	}
+	return (0);
 }
 
 static int
@@ -986,25 +1012,30 @@
 	int iflag;
 	int hflow;
 	int s;
+#ifdef DIGI_ISA
 	int window;
+#endif
 
-	port = tp->t_sc;
+	port = tty_softc(tp);
 	sc = port->sc;
 	DLOG(DIGIDB_SET, (sc->dev, "port%d: setting parameters\n", port->pnum));
 
 	if (t->c_ispeed == 0)
 		t->c_ispeed = t->c_ospeed;
 
-	cflag = ttspeedtab(t->c_ospeed, digispeedtab);
+	/* Map actual baudrate to baudrate code */
+	for (s = 0; digispeedtab[s].sp_speed >= 0; s++)
+		if (digispeedtab[s].sp_speed == t->c_ospeed)
+			break;
+	cflag = digispeedtab[s].sp_code;
 
 	if (cflag < 0 || (cflag > 0 && t->c_ispeed != t->c_ospeed))
 		return (EINVAL);
 
-	s = splclock();
-
+#ifdef DIGI_ISA
 	window = sc->window;
-	sc->setwin(sc, 0);
-
+	digi_setwin(sc, 0);
+#endif
 	if (cflag == 0) {				/* hangup */
 		DLOG(DIGIDB_SET, (sc->dev, "port%d: hangup\n", port->pnum));
 		digimodem(port->tp, 0, SER_DTR | SER_RTS);
@@ -1014,15 +1045,6 @@
 		DLOG(DIGIDB_SET, (sc->dev, "port%d: CBAUD = %d\n", port->pnum,
 		    cflag));
 
-#if 0
-		/* convert flags to sysV-style values */
-		if (t->c_cflag & PARODD)
-			cflag |= 0x0200;
-		if (t->c_cflag & PARENB)
-			cflag |= 0x0100;
-		if (t->c_cflag & CSTOPB)
-			cflag |= 0x0080;
-#else
 		/* convert flags to sysV-style values */
 		if (t->c_cflag & PARODD)
 			cflag |= FEP_PARODD;
@@ -1032,7 +1054,6 @@
 			cflag |= FEP_CSTOPB;
 		if (t->c_cflag & CLOCAL)
 			cflag |= FEP_CLOCAL;
-#endif
 
 		cflag |= (t->c_cflag & CSIZE) >> 4;
 		DLOG(DIGIDB_SET, (sc->dev, "port%d: CFLAG = 0x%x\n", port->pnum,
@@ -1042,11 +1063,11 @@
 
 	iflag =
 	    t->c_iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP);
-	if (port->c_iflag & IXON)
+	if (t->c_iflag & IXON)
 		iflag |= 0x400;
-	if (port->c_iflag & IXANY)
+	if (t->c_iflag & IXANY)
 		iflag |= 0x800;
-	if (port->c_iflag & IXOFF)
+	if (t->c_iflag & IXOFF)
 		iflag |= 0x1000;
 
 	DLOG(DIGIDB_SET, (sc->dev, "port%d: set iflag = 0x%x\n", port->pnum, iflag));
@@ -1071,27 +1092,39 @@
 	    port->pnum, t->c_cc[VSTART], t->c_cc[VSTOP]));
 	fepcmd_b(port, SONOFFC, t->c_cc[VSTART], t->c_cc[VSTOP], 0);
 
+#ifdef DIGI_ISA
 	if (sc->window != 0)
-		sc->towin(sc, 0);
+		digi_towin(sc, 0);
 	if (window != 0)
-		sc->towin(sc, window);
-	splx(s);
+		digi_towin(sc, window);
+#endif
+
+	/* save relevant bits for later */
+	port->p_hupcl = !!(t->c_cflag & HUPCL);
+	/* Want 'initial' value for CLOCAL so only set if device closed */
+	if (!tty_opened(tp))
+	    port->p_clocal = !!(t->c_cflag & CLOCAL);
 
 	return (0);
 }
 
-static void
+void
 digi_intr(void *vp)
 {
 	struct digi_p *port;
-	char *cxcon;
 	struct digi_softc *sc;
 	int ehead, etail;
 	volatile struct board_chan *bc;
 	struct tty *tp;
 	int head, tail;
 	int wrapmask;
-	int size, window;
+#ifdef DIGI_INTERRUPT
+	int islocked;
+#endif
+#ifdef DIGI_ISA
+	int window;
+#endif
+	size_t	size;
 	struct event {
 		u_char pnum;
 		u_char event;
@@ -1101,58 +1134,39 @@
 
 	sc = vp;
 
+#ifdef DIGI_INTERRUPT
+	/* When called from an interrupt, mutex isn't owned on entry */
+	islocked = mtx_owned(&sc->dg_mutex);
+	if (!islocked)
+		mtx_lock(&sc->dg_mutex);
+#endif
+
 	if (sc->status != DIGI_STATUS_ENABLED) {
 		DLOG(DIGIDB_IRQ, (sc->dev, "interrupt on disabled board !\n"));
+#ifdef DIGI_INTERRUPT
+		if (!islocked)
+			mtx_unlock(&sc->dg_mutex);
+#endif
 		return;
 	}
 
 #ifdef DIGI_INTERRUPT
-	microtime(&sc->intr_timestamp);
+	sc->interrupt_seen = 1;
 #endif
 
+#ifdef DIGI_ISA
 	window = sc->window;
-	sc->setwin(sc, 0);
+	digi_setwin(sc, 0);
+#endif
 
-	if (sc->model >= PCXEM && W(sc->vmem + 0xd00)) {
-		struct con_bios *con = con_bios_list;
-		register u_char *ptr;
-
-		ptr = sc->vmem + W(sc->vmem + 0xd00);
-		while (con) {
-			if (ptr[1] && W(ptr + 2) == W(con->bios + 2))
-				/* Not first block -- exact match */
-				break;
-
-			if (W(ptr + 4) >= W(con->bios + 4) &&
-			    W(ptr + 4) <= W(con->bios + 6))
-				/* Initial search concetrator BIOS */
-				break;
-		}
-
-		if (con == NULL) {
-			log(LOG_ERR, "digi%d: wanted bios LREV = 0x%04x"
-			    " not found!\n", sc->res.unit, W(ptr + 4));
-			W(ptr + 10) = 0;
-			W(sc->vmem + 0xd00) = 0;
-			goto eoi;
-		}
-		cxcon = con->bios;
-		W(ptr + 4) = W(cxcon + 4);
-		W(ptr + 6) = W(cxcon + 6);
-		if (ptr[1] == 0)
-			W(ptr + 2) = W(cxcon + 2);
-		W(ptr + 8) = (ptr[1] << 6) + W(cxcon + 8);
-		size = W(cxcon + 10) - (ptr[1] << 10);
-		if (size <= 0) {
-			W(ptr + 8) = W(cxcon + 8);
-			W(ptr + 10) = 0;
-		} else {
-			if (size > 1024)
-				size = 1024;
-			W(ptr + 10) = size;
-			bcopy(cxcon + (ptr[1] << 10), ptr + 12, size);
-		}
-		W(sc->vmem + 0xd00) = 0;
+	if (sc->model >= PCXEM && vW(sc->vmem + 0xd00)) {
+		register u_char volatile *ptr;
+
+		ptr = sc->vmem + vW(sc->vmem + 0xd00);
+		log(LOG_ERR, "digi%d: wanted bios LREV = 0x%04x"
+		    " not found!\n", sc->res.unit, vW(ptr + 4));
+		vW(ptr + 10) = 0;
+		vW(sc->vmem + 0xd00) = 0;
 		goto eoi;
 	}
 
@@ -1172,7 +1186,7 @@
 	while (ehead != etail) {
 		event = *(volatile struct event *)(sc->memevent + etail);
 
-		etail = (etail + 4) & sc->gdata->imax;
+		sc->gdata->eout = (etail + 4) & sc->gdata->imax;
 
 		if (event.pnum >= sc->numports) {
 			log(LOG_ERR, "digi%d: port %d: got event"
@@ -1184,7 +1198,12 @@
 		bc = port->bc;
 		tp = port->tp;
 
-		if (!(tp->t_state & TS_ISOPEN) && !tp->t_wopeners) {
+		/* Accessing the TTY subsystem requires the relevant port
+		 * mutex to be owned.  To prevent lock reversal, release
+		 * the board lock */
+		mtx_unlock(&sc->dg_mutex);
+		tty_lock(tp);
+		if (!tty_opened(tp) && !(port->status & DG_OPENED)) {
 			DLOG(DIGIDB_IRQ, (sc->dev,
 			    "port %d: event 0x%x on closed port\n",
 			    event.pnum, event.event));
@@ -1193,7 +1212,7 @@
 			bc->iempty = 0;
 			bc->ilow = 0;
 			bc->mint = 0;
-			continue;
+			goto end_of_event;
 		}
 		if (event.event & ~ALL_IND)
 			log(LOG_ERR, "digi%d: port%d: ? event 0x%x mstat 0x%x"
@@ -1208,7 +1227,7 @@
 			tail = bc->rout;
 
 			size = 0;
-			if (!(tp->t_state & TS_ISOPEN)) {
+			if (!tty_opened(tp)) {
 				bc->rout = head;
 				goto end_of_data;
 			}
@@ -1219,23 +1238,21 @@
 				    "port %d: p rx head = %d tail = %d\n",
 				    event.pnum, head, tail));
 				top = (head > tail) ? head : wrapmask + 1;
-				sc->towin(sc, port->rxwin);
 				size = top - tail;
-				if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
-					size = b_to_q((char *)port->rxbuf +
-					    tail, size, &tp->t_rawq);
+				if (ttydisc_can_bypass(tp)) {
+					size -= ttydisc_rint_bypass(tp,
+						port->rxbuf + tail, size);
 					tail = top - size;
-					ttwakeup(tp);
 				} else for (; tail < top;) {
-					ttyld_rint(tp, port->rxbuf[tail]);
-					sc->towin(sc, port->rxwin);
+					digi_towin(sc, port->rxwin);
+					if (ttydisc_rint(tp, port->rxbuf[tail],
+						0) != 0)
+						break;
 					size--;
 					tail++;
-					if (tp->t_state & TS_TBLOCK)
-						break;
 				}
 				tail &= wrapmask;
-				sc->setwin(sc, 0);
+				digi_setwin(sc, 0);
 				bc->rout = tail;
 				head = bc->rin;
 				if (size)
@@ -1243,15 +1260,14 @@
 			}
 
 			if (bc->orun) {
-				CE_RECORD(port, CE_OVERRUN);
 				log(LOG_ERR, "digi%d: port%d: %s\n",
 				    sc->res.unit, event.pnum,
 				    digi_errortxt(CE_OVERRUN));
+				ttydisc_rint(tp, 0, TRE_OVERRUN);
 				bc->orun = 0;
 			}
 end_of_data:
 			if (size) {
-				tp->t_state |= TS_TBLOCK;
 				port->status |= PAUSE_RX;
 				DLOG(DIGIDB_RX, (sc->dev, "port %d: pause RX\n",
 				    event.pnum));
@@ -1265,94 +1281,99 @@
 			    event.pnum));
 
 			if ((event.mstat ^ event.lstat) & port->cd) {
-				sc->hidewin(sc);
-				ttyld_modem(tp, event.mstat & port->cd);
-				sc->setwin(sc, 0);
-				wakeup(TSA_CARR_ON(tp));
+				digi_hidewin(sc);
+				ttydisc_modem(tp, event.mstat & port->cd);
+				digi_setwin(sc, 0);
 			}
 
 			if (event.mstat & sc->csigs->ri) {
 				DLOG(DIGIDB_RI, (sc->dev, "port %d: RING\n",
 				    event.pnum));
 				if (port->send_ring) {
-					ttyld_rint(tp, 'R');
-					ttyld_rint(tp, 'I');
-					ttyld_rint(tp, 'N');
-					ttyld_rint(tp, 'G');
-					ttyld_rint(tp, '\r');
-					ttyld_rint(tp, '\n');
+					/* Cheat a bit here - there shouldn't
+					 * be any data in the kernel buffers
+					 * and correctly supporting overflow
+					 * control would be painful */
+					ttydisc_rint(tp, 'R', 0);
+					ttydisc_rint(tp, 'I', 0);
+					ttydisc_rint(tp, 'N', 0);
+					ttydisc_rint(tp, 'G', 0);
+					ttydisc_rint(tp, '\r', 0);
+					ttydisc_rint(tp, '\n', 0);
 				}
 			}
 		}
 		if (event.event & BREAK_IND) {
 			DLOG(DIGIDB_MODEM, (sc->dev, "port %d: BREAK_IND\n",
 			    event.pnum));
-			ttyld_rint(tp, TTY_BI);
+			ttydisc_rint(tp, 0, TRE_BREAK);
 		}
 		if (event.event & (LOWTX_IND | EMPTYTX_IND)) {
 			DLOG(DIGIDB_IRQ, (sc->dev, "port %d:%s%s\n",
 			    event.pnum,
 			    event.event & LOWTX_IND ? " LOWTX" : "",
 			    event.event & EMPTYTX_IND ?  " EMPTYTX" : ""));
-			ttyld_start(tp);
+			digioutwakeup(tp);
 		}
+		ttydisc_rint_done(tp);
+end_of_event:
+		tty_unlock(tp);
+		mtx_lock(&sc->dg_mutex);
+		/* Check the device is still there and reload ring pointers */
+		if (sc->status != DIGI_STATUS_ENABLED) {
+#ifdef DIGI_INTERRUPT
+			if (!islocked)
+				mtx_unlock(&sc->dg_mutex);
+#endif
+			return;
+		}
+		ehead = sc->gdata->ein;
+		etail = sc->gdata->eout;
 	}
-	sc->gdata->eout = etail;
 eoi:
-	if (sc->window != 0)
-		sc->towin(sc, 0);
-	if (window != 0)
-		sc->towin(sc, window);
+	/* Ack any interrupt */
+#ifdef DIGI_ISA
+	if (sc->pcibus)
+#endif
+		(void)sc->vmem[0x200002];
+
+#ifdef DIGI_ISA
+	digi_towin(sc, window);
+#endif
+#ifdef DIGI_INTERRUPT
+	if (!islocked)
+		mtx_unlock(&sc->dg_mutex);
+#endif
 }
 
 static void
-digistart(struct tty *tp)
+digioutwakeup(struct tty *tp)
 {
 	struct digi_p *port;
 	struct digi_softc *sc;
 	volatile struct board_chan *bc;
 	int head, tail;
 	int size, ocount, totcnt = 0;
-	int s;
 	int wmask;
 
-	port = tp->t_sc;
+	port = tty_softc(tp);
 	sc = port->sc;
 	bc = port->bc;
 
 	wmask = port->txbufsize - 1;
 
-	s = spltty();
-	port->lcc = tp->t_outq.c_cc;
-	sc->setwin(sc, 0);
-	if (!(tp->t_state & TS_TBLOCK)) {
-		if (port->status & PAUSE_RX) {
-			DLOG(DIGIDB_RX, (sc->dev, "port %d: resume RX\n",
-			    port->pnum));
-			/*
-			 * CAREFUL - braces are needed here if the DLOG is
-			 * optimised out!
-			 */
-		}
-		port->status &= ~PAUSE_RX;
-		bc->idata = 1;
-	}
-	if (!(tp->t_state & TS_TTSTOP) && port->status & PAUSE_TX) {
+	digi_setwin(sc, 0);
+	if (port->status & PAUSE_TX) {
 		DLOG(DIGIDB_TX, (sc->dev, "port %d: resume TX\n", port->pnum));
 		port->status &= ~PAUSE_TX;
 		fepcmd_w(port, RESUMETX, 0, 10);
 	}
-	if (tp->t_outq.c_cc == 0)
-		tp->t_state &= ~TS_BUSY;
-	else
-		tp->t_state |= TS_BUSY;
 
 	head = bc->tin;
-	while (tp->t_outq.c_cc != 0) {
+	do {
 		tail = bc->tout;
 		DLOG(DIGIDB_INT, (sc->dev, "port%d: s tx head = %d tail = %d\n",
 		    port->pnum, head, tail));
-
 		if (head < tail)
 			size = tail - head - 1;
 		else {
@@ -1363,73 +1384,117 @@
 
 		if (size == 0)
 			break;
-		sc->towin(sc, port->txwin);
-		ocount = q_to_b(&tp->t_outq, port->txbuf + head, size);
+		digi_towin(sc, port->txwin);
+		ocount = ttydisc_getc(tp, port->txbuf + head, size);
+		if (ocount == 0)
+			break;
 		totcnt += ocount;
 		head += ocount;
 		head &= wmask;
-		sc->setwin(sc, 0);
+		digi_setwin(sc, 0);
 		bc->tin = head;
 		bc->iempty = 1;
 		bc->ilow = 1;
-	}
-	port->lostcc = tp->t_outq.c_cc;
-	tail = bc->tout;
-	if (head < tail)
-		size = port->txbufsize - tail + head;
-	else
-		size = head - tail;
+	} while (1);
 
-	port->lbuf = size;
-	DLOG(DIGIDB_INT, (sc->dev, "port%d: s total cnt = %d\n", port->pnum, totcnt));
-	ttwwakeup(tp);
-	splx(s);
+	DLOG(DIGIDB_INT, (sc->dev, "port%d: s total cnt = %d\n", port->pnum,
+			  totcnt));
 }
 
+/* Invoked when the TTY subsystem can accept more input from the device */
 static void
-digistop(struct tty *tp, int rw)
+digiinwakeup(struct tty *tp)
+{
+	struct digi_p *port;
+	volatile struct board_chan *bc;
+#ifdef DEBUG
+	struct digi_softc *sc;
+#endif
+
+	port = tty_softc(tp);
+	bc = port->bc;
+#ifdef DEBUG
+	sc = port->sc;
+#endif
+
+	if (port->status & PAUSE_RX) {
+		DLOG(DIGIDB_RX, (sc->dev, "port %d: resume RX\n", port->pnum));
+		port->status &= ~PAUSE_RX;
+	}
+	bc->idata = 1;
+}
+
+static void
+diginotify(struct tty *tp, char event)
 {
 	struct digi_softc *sc;
 	struct digi_p *port;
+	volatile struct board_chan *bc;
 
-	port = tp->t_sc;
+	port = tty_softc(tp);
 	sc = port->sc;
+	bc = port->bc;
 
-	DLOG(DIGIDB_TX, (sc->dev, "port %d: pause TX\n", port->pnum));
-	port->status |= PAUSE_TX;
-	fepcmd_w(port, PAUSETX, 0, 10);
+	DLOG(DIGIDB_TX, (sc->dev, "port %d: event %d\n", port->pnum, event));
+	switch (event) {
+	case TIOCPKT_FLUSHREAD:		/* flush Rx queue */
+		bc->rout = bc->rin;	/* clear input queue */
+		bc->orun = 0;		/* clear overrun */
+		break;
+	case TIOCPKT_FLUSHWRITE:	/* flush Tx queue */
+		fepcmd_w(port, STPTR, bc->tin, 10);
+		port->status &= ~PAUSE_TX;
+		fepcmd_w(port, RESUMETX, 0, 10);
+		break;
+	case TIOCPKT_STOP:		/* stop output */
+		port->status |= PAUSE_TX;
+		fepcmd_w(port, PAUSETX, 0, 10);
+		break;
+	case TIOCPKT_START:		/* start output */
+		port->status &= ~PAUSE_TX;
+		fepcmd_w(port, RESUMETX, 0, 10);
+		break;
+	}
 }
 
 static void
 fepcmd(struct digi_p *port, int cmd, int op1, int ncmds)
 {
-	u_char *mem;
+	u_char volatile *mem;
+	struct digi_softc *sc;
 	unsigned tail, head;
 	int count, n;
+	int islocked;
 
-	mem = port->sc->memcmd;
+	sc = port->sc;
+	islocked = mtx_owned(&sc->dg_mutex);
+	if (!islocked)
+		mtx_lock(&sc->dg_mutex);
+	mem = sc->memcmd;
 
-	port->sc->setwin(port->sc, 0);
+	digi_setwin(sc, 0);
 
-	head = port->sc->gdata->cin;
+	head = sc->gdata->cin;
 	mem[head + 0] = cmd;
 	mem[head + 1] = port->pnum;
-	*(u_short *)(mem + head + 2) = op1;
+	*(u_short volatile *)(mem + head + 2) = op1;
 
-	head = (head + 4) & port->sc->gdata->cmax;
-	port->sc->gdata->cin = head;
+	head = (head + 4) & sc->gdata->cmax;
+	sc->gdata->cin = head;
 
 	for (count = FEPTIMEOUT; count > 0; count--) {
-		head = port->sc->gdata->cin;
-		tail = port->sc->gdata->cout;
-		n = (head - tail) & port->sc->gdata->cmax;
+		head = sc->gdata->cin;
+		tail = sc->gdata->cout;
+		n = (head - tail) & sc->gdata->cmax;
 
 		if (n <= ncmds * sizeof(short) * 4)
 			break;
 	}
+	if (!islocked)
+		mtx_unlock(&sc->dg_mutex);
 	if (count == 0)
 		log(LOG_ERR, "digi%d: port%d: timeout on FEP command\n",
-		    port->sc->res.unit, port->pnum);
+		    sc->res.unit, port->pnum);
 }
 
 const char *
@@ -1450,16 +1515,19 @@
 int
 digi_attach(struct digi_softc *sc)
 {
+	int error;
+
 	sc->res.ctldev = make_dev(&digi_csw,
 	    sc->res.unit << 16, UID_ROOT, GID_WHEEL,
 	    0600, "digi%r.ctl", sc->res.unit);
 	sc->res.ctldev->si_drv1 = sc;
 
-	digi_loadmoduledata(sc);
-	digi_init(sc);
-	digi_freemoduledata(sc);
+	printf("digi%d: softc at %p\n", sc->res.unit, sc);
+	mtx_lock(&sc->dg_mutex);
+	error = digi_init(sc);
+	mtx_unlock(&sc->dg_mutex);
 
-	return (0);
+	return (error);
 }
 
 static int
@@ -1468,12 +1536,15 @@
 	int i;
 	struct digi_p *port;
 
+	if (sc->opencnt != 0)
+		return (1);
+
 	port = &sc->ports[0];
 	for (i = 0; i < sc->numports; i++, port++)
-		if (port->tp->t_state & TS_ISOPEN) {
+		if (tty_opened(port->tp)) {
 			DLOG(DIGIDB_INIT, (sc->dev, "port%d: busy\n", i));
 			return (1);
-		} else if (port->tp->t_wopeners || port->opencnt) {
+		} else if (port->status & DG_OPENED) {
 			DLOG(DIGIDB_INIT, (sc->dev, "port%d: blocked in open\n",
 			    i));
 			return (1);
@@ -1482,35 +1553,66 @@
 }
 
 static void
+digifree(void *arg)
+{
+	struct digi_p *port = arg;
+
+	atomic_subtract_32(&port->sc->dg_free, 1);
+}
+
+/* Free all state associated with the given DigiBoard */
+static void
 digi_free_state(struct digi_softc *sc)
 {
+#ifdef DIGI_INTERRUPT
+	u_char volatile *ptr;
+#endif
 	int i;
 
-	/* Blow it all away */
+	mtx_assert(&sc->dg_mutex, MA_OWNED);
+	sc->status = DIGI_STATUS_DISABLED;	/* Keep others out */
 
-	for (i = 0; i < sc->numports; i++)
-		ttygone(sc->ports[i].tp);
+#ifdef DIGI_INTERRUPT
+	/* Interrupt configuration */
+	ptr = digi_setwin(sc, 0xe04);
+	vW(ptr) = 0;	/* By experimentation */
+#endif
 
-	/* XXX: this might be better done as a ttypurge method */
-	untimeout(digi_poll, sc, sc->callout);
-	callout_handle_init(&sc->callout);
-	untimeout(digi_int_test, sc, sc->inttest);
-	callout_handle_init(&sc->inttest);
+	/* Need to drop the device lock to prevent a lock reversal during
+	 * the TTY cleanup, callout drain and interrupt cleanup */
+	mtx_unlock(&sc->dg_mutex);
+
+	/* Stop more data arriving */
+	callout_drain(&sc->callout);
+
+	/* Free each TTY */
+	sc->dg_free = 0;
+	for (i = 0; i < sc->numports; i++) {
+		atomic_add_32(&sc->dg_free, 1);
+		tty_lock(sc->ports[i].tp);
+		tty_rel_gone(sc->ports[i].tp);
+	}
 
-	for (i = 0; i < sc->numports; i++)
-		ttyfree(sc->ports[i].tp);
+	while (sc->dg_free != 0)
+		digi_delay(sc, "dgdie", hz / 10);
 
-	bus_teardown_intr(sc->dev, sc->res.irq, sc->res.irqHandler);
 #ifdef DIGI_INTERRUPT
+	/* Whilst it's not explicitly mentioned, holding dg_mutex whilst
+	 * calling bus_teardown_intr() seems liable to deadlock if the
+	 * interrupt handler (digi_intr()) is executing */
+	bus_teardown_intr(sc->dev, sc->res.irq, sc->res.irqHandler);
 	if (sc->res.irq != NULL) {
-		bus_release_resource(dev, SYS_RES_IRQ, sc->res.irqrid,
+		bus_release_resource(sc->dev, SYS_RES_IRQ, sc->res.irqrid,
 		    sc->res.irq);
 		sc->res.irq = NULL;
 	}
 #endif
+	/* Re-acquire device lock for remaining cleanup processing */
+	mtx_lock(&sc->dg_mutex);
+
 	if (sc->numports) {
 		KASSERT(sc->ports, ("digi%d: Lost my ports ?", sc->res.unit));
-		free(sc->ports, M_TTYS);
+		free(sc->ports, M_DEVBUF);
 		sc->ports = NULL;
 		sc->numports = 0;
 	}
@@ -1524,16 +1626,19 @@
 	struct digi_softc *sc = device_get_softc(dev);
 
 	DLOG(DIGIDB_INIT, (sc->dev, "detaching\n"));
+	mtx_lock(&sc->dg_mutex);
 
-	/* If we're INIT'd, numports must be 0 */
-	KASSERT(sc->numports == 0 || sc->status != DIGI_STATUS_NOTINIT,
-	    ("digi%d: numports(%d) & status(%d) are out of sync",
-	    sc->res.unit, sc->numports, (int)sc->status));
-
-	if (digi_inuse(sc))
+	if (digi_inuse(sc) ||
+	    sc->status == DIGI_STATUS_DISABLED ||
+	    sc->status == DIGI_STATUS_STARTING) {
+		mtx_unlock(&sc->dg_mutex);
 		return (EBUSY);
+	}
 
 	digi_free_state(sc);
+	/* Note that we're cleaning up & destroy mutex */
+	sc->status = DIGI_STATUS_DISABLED;
+	mtx_destroy(&sc->dg_mutex);
 
 	destroy_dev(sc->res.ctldev);
 
@@ -1542,11 +1647,13 @@
 		    sc->res.mem);
 		sc->res.mem = NULL;
 	}
+#ifdef DIGI_ISA
 	if (sc->res.io != NULL) {
 		bus_release_resource(dev, SYS_RES_IOPORT, sc->res.iorid,
 		    sc->res.io);
 		sc->res.io = NULL;
 	}
+#endif
 
 	return (0);
 }
@@ -1554,6 +1661,20 @@
 int
 digi_shutdown(device_t dev)
 {
+	struct digi_softc *sc = device_get_softc(dev);
+
+	DLOG(DIGIDB_INIT, (sc->dev, "shutdown\n"));
+	mtx_lock(&sc->dg_mutex);
+
+	if (digi_inuse(sc) ||
+	    sc->status == DIGI_STATUS_DISABLED ||
+	    sc->status == DIGI_STATUS_STARTING) {
+		mtx_unlock(&sc->dg_mutex);
+		return (EBUSY);
+	}
+
+	digi_free_state(sc);
+	mtx_unlock(&sc->dg_mutex);
 	return (0);
 }
 
Index: sys/dev/digi/digi.h
===================================================================
RCS file: /usr/ncvs/src/sys/dev/digi/digi.h,v
retrieving revision 1.19
diff -u -r1.19 digi.h
--- sys/dev/digi/digi.h	14 Oct 2004 18:37:59 -0000	1.19
+++ sys/dev/digi/digi.h	20 Jun 2011 22:43:51 -0000
@@ -28,7 +28,11 @@
  *
  * $FreeBSD: src/sys/dev/digi/digi.h,v 1.19 2004/10/14 18:37:59 phk Exp $
  */
+/* TODO: Someone needs to work through digi.c and digi_isa.c and add all
+ * the necessary locking for ISA-based cards to work with TTYng */
+#undef	DIGI_ISA	/* ISA-based cards aren't supported */
 
+//#define const
 #define	W(p)				(*(u_int16_t *)(p))
 #define	vW(p)				(*(u_int16_t volatile *)(p))
 #define	D(p)				(*(u_int32_t *)(p))
@@ -38,16 +42,15 @@
 #define	CE_INTERRUPT_BUF_OVERFLOW	1
 #define	CE_TTY_BUF_OVERFLOW		2
 #define	CE_NTYPES			3
-#define	CE_RECORD(com, errnum)		(++(com)->delta_error_counts[errnum])
 
-/*#define DIGI_INTERRUPT*/
+#define DIGI_INTERRUPT	/* Use interrupts instead of polling if possible */
 
 #ifndef DEBUG
 #define	DEBUG
 #endif
 
 #ifdef DEBUG
-extern unsigned digi_debug;
+extern unsigned long digi_debug;
 #define	DLOG(level, args)	if (digi_debug & (level)) device_printf args
 #else
 #define	DLOG(level, args)
@@ -62,11 +65,11 @@
 
 	int status;
 #define ENABLED 1
-#define DIGI_DTR_OFF 2
+//#define DIGI_DTR_OFF 2
 #define PAUSE_TX 8
 #define PAUSE_RX 16
+#define DG_OPENED	0x20
 
-	int opencnt;
 	u_short txbufsize;
 	u_short rxbufsize;
 	volatile struct board_chan *bc;
@@ -79,29 +82,13 @@
 
 	u_char pnum;		/* port number */
 
-	u_char modemfake;	/* Modem values to be forced */
-	u_char mstat;
-	u_char modem;		/* Force values */
-
-	/*
-	 * The high level of the driver never reads status registers directly
-	 * because there would be too many side effects to handle conveniently.
-	 * Instead, it reads copies of the registers stored here by the
-	 * interrupt handler.
-	 */
-	u_char last_modem_status;	/* last MSR read by intr handler */
-	u_char prev_modem_status;	/* last MSR handled by high level */
-
-	u_long bytes_in, bytes_out;
-	u_int delta_error_counts[CE_NTYPES];
-	u_long error_counts;
-
-	tcflag_t c_iflag;		/* hold true IXON/IXOFF/IXANY */
-	int lcc, lostcc, lbuf;
 	u_char send_ring;
 
 	unsigned laltpin : 1;		/* Alternate pin settings locked */
 	unsigned ialtpin : 1;		/* Initial alternate pin settings */
+	unsigned p_hupcl : 1;		/* Hangup on any close */
+	unsigned p_clocal : 1;		/* termios 'clocal' handling */
+
 
 	int cd;				/* Depends on the altpin setting */
 	int dsr;
@@ -120,72 +107,84 @@
 };
 
 enum digi_board_status {
-	DIGI_STATUS_NOTINIT,
-	DIGI_STATUS_ENABLED,
-	DIGI_STATUS_DISABLED
+	DIGI_STATUS_NOTINIT,		/* Board free */
+	DIGI_STATUS_ENABLED,		/* Board ready for normal use */
+	DIGI_STATUS_DISABLED,		/* Board being uninitialised */
+	DIGI_STATUS_STARTING		/* Board being initialised */
 };
 
 /* Digiboard per-board structure */
 struct digi_softc {
 	/* struct board_info */
 	device_t dev;
+	struct mtx	dg_mutex;	/* Device and TTY mutex */
 
 	const char *name;
+	const char *module;
 	enum digi_board_status status;
-	u_short numports;		/* number of ports on card */
+	u_int numports;			/* number of ports on card */
+#ifdef DIGI_ISA
 	u_int port;			/* I/O port */
 	u_int wport;			/* window select I/O port */
+#endif
 
 	struct {
-		struct resource *mem;
+		struct cdev *ctldev;
+		int unit;
 		int mrid;
+		struct resource *mem;
+#ifdef DIGI_INTERRUPT
 		struct resource *irq;
+		void *irqHandler;
 		int irqrid;
-		struct resource *io;
+#endif
+#ifdef DIGI_ISA
 		int iorid;
-		void *irqHandler;
-		int unit;
-		struct cdev *ctldev;
+		struct resource *io;
+#endif
 	} res;
 
-	u_char *vmem;			/* virtual memory address */
-	u_char *memcmd;
+	u_char volatile *vmem;			/* virtual memory address */
+	u_char volatile *memcmd;
 	volatile u_char *memevent;
+#ifdef DIGI_ISA
 	long pmem;			/* physical memory address */
-
-	struct {
-		u_char *data;
-		size_t size;
-	} bios, fep, link;
-
-#ifdef DIGI_INTERRUPT
-	struct timeval intr_timestamp;
 #endif
 
 	struct digi_p *ports;	/* pointer to array of port descriptors */
 	volatile struct global_data *gdata;
-	u_char window;		/* saved window */
+	const struct digi_control_signals *csigs;
+	struct callout callout;	/* poll timeout handle */
 	int win_size;
 	int win_bits;
-	int mem_size;
-	int mem_seg;
 	enum digi_model model;
-	const struct digi_control_signals *csigs;
+	int dg_free;
 	int opencnt;
+#ifdef DIGI_ISA
 	unsigned pcibus : 1;		/* On a PCI bus ? */
+#endif
+#ifdef DIGI_INTERRUPT
+	unsigned interrupt_seen : 1;	/* Seen an interrupt */
+#endif
 
-	struct callout_handle callout;	/* poll timeout handle */
-	struct callout_handle inttest;	/* int test timeout handle */
-	const char *module;
-	
-	u_char *(*setwin)(struct digi_softc *_sc, unsigned _addr);
+#ifdef DIGI_ISA
+	u_char volatile *(*setwin)(struct digi_softc *_sc, unsigned _addr);
 	void	(*hidewin)(struct digi_softc *_sc);
 	void	(*towin)(struct digi_softc *_sc, int _win);
+	u_char window;		/* saved window */
+	int mem_seg;
+#endif
 #ifdef DEBUG
 	int	intr_count;
 #endif
 };
 
+#ifdef DIGI_ISA
+#define	MEM_SEG(sc)	((sc)->mem_seg)
+#else
+#define	MEM_SEG(sc)	(0)
+#endif
+
 extern devclass_t digi_devclass;
 
 extern const struct digi_control_signals digi_xixe_signals;
@@ -197,3 +196,66 @@
 int		 digi_shutdown(device_t _dev);
 void		 digi_delay(struct digi_softc *_sc, const char *_txt,
 		     u_long _timo);
+void     digi_intr(void *);
+
+#ifdef DIGI_ISA
+static __inline u_char volatile *
+digi_setwin(struct digi_softc *sc, unsigned addr)
+{
+	return (sc->setwin(sc, addr));
+}
+
+static __inline void
+digi_hidewin(struct digi_softc *sc)
+{
+	sc->hidewin(sc);
+}
+
+static __inline void
+digi_towin(struct digi_softc *sc, int win)
+{
+	sc->towin(sc, win);
+}
+#else
+static __inline u_char volatile *
+digi_setwin(struct digi_softc *sc, unsigned addr)
+{
+	return (sc->vmem + addr);
+}
+
+#define	digi_hidewin(_sc)
+#define	digi_towin(_sc, _win)
+#endif
+
+static __inline u_char
+digi_inport(struct digi_softc *sc)
+{
+#ifdef DIGI_ISA
+	if (!sc->pcibus)
+		return (inb(sc->port));
+	else
+#endif
+		return (((u_char volatile *)(sc->vmem))[0x200000]);
+}
+
+static __inline void
+digi_outport(struct digi_softc *sc, u_char val)
+{
+#ifdef DIGI_ISA
+	if (!sc->pcibus)
+		return (outb(sc->port, val));
+	else
+#endif
+		(((u_char volatile *)(sc->vmem))[0x200000]) = val;
+}
+
+static __inline void
+digi_outportmem(struct digi_softc *sc, u_char val)
+{
+#ifdef DIGI_ISA
+	if (!sc->pcibus)
+		return (outb(sc->port, val | FEPMEM));
+	else
+#endif
+		(((u_char volatile *)(sc->vmem))[0x200000]) = val;
+}
Index: sys/dev/digi/digi_isa.c
===================================================================
RCS file: /usr/ncvs/src/sys/dev/digi/digi_isa.c,v
retrieving revision 1.13
diff -u -r1.13 digi_isa.c
--- sys/dev/digi/digi_isa.c	30 May 2004 20:08:30 -0000	1.13
+++ sys/dev/digi/digi_isa.c	20 Jun 2011 22:43:51 -0000
@@ -41,7 +41,9 @@
 
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/lock.h>
 #include <sys/module.h>
+#include <sys/mutex.h>
 #include <sys/tty.h>
 #include <sys/bus.h>
 #include <machine/bus.h>
@@ -54,6 +56,10 @@
 #include <dev/digi/digireg.h>
 #include <dev/digi/digi.h>
 
+#ifndef DIGI_ISA
+#error No support for ISA Digi cards
+#endif
+
 /* Valid i/o addresses are any of these with either 0 or 4 added */
 static u_long digi_validio[] = {
 	0x100, 0x110, 0x120, 0x200, 0x220, 0x300, 0x320
@@ -70,14 +76,14 @@
 };
 #define DIGI_NVALIDMEM	(sizeof(digi_validmem) / sizeof(digi_validmem[0]))
 
-static u_char *
+static u_char volatile *
 digi_isa_setwin(struct digi_softc *sc, unsigned int addr)
 {
 	outb(sc->wport, sc->window = FEPWIN | (addr >> sc->win_bits));
 	return (sc->vmem + (addr % sc->win_size));
 }
 
-static u_char *
+static u_char volatile *
 digi_xi_setwin(struct digi_softc *sc, unsigned int addr)
 {
 	outb(sc->wport, sc->window = FEPMEM);
@@ -320,7 +326,7 @@
 {
 	struct digi_softc *sc = device_get_softc(dev);
 	int i, t, res;
-	u_char *ptr;
+	u_char volatile *ptr;
 	int reset;
 	u_long msize, iosize;
 	long scport;
@@ -333,6 +339,7 @@
 	sc->status = DIGI_STATUS_NOTINIT;
 	sc->dev = dev;
 	sc->res.unit = device_get_unit(dev);
+	mtx_init(&sc->dg_mutex, "digimtx", NULL, MTX_DEF);
 	DLOG(DIGIDB_INIT, (sc->dev, "attaching\n"));
 
 	bus_get_resource(dev, SYS_RES_IOPORT, 0, &scport, &iosize);
Index: sys/dev/digi/digi_pci.c
===================================================================
RCS file: /usr/ncvs/src/sys/dev/digi/digi_pci.c,v
retrieving revision 1.12
diff -u -r1.12 digi_pci.c
--- sys/dev/digi/digi_pci.c	5 Mar 2005 18:30:10 -0000	1.12
+++ sys/dev/digi/digi_pci.c	20 Jun 2011 22:43:51 -0000
@@ -34,7 +34,9 @@
 
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/lock.h>
 #include <sys/module.h>
+#include <sys/mutex.h>
 #include <sys/tty.h>
 #include <sys/bus.h>
 #include <machine/bus.h>
@@ -49,7 +51,8 @@
 #include <dev/digi/digi.h>
 #include <dev/digi/digi_pci.h>
 
-static u_char *
+#ifdef DIGI_ISA
+static volatile u_char *
 digi_pci_setwin(struct digi_softc *sc, unsigned int addr)
 {
 	return (sc->vmem + addr);
@@ -66,6 +69,7 @@
 {
 	return;
 }
+#endif
 
 static int
 digi_pci_probe(device_t dev)
@@ -107,12 +111,15 @@
 #endif
 
 	sc = device_get_softc(dev);
+	DLOG(DIGIDB_INIT, (dev, "dev@%p, softc@%p\n", dev, sc));
+
 	KASSERT(sc, ("digi%d: softc not allocated in digi_pci_attach\n",
 	    device_get_unit(dev)));
 
 	bzero(sc, sizeof(*sc));
 	sc->dev = dev;
 	sc->res.unit = device_get_unit(dev);
+	mtx_init(&sc->dg_mutex, "digimtx", NULL, MTX_DEF);
 
 	device_id = pci_get_devid(dev);
 	switch (device_id >> 16) {
@@ -175,9 +182,11 @@
 		return (ENXIO);
 	}
 
-	pci_write_config(dev, 0x40, 0, 4);
-	pci_write_config(dev, 0x46, 0, 4);
+	pci_write_config(dev, 0x40, 0, 1);
+	pci_write_config(dev, 0x46, 0, 1);
 
+	/* Limit burst length to 2 double-words */
+	pci_write_config(dev, 0x42, 1, 1);
 	sc->res.mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->res.mrid,
 	    RF_ACTIVE);
 
@@ -189,26 +198,25 @@
 		device_printf(dev, "couldn't map interrupt\n");
 		return (ENXIO);
 	}
-	retVal = bus_setup_intr(dev, sc->res.irq, INTR_TYPE_TTY,
-	    digiintr, sc, &sc->res.irqHandler);
+	retVal = bus_setup_intr(dev, sc->res.irq, INTR_TYPE_TTY | INTR_MPSAFE,
+	    NULL, digi_intr, sc, &sc->res.irqHandler);
 #else
 	DLOG(DIGIDB_IRQ, (sc->dev, "Interrupt support compiled out\n"));
 #endif
 
 	sc->vmem = rman_get_virtual(sc->res.mem);
-	sc->pmem = vtophys(sc->vmem);
-	sc->pcibus = 1;
 	sc->win_size = 0x200000;
 	sc->win_bits = 21;
 	sc->csigs = &digi_normal_signals;
 	sc->status = DIGI_STATUS_NOTINIT;
-	callout_handle_init(&sc->callout);
-	callout_handle_init(&sc->inttest);
+	callout_init_mtx(&sc->callout, &sc->dg_mutex, 0);
+#ifdef DIGI_ISA
+	sc->pcibus = 1;
 	sc->setwin = digi_pci_setwin;
 	sc->hidewin = digi_pci_hidewin;
 	sc->towin = digi_pci_towin;
-
-	PCIPORT = FEPRST;
+#endif
+	digi_outport(sc, FEPRST);
 
 	return (digi_attach(sc));
 }
Index: sys/dev/digi/digi_pci.h
===================================================================
RCS file: /usr/ncvs/src/sys/dev/digi/digi_pci.h,v
retrieving revision 1.1
diff -u -r1.1 digi_pci.h
--- sys/dev/digi/digi_pci.h	2 May 2001 01:08:04 -0000	1.1
+++ sys/dev/digi/digi_pci.h	20 Jun 2011 22:43:51 -0000
@@ -38,5 +38,3 @@
 #define	PCI_DEVICE_920_4	0x0026	/* XR-Plus 920 K, 4 port */
 #define	PCI_DEVICE_920_8	0x0027	/* XR-Plus 920 K, 8 port */
 #define	PCI_DEVICE_920_2	0x0034	/* XR-Plus 920 K, 2 port */
-
-#define	PCIPORT			sc->vmem[0x200000]
Index: sys/dev/digi/digireg.h
===================================================================
RCS file: /usr/ncvs/src/sys/dev/digi/digireg.h,v
retrieving revision 1.3
diff -u -r1.3 digireg.h
--- sys/dev/digi/digireg.h	7 Aug 2003 15:04:24 -0000	1.3
+++ sys/dev/digi/digireg.h	20 Jun 2011 22:43:51 -0000
@@ -46,39 +46,39 @@
 	volatile u_short tcjmp;
 	volatile u_short fil1;
 	volatile u_short rpjmp;
-	
+
 	volatile u_short tseg;
 	volatile u_short tin;
 	volatile u_short tout;
 	volatile u_short tmax;
-	
+
 	volatile u_short rseg;
 	volatile u_short rin;
 	volatile u_short rout;
 	volatile u_short rmax;
-	
+
 	volatile u_short tlow;
 	volatile u_short rlow;
 	volatile u_short rhigh;
 	volatile u_short incr;
-	
+
 	volatile u_short dev;
 	volatile u_short edelay;
 	volatile u_short blen;
 	volatile u_short btime;
-	
+
 	volatile u_short iflag;
 	volatile u_short oflag;
 	volatile u_short cflag;
 	volatile u_short gmask;
-	
+
 	volatile u_short col;
 	volatile u_short delay;
 	volatile u_short imask;
 	volatile u_short tflush;
 
 	volatile u_char _1[16];
-	
+
 	volatile u_char num;
 	volatile u_char ract;
 	volatile u_char bstat;
@@ -87,7 +87,7 @@
 	volatile u_char ilow;
 	volatile u_char idata;
 	volatile u_char eflag;
-	
+
 	volatile u_char tflag;
 	volatile u_char rflag;
 	volatile u_char xmask;
@@ -112,7 +112,7 @@
 	volatile u_char _2;
 
 	volatile u_char _3[28];
-}; 
+};
 
 #define SRXLWATER      0xe0
 #define SRXHWATER      0xe1
Index: sys/modules/Makefile
===================================================================
RCS file: /usr/ncvs/src/sys/modules/Makefile,v
retrieving revision 1.681
diff -u -r1.681 Makefile
--- sys/modules/Makefile	19 Jun 2011 22:08:55 -0000	1.681
+++ sys/modules/Makefile	20 Jun 2011 22:45:29 -0000
@@ -78,6 +78,7 @@
 	dcons \
 	dcons_crom \
 	de \
+	digi \
 	${_dpms} \
 	${_dpt} \
 	${_drm} \
Index: sys/modules/digi/digi/Makefile
===================================================================
RCS file: /usr/ncvs/src/sys/modules/digi/digi/Makefile,v
retrieving revision 1.6
diff -u -r1.6 Makefile
--- sys/modules/digi/digi/Makefile	1 Sep 2008 23:59:00 -0000	1.6
+++ sys/modules/digi/digi/Makefile	20 Jun 2011 22:45:45 -0000
@@ -2,7 +2,8 @@
 
 .PATH:	${.CURDIR}/../../../dev/digi
 KMOD=	digi
-SRCS=	digi.c digi_pci.c digi_isa.c
+SRCS=	digi.c digi_pci.c
+#SRCS+=	digi_isa.c
 SRCS+=	digi.h digi_pci.h digireg.h digi_mod.h
 SRCS+=	bus_if.h pci_if.h device_if.h
 SRCS+=	opt_compat.h
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list