/* * Detach a keyboard. To keep track of users of the softc we keep * a reference count that's incremented while inside, e.g., read. * If the keyboard is active and the reference count is > 0 (0 is the * normal state) we post an event and then wait for the process * that had the reference to wake us up again. Then we blow away the * vnode and return (which will deallocate the softc). */ int wskbd_detach(device_t self, int flags) { struct wskbd_softc *sc = device_private(self); struct wseventvar *evar; int maj, mn; int s; #if NWSMUX > 0 /* Tell parent mux we're leaving. */ if (sc->sc_base.me_parent != NULL) wsmux_detach_sc(&sc->sc_base); #endif callout_halt(&sc->sc_repeat_ch, NULL); callout_destroy(&sc->sc_repeat_ch); if (sc->sc_isconsole) { KASSERT(wskbd_console_device == sc); wskbd_console_device = NULL; } pmf_device_deregister(self); evar = sc->sc_base.me_evp; if (evar != NULL && evar->io != NULL) { s = spltty(); if (--sc->sc_refcnt >= 0) { struct wscons_event event; /* Wake everyone by generating a dummy event. */ event.type = 0; event.value = 0; if (wsevent_inject(evar, &event, 1) != 0) wsevent_wakeup(evar); /* Wait for processes to go away. */ if (tsleep(sc, PZERO, "wskdet", hz * 60)) aprint_error("wskbd_detach: %s didn't detach\n", device_xname(self)); } splx(s); } /* locate the major number */ maj = cdevsw_lookup_major(&wskbd_cdevsw); /* Nuke the vnodes for any open instances. */ mn = device_unit(self); vdevgone(maj, mn, mn, VCHR); return (0); }
static void wsmouse_repeat(void *v) { int oldspl; unsigned int newdelay; struct wsmouse_softc *sc; struct wscons_event events[2]; oldspl = spltty(); sc = (struct wsmouse_softc *)v; if (sc->sc_repeat_button == -1) { /* Race condition: a "button up" event came in when * this function was already called but did not do * spltty() yet. */ splx(oldspl); return; } KASSERT(sc->sc_repeat_button >= 0); KASSERT(sc->sc_repeat.wr_buttons & (1 << sc->sc_repeat_button)); newdelay = sc->sc_repeat_delay; events[0].type = WSCONS_EVENT_MOUSE_UP; events[0].value = sc->sc_repeat_button; events[1].type = WSCONS_EVENT_MOUSE_DOWN; events[1].value = sc->sc_repeat_button; if (wsevent_inject(sc->sc_base.me_evp, events, 2) == 0) { sc->sc_ub = 1 << sc->sc_repeat_button; if (newdelay - sc->sc_repeat.wr_delay_decrement < sc->sc_repeat.wr_delay_minimum) newdelay = sc->sc_repeat.wr_delay_minimum; else if (newdelay > sc->sc_repeat.wr_delay_minimum) newdelay -= sc->sc_repeat.wr_delay_decrement; KASSERT(newdelay >= sc->sc_repeat.wr_delay_minimum && newdelay <= sc->sc_repeat.wr_delay_first); } /* * Reprogram the repeating event. */ sc->sc_repeat_delay = newdelay; callout_schedule(&sc->sc_repeat_callout, mstohz(newdelay)); splx(oldspl); }
/* * Detach a mouse. To keep track of users of the softc we keep * a reference count that's incremented while inside, e.g., read. * If the mouse is active and the reference count is > 0 (0 is the * normal state) we post an event and then wait for the process * that had the reference to wake us up again. Then we blow away the * vnode and return (which will deallocate the softc). */ int wsmouse_detach(device_t self, int flags) { struct wsmouse_softc *sc = device_private(self); struct wseventvar *evar; int maj, mn; int s; #if NWSMUX > 0 /* Tell parent mux we're leaving. */ if (sc->sc_base.me_parent != NULL) { DPRINTF(("wsmouse_detach:\n")); wsmux_detach_sc(&sc->sc_base); } #endif /* If we're open ... */ evar = sc->sc_base.me_evp; if (evar != NULL && evar->io != NULL) { s = spltty(); if (--sc->sc_refcnt >= 0) { struct wscons_event event; /* Wake everyone by generating a dummy event. */ event.type = 0; event.value = 0; if (wsevent_inject(evar, &event, 1) != 0) wsevent_wakeup(evar); /* Wait for processes to go away. */ if (tsleep(sc, PZERO, "wsmdet", hz * 60)) printf("wsmouse_detach: %s didn't detach\n", device_xname(self)); } splx(s); } /* locate the major number */ maj = cdevsw_lookup_major(&wsmouse_cdevsw); /* Nuke the vnodes for any open instances (calls close). */ mn = device_unit(self); vdevgone(maj, mn, mn, VCHR); return (0); }
/* * Keyboard is generating events. Turn this keystroke into an * event and put it in the queue. If the queue is full, the * keystroke is lost (sorry!). */ static void wskbd_deliver_event(struct wskbd_softc *sc, u_int type, int value) { struct wseventvar *evar; struct wscons_event event; evar = sc->sc_base.me_evp; if (evar == NULL) { DPRINTF(("wskbd_input: not open\n")); return; } #ifdef DIAGNOSTIC if (evar->q == NULL) { printf("wskbd_input: evar->q=NULL\n"); return; } #endif event.type = type; event.value = 0; DPRINTF(("%d ->", value)); if (sc->sc_evtrans_len > 0) { if (sc->sc_evtrans_len > value) { DPRINTF(("%d", sc->sc_evtrans[value])); event.value = sc->sc_evtrans[value]; } } else { event.value = value; } DPRINTF(("\n")); if (wsevent_inject(evar, &event, 1) != 0) log(LOG_WARNING, "%s: event queue overflow\n", device_xname(sc->sc_base.me_dv)); }
void wsmouse_input(device_t wsmousedev, u_int btns /* 0 is up */, int x, int y, int z, int w, u_int flags) { struct wsmouse_softc *sc = device_private(wsmousedev); struct wseventvar *evar; int mb, ub, d, nevents; /* one for each dimension (4) + a bit for each button */ struct wscons_event events[4 + sizeof(d) * 8]; /* * Discard input if not open. */ evar = sc->sc_base.me_evp; if (evar == NULL) return; #ifdef DIAGNOSTIC if (evar->q == NULL) { printf("wsmouse_input: evar->q=NULL\n"); return; } #endif #if NWSMUX > 0 DPRINTFN(5,("wsmouse_input: %s mux=%p, evar=%p\n", device_xname(sc->sc_base.me_dv), sc->sc_base.me_parent, evar)); #endif sc->sc_mb = btns; if (!(flags & WSMOUSE_INPUT_ABSOLUTE_X)) sc->sc_dx += x; if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Y)) sc->sc_dy += y; if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Z)) sc->sc_dz += z; if (!(flags & WSMOUSE_INPUT_ABSOLUTE_W)) sc->sc_dw += w; /* * We have at least one event (mouse button, delta-X, or * delta-Y; possibly all three, and possibly three separate * button events). Deliver these events until we are out * of changes or out of room. As events get delivered, * mark them `unchanged'. */ ub = sc->sc_ub; nevents = 0; if (flags & WSMOUSE_INPUT_ABSOLUTE_X) { if (sc->sc_x != x) { events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_X; events[nevents].value = x; nevents++; } } else { if (sc->sc_dx) { events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_X; events[nevents].value = sc->sc_dx; nevents++; } } if (flags & WSMOUSE_INPUT_ABSOLUTE_Y) { if (sc->sc_y != y) { events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_Y; events[nevents].value = y; nevents++; } } else { if (sc->sc_dy) { events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_Y; events[nevents].value = sc->sc_dy; nevents++; } } if (flags & WSMOUSE_INPUT_ABSOLUTE_Z) { if (sc->sc_z != z) { events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_Z; events[nevents].value = z; nevents++; } } else { if (sc->sc_dz) { events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_Z; events[nevents].value = sc->sc_dz; nevents++; } } if (flags & WSMOUSE_INPUT_ABSOLUTE_W) { if (sc->sc_w != w) { events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_W; events[nevents].value = w; nevents++; } } else { if (sc->sc_dw) { events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_W; events[nevents].value = sc->sc_dw; nevents++; } } mb = sc->sc_mb; while ((d = mb ^ ub) != 0) { int btnno; /* * Cancel button repeating if button status changed. */ if (sc->sc_repeat_button != -1) { KASSERT(sc->sc_repeat_button >= 0); KASSERT(sc->sc_repeat.wr_buttons & (1 << sc->sc_repeat_button)); ub &= ~(1 << sc->sc_repeat_button); sc->sc_repeat_button = -1; callout_stop(&sc->sc_repeat_callout); } /* * Mouse button change. Find the first change and drop * it into the event queue. */ btnno = ffs(d) - 1; KASSERT(btnno >= 0); if (nevents >= sizeof(events) / sizeof(events[0])) { aprint_error_dev(sc->sc_base.me_dv, "Event queue full (button status mb=0x%x" " ub=0x%x)\n", mb, ub); break; } events[nevents].type = (mb & d) ? WSCONS_EVENT_MOUSE_DOWN : WSCONS_EVENT_MOUSE_UP; events[nevents].value = btnno; nevents++; ub ^= (1 << btnno); /* * Program button repeating if configured for this button. */ if ((mb & d) && (sc->sc_repeat.wr_buttons & (1 << btnno)) && sc->sc_repeat.wr_delay_first > 0) { sc->sc_repeat_button = btnno; sc->sc_repeat_delay = sc->sc_repeat.wr_delay_first; callout_schedule(&sc->sc_repeat_callout, mstohz(sc->sc_repeat_delay)); } } if (nevents == 0 || wsevent_inject(evar, events, nevents) == 0) { /* All events were correctly injected into the queue. * Synchronize the mouse's status with what the user * has received. */ sc->sc_x = x; sc->sc_dx = 0; sc->sc_y = y; sc->sc_dy = 0; sc->sc_z = z; sc->sc_dz = 0; sc->sc_w = w; sc->sc_dw = 0; sc->sc_ub = ub; #if NWSMUX > 0 DPRINTFN(5,("wsmouse_input: %s wakeup evar=%p\n", device_xname(sc->sc_base.me_dv), evar)); #endif } }