FreeBSD Bugzilla – Attachment 116168 Details for
Bug 158086
[digi] [patch] Update digi(4) to work with TTYng
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
file.diff
file.diff (text/plain), 68.11 KB, created by
Peter.Jeremy
on 2011-06-21 05:50:08 UTC
(
hide
)
Description:
file.diff
Filename:
MIME Type:
Creator:
Peter.Jeremy
Created:
2011-06-21 05:50:08 UTC
Size:
68.11 KB
patch
obsolete
>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
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 158086
: 116168