summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ppbus/if_plip.c253
-rw-r--r--sys/dev/ppbus/immio.c2
-rw-r--r--sys/dev/ppbus/lpbb.c59
-rw-r--r--sys/dev/ppbus/lpt.c287
-rw-r--r--sys/dev/ppbus/pcfclock.c26
-rw-r--r--sys/dev/ppbus/ppb_1284.c7
-rw-r--r--sys/dev/ppbus/ppb_base.c95
-rw-r--r--sys/dev/ppbus/ppb_msq.c7
-rw-r--r--sys/dev/ppbus/ppbconf.c120
-rw-r--r--sys/dev/ppbus/ppbconf.h34
-rw-r--r--sys/dev/ppbus/ppi.c154
-rw-r--r--sys/dev/ppbus/pps.c89
-rw-r--r--sys/dev/ppbus/vpo.c30
-rw-r--r--sys/dev/ppbus/vpoio.c2
-rw-r--r--sys/dev/ppc/ppc.c122
-rw-r--r--sys/dev/ppc/ppc_acpi.c3
-rw-r--r--sys/dev/ppc/ppc_isa.c14
-rw-r--r--sys/dev/ppc/ppc_pci.c3
-rw-r--r--sys/dev/ppc/ppc_puc.c3
-rw-r--r--sys/dev/ppc/ppcreg.h13
-rw-r--r--sys/dev/ppc/ppcvar.h4
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,
OpenPOWER on IntegriCloud