From owner-svn-src-stable@FreeBSD.ORG Tue Apr 6 23:21:30 2010 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 8680F106564A; Tue, 6 Apr 2010 23:21:30 +0000 (UTC) (envelope-from thompsa@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 725A28FC13; Tue, 6 Apr 2010 23:21:30 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o36NLU10011837; Tue, 6 Apr 2010 23:21:30 GMT (envelope-from thompsa@svn.freebsd.org) Received: (from thompsa@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o36NLUTS011835; Tue, 6 Apr 2010 23:21:30 GMT (envelope-from thompsa@svn.freebsd.org) Message-Id: <201004062321.o36NLUTS011835@svn.freebsd.org> From: Andrew Thompson Date: Tue, 6 Apr 2010 23:21:30 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r206303 - stable/8/sys/dev/usb/input X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 06 Apr 2010 23:21:30 -0000 Author: thompsa Date: Tue Apr 6 23:21:30 2010 New Revision: 206303 URL: http://svn.freebsd.org/changeset/base/206303 Log: MFC r203896 Detect when we are polling from kernel via cngetc() in the boot process and reserve the keypresses so they do not get passed to syscons. Submitted by: Hans Petter Selasky Modified: stable/8/sys/dev/usb/input/ukbd.c Directory Properties: stable/8/sys/ (props changed) stable/8/sys/amd64/include/xen/ (props changed) stable/8/sys/cddl/contrib/opensolaris/ (props changed) stable/8/sys/contrib/dev/acpica/ (props changed) stable/8/sys/contrib/pf/ (props changed) stable/8/sys/dev/xen/xenpci/ (props changed) Modified: stable/8/sys/dev/usb/input/ukbd.c ============================================================================== --- stable/8/sys/dev/usb/input/ukbd.c Tue Apr 6 23:21:06 2010 (r206302) +++ stable/8/sys/dev/usb/input/ukbd.c Tue Apr 6 23:21:30 2010 (r206303) @@ -151,6 +151,7 @@ struct ukbd_softc { struct ukbd_data sc_ndata; struct ukbd_data sc_odata; + struct thread *sc_poll_thread; struct usb_device *sc_udev; struct usb_interface *sc_iface; struct usb_xfer *sc_xfer[UKBD_N_TRANSFER]; @@ -174,9 +175,10 @@ struct ukbd_softc { #define UKBD_FLAG_APPLE_SWAP 0x0100 #define UKBD_FLAG_TIMER_RUNNING 0x0200 - int32_t sc_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */ - int32_t sc_state; /* shift/lock key state */ - int32_t sc_accents; /* accent key index (> 0) */ + int sc_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */ + int sc_state; /* shift/lock key state */ + int sc_accents; /* accent key index (> 0) */ + int sc_poll_tick_last; uint16_t sc_inputs; uint16_t sc_inputhead; @@ -187,6 +189,7 @@ struct ukbd_softc { uint8_t sc_iface_no; uint8_t sc_kbd_id; uint8_t sc_led_id; + uint8_t sc_poll_detected; }; #define KEY_ERROR 0x01 @@ -281,6 +284,9 @@ static int ukbd_ioctl(keyboard_t *, u_lo static int ukbd_enable(keyboard_t *); static int ukbd_disable(keyboard_t *); static void ukbd_interrupt(struct ukbd_softc *); +static int ukbd_is_polling(struct ukbd_softc *); +static int ukbd_polls_other_thread(struct ukbd_softc *); +static void ukbd_event_keyinput(struct ukbd_softc *); static device_probe_t ukbd_probe; static device_attach_t ukbd_attach; @@ -331,8 +337,21 @@ ukbd_do_poll(struct ukbd_softc *sc, uint { DPRINTFN(2, "polling\n"); - if (kdb_active == 0) + /* update stats about last polling event */ + sc->sc_poll_tick_last = ticks; + sc->sc_poll_detected = 1; + + if (kdb_active == 0) { + while (sc->sc_inputs == 0) { + /* make sure the USB code gets a chance to run */ + pause("UKBD", 1); + + /* check if we should wait */ + if (!wait) + break; + } return; /* Only poll if KDB is active */ + } while (sc->sc_inputs == 0) { @@ -366,9 +385,13 @@ ukbd_get_key(struct ukbd_softc *sc, uint /* start transfer, if not already started */ usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT]); } - if (sc->sc_flags & UKBD_FLAG_POLLING) { + + if (ukbd_polls_other_thread(sc)) + return (-1); + + if (sc->sc_flags & UKBD_FLAG_POLLING) ukbd_do_poll(sc, wait); - } + if (sc->sc_inputs == 0) { c = -1; } else { @@ -389,14 +412,13 @@ ukbd_interrupt(struct ukbd_softc *sc) uint32_t o_mod; uint32_t now = sc->sc_time_ms; uint32_t dtime; - uint32_t c; uint8_t key; uint8_t i; uint8_t j; - if (sc->sc_ndata.keycode[0] == KEY_ERROR) { - goto done; - } + if (sc->sc_ndata.keycode[0] == KEY_ERROR) + return; + n_mod = sc->sc_ndata.modifiers; o_mod = sc->sc_odata.modifiers; if (n_mod != o_mod) { @@ -469,14 +491,22 @@ pfound: ; sc->sc_odata = sc->sc_ndata; - bcopy(sc->sc_ntime, sc->sc_otime, sizeof(sc->sc_otime)); + memcpy(sc->sc_otime, sc->sc_ntime, sizeof(sc->sc_otime)); + + ukbd_event_keyinput(sc); +} + +static void +ukbd_event_keyinput(struct ukbd_softc *sc) +{ + int c; + + if (ukbd_is_polling(sc)) + return; + + if (sc->sc_inputs == 0) + return; - if (sc->sc_inputs == 0) { - goto done; - } - if (sc->sc_flags & UKBD_FLAG_POLLING) { - goto done; - } if (KBD_IS_ACTIVE(&sc->sc_kbd) && KBD_IS_BUSY(&sc->sc_kbd)) { /* let the callback function process the input */ @@ -488,8 +518,6 @@ pfound: ; c = ukbd_read_char(&sc->sc_kbd, 0); } while (c != NOKEY); } -done: - return; } static void @@ -499,12 +527,14 @@ ukbd_timeout(void *arg) mtx_assert(&Giant, MA_OWNED); - if (!(sc->sc_flags & UKBD_FLAG_POLLING)) { - sc->sc_time_ms += 25; /* milliseconds */ - } + sc->sc_time_ms += 25; /* milliseconds */ + ukbd_interrupt(sc); - if (ukbd_any_key_pressed(sc)) { + /* Make sure any leftover key events gets read out */ + ukbd_event_keyinput(sc); + + if (ukbd_any_key_pressed(sc) || (sc->sc_inputs != 0)) { ukbd_start_timer(sc); } else { sc->sc_flags &= ~UKBD_FLAG_TIMER_RUNNING; @@ -837,6 +867,18 @@ ukbd_attach(device_t dev) */ KBD_PROBE_DONE(kbd); + /* + * Set boot protocol if we need the quirk. + */ + if (usb_test_quirk(uaa, UQ_KBD_BOOTPROTO)) { + err = usbd_req_set_protocol(sc->sc_udev, NULL, + sc->sc_iface_index, 0); + if (err != USB_ERR_NORMAL_COMPLETION) { + DPRINTF("set protocol error=%s\n", usbd_errstr(err)); + goto detach; + } + } + /* figure out if there is an ID byte in the data */ err = usbd_req_get_hid_desc(uaa->device, NULL, &hid_ptr, &hid_len, M_TEMP, uaa->info.bIfaceIndex); @@ -880,10 +922,14 @@ ukbd_attach(device_t dev) /* ignore if SETIDLE fails, hence it is not crucial */ err = usbd_req_set_idle(sc->sc_udev, NULL, sc->sc_iface_index, 0, 0); + mtx_lock(&Giant); + ukbd_ioctl(kbd, KDSETLED, (caddr_t)&sc->sc_state); KBD_INIT_DONE(kbd); + mtx_unlock(&Giant); + if (kbd_register(kbd) < 0) { goto detach; } @@ -925,9 +971,8 @@ ukbd_detach(device_t dev) DPRINTF("\n"); - if (sc->sc_flags & UKBD_FLAG_POLLING) { - panic("cannot detach polled keyboard\n"); - } + mtx_lock(&Giant); + sc->sc_flags |= UKBD_FLAG_GONE; usb_callout_stop(&sc->sc_callout); @@ -954,6 +999,8 @@ ukbd_detach(device_t dev) } sc->sc_kbd.kb_flags = 0; + mtx_unlock(&Giant); + usbd_transfer_unsetup(sc->sc_xfer, UKBD_N_TRANSFER); usb_callout_drain(&sc->sc_callout); @@ -969,8 +1016,12 @@ ukbd_resume(device_t dev) { struct ukbd_softc *sc = device_get_softc(dev); + mtx_lock(&Giant); + ukbd_clear_state(&sc->sc_kbd); + mtx_unlock(&Giant); + return (0); } @@ -1076,13 +1127,19 @@ ukbd_check(keyboard_t *kbd) mtx_unlock(&Giant); return (retval); } - ukbd_do_poll(sc, 0); } else { /* XXX the keyboard layer requires Giant */ if (!mtx_owned(&Giant)) return (0); } + /* check if key belongs to this thread */ + if (ukbd_polls_other_thread(sc)) + return (0); + + if (sc->sc_flags & UKBD_FLAG_POLLING) + ukbd_do_poll(sc, 0); + #ifdef UKBD_EMULATE_ATSCANCODE if (sc->sc_buffered_char[0]) { return (1); @@ -1118,6 +1175,10 @@ ukbd_check_char(keyboard_t *kbd) return (0); } + /* check if key belongs to this thread */ + if (ukbd_polls_other_thread(sc)) + return (0); + if ((sc->sc_composed_char > 0) && (!(sc->sc_flags & UKBD_FLAG_COMPOSE))) { return (1); @@ -1156,6 +1217,10 @@ ukbd_read(keyboard_t *kbd, int wait) return (-1); } + /* check if key belongs to this thread */ + if (ukbd_polls_other_thread(sc)) + return (-1); + #ifdef UKBD_EMULATE_ATSCANCODE if (sc->sc_buffered_char[0]) { scancode = sc->sc_buffered_char[0]; @@ -1220,6 +1285,10 @@ ukbd_read_char(keyboard_t *kbd, int wait return (NOKEY); } + /* check if key belongs to this thread */ + if (ukbd_polls_other_thread(sc)) + return (NOKEY); + next_code: /* do we have a composed char to return ? */ @@ -1419,7 +1488,17 @@ ukbd_ioctl(keyboard_t *kbd, u_long cmd, * keyboard system must get out of "Giant" first, before the * CPU can proceed here ... */ - return (EINVAL); + switch (cmd) { + case KDGKBMODE: + case KDSKBMODE: + /* workaround for Geli */ + mtx_lock(&Giant); + i = ukbd_ioctl(kbd, cmd, arg); + mtx_unlock(&Giant); + return (i); + default: + return (EINVAL); + } } switch (cmd) { @@ -1445,7 +1524,8 @@ ukbd_ioctl(keyboard_t *kbd, u_long cmd, case K_RAW: case K_CODE: if (sc->sc_mode != *(int *)arg) { - ukbd_clear_state(kbd); + if (ukbd_is_polling(sc) == 0) + ukbd_clear_state(kbd); sc->sc_mode = *(int *)arg; } break; @@ -1552,7 +1632,11 @@ ukbd_clear_state(keyboard_t *kbd) struct ukbd_softc *sc = kbd->kb_data; if (!mtx_owned(&Giant)) { - return; /* XXX */ + /* XXX cludge */ + mtx_lock(&Giant); + ukbd_clear_state(kbd); + mtx_unlock(&Giant); + return; } sc->sc_flags &= ~(UKBD_FLAG_COMPOSE | UKBD_FLAG_POLLING); @@ -1563,10 +1647,10 @@ ukbd_clear_state(keyboard_t *kbd) sc->sc_buffered_char[0] = 0; sc->sc_buffered_char[1] = 0; #endif - bzero(&sc->sc_ndata, sizeof(sc->sc_ndata)); - bzero(&sc->sc_odata, sizeof(sc->sc_odata)); - bzero(&sc->sc_ntime, sizeof(sc->sc_ntime)); - bzero(&sc->sc_otime, sizeof(sc->sc_otime)); + memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata)); + memset(&sc->sc_odata, 0, sizeof(sc->sc_odata)); + memset(&sc->sc_ntime, 0, sizeof(sc->sc_ntime)); + memset(&sc->sc_otime, 0, sizeof(sc->sc_otime)); } /* save the internal state, not used */ @@ -1584,6 +1668,30 @@ ukbd_set_state(keyboard_t *kbd, void *bu } static int +ukbd_is_polling(struct ukbd_softc *sc) +{ + int delta; + + if (sc->sc_flags & UKBD_FLAG_POLLING) + return (1); /* polling */ + + delta = ticks - sc->sc_poll_tick_last; + if ((delta < 0) || (delta >= hz)) { + sc->sc_poll_detected = 0; + return (0); /* not polling */ + } + + return (sc->sc_poll_detected); +} + +static int +ukbd_polls_other_thread(struct ukbd_softc *sc) +{ + return (ukbd_is_polling(sc) && + (sc->sc_poll_thread != curthread)); +} + +static int ukbd_poll(keyboard_t *kbd, int on) { struct ukbd_softc *sc = kbd->kb_data; @@ -1599,8 +1707,10 @@ ukbd_poll(keyboard_t *kbd, int on) if (on) { sc->sc_flags |= UKBD_FLAG_POLLING; + sc->sc_poll_thread = curthread; } else { sc->sc_flags &= ~UKBD_FLAG_POLLING; + ukbd_start_timer(sc); /* start timer */ } return (0); }