--- //depot/vendor/freebsd/src/sys/dev/ppbus/if_plip.c 2008/11/16 17:45:16 +++ //depot/user/jhb/acpipci/dev/ppbus/if_plip.c 2008/11/19 15:57:28 @@ -152,8 +152,12 @@ 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 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 @@ { struct lp_data *lp = DEVTOSOFTC(dev); struct ifnet *ifp; - int rid = 0; + int error, rid = 0; lp->sc_dev = dev; @@ -224,8 +256,7 @@ 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 @@ 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 @@ { 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 @@ 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 @@ 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 @@ 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)) { + (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); - 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))) { - - /* 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); + 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); } - - sc->sc_ifbuf = malloc(sc->sc_ifp->if_mtu + MLPIPHDRLEN, - M_DEVBUF, M_WAITOK); - if (sc->sc_ifbuf == NULL) { - ppb_release_bus(ppbus, dev); - 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 @@ { 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ sc->sc_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; sc->sc_iferrs = 0; } - -done: - splx(s); } static __inline int @@ -602,7 +683,7 @@ 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 @@ /* 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 @@ 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 @@ 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 @@ --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 @@ 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 @@ 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 @@ 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); --- //depot/vendor/freebsd/src/sys/dev/ppbus/immio.c 2008/11/16 17:45:16 +++ //depot/user/jhb/acpipci/dev/ppbus/immio.c 2008/11/16 18:00:11 @@ -606,6 +606,7 @@ /* * 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 @@ ppb_release_bus(ppbus, vpo->vpo_dev); error: + ppb_unlock(ppbus); return (error); } --- //depot/vendor/freebsd/src/sys/dev/ppbus/lpbb.c 2008/11/16 17:45:16 +++ //depot/user/jhb/acpipci/dev/ppbus/lpbb.c 2008/11/16 18:07:55 @@ -103,16 +103,16 @@ 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 @@ #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 @@ { 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 @@ { 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 @@ { 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 @@ { 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); } --- //depot/vendor/freebsd/src/sys/dev/ppbus/lpt.c 2008/11/16 17:45:16 +++ //depot/user/jhb/acpipci/dev/ppbus/lpt.c 2008/11/16 18:07:55 @@ -105,9 +105,9 @@ #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 @@ #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 @@ #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 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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,19 @@ static void lptout(void *arg) { - device_t dev = (device_t)arg; - struct lpt_data *sc = DEVTOSOFTC(dev); + struct lpt_data *sc = arg; + device_t dev = sc->sc_dev; #ifdef LPT_DEBUG 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 +468,7 @@ * Avoid possible hangs due to missed interrupts */ if (sc->sc_xfercnt) { - lptintr(dev); + lptintr(sc); } else { sc->sc_state &= ~OBUSY; wakeup(dev); @@ -458,17 +484,19 @@ 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 +506,7 @@ /* Check for open with BYPASS flag set. */ if (sc->sc_flags & LP_BYPASS) { sc->sc_state = OPEN; + ppb_unlock(ppbus); return(0); } @@ -485,11 +514,12 @@ 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 +544,21 @@ 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 +578,20 @@ 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 +606,21 @@ 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 +628,23 @@ (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 +658,14 @@ * 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 +694,7 @@ */ 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 +720,7 @@ 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 +729,11 @@ 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 +747,16 @@ 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 +773,30 @@ 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 +810,17 @@ 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 +828,14 @@ /* 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 +844,37 @@ 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 +920,18 @@ 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 +943,7 @@ * 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 +967,14 @@ 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; --- //depot/vendor/freebsd/src/sys/dev/ppbus/pcfclock.c 2008/11/16 17:45:16 +++ //depot/user/jhb/acpipci/dev/ppbus/pcfclock.c 2008/11/16 18:07:55 @@ -54,7 +54,6 @@ struct pcfclock_data { device_t dev; struct cdev *cdev; - int count; }; static devclass_t pcfclock_devclass; @@ -65,7 +64,6 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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"); --- //depot/vendor/freebsd/src/sys/dev/ppbus/ppb_1284.c 2008/11/16 17:45:16 +++ //depot/user/jhb/acpipci/dev/ppbus/ppb_1284.c 2008/11/16 18:00:11 @@ -36,6 +36,8 @@ #include "opt_ppb_1284.h" #include +#include +#include #include #include @@ -92,8 +94,10 @@ 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 @@ /* 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; --- //depot/vendor/freebsd/src/sys/dev/ppbus/ppb_base.c 2008/11/16 17:45:16 +++ //depot/user/jhb/acpipci/dev/ppbus/ppb_base.c 2008/11/16 18:00:11 @@ -28,9 +28,11 @@ __FBSDID("$FreeBSD: src/sys/dev/ppbus/ppb_base.c,v 1.16 2008/11/16 17:42:02 jhb Exp $"); #include -#include +#include #include #include +#include +#include #include #include @@ -54,9 +56,12 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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)); +} --- //depot/vendor/freebsd/src/sys/dev/ppbus/ppb_msq.c 2008/11/16 17:45:16 +++ //depot/user/jhb/acpipci/dev/ppbus/ppb_msq.c 2008/11/16 18:00:11 @@ -31,6 +31,8 @@ #include #include +#include +#include #include #include @@ -115,9 +117,13 @@ 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 @@ MS_RET(0) }; + mtx_assert(ppb->ppc_lock, MA_OWNED); if (ppb->ppb_owner != dev) return (EACCES); --- //depot/vendor/freebsd/src/sys/dev/ppbus/ppbconf.c 2008/11/16 17:45:16 +++ //depot/user/jhb/acpipci/dev/ppbus/ppbconf.c 2008/11/16 18:00:11 @@ -33,7 +33,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -50,6 +52,8 @@ static MALLOC_DEFINE(M_PPBUSDEV, "ppbusdev", "Parallel Port bus device"); +static int ppbus_intr(void *arg); + /* * Device methods */ @@ -375,13 +379,36 @@ 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 @@ } 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_device *ppbdev = device_get_ivars(child); struct ppb_data *ppb = DEVTOSOFTC(bus); - struct ppb_device *ppbdev = device_get_ivars(child); - /* 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 @@ 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 @@ 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 @@ if (ppbdev->ctx.valid) ppb_set_mode(bus, ppbdev->ctx.mode); - splx(s); return (0); } } @@ -515,31 +557,21 @@ 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); /* ok, now the context of the device is valid */ ppbdev->ctx.valid = 1; + ppb->ppb_owner = 0; + /* wakeup waiting processes */ wakeup(ppb); --- //depot/vendor/freebsd/src/sys/dev/ppbus/ppbconf.h 2008/11/16 17:45:16 +++ //depot/user/jhb/acpipci/dev/ppbus/ppbconf.h 2008/11/16 18:00:11 @@ -199,8 +199,8 @@ 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 @@ /* 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 @@ 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_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); + +#ifdef INVARIANTS +#define ppb_assert_locked(dev) _ppb_assert_locked(dev, __FILE__, __LINE__) +#else +#define ppb_assert_locked(dev) +#endif #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) - */ - -#endif +#endif /* !__PPBCONF_H */ --- //depot/vendor/freebsd/src/sys/dev/ppbus/ppi.c 2008/11/16 17:45:16 +++ //depot/user/jhb/acpipci/dev/ppbus/ppi.c 2008/11/16 18:00:11 @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include #include @@ -61,11 +63,10 @@ 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]; @@ -88,7 +89,6 @@ static struct cdevsw ppi_cdevsw = { .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, .d_open = ppiopen, .d_close = ppiclose, .d_read = ppiread, @@ -165,8 +165,22 @@ /* 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 +194,22 @@ 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 +230,7 @@ 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 +290,20 @@ 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 +315,28 @@ 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 +357,11 @@ 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 +377,14 @@ /* XXX Wait 2 seconds to let the remote host some * time to terminate its interrupt */ - tsleep(ppi, PPBPRI, "ppiread", 2*hz); + ppb_sleep(ppb, 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 +401,11 @@ /* 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 +413,14 @@ #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 +449,7 @@ 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 +462,26 @@ 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 +499,7 @@ ppi_enable_intr(ppidev); /* sleep until IEEE1284 negotiation starts */ - error = tsleep(ppi, PCATCH | PPBPRI, "ppiwrite", 0); + error = ppb_sleep(ppb, ppi, PCATCH | PPBPRI, "ppiwrite", 0); switch (error) { case 0: @@ -473,9 +518,11 @@ /* 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 +530,8 @@ } error: - + ppb_unlock(ppbus); + free(buffer, M_DEVBUF); #else /* PERIPH_1284 */ int error = ENODEV; #endif @@ -500,6 +548,7 @@ int error = 0; u_int8_t *val = (u_int8_t *)data; + ppb_lock(ppbus); switch (cmd) { case PPIGDATA: /* get data register */ @@ -548,6 +597,7 @@ error = ENOTTY; break; } + ppb_unlock(ppbus); return (error); } @@ -557,6 +607,7 @@ DEVMETHOD(device_identify, ppi_identify), DEVMETHOD(device_probe, ppi_probe), DEVMETHOD(device_attach, ppi_attach), + DEVMETHOD(device_detach, ppi_detach), { 0, 0 } }; --- //depot/vendor/freebsd/src/sys/dev/ppbus/pps.c 2008/11/16 17:45:16 +++ //depot/user/jhb/acpipci/dev/ppbus/pps.c 2008/11/16 18:00:11 @@ -18,9 +18,11 @@ __FBSDID("$FreeBSD: src/sys/dev/ppbus/pps.c,v 1.55 2008/11/16 17:42:02 jhb Exp $"); #include +#include #include #include #include +#include #include #include #include @@ -43,15 +45,15 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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); } --- //depot/vendor/freebsd/src/sys/dev/ppbus/vpo.c 2008/11/16 17:45:16 +++ //depot/user/jhb/acpipci/dev/ppbus/vpo.c 2008/11/16 18:00:11 @@ -104,6 +104,7 @@ static int vpo_probe(device_t dev) { + device_t ppbus = device_get_parent(dev); struct vpo_data *vpo; int error; @@ -112,6 +113,7 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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->vpo_error); csio->ccb_h.status = CAM_CMD_TIMEOUT; - goto error; + return; } /* check scsi status */ @@ -317,24 +323,22 @@ 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: { --- //depot/vendor/freebsd/src/sys/dev/ppbus/vpoio.c 2008/11/16 17:45:16 +++ //depot/user/jhb/acpipci/dev/ppbus/vpoio.c 2008/11/19 16:34:36 @@ -609,6 +609,7 @@ /* * 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 @@ ppb_release_bus(ppbus, vpo->vpo_dev); error: + ppb_unlock(ppbus); return (error); } --- //depot/vendor/freebsd/src/sys/dev/ppc/ppc.c 2008/11/16 17:45:16 +++ //depot/user/jhb/acpipci/dev/ppc/ppc.c 2008/11/18 23:26:47 @@ -34,9 +34,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -119,6 +121,7 @@ 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 @@ /* 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 @@ #define INCR_PC (mi ++) /* increment program counter */ + PPC_ASSERT_LOCKED(ppc); mi = *p_msq; for (;;) { switch (mi->opcode) { @@ -1388,8 +1392,11 @@ 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 @@ * 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 @@ /* don't use ecp mode with IRQENABLE set */ if (ctr & IRQENABLE) { + PPC_UNLOCK(ppc); return; } @@ -1550,6 +1560,7 @@ ppc->ppc_irqstat &= ~PPC_IRQ_nFAULT; } else { /* shall be handled by underlying layers XXX */ + PPC_UNLOCK(ppc); return; } } @@ -1585,6 +1596,7 @@ /* classic interrupt I/O */ ppc->ppc_irqstat &= ~PPC_IRQ_FIFO; } + PPC_UNLOCK(ppc); return; } @@ -1606,6 +1618,7 @@ { struct ppc_data *ppc = DEVTOSOFTC(dev); + PPC_ASSERT_LOCKED(ppc); ppc_reset_epp_timeout(ppc); return; @@ -1616,6 +1629,7 @@ { 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 @@ 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->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->res_drq); } + mtx_destroy(&ppc->ppc_lock); + return (0); } @@ -1884,6 +1890,7 @@ { 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 @@ 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 @@ 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); --- //depot/vendor/freebsd/src/sys/dev/ppc/ppc_acpi.c 2008/11/16 17:45:16 +++ //depot/user/jhb/acpipci/dev/ppc/ppc_acpi.c 2008/11/16 18:00:11 @@ -63,8 +63,7 @@ /* 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), --- //depot/vendor/freebsd/src/sys/dev/ppc/ppc_isa.c 2008/09/15 22:30:14 +++ //depot/user/jhb/acpipci/dev/ppc/ppc_isa.c 2008/11/15 23:26:35 @@ -32,7 +32,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -56,12 +58,11 @@ /* 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 @@ 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 @@ */ 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 @@ #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"); --- //depot/vendor/freebsd/src/sys/dev/ppc/ppc_pci.c 2008/09/15 22:30:14 +++ //depot/user/jhb/acpipci/dev/ppc/ppc_pci.c 2008/11/15 23:26:35 @@ -53,8 +53,7 @@ /* 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), --- //depot/vendor/freebsd/src/sys/dev/ppc/ppc_puc.c 2008/09/15 22:30:14 +++ //depot/user/jhb/acpipci/dev/ppc/ppc_puc.c 2008/11/15 23:26:35 @@ -55,8 +55,7 @@ /* 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), --- //depot/vendor/freebsd/src/sys/dev/ppc/ppcreg.h 2008/10/21 18:35:13 +++ //depot/user/jhb/acpipci/dev/ppc/ppcreg.h 2008/11/15 23:26:35 @@ -29,6 +29,9 @@ #ifndef __PPCREG_H #define __PPCREG_H +#include +#include + /* * Parallel Port Chipset type. */ @@ -108,10 +111,16 @@ 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. */ --- //depot/vendor/freebsd/src/sys/dev/ppc/ppcvar.h 2008/09/15 22:30:14 +++ //depot/user/jhb/acpipci/dev/ppc/ppcvar.h 2008/11/15 23:26:35 @@ -32,6 +32,7 @@ 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 @@ 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,