Add locking to ppc and ppbus and mark the whole lot MPSAFE:

- To avoid having a bunch of locks that end up always getting acquired as
  a group, give each ppc(4) device a mutex which it shares with all the
  child devices including ppbus(4), lpt(4), plip(4), etc.  This mutex
  is then used for all the locking.
- Rework the interrupt handling stuff yet again.  Now ppbus drivers setup
  their interrupt handler during attach and tear it down during detach
  like most other drivers.  ppbus(4) only invokes the interrupt handler
  of the device that currently owns the bus (if any) when an interrupt
  occurs, however.  Also, interrupt handlers in general now accept their
  softc pointers as their argument rather than the device_t.  Another
  feature of the ppbus interrupt handlers is that they are called with
  the parent ppc device's lock already held.  This minimizes the number
  of lock operations during an interrupt.
- Mark plip(4), lpt(4), pcfclock(4), ppi(4), vpo(4) MPSAFE.
- lpbb(4) uses the ppc lock instead of Giant.
- Other plip(4) changes:
  - Add a mutex to protect the global tables in plip(4) and free them on
    module unload.
  - Add a detach routine.
  - Split out the init/stop code from the ioctl routine into separate
    functions.
- Other lpt(4) changes:
  - Use device_printf().
  - Use a dedicated callout for the lptout timer.
  - Allocate the I/O buffers at attach and detach rather than during
    open and close as this simplifies the locking at the cost of
    1024+32 bytes when the driver is attached.
- Other ppi(4) changes:
  - Use an sx lock to serialize open and close.
  - Remove unused HADBUS flag.
  - Add a detach routine.
  - Use a malloc'd buffer for each read and write to avoid races with
    concurrent read/write.
- Other pps(4) changes:
  - Use a callout rather than a callout handle with timeout().
  - Conform to the new ppbus requirements (regular mutex, non-filter
    interrupt handler).  pps(4) is probably going to have to become a
    standalone driver that doesn't use ppbus(4) to satisfy it's
    requirements for low latency as a result.
  - Use an sx lock to serialize open and close.
- Other vpo(4) changes:
  - Use the parent ppc device's lock to create the CAM sim instead of
    Giant.
- Other ppc(4) changes:
  - Fix ppc_isa's detach method to detach instead of calling attach.

Tested by:	  no one :-(
This commit is contained in:
John Baldwin 2009-01-21 23:10:06 +00:00
parent d40caf29b4
commit 2067d312d4
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=187576
21 changed files with 831 additions and 498 deletions

View file

@ -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))) {
/* 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);
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;
(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);
case SIOCSIFMTU:
ptr = sc->sc_ifbuf;
sc->sc_ifbuf = malloc(ifr->ifr_mtu + MLPIPHDRLEN, M_DEVBUF,
M_NOWAIT);
if (sc->sc_ifbuf == NULL) {
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);
}
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 @@ lp_intr(void *arg)
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 @@ lpoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
--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 @@ lpoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
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);

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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 @@ lptclose(struct cdev *dev, int flags, int fmt, struct thread *td)
* 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;

View file

@ -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");

View file

@ -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;

View file

@ -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));
}

View file

@ -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);

View file

@ -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 @@ ppb_scan_bus(device_t bus)
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 */
@ -411,27 +438,44 @@ ppbus_detach(device_t dev)
return (0);
}
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);

View file

@ -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);
#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 */

View file

@ -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 }
};

View file

@ -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);
}

View file

@ -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:
{

View file

@ -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);
}

View file

@ -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);

View file

@ -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),

View file

@ -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");

View file

@ -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),

View file

@ -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),

View file

@ -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.
*/

View file

@ -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,