diff options
-rw-r--r-- | sys/dev/ppbus/if_plip.c | 253 | ||||
-rw-r--r-- | sys/dev/ppbus/immio.c | 2 | ||||
-rw-r--r-- | sys/dev/ppbus/lpbb.c | 59 | ||||
-rw-r--r-- | sys/dev/ppbus/lpt.c | 287 | ||||
-rw-r--r-- | sys/dev/ppbus/pcfclock.c | 26 | ||||
-rw-r--r-- | sys/dev/ppbus/ppb_1284.c | 7 | ||||
-rw-r--r-- | sys/dev/ppbus/ppb_base.c | 95 | ||||
-rw-r--r-- | sys/dev/ppbus/ppb_msq.c | 7 | ||||
-rw-r--r-- | sys/dev/ppbus/ppbconf.c | 120 | ||||
-rw-r--r-- | sys/dev/ppbus/ppbconf.h | 34 | ||||
-rw-r--r-- | sys/dev/ppbus/ppi.c | 154 | ||||
-rw-r--r-- | sys/dev/ppbus/pps.c | 89 | ||||
-rw-r--r-- | sys/dev/ppbus/vpo.c | 30 | ||||
-rw-r--r-- | sys/dev/ppbus/vpoio.c | 2 | ||||
-rw-r--r-- | sys/dev/ppc/ppc.c | 122 | ||||
-rw-r--r-- | sys/dev/ppc/ppc_acpi.c | 3 | ||||
-rw-r--r-- | sys/dev/ppc/ppc_isa.c | 14 | ||||
-rw-r--r-- | sys/dev/ppc/ppc_pci.c | 3 | ||||
-rw-r--r-- | sys/dev/ppc/ppc_puc.c | 3 | ||||
-rw-r--r-- | sys/dev/ppc/ppcreg.h | 13 | ||||
-rw-r--r-- | sys/dev/ppc/ppcvar.h | 4 |
21 files changed, 830 insertions, 497 deletions
diff --git a/sys/dev/ppbus/if_plip.c b/sys/dev/ppbus/if_plip.c index 5d6417f..3ff11df 100644 --- a/sys/dev/ppbus/if_plip.c +++ b/sys/dev/ppbus/if_plip.c @@ -152,8 +152,12 @@ struct lp_data { int sc_iferrs; struct resource *res_irq; + void *sc_intr_cookie; }; +static struct mtx lp_tables_lock; +MTX_SYSINIT(lp_tables, &lp_tables_lock, "plip tables", MTX_DEF); + /* Tables for the lp# interface */ static u_char *txmith; #define txmitl (txmith + (1 * LPIPTBLSIZE)) @@ -170,13 +174,41 @@ static int lpinittables(void); static int lpioctl(struct ifnet *, u_long, caddr_t); static int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); +static void lpstop(struct lp_data *); static void lp_intr(void *); +static int lp_module_handler(module_t, int, void *); #define DEVTOSOFTC(dev) \ ((struct lp_data *)device_get_softc(dev)) static devclass_t lp_devclass; +static int +lp_module_handler(module_t mod, int what, void *arg) +{ + + switch (what) { + case MOD_UNLOAD: + mtx_lock(&lp_tables_lock); + if (txmith != NULL) { + free(txmith, M_DEVBUF); + txmith = NULL; + } + if (ctxmith != NULL) { + free(ctxmith, M_DEVBUF); + ctxmith = NULL; + } + mtx_unlock(&lp_tables_lock); + break; + case MOD_LOAD: + case MOD_QUIESCE: + break; + default: + return (EOPNOTSUPP); + } + return (0); +} + static void lp_identify(driver_t *driver, device_t parent) { @@ -201,7 +233,7 @@ lp_attach(device_t dev) { struct lp_data *lp = DEVTOSOFTC(dev); struct ifnet *ifp; - int rid = 0; + int error, rid = 0; lp->sc_dev = dev; @@ -224,8 +256,7 @@ lp_attach(device_t dev) ifp->if_softc = lp; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_mtu = LPMTU; - ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST | - IFF_NEEDSGIANT; + ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST; ifp->if_ioctl = lpioctl; ifp->if_output = lpoutput; ifp->if_hdrlen = 0; @@ -235,8 +266,39 @@ lp_attach(device_t dev) bpfattach(ifp, DLT_NULL, sizeof(u_int32_t)); + /* + * Attach our interrupt handler. It is only called while we + * own the ppbus. + */ + error = bus_setup_intr(dev, lp->res_irq, INTR_TYPE_NET | INTR_MPSAFE, + NULL, lp_intr, lp, &lp->sc_intr_cookie); + if (error) { + bpfdetach(ifp); + if_detach(ifp); + bus_release_resource(dev, SYS_RES_IRQ, 0, lp->res_irq); + device_printf(dev, "Unable to register interrupt handler\n"); + return (error); + } + return (0); } + +static int +lp_detach(device_t dev) +{ + struct lp_data *sc = device_get_softc(dev); + device_t ppbus = device_get_parent(dev); + + ppb_lock(ppbus); + lpstop(sc); + ppb_unlock(ppbus); + bpfdetach(sc->sc_ifp); + if_detach(sc->sc_ifp); + bus_teardown_intr(dev, sc->res_irq, sc->sc_intr_cookie); + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->res_irq); + return (0); +} + /* * Build the translation tables for the LPIP (BSD unix) protocol. * We don't want to calculate these nasties in our tight loop, so we @@ -247,17 +309,22 @@ lpinittables(void) { int i; + mtx_lock(&lp_tables_lock); if (txmith == NULL) txmith = malloc(4 * LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); - if (txmith == NULL) + if (txmith == NULL) { + mtx_unlock(&lp_tables_lock); return (1); + } if (ctxmith == NULL) ctxmith = malloc(4 * LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); - if (ctxmith == NULL) + if (ctxmith == NULL) { + mtx_unlock(&lp_tables_lock); return (1); + } for (i = 0; i < LPIPTBLSIZE; i++) { ctxmith[i] = (i & 0xF0) >> 4; @@ -272,10 +339,61 @@ lpinittables(void) trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1); trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3); } + mtx_unlock(&lp_tables_lock); return (0); } +static void +lpstop(struct lp_data *sc) +{ + device_t ppbus = device_get_parent(sc->sc_dev); + + ppb_assert_locked(ppbus); + ppb_wctr(ppbus, 0x00); + sc->sc_ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + free(sc->sc_ifbuf, M_DEVBUF); + sc->sc_ifbuf = NULL; + + /* IFF_UP is not set, try to release the bus anyway */ + ppb_release_bus(ppbus, sc->sc_dev); +} + +static int +lpinit_locked(struct ifnet *ifp) +{ + struct lp_data *sc = ifp->if_softc; + device_t dev = sc->sc_dev; + device_t ppbus = device_get_parent(dev); + int error; + + ppb_assert_locked(ppbus); + error = ppb_request_bus(ppbus, dev, PPB_DONTWAIT); + if (error) + return (error); + + /* Now IFF_UP means that we own the bus */ + ppb_set_mode(ppbus, PPB_COMPATIBLE); + + if (lpinittables()) { + ppb_release_bus(ppbus, dev); + return (ENOBUFS); + } + + sc->sc_ifbuf = malloc(sc->sc_ifp->if_mtu + MLPIPHDRLEN, + M_DEVBUF, M_NOWAIT); + if (sc->sc_ifbuf == NULL) { + ppb_release_bus(ppbus, dev); + return (ENOBUFS); + } + + ppb_wctr(ppbus, IRQENABLE); + + ifp->if_drv_flags |= IFF_DRV_RUNNING; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + return (0); +} + /* * Process an ioctl request. */ @@ -288,7 +406,6 @@ lpioctl(struct ifnet *ifp, u_long cmd, caddr_t data) struct ifaddr *ifa = (struct ifaddr *)data; struct ifreq *ifr = (struct ifreq *)data; u_char *ptr; - void *ih; int error; switch (cmd) { @@ -301,67 +418,32 @@ lpioctl(struct ifnet *ifp, u_long cmd, caddr_t data) ifp->if_flags |= IFF_UP; /* FALLTHROUGH */ case SIOCSIFFLAGS: + error = 0; + ppb_lock(ppbus); if ((!(ifp->if_flags & IFF_UP)) && - (ifp->if_drv_flags & IFF_DRV_RUNNING)) { - - ppb_wctr(ppbus, 0x00); - ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - - /* IFF_UP is not set, try to release the bus anyway */ - ppb_release_bus(ppbus, dev); - break; - } - if (((ifp->if_flags & IFF_UP)) && - (!(ifp->if_drv_flags & IFF_DRV_RUNNING))) { + (ifp->if_drv_flags & IFF_DRV_RUNNING)) + lpstop(sc); + else if (((ifp->if_flags & IFF_UP)) && + (!(ifp->if_drv_flags & IFF_DRV_RUNNING))) + error = lpinit_locked(ifp); + ppb_unlock(ppbus); + return (error); - /* XXX - * Should the request be interruptible? - */ - if ((error = ppb_request_bus(ppbus, dev, PPB_WAIT | - PPB_INTR))) - return (error); - - /* Now IFF_UP means that we own the bus */ - ppb_set_mode(ppbus, PPB_COMPATIBLE); - - if (lpinittables()) { - ppb_release_bus(ppbus, dev); - return (ENOBUFS); - } - - sc->sc_ifbuf = malloc(sc->sc_ifp->if_mtu + MLPIPHDRLEN, - M_DEVBUF, M_WAITOK); - if (sc->sc_ifbuf == NULL) { - ppb_release_bus(ppbus, dev); + case SIOCSIFMTU: + ppb_lock(ppbus); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + ptr = malloc(ifr->ifr_mtu + MLPIPHDRLEN, M_DEVBUF, + M_NOWAIT); + if (ptr == NULL) { + ppb_unlock(ppbus); return (ENOBUFS); } - - /* - * Attach our interrupt handler. It is - * detached later when the bus is released. - */ - if ((error = bus_setup_intr(dev, sc->res_irq, - INTR_TYPE_NET, NULL, lp_intr, dev, &ih))) { - ppb_release_bus(ppbus, dev); - return (error); - } - - ppb_wctr(ppbus, IRQENABLE); - ifp->if_drv_flags |= IFF_DRV_RUNNING; - } - break; - - case SIOCSIFMTU: - ptr = sc->sc_ifbuf; - sc->sc_ifbuf = malloc(ifr->ifr_mtu + MLPIPHDRLEN, M_DEVBUF, - M_NOWAIT); - if (sc->sc_ifbuf == NULL) { + if (sc->sc_ifbuf) + free(sc->sc_ifbuf, M_DEVBUF); sc->sc_ifbuf = ptr; - return (ENOBUFS); } - if (ptr) - free(ptr, M_DEVBUF); sc->sc_ifp->if_mtu = ifr->ifr_mtu; + ppb_unlock(ppbus); break; case SIOCGIFMTU: @@ -417,14 +499,14 @@ clpinbyte(int spin, device_t ppbus) { u_char c, cl; - while((ppb_rstr(ppbus) & CLPIP_SHAKE)) + while ((ppb_rstr(ppbus) & CLPIP_SHAKE)) if (!--spin) { return (-1); } cl = ppb_rstr(ppbus); ppb_wdtr(ppbus, 0x10); - while(!(ppb_rstr(ppbus) & CLPIP_SHAKE)) + while (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) if (!--spin) { return (-1); } @@ -445,16 +527,14 @@ lptap(struct ifnet *ifp, struct mbuf *m) static void lp_intr(void *arg) { - device_t dev = (device_t)arg; - device_t ppbus = device_get_parent(dev); - struct lp_data *sc = DEVTOSOFTC(dev); - int len, s, j; + struct lp_data *sc = arg; + device_t ppbus = device_get_parent(sc->sc_dev); + int len, j; u_char *bp; u_char c, cl; struct mbuf *top; - s = splhigh(); - + ppb_assert_locked(ppbus); if (sc->sc_ifp->if_flags & IFF_LINK0) { /* Ack. the request */ @@ -500,13 +580,15 @@ lp_intr(void *arg) top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, sc->sc_ifp, 0); if (top) { + ppb_unlock(ppbus); if (bpf_peers_present(sc->sc_ifp->if_bpf)) lptap(sc->sc_ifp, top); /* mbuf is free'd on failure. */ netisr_queue(NETISR_IP, top); + ppb_lock(ppbus); } - goto done; + return; } while ((ppb_rstr(ppbus) & LPIP_SHAKE)) { len = sc->sc_ifp->if_mtu + LPIPHDRLEN; @@ -517,7 +599,7 @@ lp_intr(void *arg) ppb_wdtr(ppbus, 8); j = LPMAXSPIN2; - while((ppb_rstr(ppbus) & LPIP_SHAKE)) + while ((ppb_rstr(ppbus) & LPIP_SHAKE)) if (!--j) goto err; @@ -550,14 +632,16 @@ lp_intr(void *arg) top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, sc->sc_ifp, 0); if (top) { + ppb_unlock(ppbus); if (bpf_peers_present(sc->sc_ifp->if_bpf)) lptap(sc->sc_ifp, top); /* mbuf is free'd on failure. */ netisr_queue(NETISR_IP, top); + ppb_lock(ppbus); } } - goto done; + return; err: ppb_wdtr(ppbus, 0); @@ -575,9 +659,6 @@ err: sc->sc_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; sc->sc_iferrs = 0; } - -done: - splx(s); } static __inline int @@ -602,7 +683,7 @@ lpoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct lp_data *sc = ifp->if_softc; device_t dev = sc->sc_dev; device_t ppbus = device_get_parent(dev); - int s, err; + int err; struct mbuf *mm; u_char *cp = "\0\0"; u_char chksum = 0; @@ -611,19 +692,18 @@ lpoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, /* We need a sensible value if we abort */ cp++; - ifp->if_drv_flags |= IFF_DRV_RUNNING; + ppb_lock(ppbus); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; err = 1; /* assume we're aborting because of an error */ - s = splhigh(); - /* Suspend (on laptops) or receive-errors might have taken us offline */ ppb_wctr(ppbus, IRQENABLE); if (ifp->if_flags & IFF_LINK0) { if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) { lprintf("&"); - lp_intr(dev); + lp_intr(sc); } /* Alert other end to pending packet */ @@ -681,6 +761,7 @@ lpoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, err = 0; /* No errors */ nend: + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; if (err) { /* if we didn't timeout... */ ifp->if_oerrors++; lprintf("X"); @@ -695,15 +776,15 @@ lpoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, if (!(ppb_rstr(ppbus) & CLPIP_SHAKE)) { lprintf("^"); - lp_intr(dev); + lp_intr(sc); } - (void) splx(s); + ppb_unlock(ppbus); return (0); } if (ppb_rstr(ppbus) & LPIP_SHAKE) { lprintf("&"); - lp_intr(dev); + lp_intr(sc); } if (lpoutbyte(0x08, LPMAXSPIN1, ppbus)) @@ -726,6 +807,7 @@ end: --cp; ppb_wdtr(ppbus, txmitl[*cp] ^ 0x17); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; if (err) { /* if we didn't timeout... */ ifp->if_oerrors++; lprintf("X"); @@ -740,10 +822,10 @@ end: if (ppb_rstr(ppbus) & LPIP_SHAKE) { lprintf("^"); - lp_intr(dev); + lp_intr(sc); } - (void) splx(s); + ppb_unlock(ppbus); return (0); } @@ -752,6 +834,7 @@ static device_method_t lp_methods[] = { DEVMETHOD(device_identify, lp_identify), DEVMETHOD(device_probe, lp_probe), DEVMETHOD(device_attach, lp_attach), + DEVMETHOD(device_detach, lp_detach), { 0, 0 } }; @@ -762,5 +845,5 @@ static driver_t lp_driver = { sizeof(struct lp_data), }; -DRIVER_MODULE(plip, ppbus, lp_driver, lp_devclass, 0, 0); +DRIVER_MODULE(plip, ppbus, lp_driver, lp_devclass, lp_module_handler, 0); MODULE_DEPEND(plip, ppbus, 1, 1, 1); diff --git a/sys/dev/ppbus/immio.c b/sys/dev/ppbus/immio.c index bd0c0c9..8b0c8de 100644 --- a/sys/dev/ppbus/immio.c +++ b/sys/dev/ppbus/immio.c @@ -606,6 +606,7 @@ imm_attach(struct vpoio_data *vpo) /* * Initialize mode dependent in/out microsequences */ + ppb_lock(ppbus); if ((error = ppb_request_bus(ppbus, vpo->vpo_dev, PPB_WAIT))) goto error; @@ -632,6 +633,7 @@ imm_attach(struct vpoio_data *vpo) ppb_release_bus(ppbus, vpo->vpo_dev); error: + ppb_unlock(ppbus); return (error); } diff --git a/sys/dev/ppbus/lpbb.c b/sys/dev/ppbus/lpbb.c index 87ce6c7..872db24 100644 --- a/sys/dev/ppbus/lpbb.c +++ b/sys/dev/ppbus/lpbb.c @@ -103,16 +103,16 @@ lpbb_callback(device_t dev, int index, caddr_t *data) case IIC_REQUEST_BUS: /* request the ppbus */ how = *(int *)data; - mtx_lock(&Giant); + ppb_lock(ppbus); error = ppb_request_bus(ppbus, dev, how); - mtx_unlock(&Giant); + ppb_unlock(ppbus); break; case IIC_RELEASE_BUS: /* release the ppbus */ - mtx_lock(&Giant); + ppb_lock(ppbus); error = ppb_release_bus(ppbus, dev); - mtx_unlock(&Giant); + ppb_unlock(ppbus); break; default: @@ -129,25 +129,38 @@ lpbb_callback(device_t dev, int index, caddr_t *data) #define ALIM 0x20 #define I2CKEY 0x50 +/* Reset bus by setting SDA first and then SCL. */ +static void +lpbb_reset_bus(device_t dev) +{ + device_t ppbus = device_get_parent(dev); + + ppb_assert_locked(ppbus); + ppb_wdtr(ppbus, (u_char)~SDA_out); + ppb_wctr(ppbus, (u_char)(ppb_rctr(ppbus) | SCL_out)); +} + static int lpbb_getscl(device_t dev) { + device_t ppbus = device_get_parent(dev); int rval; - mtx_lock(&Giant); - rval = ((ppb_rstr(device_get_parent(dev)) & SCL_in) == SCL_in); - mtx_unlock(&Giant); + ppb_lock(ppbus); + rval = ((ppb_rstr(ppbus) & SCL_in) == SCL_in); + ppb_unlock(ppbus); return (rval); } static int lpbb_getsda(device_t dev) { + device_t ppbus = device_get_parent(dev); int rval; - mtx_lock(&Giant); - rval = ((ppb_rstr(device_get_parent(dev)) & SDA_in) == SDA_in); - mtx_unlock(&Giant); + ppb_lock(ppbus); + rval = ((ppb_rstr(ppbus) & SDA_in) == SDA_in); + ppb_unlock(ppbus); return (rval); } @@ -156,12 +169,12 @@ lpbb_setsda(device_t dev, char val) { device_t ppbus = device_get_parent(dev); - mtx_lock(&Giant); + ppb_lock(ppbus); if (val == 0) ppb_wdtr(ppbus, (u_char)SDA_out); else ppb_wdtr(ppbus, (u_char)~SDA_out); - mtx_unlock(&Giant); + ppb_unlock(ppbus); } static void @@ -169,12 +182,12 @@ lpbb_setscl(device_t dev, unsigned char val) { device_t ppbus = device_get_parent(dev); - mtx_lock(&Giant); + ppb_lock(ppbus); if (val == 0) ppb_wctr(ppbus, (u_char)(ppb_rctr(ppbus) & ~SCL_out)); else ppb_wctr(ppbus, (u_char)(ppb_rctr(ppbus) | SCL_out)); - mtx_unlock(&Giant); + ppb_unlock(ppbus); } static int @@ -182,23 +195,24 @@ lpbb_detect(device_t dev) { device_t ppbus = device_get_parent(dev); + ppb_lock(ppbus); if (ppb_request_bus(ppbus, dev, PPB_DONTWAIT)) { + ppb_unlock(ppbus); device_printf(dev, "can't allocate ppbus\n"); return (0); } - /* reset bus */ - lpbb_setsda(dev, 1); - lpbb_setscl(dev, 1); + lpbb_reset_bus(dev); if ((ppb_rstr(ppbus) & I2CKEY) || ((ppb_rstr(ppbus) & ALIM) != ALIM)) { - ppb_release_bus(ppbus, dev); + ppb_unlock(ppbus); return (0); } ppb_release_bus(ppbus, dev); + ppb_unlock(ppbus); return (1); } @@ -208,18 +222,17 @@ lpbb_reset(device_t dev, u_char speed, u_char addr, u_char * oldaddr) { device_t ppbus = device_get_parent(dev); - mtx_lock(&Giant); + ppb_lock(ppbus); if (ppb_request_bus(ppbus, dev, PPB_DONTWAIT)) { + ppb_unlock(ppbus); device_printf(dev, "can't allocate ppbus\n"); return (0); } - /* reset bus */ - lpbb_setsda(dev, 1); - lpbb_setscl(dev, 1); + lpbb_reset_bus(dev); ppb_release_bus(ppbus, dev); - mtx_unlock(&Giant); + ppb_unlock(ppbus); return (IIC_ENOADDR); } diff --git a/sys/dev/ppbus/lpt.c b/sys/dev/ppbus/lpt.c index 3659252..e4288fc 100644 --- a/sys/dev/ppbus/lpt.c +++ b/sys/dev/ppbus/lpt.c @@ -105,9 +105,9 @@ static int volatile lptflag = 1; #define BUFSTATSIZE 32 struct lpt_data { - device_t dev; - struct cdev *cdev; - struct cdev *cdev_bypass; + device_t sc_dev; + struct cdev *sc_cdev; + struct cdev *sc_cdev_bypass; short sc_state; /* default case: negative prime, negative ack, handshake strobe, prime once */ @@ -130,9 +130,10 @@ struct lpt_data { #define LP_ENABLE_IRQ 0x04 /* enable IRQ on open */ #define LP_ENABLE_EXT 0x10 /* we shall use advanced mode when possible */ u_char sc_backoff ; /* time to call lptout() again */ + struct callout sc_timer; - struct resource *intr_resource; /* interrupt resource */ - void *intr_cookie; /* interrupt registration cookie */ + struct resource *sc_intr_resource; /* interrupt resource */ + void *sc_intr_cookie; /* interrupt cookie */ }; #define LPT_NAME "lpt" /* our official name */ @@ -144,8 +145,7 @@ static int lpt_detect(device_t dev); #define DEVTOSOFTC(dev) \ ((struct lpt_data *)device_get_softc(dev)) -static void lptintr(device_t dev); -static void lpt_intr(void *arg); /* without spls */ +static void lptintr(void *arg); static devclass_t lpt_devclass; @@ -183,7 +183,6 @@ static d_ioctl_t lptioctl; static struct cdevsw lpt_cdevsw = { .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, .d_open = lptopen, .d_close = lptclose, .d_read = lptread, @@ -199,13 +198,17 @@ lpt_request_ppbus(device_t dev, int how) struct lpt_data *sc = DEVTOSOFTC(dev); int error; + /* + * We might already have the bus for a write(2) after an interrupted + * write(2) call. + */ + ppb_assert_locked(ppbus); if (sc->sc_state & HAVEBUS) return (0); - /* we have the bus only if the request succeded */ - if ((error = ppb_request_bus(ppbus, dev, how)) == 0) + error = ppb_request_bus(ppbus, dev, how); + if (error == 0) sc->sc_state |= HAVEBUS; - return (error); } @@ -216,9 +219,12 @@ lpt_release_ppbus(device_t dev) struct lpt_data *sc = DEVTOSOFTC(dev); int error = 0; - if ((error = ppb_release_bus(ppbus, dev)) == 0) - sc->sc_state &= ~HAVEBUS; - + ppb_assert_locked(ppbus); + if (sc->sc_state & HAVEBUS) { + error = ppb_release_bus(ppbus, dev); + if (error == 0) + sc->sc_state &= ~HAVEBUS; + } return (error); } @@ -306,24 +312,25 @@ lpt_detect(device_t dev) status = 1; /* assume success */ + ppb_lock(ppbus); if ((error = lpt_request_ppbus(dev, PPB_DONTWAIT))) { - printf(LPT_NAME ": cannot alloc ppbus (%d)!\n", error); - status = 0; - goto end_probe; + ppb_unlock(ppbus); + device_printf(dev, "cannot alloc ppbus (%d)!\n", error); + return (0); } for (i = 0; i < 18 && status; i++) if (!lpt_port_test(ppbus, testbyte[i], 0xff)) { status = 0; - goto end_probe; + break; } -end_probe: /* write 0's to control and data ports */ ppb_wdtr(ppbus, 0); ppb_wctr(ppbus, 0); lpt_release_ppbus(dev); + ppb_unlock(ppbus); return (status); } @@ -363,21 +370,33 @@ lpt_attach(device_t dev) int error; sc->sc_primed = 0; /* not primed yet */ + ppb_init_callout(ppbus, &sc->sc_timer, 0); + ppb_lock(ppbus); if ((error = lpt_request_ppbus(dev, PPB_DONTWAIT))) { - printf(LPT_NAME ": cannot alloc ppbus (%d)!\n", error); + ppb_unlock(ppbus); + device_printf(dev, "cannot alloc ppbus (%d)!\n", error); return (0); } ppb_wctr(ppbus, LPC_NINIT); - - /* check if we can use interrupt, should be done by ppc stuff */ - lprintf(("oldirq %x\n", sc->sc_irq)); + ppb_unlock(ppbus); + lpt_release_ppbus(dev); /* declare our interrupt handler */ - sc->intr_resource = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + sc->sc_intr_resource = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE); - if (sc->intr_resource) { + if (sc->sc_intr_resource) { + error = bus_setup_intr(dev, sc->sc_intr_resource, + INTR_TYPE_TTY | INTR_MPSAFE, NULL, lptintr, sc, + &sc->sc_intr_cookie); + if (error) { + bus_release_resource(dev, SYS_RES_IRQ, rid, + sc->sc_intr_resource); + device_printf(dev, + "Unable to register interrupt handler\n"); + return (error); + } sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ; device_printf(dev, "Interrupt-driven port\n"); } else { @@ -386,17 +405,17 @@ lpt_attach(device_t dev) } lprintf(("irq %x\n", sc->sc_irq)); - lpt_release_ppbus(dev); - - sc->dev = dev; - sc->cdev = make_dev(&lpt_cdevsw, unit, + sc->sc_inbuf = malloc(BUFSIZE, M_DEVBUF, M_WAITOK); + sc->sc_statbuf = malloc(BUFSTATSIZE, M_DEVBUF, M_WAITOK); + sc->sc_dev = dev; + sc->sc_cdev = make_dev(&lpt_cdevsw, unit, UID_ROOT, GID_WHEEL, 0600, LPT_NAME "%d", unit); - sc->cdev->si_drv1 = sc; - sc->cdev->si_drv2 = 0; - sc->cdev_bypass = make_dev(&lpt_cdevsw, unit, + sc->sc_cdev->si_drv1 = sc; + sc->sc_cdev->si_drv2 = 0; + sc->sc_cdev_bypass = make_dev(&lpt_cdevsw, unit, UID_ROOT, GID_WHEEL, 0600, LPT_NAME "%d.ctl", unit); - sc->cdev_bypass->si_drv1 = sc; - sc->cdev_bypass->si_drv2 = (void *)LP_BYPASS; + sc->sc_cdev_bypass->si_drv1 = sc; + sc->sc_cdev_bypass->si_drv2 = (void *)LP_BYPASS; return (0); } @@ -404,15 +423,21 @@ static int lpt_detach(device_t dev) { struct lpt_data *sc = DEVTOSOFTC(dev); + device_t ppbus = device_get_parent(dev); - destroy_dev(sc->cdev); - destroy_dev(sc->cdev_bypass); + destroy_dev(sc->sc_cdev); + destroy_dev(sc->sc_cdev_bypass); + ppb_lock(ppbus); lpt_release_ppbus(dev); - if (sc->intr_resource != 0) { - BUS_TEARDOWN_INTR(device_get_parent(dev), dev, - sc->intr_resource, sc->intr_cookie); - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->intr_resource); + ppb_unlock(ppbus); + callout_drain(&sc->sc_timer); + if (sc->sc_intr_resource != NULL) { + bus_teardown_intr(dev, sc->sc_intr_resource, + sc->sc_intr_cookie); + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_intr_resource); } + free(sc->sc_inbuf, M_DEVBUF); + free(sc->sc_statbuf, M_DEVBUF); return (0); } @@ -420,18 +445,17 @@ lpt_detach(device_t dev) static void lptout(void *arg) { - device_t dev = (device_t)arg; - struct lpt_data *sc = DEVTOSOFTC(dev); -#ifdef LPT_DEBUG + struct lpt_data *sc = arg; + device_t dev = sc->sc_dev; device_t ppbus = device_get_parent(dev); -#endif + ppb_assert_locked(ppbus); lprintf(("T %x ", ppb_rstr(ppbus))); if (sc->sc_state & OPEN) { sc->sc_backoff++; if (sc->sc_backoff > hz/LPTOUTMAX) sc->sc_backoff = sc->sc_backoff > hz/LPTOUTMAX; - timeout(lptout, (caddr_t)dev, sc->sc_backoff); + callout_reset(&sc->sc_timer, sc->sc_backoff, lptout, sc); } else sc->sc_state &= ~TOUT; @@ -442,7 +466,7 @@ lptout(void *arg) * Avoid possible hangs due to missed interrupts */ if (sc->sc_xfercnt) { - lptintr(dev); + lptintr(sc); } else { sc->sc_state &= ~OBUSY; wakeup(dev); @@ -458,17 +482,19 @@ lptout(void *arg) static int lptopen(struct cdev *dev, int flags, int fmt, struct thread *td) { - int s; int trys, err; struct lpt_data *sc = dev->si_drv1; - device_t lptdev = sc->dev; + device_t lptdev = sc->sc_dev; device_t ppbus = device_get_parent(lptdev); if (!sc) return (ENXIO); + ppb_lock(ppbus); if (sc->sc_state) { - lprintf((LPT_NAME ": still open %x\n", sc->sc_state)); + lprintf(("%s: still open %x\n", device_get_nameunit(lptdev), + sc->sc_state)); + ppb_unlock(ppbus); return(EBUSY); } else sc->sc_state |= LPTINIT; @@ -478,6 +504,7 @@ lptopen(struct cdev *dev, int flags, int fmt, struct thread *td) /* Check for open with BYPASS flag set. */ if (sc->sc_flags & LP_BYPASS) { sc->sc_state = OPEN; + ppb_unlock(ppbus); return(0); } @@ -485,11 +512,12 @@ lptopen(struct cdev *dev, int flags, int fmt, struct thread *td) if ((err = lpt_request_ppbus(lptdev, PPB_WAIT|PPB_INTR)) != 0) { /* give it a chance to try later */ sc->sc_state = 0; + ppb_unlock(ppbus); return (err); } - s = spltty(); - lprintf((LPT_NAME " flags 0x%x\n", sc->sc_flags)); + lprintf(("%s flags 0x%x\n", device_get_nameunit(lptdev), + sc->sc_flags)); /* set IRQ status according to ENABLE_IRQ flag */ @@ -514,21 +542,21 @@ lptopen(struct cdev *dev, int flags, int fmt, struct thread *td) do { /* ran out of waiting for the printer */ if (trys++ >= LPINITRDY*4) { - splx(s); sc->sc_state = 0; lprintf(("status %x\n", ppb_rstr(ppbus))); lpt_release_ppbus(lptdev); + ppb_unlock(ppbus); return (EBUSY); } /* wait 1/4 second, give up if we get a signal */ - if (tsleep(lptdev, LPPRI|PCATCH, "lptinit", hz/4) != - EWOULDBLOCK) { + if (ppb_sleep(ppbus, lptdev, LPPRI | PCATCH, "lptinit", + hz / 4) != EWOULDBLOCK) { sc->sc_state = 0; - splx(s); lpt_release_ppbus(lptdev); + ppb_unlock(ppbus); return (EBUSY); } @@ -548,22 +576,20 @@ lptopen(struct cdev *dev, int flags, int fmt, struct thread *td) ppb_wctr(ppbus, sc->sc_control); sc->sc_state = OPEN; - sc->sc_inbuf = malloc(BUFSIZE, M_DEVBUF, M_WAITOK); - sc->sc_statbuf = malloc(BUFSTATSIZE, M_DEVBUF, M_WAITOK); sc->sc_xfercnt = 0; - splx(s); - - /* release the ppbus */ - lpt_release_ppbus(lptdev); /* only use timeout if using interrupt */ lprintf(("irq %x\n", sc->sc_irq)); if (sc->sc_irq & LP_USE_IRQ) { sc->sc_state |= TOUT; - timeout(lptout, (caddr_t)lptdev, - (sc->sc_backoff = hz/LPTOUTINITIAL)); + sc->sc_backoff = hz / LPTOUTINITIAL; + callout_reset(&sc->sc_timer, sc->sc_backoff, lptout, sc); } + /* release the ppbus */ + lpt_release_ppbus(lptdev); + ppb_unlock(ppbus); + lprintf(("opened.\n")); return(0); } @@ -578,17 +604,21 @@ static int lptclose(struct cdev *dev, int flags, int fmt, struct thread *td) { struct lpt_data *sc = dev->si_drv1; - device_t lptdev = sc->dev; + device_t lptdev = sc->sc_dev; device_t ppbus = device_get_parent(lptdev); int err; - if (sc->sc_flags & LP_BYPASS) + ppb_lock(ppbus); + if (sc->sc_flags & LP_BYPASS) { + sc->sc_state = 0; + ppb_unlock(ppbus); goto end_close; + } - if ((err = lpt_request_ppbus(lptdev, PPB_WAIT|PPB_INTR)) != 0) + if ((err = lpt_request_ppbus(lptdev, PPB_WAIT|PPB_INTR)) != 0) { + ppb_unlock(ppbus); return (err); - - sc->sc_state &= ~OPEN; + } /* if the last write was interrupted, don't complete it */ if ((!(sc->sc_state & INTERRUPTED)) && (sc->sc_irq & LP_USE_IRQ)) @@ -596,22 +626,23 @@ lptclose(struct cdev *dev, int flags, int fmt, struct thread *td) (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != (LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt) /* wait 1/4 second, give up if we get a signal */ - if (tsleep(lptdev, LPPRI|PCATCH, - "lpclose", hz) != EWOULDBLOCK) + if (ppb_sleep(ppbus, lptdev, LPPRI | PCATCH, "lpclose", + hz) != EWOULDBLOCK) break; + sc->sc_state &= ~OPEN; + callout_stop(&sc->sc_timer); ppb_wctr(ppbus, LPC_NINIT); - free(sc->sc_inbuf, M_DEVBUF); - free(sc->sc_statbuf, M_DEVBUF); + sc->sc_state = 0; + sc->sc_xfercnt = 0; -end_close: - /* release the bus anyway + /* * unregistration of interrupt forced by release */ lpt_release_ppbus(lptdev); + ppb_unlock(ppbus); - sc->sc_state = 0; - sc->sc_xfercnt = 0; +end_close: lprintf(("closed.\n")); return(0); } @@ -625,13 +656,14 @@ end_close: * This code is only used when we are polling the port */ static int -lpt_pushbytes(device_t dev) +lpt_pushbytes(struct lpt_data *sc) { - struct lpt_data *sc = DEVTOSOFTC(dev); + device_t dev = sc->sc_dev; device_t ppbus = device_get_parent(dev); int spin, err, tic; char ch; + ppb_assert_locked(ppbus); lprintf(("p")); /* loop for every character .. */ while (sc->sc_xfercnt > 0) { @@ -660,7 +692,7 @@ lpt_pushbytes(device_t dev) */ if (tic > MAX_SLEEP) tic = MAX_SLEEP; - err = tsleep(dev, LPPRI, + err = ppb_sleep(ppbus, dev, LPPRI, LPT_NAME "poll", tic); if (err != EWOULDBLOCK) { return (err); @@ -686,7 +718,7 @@ static int lptread(struct cdev *dev, struct uio *uio, int ioflag) { struct lpt_data *sc = dev->si_drv1; - device_t lptdev = sc->dev; + device_t lptdev = sc->sc_dev; device_t ppbus = device_get_parent(lptdev); int error = 0, len; @@ -695,8 +727,11 @@ lptread(struct cdev *dev, struct uio *uio, int ioflag) return (EPERM); } - if ((error = ppb_1284_negociate(ppbus, PPB_NIBBLE, 0))) + ppb_lock(ppbus); + if ((error = ppb_1284_negociate(ppbus, PPB_NIBBLE, 0))) { + ppb_unlock(ppbus); return (error); + } /* read data in an other buffer, read/write may be simultaneous */ len = 0; @@ -710,12 +745,16 @@ lptread(struct cdev *dev, struct uio *uio, int ioflag) if (!len) goto error; /* no more data */ - if ((error = uiomove(sc->sc_statbuf, len, uio))) + ppb_unlock(ppbus); + error = uiomove(sc->sc_statbuf, len, uio); + ppb_lock(ppbus); + if (error) goto error; } error: ppb_1284_terminate(ppbus); + ppb_unlock(ppbus); return (error); } @@ -732,36 +771,30 @@ lptwrite(struct cdev *dev, struct uio *uio, int ioflag) register unsigned n; int err; struct lpt_data *sc = dev->si_drv1; - device_t lptdev = sc->dev; + device_t lptdev = sc->sc_dev; device_t ppbus = device_get_parent(lptdev); if (sc->sc_flags & LP_BYPASS) { /* we can't do writes in bypass mode */ - return(EPERM); + return (EPERM); } /* request the ppbus only if we don't have it already */ - /* XXX interrupt registration?! */ - if ((err = lpt_request_ppbus(lptdev, PPB_WAIT|PPB_INTR)) != 0) + ppb_lock(ppbus); + if ((err = lpt_request_ppbus(lptdev, PPB_WAIT|PPB_INTR)) != 0) { + ppb_unlock(ppbus); return (err); - - /* if interrupts are working, register the handler */ - if (sc->sc_irq & LP_USE_IRQ) { - /* register our interrupt handler */ - err = bus_setup_intr(lptdev, sc->intr_resource, - INTR_TYPE_TTY, NULL, lpt_intr, lptdev, - &sc->intr_cookie); - if (err) { - device_printf(lptdev, "handler registration failed, polled mode.\n"); - sc->sc_irq &= ~LP_USE_IRQ; - } } sc->sc_state &= ~INTERRUPTED; while ((n = min(BUFSIZE, uio->uio_resid)) != 0) { sc->sc_cp = sc->sc_inbuf; - uiomove(sc->sc_cp, n, uio); - sc->sc_xfercnt = n ; + ppb_unlock(ppbus); + err = uiomove(sc->sc_cp, n, uio); + ppb_lock(ppbus); + if (err) + break; + sc->sc_xfercnt = n; if (sc->sc_irq & LP_ENABLE_EXT) { /* try any extended mode */ @@ -775,15 +808,17 @@ lptwrite(struct cdev *dev, struct uio *uio, int ioflag) break; case EINTR: sc->sc_state |= INTERRUPTED; - return(err); + ppb_unlock(ppbus); + return (err); case EINVAL: /* advanced mode not avail */ log(LOG_NOTICE, "%s: advanced mode not avail, polling\n", - device_get_nameunit(sc->dev)); + device_get_nameunit(sc->sc_dev)); break; default: - return(err); + ppb_unlock(ppbus); + return (err); } } else while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) { lprintf(("i")); @@ -791,13 +826,14 @@ lptwrite(struct cdev *dev, struct uio *uio, int ioflag) /* give it one */ if ((sc->sc_state & OBUSY) == 0){ lprintf(("\nC %d. ", sc->sc_xfercnt)); - lptintr(lptdev); + lptintr(sc); } lprintf(("W ")); if (sc->sc_state & OBUSY) - if ((err = tsleep(lptdev, + if ((err = ppb_sleep(ppbus, lptdev, LPPRI|PCATCH, LPT_NAME "write", 0))) { sc->sc_state |= INTERRUPTED; + ppb_unlock(ppbus); return(err); } } @@ -806,38 +842,37 @@ lptwrite(struct cdev *dev, struct uio *uio, int ioflag) if (!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) { lprintf(("p")); - err = lpt_pushbytes(lptdev); + err = lpt_pushbytes(sc); - if (err) - return(err); + if (err) { + ppb_unlock(ppbus); + return (err); + } } } /* we have not been interrupted, release the ppbus */ lpt_release_ppbus(lptdev); + ppb_unlock(ppbus); - return(0); + return (err); } /* - * lpt_intr -- handle printer interrupts which occur when the printer is + * lptintr -- handle printer interrupts which occur when the printer is * ready to accept another char. * * do checking for interrupted write call. */ static void -lpt_intr(void *arg) +lptintr(void *arg) { - device_t lptdev = (device_t)arg; + struct lpt_data *sc = arg; + device_t lptdev = sc->sc_dev; device_t ppbus = device_get_parent(lptdev); - struct lpt_data *sc = DEVTOSOFTC(lptdev); int sts = 0; int i; - /* we must own the bus to use it */ - if ((sc->sc_state & HAVEBUS) == 0) - return; - /* * Is printer online and ready for output? * @@ -883,27 +918,18 @@ lpt_intr(void *arg) lprintf(("sts %x ", sts)); } -static void -lptintr(device_t dev) -{ - /* call the interrupt at required spl level */ - int s = spltty(); - - lpt_intr(dev); - - splx(s); - return; -} - static int lptioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td) { int error = 0; struct lpt_data *sc = dev->si_drv1; + device_t ppbus; u_char old_sc_irq; /* old printer IRQ status */ switch (cmd) { case LPT_IRQ : + ppbus = device_get_parent(sc->sc_dev); + ppb_lock(ppbus); if (sc->sc_irq & LP_HAS_IRQ) { /* * NOTE: @@ -915,7 +941,7 @@ lptioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t * this gets syslog'd. */ old_sc_irq = sc->sc_irq; - switch(*(int*)data) { + switch (*(int*)data) { case 0: sc->sc_irq &= (~LP_ENABLE_IRQ); break; @@ -939,13 +965,14 @@ lptioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t if (old_sc_irq != sc->sc_irq ) log(LOG_NOTICE, "%s: switched to %s %s mode\n", - device_get_nameunit(sc->dev), + device_get_nameunit(sc->sc_dev), (sc->sc_irq & LP_ENABLE_IRQ)? "interrupt-driven":"polled", (sc->sc_irq & LP_ENABLE_EXT)? "extended":"standard"); } else /* polled port */ error = EOPNOTSUPP; + ppb_unlock(ppbus); break; default: error = ENODEV; diff --git a/sys/dev/ppbus/pcfclock.c b/sys/dev/ppbus/pcfclock.c index a969a84..e59a891 100644 --- a/sys/dev/ppbus/pcfclock.c +++ b/sys/dev/ppbus/pcfclock.c @@ -54,7 +54,6 @@ __FBSDID("$FreeBSD$"); struct pcfclock_data { device_t dev; struct cdev *cdev; - int count; }; static devclass_t pcfclock_devclass; @@ -65,7 +64,6 @@ static d_read_t pcfclock_read; static struct cdevsw pcfclock_cdevsw = { .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, .d_open = pcfclock_open, .d_close = pcfclock_close, .d_read = pcfclock_read, @@ -159,13 +157,11 @@ pcfclock_open(struct cdev *dev, int flag, int fms, struct thread *td) if (!sc) return (ENXIO); - if ((res = ppb_request_bus(ppbus, pcfclockdev, - (flag & O_NONBLOCK) ? PPB_DONTWAIT : PPB_WAIT))) - return (res); - - sc->count++; - - return (0); + ppb_lock(ppbus); + res = ppb_request_bus(ppbus, pcfclockdev, + (flag & O_NONBLOCK) ? PPB_DONTWAIT : PPB_WAIT); + ppb_unlock(ppbus); + return (res); } static int @@ -175,9 +171,9 @@ pcfclock_close(struct cdev *dev, int flags, int fmt, struct thread *td) device_t pcfclockdev = sc->dev; device_t ppbus = device_get_parent(pcfclockdev); - sc->count--; - if (sc->count == 0) - ppb_release_bus(ppbus, pcfclockdev); + ppb_lock(ppbus); + ppb_release_bus(ppbus, pcfclockdev); + ppb_unlock(ppbus); return (0); } @@ -240,7 +236,7 @@ pcfclock_read_data(struct cdev *dev, char *buf, ssize_t bits) waitfor = 100; for (i = 0; i <= bits; i++) { /* wait for clock, maximum (waitfor*100) usec */ - while(!CLOCK_OK && --waitfor > 0) + while (!CLOCK_OK && --waitfor > 0) DELAY(100); /* timed out? */ @@ -297,13 +293,17 @@ static int pcfclock_read(struct cdev *dev, struct uio *uio, int ioflag) { struct pcfclock_data *sc = dev->si_drv1; + device_t ppbus; char buf[18]; int error = 0; if (uio->uio_resid < 18) return (ERANGE); + ppbus = device_get_parent(sc->dev); + ppb_lock(ppbus); error = pcfclock_read_dev(dev, buf, PCFCLOCK_MAX_RETRIES); + ppb_unlock(ppbus); if (error) { device_printf(sc->dev, "no PCF found\n"); diff --git a/sys/dev/ppbus/ppb_1284.c b/sys/dev/ppbus/ppb_1284.c index 28ee321..e909e8e 100644 --- a/sys/dev/ppbus/ppb_1284.c +++ b/sys/dev/ppbus/ppb_1284.c @@ -36,6 +36,8 @@ __FBSDID("$FreeBSD$"); #include "opt_ppb_1284.h" #include <sys/param.h> +#include <sys/lock.h> +#include <sys/mutex.h> #include <sys/systm.h> #include <sys/bus.h> @@ -92,8 +94,10 @@ ppb_1284_reset_error(device_t bus, int state) int ppb_1284_get_state(device_t bus) { + struct ppb_data *ppb = DEVTOSOFTC(bus); - return (DEVTOSOFTC(bus)->state); + mtx_assert(ppb->ppc_lock, MA_OWNED); + return (ppb->state); } /* @@ -108,6 +112,7 @@ ppb_1284_set_state(device_t bus, int state) /* call ppb_1284_reset_error() if you absolutly want to change * the state from PPB_ERROR to another */ + mtx_assert(ppb->ppc_lock, MA_OWNED); if ((ppb->state != PPB_ERROR) && (ppb->error == PPB_NO_ERROR)) { ppb->state = state; diff --git a/sys/dev/ppbus/ppb_base.c b/sys/dev/ppbus/ppb_base.c index c288616..30c42a4 100644 --- a/sys/dev/ppbus/ppb_base.c +++ b/sys/dev/ppbus/ppb_base.c @@ -28,9 +28,11 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> -#include <sys/systm.h> +#include <sys/lock.h> #include <sys/kernel.h> #include <sys/module.h> +#include <sys/mutex.h> +#include <sys/systm.h> #include <sys/bus.h> #include <dev/ppbus/ppbconf.h> @@ -54,9 +56,12 @@ int ppb_poll_bus(device_t bus, int max, char mask, char status, int how) { + struct ppb_data *ppb = DEVTOSOFTC(bus); int i, j, error; char r; + mtx_assert(ppb->ppc_lock, MA_OWNED); + /* try at least up to 10ms */ for (j = 0; j < ((how & PPB_POLL) ? max : 1); j++) { for (i = 0; i < 10000; i++) { @@ -72,21 +77,11 @@ ppb_poll_bus(device_t bus, int max, if ((ppb_rstr(bus) & mask) == status) return (0); - switch (how) { - case PPB_NOINTR: - /* wait 10 ms */ - pause("ppbpoll", hz/100); - break; - - case PPB_INTR: - default: - /* wait 10 ms */ - if (((error = tsleep((caddr_t)bus, PPBPRI | PCATCH, - "ppbpoll", hz/100)) != EWOULDBLOCK) != 0) { - return (error); - } - break; - } + /* wait 10 ms */ + error = mtx_sleep((caddr_t)bus, ppb->ppc_lock, PPBPRI | + (how == PPB_NOINTR ? 0 : PCATCH), "ppbpoll", hz/100); + if (error != EWOULDBLOCK) + return (error); } } @@ -101,8 +96,12 @@ ppb_poll_bus(device_t bus, int max, int ppb_get_epp_protocol(device_t bus) { +#ifdef INVARIANTS + struct ppb_data *ppb = DEVTOSOFTC(bus); +#endif uintptr_t protocol; + mtx_assert(ppb->ppc_lock, MA_OWNED); BUS_READ_IVAR(device_get_parent(bus), bus, PPC_IVAR_EPP_PROTO, &protocol); return (protocol); @@ -118,6 +117,7 @@ ppb_get_mode(device_t bus) struct ppb_data *ppb = DEVTOSOFTC(bus); /* XXX yet device mode = ppbus mode = chipset mode */ + mtx_assert(ppb->ppc_lock, MA_OWNED); return (ppb->mode); } @@ -132,6 +132,7 @@ ppb_set_mode(device_t bus, int mode) struct ppb_data *ppb = DEVTOSOFTC(bus); int old_mode = ppb_get_mode(bus); + mtx_assert(ppb->ppc_lock, MA_OWNED); if (PPBUS_SETMODE(device_get_parent(bus), mode)) return (-1); @@ -149,6 +150,11 @@ ppb_set_mode(device_t bus, int mode) int ppb_write(device_t bus, char *buf, int len, int how) { +#ifdef INVARIANTS + struct ppb_data *ppb = DEVTOSOFTC(bus); +#endif + + mtx_assert(ppb->ppc_lock, MA_OWNED); return (PPBUS_WRITE(device_get_parent(bus), buf, len, how)); } @@ -160,6 +166,11 @@ ppb_write(device_t bus, char *buf, int len, int how) int ppb_reset_epp_timeout(device_t bus) { +#ifdef INVARIANTS + struct ppb_data *ppb = DEVTOSOFTC(bus); +#endif + + mtx_assert(ppb->ppc_lock, MA_OWNED); return(PPBUS_RESET_EPP(device_get_parent(bus))); } @@ -171,6 +182,11 @@ ppb_reset_epp_timeout(device_t bus) int ppb_ecp_sync(device_t bus) { +#ifdef INVARIANTS + struct ppb_data *ppb = DEVTOSOFTC(bus); +#endif + + mtx_assert(ppb->ppc_lock, MA_OWNED); return (PPBUS_ECP_SYNC(device_get_parent(bus))); } @@ -182,8 +198,13 @@ ppb_ecp_sync(device_t bus) int ppb_get_status(device_t bus, struct ppb_status *status) { +#ifdef INVARIANTS + struct ppb_data *ppb = DEVTOSOFTC(bus); +#endif register char r; + mtx_assert(ppb->ppc_lock, MA_OWNED); + r = status->status = ppb_rstr(bus); status->timeout = r & TIMEOUT; @@ -195,3 +216,45 @@ ppb_get_status(device_t bus, struct ppb_status *status) return (0); } + +void +ppb_lock(device_t bus) +{ + struct ppb_data *ppb = DEVTOSOFTC(bus); + + mtx_lock(ppb->ppc_lock); +} + +void +ppb_unlock(device_t bus) +{ + struct ppb_data *ppb = DEVTOSOFTC(bus); + + mtx_unlock(ppb->ppc_lock); +} + +void +_ppb_assert_locked(device_t bus, const char *file, int line) +{ +#ifdef INVARIANTS + struct ppb_data *ppb = DEVTOSOFTC(bus); + + _mtx_assert(ppb->ppc_lock, MA_OWNED, file, line); +#endif +} + +void +ppb_init_callout(device_t bus, struct callout *c, int flags) +{ + struct ppb_data *ppb = DEVTOSOFTC(bus); + + callout_init_mtx(c, ppb->ppc_lock, flags); +} + +int +ppb_sleep(device_t bus, void *wchan, int priority, const char *wmesg, int timo) +{ + struct ppb_data *ppb = DEVTOSOFTC(bus); + + return (mtx_sleep(wchan, ppb->ppc_lock, priority, wmesg, timo)); +} diff --git a/sys/dev/ppbus/ppb_msq.c b/sys/dev/ppbus/ppb_msq.c index a02f9e1..89be014 100644 --- a/sys/dev/ppbus/ppb_msq.c +++ b/sys/dev/ppbus/ppb_msq.c @@ -31,6 +31,8 @@ __FBSDID("$FreeBSD$"); #include <machine/stdarg.h> #include <sys/param.h> +#include <sys/lock.h> +#include <sys/mutex.h> #include <sys/systm.h> #include <sys/bus.h> @@ -115,9 +117,13 @@ mode2xfer(device_t bus, struct ppb_device *ppbdev, int opcode) int ppb_MS_init(device_t bus, device_t dev, struct ppb_microseq *loop, int opcode) { +#ifdef INVARIANTS + struct ppb_data *ppb = device_get_softc(bus); +#endif struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); struct ppb_xfer *xfer = mode2xfer(bus, ppbdev, opcode); + mtx_assert(ppb->ppc_lock, MA_OWNED); xfer->loop = loop; return (0); @@ -265,6 +271,7 @@ ppb_MS_microseq(device_t bus, device_t dev, struct ppb_microseq *msq, int *ret) MS_RET(0) }; + mtx_assert(ppb->ppc_lock, MA_OWNED); if (ppb->ppb_owner != dev) return (EACCES); diff --git a/sys/dev/ppbus/ppbconf.c b/sys/dev/ppbus/ppbconf.c index 196e2b8..a3617be 100644 --- a/sys/dev/ppbus/ppbconf.c +++ b/sys/dev/ppbus/ppbconf.c @@ -33,7 +33,9 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/lock.h> #include <sys/module.h> +#include <sys/mutex.h> #include <sys/bus.h> #include <sys/malloc.h> #include <sys/rman.h> @@ -50,6 +52,8 @@ __FBSDID("$FreeBSD$"); static MALLOC_DEFINE(M_PPBUSDEV, "ppbusdev", "Parallel Port bus device"); +static int ppbus_intr(void *arg); + /* * Device methods */ @@ -375,13 +379,36 @@ end_scan: static int ppbus_attach(device_t dev) { + struct ppb_data *ppb = device_get_softc(dev); + int error, rid; + + error = BUS_READ_IVAR(device_get_parent(dev), dev, PPC_IVAR_LOCK, + (uintptr_t *)&ppb->ppc_lock); + if (error) { + device_printf(dev, "Unable to fetch parent's lock\n"); + return (error); + } + + rid = 0; + ppb->ppc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_SHAREABLE); + if (ppb->ppc_irq_res != NULL) { + error = BUS_WRITE_IVAR(device_get_parent(dev), dev, + PPC_IVAR_INTR_HANDLER, (uintptr_t)&ppbus_intr); + if (error) { + device_printf(dev, "Unable to set interrupt handler\n"); + return (error); + } + } /* Locate our children */ bus_generic_probe(dev); #ifndef DONTPROBE_1284 /* detect IEEE1284 compliant devices */ + mtx_lock(ppb->ppc_lock); ppb_scan_bus(dev); + mtx_unlock(ppb->ppc_lock); #endif /* !DONTPROBE_1284 */ /* launch attachment of the added children */ @@ -412,26 +439,43 @@ ppbus_detach(device_t dev) } static int +ppbus_intr(void *arg) +{ + struct ppb_device *ppbdev; + struct ppb_data *ppb = arg; + + mtx_assert(ppb->ppc_lock, MA_OWNED); + if (ppb->ppb_owner == NULL) + return (ENOENT); + + ppbdev = device_get_ivars(ppb->ppb_owner); + if (ppbdev->intr_hook == NULL) + return (ENOENT); + + ppbdev->intr_hook(ppbdev->intr_arg); + return (0); +} + +static int ppbus_setup_intr(device_t bus, device_t child, struct resource *r, int flags, driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep) { - int error; - struct ppb_data *ppb = DEVTOSOFTC(bus); struct ppb_device *ppbdev = device_get_ivars(child); + struct ppb_data *ppb = DEVTOSOFTC(bus); - /* a device driver must own the bus to register an interrupt */ - if (ppb->ppb_owner != child) + /* We do not support filters. */ + if (filt != NULL || ihand == NULL) return (EINVAL); - if ((error = BUS_SETUP_INTR(device_get_parent(bus), child, r, flags, - filt, ihand, arg, cookiep))) - return (error); + /* Can only attach handlers to the parent device's resource. */ + if (ppb->ppc_irq_res != r) + return (EINVAL); - /* store the resource and the cookie for eventually forcing - * handler unregistration - */ - ppbdev->intr_cookie = *cookiep; - ppbdev->intr_resource = r; + mtx_lock(ppb->ppc_lock); + ppbdev->intr_hook = ihand; + ppbdev->intr_arg = arg; + *cookiep = ppbdev; + mtx_unlock(ppb->ppc_lock); return (0); } @@ -439,19 +483,19 @@ ppbus_setup_intr(device_t bus, device_t child, struct resource *r, int flags, static int ppbus_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih) { + struct ppb_device *ppbdev = device_get_ivars(child); struct ppb_data *ppb = DEVTOSOFTC(bus); - struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(child); - /* a device driver must own the bus to unregister an interrupt */ - if ((ppb->ppb_owner != child) || (ppbdev->intr_cookie != ih) || - (ppbdev->intr_resource != r)) + mtx_lock(ppb->ppc_lock); + if (ppbdev != ih || ppb->ppc_irq_res != r) { + mtx_unlock(ppb->ppc_lock); return (EINVAL); + } - ppbdev->intr_cookie = 0; - ppbdev->intr_resource = 0; + ppbdev->intr_hook = NULL; + mtx_unlock(ppb->ppc_lock); - /* pass unregistration to the upper layer */ - return (BUS_TEARDOWN_INTR(device_get_parent(bus), child, r, ih)); + return (0); } /* @@ -464,27 +508,26 @@ ppbus_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih) int ppb_request_bus(device_t bus, device_t dev, int how) { - int s, error = 0; struct ppb_data *ppb = DEVTOSOFTC(bus); struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); + int error = 0; + mtx_assert(ppb->ppc_lock, MA_OWNED); while (!error) { - s = splhigh(); if (ppb->ppb_owner) { - splx(s); - switch (how) { - case (PPB_WAIT | PPB_INTR): - error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0); + case PPB_WAIT | PPB_INTR: + error = mtx_sleep(ppb, ppb->ppc_lock, + PPBPRI | PCATCH, "ppbreq", 0); break; - case (PPB_WAIT | PPB_NOINTR): - error = tsleep(ppb, PPBPRI, "ppbreq", 0); + case PPB_WAIT | PPB_NOINTR: + error = mtx_sleep(ppb, ppb->ppc_lock, PPBPRI, + "ppbreq", 0); break; default: return (EWOULDBLOCK); - break; } } else { @@ -499,7 +542,6 @@ ppb_request_bus(device_t bus, device_t dev, int how) if (ppbdev->ctx.valid) ppb_set_mode(bus, ppbdev->ctx.mode); - splx(s); return (0); } } @@ -515,24 +557,12 @@ ppb_request_bus(device_t bus, device_t dev, int how) int ppb_release_bus(device_t bus, device_t dev) { - int s, error; struct ppb_data *ppb = DEVTOSOFTC(bus); struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); - if (ppbdev->intr_resource != 0) - /* force interrupt handler unregistration when the ppbus is released */ - if ((error = BUS_TEARDOWN_INTR(bus, dev, ppbdev->intr_resource, - ppbdev->intr_cookie))) - return (error); - - s = splhigh(); - if (ppb->ppb_owner != dev) { - splx(s); + mtx_assert(ppb->ppc_lock, MA_OWNED); + if (ppb->ppb_owner != dev) return (EACCES); - } - - ppb->ppb_owner = 0; - splx(s); /* save the context of the device */ ppbdev->ctx.mode = ppb_get_mode(bus); @@ -540,6 +570,8 @@ ppb_release_bus(device_t bus, device_t dev) /* ok, now the context of the device is valid */ ppbdev->ctx.valid = 1; + ppb->ppb_owner = 0; + /* wakeup waiting processes */ wakeup(ppb); diff --git a/sys/dev/ppbus/ppbconf.h b/sys/dev/ppbus/ppbconf.h index 482d34f..9981a9a 100644 --- a/sys/dev/ppbus/ppbconf.h +++ b/sys/dev/ppbus/ppbconf.h @@ -199,8 +199,8 @@ struct ppb_device { struct ppb_xfer put_xfer[PPB_MAX_XFER]; - struct resource *intr_resource; - void *intr_cookie; + driver_intr_t *intr_hook; + void *intr_arg; }; /* EPP standards */ @@ -209,6 +209,8 @@ struct ppb_device { /* Parallel Port Chipset IVARS */ /* elsewhere XXX */ #define PPC_IVAR_EPP_PROTO 0 +#define PPC_IVAR_LOCK 1 +#define PPC_IVAR_INTR_HANDLER 2 /* * Maximum size of the PnP info string @@ -239,15 +241,27 @@ struct ppb_data { int mode; /* IEEE 1284-1994 mode * NIBBLE, PS2, EPP or ECP */ - void *ppb_owner; /* device which owns the bus */ + device_t ppb_owner; /* device which owns the bus */ + + struct mtx *ppc_lock; /* lock of parent device */ + struct resource *ppc_irq_res; }; +struct callout; + +typedef int (*ppc_intr_handler)(void *); + #ifdef _KERNEL extern int ppb_attach_device(device_t); extern int ppb_request_bus(device_t, device_t, int); extern int ppb_release_bus(device_t, device_t); /* bus related functions */ +extern void ppb_lock(device_t); +extern void ppb_unlock(device_t); +extern void _ppb_assert_locked(device_t, const char *, int); +extern void ppb_init_callout(device_t, struct callout *, int); +extern int ppb_sleep(device_t, void *, int, const char *, int); extern int ppb_get_status(device_t, struct ppb_status *); extern int ppb_poll_bus(device_t, int, char, char, int); extern int ppb_reset_epp_timeout(device_t); @@ -256,12 +270,12 @@ extern int ppb_get_epp_protocol(device_t); extern int ppb_set_mode(device_t, int); /* returns old mode */ extern int ppb_get_mode(device_t); /* returns current mode */ extern int ppb_write(device_t, char *, int, int); -#endif /* _KERNEL */ - -/* - * These are defined as macros for speedup. -#define ppb_get_base_addr(dev) ((dev)->ppb->ppb_link->base) -#define ppb_get_epp_protocol(dev) ((dev)->ppb->ppb_link->epp_protocol) - */ +#ifdef INVARIANTS +#define ppb_assert_locked(dev) _ppb_assert_locked(dev, __FILE__, __LINE__) +#else +#define ppb_assert_locked(dev) #endif +#endif /* _KERNEL */ + +#endif /* !__PPBCONF_H */ diff --git a/sys/dev/ppbus/ppi.c b/sys/dev/ppbus/ppi.c index 8c168d8..2ee8fa6 100644 --- a/sys/dev/ppbus/ppi.c +++ b/sys/dev/ppbus/ppi.c @@ -36,6 +36,8 @@ __FBSDID("$FreeBSD$"); #include <sys/bus.h> #include <sys/conf.h> #include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/sx.h> #include <sys/uio.h> #include <sys/fcntl.h> @@ -47,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include <dev/ppbus/ppb_msq.h> #ifdef PERIPH_1284 +#include <sys/malloc.h> #include <dev/ppbus/ppb_1284.h> #endif @@ -61,11 +64,10 @@ __FBSDID("$FreeBSD$"); struct ppi_data { device_t ppi_device; struct cdev *ppi_cdev; + struct sx ppi_lock; int ppi_flags; #define HAVE_PPBUS (1<<0) -#define HAD_PPBUS (1<<1) - int ppi_count; int ppi_mode; /* IEEE1284 mode */ char ppi_buffer[BUFSIZE]; @@ -80,6 +82,10 @@ struct ppi_data { static devclass_t ppi_devclass; +#ifdef PERIPH_1284 +static void ppiintr(void *arg); +#endif + static d_open_t ppiopen; static d_close_t ppiclose; static d_ioctl_t ppiioctl; @@ -88,7 +94,6 @@ static d_read_t ppiread; static struct cdevsw ppi_cdevsw = { .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, .d_open = ppiopen, .d_close = ppiclose, .d_read = ppiread, @@ -160,13 +165,27 @@ ppi_attach(device_t dev) { struct ppi_data *ppi = DEVTOSOFTC(dev); #ifdef PERIPH_1284 - int rid = 0; + int error, rid = 0; /* declare our interrupt handler */ ppi->intr_resource = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); + if (ppi->intr_resource) { + /* register our interrupt handler */ + error = bus_setup_intr(dev, ppi->intr_resource, + INTR_TYPE_TTY | INTR_MPSAFE, NULL, ppiintr, dev, + &ppi->intr_cookie); + if (error) { + bus_release_resource(dev, SYS_RES_IRQ, rid, + ppi->intr_resource); + device_printf(dev, + "Unable to register interrupt handler\n"); + return (error); + } + } #endif /* PERIPH_1284 */ + sx_init(&ppi->ppi_lock, "ppi"); ppi->ppi_cdev = make_dev(&ppi_cdevsw, device_get_unit(dev), UID_ROOT, GID_WHEEL, 0600, "ppi%d", device_get_unit(dev)); @@ -180,6 +199,22 @@ ppi_attach(device_t dev) return (0); } +static int +ppi_detach(device_t dev) +{ + struct ppi_data *ppi = DEVTOSOFTC(dev); + + destroy_dev(ppi->ppi_cdev); +#ifdef PERIPH_1284 + if (ppi->intr_resource != NULL) { + bus_teardown_intr(dev, ppi->intr_resource, ppi->intr_cookie); + bus_release_resource(dev, SYS_RES_IRQ, 0, ppi->intr_resource); + } +#endif + sx_destroy(&ppi->ppi_lock); + return (0); +} + #ifdef PERIPH_1284 /* * Cable @@ -200,6 +235,7 @@ ppiintr(void *arg) device_t ppbus = device_get_parent(ppidev); struct ppi_data *ppi = DEVTOSOFTC(ppidev); + ppb_assert_locked(ppbus); ppi_disable_intr(ppidev); switch (ppb_1284_get_state(ppbus)) { @@ -259,24 +295,20 @@ ppiopen(struct cdev *dev, int flags, int fmt, struct thread *td) device_t ppbus = device_get_parent(ppidev); int res; + sx_xlock(&ppi->ppi_lock); if (!(ppi->ppi_flags & HAVE_PPBUS)) { - if ((res = ppb_request_bus(ppbus, ppidev, - (flags & O_NONBLOCK) ? PPB_DONTWAIT : - (PPB_WAIT | PPB_INTR)))) + ppb_lock(ppbus); + res = ppb_request_bus(ppbus, ppidev, + (flags & O_NONBLOCK) ? PPB_DONTWAIT : PPB_WAIT | PPB_INTR); + ppb_unlock(ppbus); + if (res) { + sx_xunlock(&ppi->ppi_lock); return (res); + } ppi->ppi_flags |= HAVE_PPBUS; - -#ifdef PERIPH_1284 - if (ppi->intr_resource) { - /* register our interrupt handler */ - bus_setup_intr(ppidev, ppi->intr_resource, - INTR_TYPE_TTY, NULL, ppiintr, dev, - &ppi->intr_cookie); - } -#endif /* PERIPH_1284 */ } - ppi->ppi_count += 1; + sx_xunlock(&ppi->ppi_lock); return (0); } @@ -288,28 +320,28 @@ ppiclose(struct cdev *dev, int flags, int fmt, struct thread *td) device_t ppidev = ppi->ppi_device; device_t ppbus = device_get_parent(ppidev); - ppi->ppi_count --; - if (!ppi->ppi_count) { - + sx_xlock(&ppi->ppi_lock); + ppb_lock(ppbus); #ifdef PERIPH_1284 - switch (ppb_1284_get_state(ppbus)) { - case PPB_PERIPHERAL_IDLE: - ppb_peripheral_terminate(ppbus, 0); - break; - case PPB_REVERSE_IDLE: - case PPB_EPP_IDLE: - case PPB_ECP_FORWARD_IDLE: - default: - ppb_1284_terminate(ppbus); - break; - } + switch (ppb_1284_get_state(ppbus)) { + case PPB_PERIPHERAL_IDLE: + ppb_peripheral_terminate(ppbus, 0); + break; + case PPB_REVERSE_IDLE: + case PPB_EPP_IDLE: + case PPB_ECP_FORWARD_IDLE: + default: + ppb_1284_terminate(ppbus); + break; + } #endif /* PERIPH_1284 */ - /* unregistration of interrupt forced by release */ - ppb_release_bus(ppbus, ppidev); + /* unregistration of interrupt forced by release */ + ppb_release_bus(ppbus, ppidev); + ppb_unlock(ppbus); - ppi->ppi_flags &= ~HAVE_PPBUS; - } + ppi->ppi_flags &= ~HAVE_PPBUS; + sx_xunlock(&ppi->ppi_lock); return (0); } @@ -330,7 +362,11 @@ ppiread(struct cdev *dev, struct uio *uio, int ioflag) device_t ppidev = ppi->ppi_device; device_t ppbus = device_get_parent(ppidev); int len, error = 0; + char *buffer; + buffer = malloc(BUFSIZE, M_DEVBUF, M_WAITOK); + + ppb_lock(ppbus); switch (ppb_1284_get_state(ppbus)) { case PPB_PERIPHERAL_IDLE: ppb_peripheral_terminate(ppbus, 0); @@ -346,11 +382,14 @@ ppiread(struct cdev *dev, struct uio *uio, int ioflag) /* XXX Wait 2 seconds to let the remote host some * time to terminate its interrupt */ - tsleep(ppi, PPBPRI, "ppiread", 2*hz); + ppb_sleep(ppbus, ppi, PPBPRI, "ppiread", 2 * hz); if ((error = ppb_1284_negociate(ppbus, - ppi->ppi_mode = PPB_BYTE, 0))) + ppi->ppi_mode = PPB_BYTE, 0))) { + ppb_unlock(ppbus); + free(buffer, M_DEVBUF); return (error); + } } break; @@ -367,11 +406,11 @@ ppiread(struct cdev *dev, struct uio *uio, int ioflag) /* read data */ len = 0; while (uio->uio_resid) { - if ((error = ppb_1284_read(ppbus, ppi->ppi_mode, - ppi->ppi_buffer, min(BUFSIZE, uio->uio_resid), - &len))) { + error = ppb_1284_read(ppbus, ppi->ppi_mode, + buffer, min(BUFSIZE, uio->uio_resid), &len); + ppb_unlock(ppbus); + if (error) goto error; - } if (!len) goto error; /* no more data */ @@ -379,12 +418,14 @@ ppiread(struct cdev *dev, struct uio *uio, int ioflag) #ifdef DEBUG_1284 printf("d"); #endif - if ((error = uiomove(ppi->ppi_buffer, len, uio))) + if ((error = uiomove(buffer, len, uio))) goto error; + ppb_lock(ppbus); } + ppb_unlock(ppbus); error: - + free(buffer, M_DEVBUF); #else /* PERIPH_1284 */ int error = ENODEV; #endif @@ -413,6 +454,7 @@ ppiwrite(struct cdev *dev, struct uio *uio, int ioflag) device_t ppidev = ppi->ppi_device; device_t ppbus = device_get_parent(ppidev); int len, error = 0, sent; + char *buffer; #if 0 int ret; @@ -425,18 +467,26 @@ ppiwrite(struct cdev *dev, struct uio *uio, int ioflag) MS_RET(0) }; + buffer = malloc(BUFSIZE, M_DEVBUF, M_WAITOK); + ppb_lock(ppbus); + /* negotiate ECP mode */ if (ppb_1284_negociate(ppbus, PPB_ECP, 0)) { printf("ppiwrite: ECP negotiation failed\n"); } while (!error && (len = min(uio->uio_resid, BUFSIZE))) { - uiomove(ppi->ppi_buffer, len, uio); + ppb_unlock(ppbus); + uiomove(buffer, len, uio); - ppb_MS_init_msq(msq, 2, ADDRESS, ppi->ppi_buffer, LENGTH, len); + ppb_MS_init_msq(msq, 2, ADDRESS, buffer, LENGTH, len); + ppb_lock(ppbus); error = ppb_MS_microseq(ppbus, msq, &ret); } +#else + buffer = malloc(BUFSIZE, M_DEVBUF, M_WAITOK); + ppb_lock(ppbus); #endif /* we have to be peripheral to be able to send data, so @@ -454,7 +504,7 @@ ppiwrite(struct cdev *dev, struct uio *uio, int ioflag) ppi_enable_intr(ppidev); /* sleep until IEEE1284 negotiation starts */ - error = tsleep(ppi, PCATCH | PPBPRI, "ppiwrite", 0); + error = ppb_sleep(ppbus, ppi, PCATCH | PPBPRI, "ppiwrite", 0); switch (error) { case 0: @@ -473,9 +523,11 @@ ppiwrite(struct cdev *dev, struct uio *uio, int ioflag) /* negotiation done, write bytes to master host */ while ((len = min(uio->uio_resid, BUFSIZE)) != 0) { - uiomove(ppi->ppi_buffer, len, uio); + ppb_unlock(ppbus); + uiomove(buffer, len, uio); + ppb_lock(ppbus); if ((error = byte_peripheral_write(ppbus, - ppi->ppi_buffer, len, &sent))) + buffer, len, &sent))) goto error; #ifdef DEBUG_1284 printf("d"); @@ -483,7 +535,8 @@ ppiwrite(struct cdev *dev, struct uio *uio, int ioflag) } error: - + ppb_unlock(ppbus); + free(buffer, M_DEVBUF); #else /* PERIPH_1284 */ int error = ENODEV; #endif @@ -500,6 +553,7 @@ ppiioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t int error = 0; u_int8_t *val = (u_int8_t *)data; + ppb_lock(ppbus); switch (cmd) { case PPIGDATA: /* get data register */ @@ -548,6 +602,7 @@ ppiioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t error = ENOTTY; break; } + ppb_unlock(ppbus); return (error); } @@ -557,6 +612,7 @@ static device_method_t ppi_methods[] = { DEVMETHOD(device_identify, ppi_identify), DEVMETHOD(device_probe, ppi_probe), DEVMETHOD(device_attach, ppi_attach), + DEVMETHOD(device_detach, ppi_detach), { 0, 0 } }; diff --git a/sys/dev/ppbus/pps.c b/sys/dev/ppbus/pps.c index 606c179..7a360d1 100644 --- a/sys/dev/ppbus/pps.c +++ b/sys/dev/ppbus/pps.c @@ -18,9 +18,11 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/lock.h> #include <sys/kernel.h> #include <sys/systm.h> #include <sys/module.h> +#include <sys/sx.h> #include <sys/bus.h> #include <sys/conf.h> #include <sys/timepps.h> @@ -43,15 +45,15 @@ struct pps_data { device_t ppsdev; device_t ppbus; int busy; - struct callout_handle timeout; + struct callout timeout; int lastdata; - struct mtx mtx; + struct sx lock; struct resource *intr_resource; /* interrupt resource */ void *intr_cookie; /* interrupt registration cookie */ }; -static int ppsintr(void *arg); +static void ppsintr(void *arg); static void ppshcpoll(void *arg); #define DEVTOSOFTC(dev) \ @@ -107,18 +109,29 @@ ppsattach(device_t dev) struct pps_data *sc = DEVTOSOFTC(dev); device_t ppbus = device_get_parent(dev); struct cdev *d; - int i, unit, rid = 0; - - mtx_init(&sc->mtx, device_get_nameunit(dev), "pps", MTX_SPIN); + int error, i, unit, rid = 0; /* declare our interrupt handler */ sc->intr_resource = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE); /* interrupts seem mandatory */ - if (sc->intr_resource == NULL) + if (sc->intr_resource == NULL) { + device_printf(dev, "Unable to allocate interrupt resource\n"); return (ENXIO); + } + + error = bus_setup_intr(dev, sc->intr_resource, + INTR_TYPE_TTY | INTR_MPSAFE, NULL, ppsintr, + sc, &sc->intr_cookie); + if (error) { + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->intr_resource); + device_printf(dev, "Unable to register interrupt handler\n"); + return (error); + } + sx_init(&sc->lock, "pps"); + ppb_init_callout(ppbus, &sc->timeout, 0); sc->ppsdev = dev; sc->ppbus = ppbus; unit = device_get_unit(ppbus); @@ -130,8 +143,11 @@ ppsattach(device_t dev) d->si_drv2 = (void*)0; pps_init(&sc->pps[0]); - if (ppb_request_bus(ppbus, dev, PPB_DONTWAIT)) + ppb_lock(ppbus); + if (ppb_request_bus(ppbus, dev, PPB_DONTWAIT)) { + ppb_unlock(ppbus); return (0); + } do { i = ppb_set_mode(sc->ppbus, PPB_EPP); @@ -168,6 +184,7 @@ ppsattach(device_t dev) ppstry(ppbus, 0x55, 0xff); ppstry(ppbus, 0xaa, 0xff); ppstry(ppbus, 0xff, 0xff); + ppb_unlock(ppbus); for (i = 1; i < 9; i++) { d = make_dev(&pps_cdevsw, unit + 0x10000 * i, @@ -178,9 +195,11 @@ ppsattach(device_t dev) d->si_drv2 = (void *)(intptr_t)i; pps_init(&sc->pps[i]); } + ppb_lock(ppbus); } while (0); i = ppb_set_mode(sc->ppbus, PPB_COMPATIBLE); ppb_release_bus(ppbus, dev); + ppb_unlock(ppbus); return (0); } @@ -189,22 +208,24 @@ static int ppsopen(struct cdev *dev, int flags, int fmt, struct thread *td) { struct pps_data *sc = dev->si_drv1; + device_t ppbus = sc->ppbus; int subdev = (intptr_t)dev->si_drv2; - int error, i; + int i; + /* + * The sx lock is here solely to serialize open()'s to close + * the race of concurrent open()'s when pps(4) doesn't own the + * ppbus. + */ + sx_xlock(&sc->lock); + ppb_lock(ppbus); if (!sc->busy) { device_t ppsdev = sc->ppsdev; - device_t ppbus = sc->ppbus; - if (ppb_request_bus(ppbus, ppsdev, PPB_WAIT|PPB_INTR)) + if (ppb_request_bus(ppbus, ppsdev, PPB_WAIT|PPB_INTR)) { + ppb_unlock(ppbus); + sx_xunlock(&sc->lock); return (EINTR); - - /* attach the interrupt handler */ - if ((error = bus_setup_intr(ppsdev, sc->intr_resource, - (INTR_TYPE_TTY | INTR_MPSAFE), ppsintr, NULL, - sc, &sc->intr_cookie))) { - ppb_release_bus(ppbus, ppsdev); - return (error); } i = ppb_set_mode(sc->ppbus, PPB_PS2); @@ -214,10 +235,13 @@ ppsopen(struct cdev *dev, int flags, int fmt, struct thread *td) ppb_wctr(ppbus, i); } if (subdev > 0 && !(sc->busy & ~1)) { - sc->timeout = timeout(ppshcpoll, sc, 1); + /* XXX: Timeout of 1? hz/100 instead perhaps? */ + callout_reset(&sc->timeout, 1, ppshcpoll, sc); sc->lastdata = ppb_rdtr(sc->ppbus); } sc->busy |= (1 << subdev); + ppb_unlock(ppbus); + sx_xunlock(&sc->lock); return(0); } @@ -227,10 +251,12 @@ ppsclose(struct cdev *dev, int flags, int fmt, struct thread *td) struct pps_data *sc = dev->si_drv1; int subdev = (intptr_t)dev->si_drv2; + sx_xlock(&sc->lock); sc->pps[subdev].ppsparam.mode = 0; /* PHK ??? */ + ppb_lock(sc->ppbus); sc->busy &= ~(1 << subdev); if (subdev > 0 && !(sc->busy & ~1)) - untimeout(ppshcpoll, sc, sc->timeout); + callout_stop(&sc->timeout); if (!sc->busy) { device_t ppsdev = sc->ppsdev; device_t ppbus = sc->ppbus; @@ -238,10 +264,11 @@ ppsclose(struct cdev *dev, int flags, int fmt, struct thread *td) ppb_wdtr(ppbus, 0); ppb_wctr(ppbus, 0); - /* Note: the interrupt handler is automatically detached */ ppb_set_mode(ppbus, PPB_COMPATIBLE); ppb_release_bus(ppbus, ppsdev); } + ppb_unlock(sc->ppbus); + sx_xunlock(&sc->lock); return(0); } @@ -251,10 +278,7 @@ ppshcpoll(void *arg) struct pps_data *sc = arg; int i, j, k, l; - if (!(sc->busy & ~1)) - return; - mtx_lock_spin(&sc->mtx); - sc->timeout = timeout(ppshcpoll, sc, 1); + KASSERT(sc->busy & ~1, ("pps polling w/o opened devices")); i = ppb_rdtr(sc->ppbus); if (i == sc->lastdata) return; @@ -269,25 +293,24 @@ ppshcpoll(void *arg) k += k; } sc->lastdata = i; - mtx_unlock_spin(&sc->mtx); + callout_reset(&sc->timeout, 1, ppshcpoll, sc); } -static int +static void ppsintr(void *arg) { struct pps_data *sc = (struct pps_data *)arg; + ppb_assert_locked(sc->ppbus); pps_capture(&sc->pps[0]); if (!(ppb_rstr(sc->ppbus) & nACK)) - return (FILTER_STRAY); + return; + if (sc->pps[0].ppsparam.mode & PPS_ECHOASSERT) ppb_wctr(sc->ppbus, IRQENABLE | AUTOFEED); - mtx_lock_spin(&sc->mtx); pps_event(&sc->pps[0], PPS_CAPTUREASSERT); - mtx_unlock_spin(&sc->mtx); if (sc->pps[0].ppsparam.mode & PPS_ECHOASSERT) ppb_wctr(sc->ppbus, IRQENABLE); - return (FILTER_HANDLED); } static int @@ -297,9 +320,9 @@ ppsioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t int subdev = (intptr_t)dev->si_drv2; int err; - mtx_lock_spin(&sc->mtx); + ppb_lock(sc->ppbus); err = pps_ioctl(cmd, data, &sc->pps[subdev]); - mtx_unlock_spin(&sc->mtx); + ppb_unlock(sc->ppbus); return (err); } diff --git a/sys/dev/ppbus/vpo.c b/sys/dev/ppbus/vpo.c index d0a8241..f63ff49 100644 --- a/sys/dev/ppbus/vpo.c +++ b/sys/dev/ppbus/vpo.c @@ -104,6 +104,7 @@ vpo_identify(driver_t *driver, device_t parent) static int vpo_probe(device_t dev) { + device_t ppbus = device_get_parent(dev); struct vpo_data *vpo; int error; @@ -112,6 +113,7 @@ vpo_probe(device_t dev) /* check ZIP before ZIP+ or imm_probe() will send controls to * the printer or whatelse connected to the port */ + ppb_lock(ppbus); if ((error = vpoio_probe(dev, &vpo->vpo_io)) == 0) { vpo->vpo_isplus = 0; device_set_desc(dev, @@ -121,8 +123,10 @@ vpo_probe(device_t dev) device_set_desc(dev, "Iomega Matchmaker Parallel to SCSI interface"); } else { + ppb_unlock(ppbus); return (error); } + ppb_unlock(ppbus); return (0); } @@ -134,6 +138,8 @@ static int vpo_attach(device_t dev) { struct vpo_data *vpo = DEVTOSOFTC(dev); + device_t ppbus = device_get_parent(dev); + struct ppb_data *ppb = device_get_softc(ppbus); /* XXX: layering */ struct cam_devq *devq; int error; @@ -156,17 +162,20 @@ vpo_attach(device_t dev) return (ENXIO); vpo->sim = cam_sim_alloc(vpo_action, vpo_poll, "vpo", vpo, - device_get_unit(dev), &Giant, + device_get_unit(dev), ppb->ppc_lock, /*untagged*/1, /*tagged*/0, devq); if (vpo->sim == NULL) { cam_simq_free(devq); return (ENXIO); } + ppb_lock(ppbus); if (xpt_bus_register(vpo->sim, dev, /*bus*/0) != CAM_SUCCESS) { cam_sim_free(vpo->sim, /*free_devq*/TRUE); + ppb_unlock(ppbus); return (ENXIO); } + ppb_unlock(ppbus); /* all went ok */ @@ -211,13 +220,10 @@ static void vpo_intr(struct vpo_data *vpo, struct ccb_scsiio *csio) { int errno; /* error in errno.h */ - int s; #ifdef VP0_DEBUG int i; #endif - s = splcam(); - if (vpo->vpo_isplus) { errno = imm_do_scsi(&vpo->vpo_io, VP0_INITIATOR, csio->ccb_h.target_id, @@ -246,7 +252,7 @@ vpo_intr(struct vpo_data *vpo, struct ccb_scsiio *csio) if (errno) { /* connection to ppbus interrupted */ csio->ccb_h.status = CAM_CMD_TIMEOUT; - goto error; + return; } /* if a timeout occured, no sense */ @@ -256,7 +262,7 @@ vpo_intr(struct vpo_data *vpo, struct ccb_scsiio *csio) vpo->vpo_error); csio->ccb_h.status = CAM_CMD_TIMEOUT; - goto error; + return; } /* check scsi status */ @@ -317,24 +323,22 @@ vpo_intr(struct vpo_data *vpo, struct ccb_scsiio *csio) csio->ccb_h.status = CAM_SCSI_STATUS_ERROR; } - goto error; + return; } csio->resid = csio->dxfer_len - vpo->vpo_count; csio->ccb_h.status = CAM_REQ_CMP; - -error: - splx(s); - - return; } static void vpo_action(struct cam_sim *sim, union ccb *ccb) { - struct vpo_data *vpo = (struct vpo_data *)sim->softc; +#ifdef INVARIANTS + device_t ppbus = device_get_parent(vpo->vpo_dev); + ppb_assert_locked(ppbus); +#endif switch (ccb->ccb_h.func_code) { case XPT_SCSI_IO: { diff --git a/sys/dev/ppbus/vpoio.c b/sys/dev/ppbus/vpoio.c index 7d8354a..62af869 100644 --- a/sys/dev/ppbus/vpoio.c +++ b/sys/dev/ppbus/vpoio.c @@ -609,6 +609,7 @@ vpoio_attach(struct vpoio_data *vpo) /* * Initialize mode dependent in/out microsequences */ + ppb_lock(ppbus); if ((error = ppb_request_bus(ppbus, vpo->vpo_dev, PPB_WAIT))) goto error; @@ -636,6 +637,7 @@ vpoio_attach(struct vpoio_data *vpo) ppb_release_bus(ppbus, vpo->vpo_dev); error: + ppb_unlock(ppbus); return (error); } diff --git a/sys/dev/ppc/ppc.c b/sys/dev/ppc/ppc.c index b318932..2ad788e 100644 --- a/sys/dev/ppc/ppc.c +++ b/sys/dev/ppc/ppc.c @@ -34,9 +34,11 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/bus.h> #include <sys/kernel.h> +#include <sys/lock.h> #include <sys/interrupt.h> #include <sys/module.h> #include <sys/malloc.h> +#include <sys/mutex.h> #include <sys/proc.h> #include <machine/bus.h> @@ -119,6 +121,7 @@ ppc_ecp_sync(device_t dev) int i, r; struct ppc_data *ppc = DEVTOSOFTC(dev); + PPC_ASSERT_LOCKED(ppc); if (!(ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_dtm & PPB_ECP)) return; @@ -474,7 +477,7 @@ ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never for /* First try to change the port address to that requested... */ - switch(ppc->ppc_base) { + switch (ppc->ppc_base) { case 0x378: val &= 0xfc; break; @@ -1320,6 +1323,7 @@ ppc_exec_microseq(device_t dev, struct ppb_microseq **p_msq) #define INCR_PC (mi ++) /* increment program counter */ + PPC_ASSERT_LOCKED(ppc); mi = *p_msq; for (;;) { switch (mi->opcode) { @@ -1388,8 +1392,11 @@ ppc_exec_microseq(device_t dev, struct ppb_microseq **p_msq) break; case MS_OP_ADELAY: - if (mi->arg[0].i) + if (mi->arg[0].i) { + PPC_UNLOCK(ppc); pause("ppbdelay", mi->arg[0].i * (hz/1000)); + PPC_LOCK(ppc); + } INCR_PC; break; @@ -1521,8 +1528,10 @@ ppcintr(void *arg) * XXX: If DMA is in progress should we just complete that w/o * doing this? */ - if (ppc->ppc_child_handlers > 0) { - intr_event_execute_handlers(curproc, ppc->ppc_intr_event); + PPC_LOCK(ppc); + if (ppc->ppc_intr_hook != NULL && + ppc->ppc_intr_hook(ppc->ppc_intr_arg) == 0) { + PPC_UNLOCK(ppc); return; } @@ -1536,6 +1545,7 @@ ppcintr(void *arg) /* don't use ecp mode with IRQENABLE set */ if (ctr & IRQENABLE) { + PPC_UNLOCK(ppc); return; } @@ -1550,6 +1560,7 @@ ppcintr(void *arg) ppc->ppc_irqstat &= ~PPC_IRQ_nFAULT; } else { /* shall be handled by underlying layers XXX */ + PPC_UNLOCK(ppc); return; } } @@ -1585,6 +1596,7 @@ ppcintr(void *arg) /* classic interrupt I/O */ ppc->ppc_irqstat &= ~PPC_IRQ_FIFO; } + PPC_UNLOCK(ppc); return; } @@ -1606,6 +1618,7 @@ ppc_reset_epp(device_t dev) { struct ppc_data *ppc = DEVTOSOFTC(dev); + PPC_ASSERT_LOCKED(ppc); ppc_reset_epp_timeout(ppc); return; @@ -1616,6 +1629,7 @@ ppc_setmode(device_t dev, int mode) { struct ppc_data *ppc = DEVTOSOFTC(dev); + PPC_ASSERT_LOCKED(ppc); switch (ppc->ppc_type) { case PPC_TYPE_SMCLIKE: return (ppc_smclike_setmode(ppc, mode)); @@ -1796,9 +1810,10 @@ int ppc_attach(device_t dev) { struct ppc_data *ppc = DEVTOSOFTC(dev); - device_t ppbus; int error; + mtx_init(&ppc->ppc_lock, device_get_nameunit(dev), "ppc", MTX_DEF); + device_printf(dev, "%s chipset (%s) in %s mode%s\n", ppc_models[ppc->ppc_model], ppc_avms[ppc->ppc_avm], ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ? @@ -1809,36 +1824,25 @@ ppc_attach(device_t dev) ppc->ppc_fifo, ppc->ppc_wthr, ppc->ppc_rthr); if (ppc->res_irq) { - /* - * Create an interrupt event to manage the handlers of - * child devices. - */ - error = intr_event_create(&ppc->ppc_intr_event, ppc, 0, -1, - NULL, NULL, NULL, NULL, "%s:", device_get_nameunit(dev)); - if (error) { - device_printf(dev, - "failed to create interrupt event: %d\n", error); - return (error); - } - /* default to the tty mask for registration */ /* XXX */ - error = bus_setup_intr(dev, ppc->res_irq, INTR_TYPE_TTY, - NULL, ppcintr, ppc, &ppc->intr_cookie); + error = bus_setup_intr(dev, ppc->res_irq, INTR_TYPE_TTY | + INTR_MPSAFE, NULL, ppcintr, ppc, &ppc->intr_cookie); if (error) { device_printf(dev, "failed to register interrupt handler: %d\n", error); + mtx_destroy(&ppc->ppc_lock); return (error); } } /* add ppbus as a child of this isa to parallel bridge */ - ppbus = device_add_child(dev, "ppbus", -1); + ppc->ppbus = device_add_child(dev, "ppbus", -1); /* * Probe the ppbus and attach devices found. */ - device_probe_and_attach(ppbus); + device_probe_and_attach(ppc->ppbus); return (0); } @@ -1876,6 +1880,8 @@ ppc_detach(device_t dev) ppc->res_drq); } + mtx_destroy(&ppc->ppc_lock); + return (0); } @@ -1884,6 +1890,7 @@ ppc_io(device_t ppcdev, int iop, u_char *addr, int cnt, u_char byte) { struct ppc_data *ppc = DEVTOSOFTC(ppcdev); + PPC_ASSERT_LOCKED(ppc); switch (iop) { case PPB_OUTSB_EPP: bus_write_multi_1(ppc->res_ioport, PPC_EPP_DATA, addr, cnt); @@ -1953,8 +1960,38 @@ ppc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val) switch (index) { case PPC_IVAR_EPP_PROTO: + PPC_ASSERT_LOCKED(ppc); *val = (u_long)ppc->ppc_epp; break; + case PPC_IVAR_LOCK: + *val = (uintptr_t)&ppc->ppc_lock; + break; + default: + return (ENOENT); + } + + return (0); +} + +int +ppc_write_ivar(device_t bus, device_t dev, int index, uintptr_t val) +{ + struct ppc_data *ppc = (struct ppc_data *)device_get_softc(bus); + + switch (index) { + case PPC_IVAR_INTR_HANDLER: + PPC_ASSERT_LOCKED(ppc); + if (dev != ppc->ppbus) + return (EINVAL); + if (val == 0) { + ppc->ppc_intr_hook = NULL; + break; + } + if (ppc->ppc_intr_hook != NULL) + return (EBUSY); + ppc->ppc_intr_hook = (void *)val; + ppc->ppc_intr_arg = device_get_softc(dev); + break; default: return (ENOENT); } @@ -2001,47 +2038,4 @@ ppc_release_resource(device_t bus, device_t child, int type, int rid, return (EINVAL); } -/* - * If a child wants to add a handler for our IRQ, add it to our interrupt - * event. Otherwise, fail the request. - */ -int -ppc_setup_intr(device_t bus, device_t child, struct resource *r, int flags, - driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep) -{ - struct ppc_data *ppc = DEVTOSOFTC(bus); - int error; - - if (r != ppc->res_irq) - return (EINVAL); - - /* We don't allow filters. */ - if (filt != NULL) - return (EINVAL); - - error = intr_event_add_handler(ppc->ppc_intr_event, - device_get_nameunit(child), NULL, ihand, arg, intr_priority(flags), - flags, cookiep); - if (error == 0) - ppc->ppc_child_handlers++; - return (error); -} - -int -ppc_teardown_intr(device_t bus, device_t child, struct resource *r, void *cookie) -{ - struct ppc_data *ppc = DEVTOSOFTC(bus); - int error; - - if (r != ppc->res_irq) - return (EINVAL); - - KASSERT(intr_handler_source(cookie) == ppc, - ("ppc_teardown_intr: source mismatch")); - error = intr_event_remove_handler(cookie); - if (error == 0) - ppc->ppc_child_handlers--; - return (error); -} - MODULE_DEPEND(ppc, ppbus, 1, 1, 1); diff --git a/sys/dev/ppc/ppc_acpi.c b/sys/dev/ppc/ppc_acpi.c index 032f196..b0a30b4 100644 --- a/sys/dev/ppc/ppc_acpi.c +++ b/sys/dev/ppc/ppc_acpi.c @@ -63,8 +63,7 @@ static device_method_t ppc_acpi_methods[] = { /* bus interface */ DEVMETHOD(bus_read_ivar, ppc_read_ivar), - DEVMETHOD(bus_setup_intr, ppc_setup_intr), - DEVMETHOD(bus_teardown_intr, ppc_teardown_intr), + DEVMETHOD(bus_write_ivar, ppc_write_ivar), DEVMETHOD(bus_alloc_resource, ppc_alloc_resource), DEVMETHOD(bus_release_resource, ppc_release_resource), diff --git a/sys/dev/ppc/ppc_isa.c b/sys/dev/ppc/ppc_isa.c index 5ac6990..14424a3 100644 --- a/sys/dev/ppc/ppc_isa.c +++ b/sys/dev/ppc/ppc_isa.c @@ -32,7 +32,9 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/lock.h> #include <sys/module.h> +#include <sys/mutex.h> #include <sys/bus.h> #include <machine/bus.h> #include <sys/malloc.h> @@ -56,12 +58,11 @@ static device_method_t ppc_isa_methods[] = { /* device interface */ DEVMETHOD(device_probe, ppc_isa_probe), DEVMETHOD(device_attach, ppc_isa_attach), - DEVMETHOD(device_detach, ppc_attach), + DEVMETHOD(device_detach, ppc_detach), /* bus interface */ DEVMETHOD(bus_read_ivar, ppc_read_ivar), - DEVMETHOD(bus_setup_intr, ppc_setup_intr), - DEVMETHOD(bus_teardown_intr, ppc_teardown_intr), + DEVMETHOD(bus_write_ivar, ppc_write_ivar), DEVMETHOD(bus_alloc_resource, ppc_alloc_resource), DEVMETHOD(bus_release_resource, ppc_release_resource), @@ -143,6 +144,7 @@ ppc_isa_write(device_t dev, char *buf, int len, int how) int s, error = 0; int spin; + PPC_ASSERT_LOCKED(ppc); if (!(ppc->ppc_avm & PPB_ECP)) return (EINVAL); if (ppc->ppc_dmachan == 0) @@ -215,7 +217,8 @@ ppc_isa_write(device_t dev, char *buf, int len, int how) */ do { /* release CPU */ - error = tsleep(ppc, PPBPRI | PCATCH, "ppcdma", 0); + error = mtx_sleep(ppc, &ppc->ppc_lock, PPBPRI | PCATCH, + "ppcdma", 0); } while (error == EWOULDBLOCK); splx(s); @@ -244,7 +247,8 @@ ppc_isa_write(device_t dev, char *buf, int len, int how) #ifdef PPC_DEBUG printf("Z"); #endif - error = tsleep(ppc, PPBPRI | PCATCH, "ppcfifo", hz/100); + error = mtx_sleep(ppc, &ppc->ppc_lock, PPBPRI | PCATCH, + "ppcfifo", hz / 100); if (error != EWOULDBLOCK) { #ifdef PPC_DEBUG printf("I"); diff --git a/sys/dev/ppc/ppc_pci.c b/sys/dev/ppc/ppc_pci.c index a64a3fd..991de1f 100644 --- a/sys/dev/ppc/ppc_pci.c +++ b/sys/dev/ppc/ppc_pci.c @@ -53,8 +53,7 @@ static device_method_t ppc_pci_methods[] = { /* bus interface */ DEVMETHOD(bus_read_ivar, ppc_read_ivar), - DEVMETHOD(bus_setup_intr, ppc_setup_intr), - DEVMETHOD(bus_teardown_intr, ppc_teardown_intr), + DEVMETHOD(bus_write_ivar, ppc_write_ivar), DEVMETHOD(bus_alloc_resource, ppc_alloc_resource), DEVMETHOD(bus_release_resource, ppc_release_resource), diff --git a/sys/dev/ppc/ppc_puc.c b/sys/dev/ppc/ppc_puc.c index 0aec89c..361d9b7 100644 --- a/sys/dev/ppc/ppc_puc.c +++ b/sys/dev/ppc/ppc_puc.c @@ -55,8 +55,7 @@ static device_method_t ppc_puc_methods[] = { /* bus interface */ DEVMETHOD(bus_read_ivar, ppc_read_ivar), - DEVMETHOD(bus_setup_intr, ppc_setup_intr), - DEVMETHOD(bus_teardown_intr, ppc_teardown_intr), + DEVMETHOD(bus_write_ivar, ppc_write_ivar), DEVMETHOD(bus_alloc_resource, ppc_alloc_resource), DEVMETHOD(bus_release_resource, ppc_release_resource), diff --git a/sys/dev/ppc/ppcreg.h b/sys/dev/ppc/ppcreg.h index 0e69dd9..a729503 100644 --- a/sys/dev/ppc/ppcreg.h +++ b/sys/dev/ppc/ppcreg.h @@ -29,6 +29,9 @@ #ifndef __PPCREG_H #define __PPCREG_H +#include <sys/_lock.h> +#include <sys/_mutex.h> + /* * Parallel Port Chipset type. */ @@ -108,10 +111,16 @@ struct ppc_data { void *intr_cookie; - struct intr_event *ppc_intr_event; - int ppc_child_handlers; + ppc_intr_handler ppc_intr_hook; + void *ppc_intr_arg; + + struct mtx ppc_lock; }; +#define PPC_LOCK(data) mtx_lock(&(data)->ppc_lock) +#define PPC_UNLOCK(data) mtx_unlock(&(data)->ppc_lock) +#define PPC_ASSERT_LOCKED(data) mtx_assert(&(data)->ppc_lock, MA_OWNED) + /* * Parallel Port Chipset registers. */ diff --git a/sys/dev/ppc/ppcvar.h b/sys/dev/ppc/ppcvar.h index 18c159f..a8b1a92 100644 --- a/sys/dev/ppc/ppcvar.h +++ b/sys/dev/ppc/ppcvar.h @@ -32,6 +32,7 @@ int ppc_probe(device_t dev, int rid); int ppc_attach(device_t dev); int ppc_detach(device_t dev); int ppc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val); +int ppc_write_ivar(device_t bus, device_t dev, int index, uintptr_t val); int ppc_read(device_t, char *, int, int); int ppc_write(device_t, char *, int, int); @@ -39,9 +40,6 @@ int ppc_write(device_t, char *, int, int); u_char ppc_io(device_t, int, u_char *, int, u_char); int ppc_exec_microseq(device_t, struct ppb_microseq **); -int ppc_setup_intr(device_t, device_t, struct resource *, int, - driver_filter_t *filt, void (*)(void *), void *, void **); -int ppc_teardown_intr(device_t, device_t, struct resource *, void *); struct resource *ppc_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags); int ppc_release_resource(device_t bus, device_t child, int type, int rid, |