Fix the keyboard lockup problem. There were two big clues: The first was a
authorMatthew Dillon <dillon@dragonflybsd.org>
Thu, 16 Dec 2004 08:30:15 +0000 (08:30 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Thu, 16 Dec 2004 08:30:15 +0000 (08:30 +0000)
report that it sometimes seemed to occur during heavy video operations.  The
second was a set of kernel dates from Jansen Gotis and Michael Powell that
focused me in on the right part of the code.

Simply put, there is a hack for AT keyboards that polls the keyboard for
data 10 times a second in order to catch lost interrupts.  Lost interrupts
can occur because unlike other interrupts the AT keyboard interrupt is
edge-triggered.  This means that latency in the system can cause the
keyboard interrupt to retrigger before it is reenabled after an earlier
event but not cause any further interrupts.

There is a big hack in the system that polls for keyboard data 10 times a
second in order to detect this 'lost' interrupt case.  However, that code
was broken by the timeout->callout work I did on September 19th.  An
incorrectly placed callout_reset() stopped the polling code in its tracks.

Reported-by: Jeroen Ruigrok/asmodai <asmodai@wxs.nl>,
Chris Pressey <cpressey@catseye.mine.nu>,
Michael Powell <nightrecon@hotmail.com>,
Jansen Gotis <jtgotis@gmail.com>,
And others.

sys/dev/misc/kbd/kbd.c

index afa79ad..39721ea 100644 (file)
@@ -24,7 +24,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/kbd/kbd.c,v 1.17.2.2 2001/07/30 16:46:43 yokota Exp $
- * $DragonFly: src/sys/dev/misc/kbd/kbd.c,v 1.13 2004/10/07 01:32:04 dillon Exp $
+ * $DragonFly: src/sys/dev/misc/kbd/kbd.c,v 1.14 2004/12/16 08:30:15 dillon Exp $
  */
 /*
  * Generic keyboard driver.
@@ -210,6 +210,7 @@ kbd_register(keyboard_t *kbd)
        kbd->kb_token = NULL;
        kbd->kb_callback.kc_func = NULL;
        kbd->kb_callback.kc_arg = NULL;
+       callout_init(&kbd->kb_atkbd_timeout_ch);
 
        SLIST_FOREACH(p, &keyboard_drivers, link) {
                if (strcmp(p->name, kbd->kb_name) == 0) {
@@ -241,6 +242,7 @@ kbd_unregister(keyboard_t *kbd)
                return ENOENT;
 
        crit_enter();
+       callout_stop(&kbd->kb_atkbd_timeout_ch);
        if (KBD_IS_BUSY(kbd)) {
                error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING,
                                                    kbd->kb_callback.kc_arg);
@@ -333,7 +335,6 @@ kbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func,
                        crit_exit();
                        return -1;
                }
-               callout_init(&keyboard[index]->kb_atkbd_timeout_ch);
                keyboard[index]->kb_token = id;
                KBD_BUSY(keyboard[index]);
                keyboard[index]->kb_callback.kc_func = func;
@@ -355,7 +356,6 @@ kbd_release(keyboard_t *kbd, void *id)
        } else if (kbd->kb_token != id) {
                error = EPERM;
        } else {
-               callout_stop(&kbd->kb_atkbd_timeout_ch);
                kbd->kb_token = NULL;
                KBD_UNBUSY(kbd);
                kbd->kb_callback.kc_func = NULL;