Index: sys/dev/atkbdc/psm.c =================================================================== --- sys/dev/atkbdc/psm.c +++ sys/dev/atkbdc/psm.c @@ -371,6 +371,7 @@ /* driver control block */ struct psm_softc { /* Driver status information */ int unit; + struct mtx mtx; /* Driver`s mutex */ struct selinfo rsel; /* Process selecting for Input */ u_char state; /* Mouse driver state */ int config; /* driver configuration flags */ @@ -553,8 +554,12 @@ static int doopen(struct psm_softc *, int); static int reinitialize(struct psm_softc *, int); static char *model_name(int); +static void psm_lock(struct psm_softc *); +static void psm_unlock(struct psm_softc *); +static void psm_lock_assert(struct psm_softc *); static void psmsoftintr(void *); static void psmsoftintridle(void *); +static void psmintr_locked(void *); static void psmintr(void *); static void psmtimeout(void *); static int timeelapsed(const struct timeval *, int, int, @@ -665,7 +670,6 @@ static struct cdevsw psm_cdevsw = { .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, .d_open = psmopen, .d_close = psmclose, .d_read = psmread, @@ -1055,6 +1059,7 @@ { int stat[3]; + psm_lock_assert(sc); kbdc_lock_assert(sc->kbdc); /* @@ -1159,11 +1164,11 @@ { int err; int c; - int s; + + psm_lock_assert(sc); /* don't let anybody mess with the aux device */ kbdc_lock(sc->kbdc); - s = spltty(); /* block our watchdog timer */ sc->watchdog = FALSE; @@ -1182,7 +1187,6 @@ KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { /* CONTROLLER ERROR */ - splx(s); kbdc_unlock(sc->kbdc); log(LOG_ERR, "psm%d: unable to set the command byte (reinitialize).\n", @@ -1217,7 +1221,6 @@ err = ENXIO; } } - splx(s); /* restore the driver state */ if ((sc->state & PSM_OPEN) && (err == 0)) { @@ -1243,6 +1246,27 @@ return (err); } +static void +psm_lock(struct psm_softc *sc) +{ + + mtx_lock(&sc->mtx); +} + +static void +psm_unlock(struct psm_softc *sc) +{ + + mtx_unlock(&sc->mtx); +} + +static void +psm_lock_assert(struct psm_softc *sc) +{ + + mtx_assert(&sc->mtx, MA_OWNED); +} + /* psm driver entry points */ static void @@ -1606,16 +1630,17 @@ /* Setup initial state */ sc->state = PSM_VALID; - callout_init(&sc->callout, 0); - callout_init(&sc->softcallout, 0); + mtx_init(&sc->mtx, "psm lock", NULL, MTX_DEF); + callout_init_mtx(&sc->callout, &sc->mtx, 0); + callout_init_mtx(&sc->softcallout, &sc->mtx, 0); /* Setup our interrupt handler */ rid = KBDC_RID_AUX; sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->intr == NULL) return (ENXIO); - error = bus_setup_intr(dev, sc->intr, INTR_TYPE_TTY, NULL, psmintr, sc, - &sc->ih); + error = bus_setup_intr(dev, sc->intr, INTR_TYPE_TTY | INTR_MPSAFE, + NULL, psmintr, sc, &sc->ih); if (error) { bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr); return (error); @@ -1682,8 +1707,11 @@ destroy_dev(sc->dev); destroy_dev(sc->bdev); - callout_drain(&sc->callout); - callout_drain(&sc->softcallout); + psm_lock(sc); + callout_stop(&sc->callout); + callout_stop(&sc->softcallout); + psm_unlock(sc); + mtx_destroy(&sc->mtx); return (0); } @@ -1702,9 +1730,13 @@ return (ENXIO); } + psm_lock(sc); + /* Disallow multiple opens */ - if (sc->state & PSM_OPEN) + if (sc->state & PSM_OPEN) { + psm_unlock(sc); return (EBUSY); + } device_busy(devclass_get_device(psm_devclass, sc->unit)); @@ -1746,6 +1778,7 @@ KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { /* CONTROLLER ERROR; do you know how to get out of this? */ kbdc_unlock(sc->kbdc); + psm_unlock(sc); log(LOG_ERR, "psm%d: unable to set the command byte (psmopen).\n", sc->unit); @@ -1759,6 +1792,7 @@ if (err == 0) sc->state |= PSM_OPEN; kbdc_unlock(sc->kbdc); + psm_unlock(sc); return (err); } @@ -1769,6 +1803,8 @@ int stat[3]; int command_byte; + psm_lock(sc); + /* don't let timeout routines in the keyboard driver to poll the kbdc */ kbdc_lock(sc->kbdc); @@ -1776,6 +1812,7 @@ command_byte = get_controller_command_byte(sc->kbdc); if (command_byte == -1) { kbdc_unlock(sc->kbdc); + psm_unlock(sc); return (EIO); } @@ -1847,6 +1884,7 @@ sc->state &= ~PSM_OPEN; kbdc_unlock(sc->kbdc); device_unbusy(devclass_get_device(psm_devclass, sc->unit)); + psm_unlock(sc); return (0); } @@ -1918,36 +1956,33 @@ struct psm_softc *sc = dev->si_drv1; u_char buf[PSM_SMALLBUFSIZE]; int error = 0; - int s; int l; if ((sc->state & PSM_VALID) == 0) return (EIO); /* block until mouse activity occurred */ - s = spltty(); + psm_lock(sc); while (sc->queue.count <= 0) { if (dev != sc->bdev) { - splx(s); + psm_unlock(sc); return (EWOULDBLOCK); } sc->state |= PSM_ASLP; - error = tsleep(sc, PZERO | PCATCH, "psmrea", 0); + error = mtx_sleep(sc, &sc->mtx, PZERO | PCATCH, "psmrea", 0); sc->state &= ~PSM_ASLP; if (error) { - splx(s); + psm_unlock(sc); return (error); } else if ((sc->state & PSM_VALID) == 0) { /* the device disappeared! */ - splx(s); + psm_unlock(sc); return (EIO); } } - splx(s); /* copy data to the user land */ while ((sc->queue.count > 0) && (uio->uio_resid > 0)) { - s = spltty(); l = imin(sc->queue.count, uio->uio_resid); if (l > sizeof(buf)) l = sizeof(buf); @@ -1961,11 +1996,13 @@ bcopy(&sc->queue.buf[sc->queue.head], &buf[0], l); sc->queue.count -= l; sc->queue.head = (sc->queue.head + l) % sizeof(sc->queue.buf); - splx(s); + psm_unlock(sc); error = uiomove(buf, l, uio); + psm_lock(sc); if (error) break; } + psm_unlock(sc); return (error); } @@ -1973,19 +2010,18 @@ static int block_mouse_data(struct psm_softc *sc, int *c) { - int s; + psm_lock(sc); kbdc_lock(sc->kbdc); - s = spltty(); *c = get_controller_command_byte(sc->kbdc); if ((*c == -1) || !set_controller_command_byte(sc->kbdc, kbdc_get_device_mask(sc->kbdc), KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { /* this is CONTROLLER ERROR */ - splx(s); kbdc_unlock(sc->kbdc); + psm_unlock(sc); return (EIO); } @@ -2004,7 +2040,6 @@ empty_aux_buffer(sc->kbdc, 0); /* flush the queue */ read_aux_data_no_wait(sc->kbdc); /* throw away data if any */ flushpackets(sc); - splx(s); return (0); } @@ -2013,6 +2048,8 @@ dropqueue(struct psm_softc *sc) { + psm_lock_assert(sc); + sc->queue.count = 0; sc->queue.head = 0; sc->queue.tail = 0; @@ -2027,6 +2064,8 @@ flushpackets(struct psm_softc *sc) { + psm_lock_assert(sc); + dropqueue(sc); bzero(&sc->pqueue, sizeof(sc->pqueue)); } @@ -2055,6 +2094,7 @@ } kbdc_unlock(sc->kbdc); + psm_unlock(sc); return (error); } @@ -2084,7 +2124,10 @@ kbdc_unlock(sc->kbdc); VLOG(2, (LOG_DEBUG, "psm: cmd 0x%x failed.\n", buf[i])); - return (reinitialize(sc, FALSE)); + psm_lock(sc); + error = reinitialize(sc, FALSE); + psm_unlock(sc); + return (error); } } kbdc_unlock(sc->kbdc); @@ -2107,39 +2150,38 @@ int stat[3]; int command_byte; int error = 0; - int s; /* Perform IOCTL command */ switch (cmd) { case OLD_MOUSE_GETHWINFO: - s = spltty(); + psm_lock(sc); ((old_mousehw_t *)addr)->buttons = sc->hw.buttons; ((old_mousehw_t *)addr)->iftype = sc->hw.iftype; ((old_mousehw_t *)addr)->type = sc->hw.type; ((old_mousehw_t *)addr)->hwid = sc->hw.hwid & 0x00ff; - splx(s); + psm_unlock(sc); break; case MOUSE_GETHWINFO: - s = spltty(); + psm_lock(sc); *(mousehw_t *)addr = sc->hw; if (sc->mode.level == PSM_LEVEL_BASE) ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC; - splx(s); + psm_unlock(sc); break; case MOUSE_SYN_GETHWINFO: - s = spltty(); + psm_lock(sc); if (sc->synhw.infoMajor >= 4) *(synapticshw_t *)addr = sc->synhw; else error = EINVAL; - splx(s); + psm_unlock(sc); break; case OLD_MOUSE_GETMODE: - s = spltty(); + psm_lock(sc); switch (sc->mode.level) { case PSM_LEVEL_BASE: ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2; @@ -2155,11 +2197,11 @@ ((old_mousemode_t *)addr)->rate = sc->mode.rate; ((old_mousemode_t *)addr)->resolution = sc->mode.resolution; ((old_mousemode_t *)addr)->accelfactor = sc->mode.accelfactor; - splx(s); + psm_unlock(sc); break; case MOUSE_GETMODE: - s = spltty(); + psm_lock(sc); *(mousemode_t *)addr = sc->mode; if ((sc->flags & PSM_NEED_SYNCBITS) != 0) { ((mousemode_t *)addr)->syncmask[0] = 0; @@ -2185,7 +2227,7 @@ ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2; break; } - splx(s); + psm_unlock(sc); break; case OLD_MOUSE_SETMODE: @@ -2265,12 +2307,10 @@ set_mouse_scaling(sc->kbdc, 1); get_mouse_status(sc->kbdc, stat, 0, 3); - s = spltty(); sc->mode.rate = mode.rate; sc->mode.resolution = mode.resolution; sc->mode.accelfactor = mode.accelfactor; sc->mode.level = mode.level; - splx(s); unblock_mouse_data(sc, command_byte); break; @@ -2287,7 +2327,7 @@ break; case MOUSE_GETSTATUS: - s = spltty(); + psm_lock(sc); status = sc->status; sc->status.flags = 0; sc->status.obutton = sc->status.button; @@ -2295,7 +2335,7 @@ sc->status.dx = 0; sc->status.dy = 0; sc->status.dz = 0; - splx(s); + psm_unlock(sc); *(mousestatus_t *)addr = status; break; @@ -2303,11 +2343,11 @@ case MOUSE_GETVARS: var = (mousevar_t *)addr; bzero(var, sizeof(*var)); - s = spltty(); + psm_lock(sc); var->var[0] = MOUSE_VARS_PS2_SIG; var->var[1] = sc->config; var->var[2] = sc->flags; - splx(s); + psm_unlock(sc); break; case MOUSE_SETVARS: @@ -2426,16 +2466,13 @@ psmtimeout(void *arg) { struct psm_softc *sc; - int s; sc = (struct psm_softc *)arg; - s = spltty(); if (sc->watchdog) { VLOG(4, (LOG_DEBUG, "psm%d: lost interrupt?\n", sc->unit)); - psmintr(sc); + psmintr_locked(sc); } sc->watchdog = TRUE; - splx(s); callout_reset(&sc->callout, hz, psmtimeout, sc); } @@ -2496,13 +2533,14 @@ } static void -psmintr(void *arg) +psmintr_locked(void *arg) { struct psm_softc *sc = arg; struct timeval now; int c; packetbuf_t *pb; + psm_lock_assert(sc); /* read until there is nothing to read */ while((c = psm_read_aux_data(sc->kbdc)) != -1) { @@ -2653,6 +2691,16 @@ } static void +psmintr(void *arg) +{ + struct psm_softc *sc = arg; + + psm_lock(sc); + psmintr_locked(sc); + psm_unlock(sc); +} + +static void proc_mmanplus(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, int *x, int *y, int *z) { @@ -4137,6 +4185,8 @@ struct psm_softc *sc = arg; packetbuf_t *pb; + psm_lock_assert(sc); + /* Invoke soft handler only when pqueue is empty. Otherwise it will be * invoked from psmintr soon with pqueue filled with real data */ if (sc->pqueue_start == sc->pqueue_end && @@ -4176,11 +4226,11 @@ struct psm_softc *sc = arg; mousestatus_t ms; packetbuf_t *pb; - int x, y, z, c, l, s; + int x, y, z, c, l; - getmicrouptime(&sc->lastsoftintr); + psm_lock_assert(sc); - s = spltty(); + getmicrouptime(&sc->lastsoftintr); do { pb = &sc->pqueue[sc->pqueue_start]; @@ -4438,25 +4488,23 @@ VLOG(2, (LOG_DEBUG, "softintr: callout set: %d ticks\n", tvtohz(&sc->idletimeout))); } - splx(s); } static int psmpoll(struct cdev *dev, int events, struct thread *td) { struct psm_softc *sc = dev->si_drv1; - int s; int revents = 0; /* Return true if a mouse event available */ - s = spltty(); + psm_lock(sc); if (events & (POLLIN | POLLRDNORM)) { if (sc->queue.count > 0) revents |= events & (POLLIN | POLLRDNORM); else selrecord(td, &sc->rsel); } - splx(s); + psm_unlock(sc); return (revents); }