This patch implements a new KDB interface for USB keyboards
which fixes the following problems:

1. Currently KDB is only "OHCI" type USB aware. If a keyboard is attached
   via a USB2.0 hub, the Linux kernel EHCI driver is used instead of OHCI, but
   kdb will still attempt to use the OHCI driver poll interface to
   read a character from the keyboard - this results in a crash from
   within kdb and, hence, kdb is unuseable.

   This patch allows KDB to work with any Host Contoller driver
   and call the correct HC driver poll routine (as long as the
   HC driver provides a .kdb_poll_char routine via it's
   associated hc_driver struct).
   If a HC driver is managing a keyboard, but doesn't provide a
   valid .kdb_poll_char routine, the keyboard will be ignored by KDB.

2. Hotplug - currently, if a USB keyboard is unplugged and plugged back
   in, KDB loses track and no longer recognizes the keyboard for use from KDB.
   This is because the "kdb_usb_infos" struct was getting zeroed and the
   .poll_func field set to NULL on hotunplugs (and not set to something
   valid on hotplugs)

   Hotplugged keyboards are now recognized by KDB.

3. Currently KDB can only make use of 1 USB type keyboard. This is because
   of the single "kdb_usb_infos" structure interface - which can only describe
   a single keyboard/urb.

   New code can handle up to 8 attached keyboards - input is multiplexed
   from all of them while in kdb. The number of supported USB keyboards can
   easily be changed via the KDB_USB_NUM_KEYBOARDS def in appropriate
   arch/XXX/kdb//kdba_io.c file.


General notes about the new code:

   The new USB interface is composed of two new routines which
   HID drivers need to call when configuring USB keyboards:

kdb_usb_keyboard_attach() - to attach a USB keyboard to KDB
kdb_usb_keyboard_detach() - to detach a USB keyboard from KDB

   These should be called from the hotplug interfaces so that hotplugs/
   unplugs keep KDB up-to-date on what keyboards are on the system.

   Each USB Host Controller driver which could manage keyboards needs
   to add a .kdb_poll_char entry to it's associated hc_driver struct and
   and, of course, provide the routine to poll a keyboard's URB for characters.
   The OHCI implementation is complete and there. UHCI is completely
   missing at this point and EHCI is partially there - i.e. EHCI provides
   the .kdb_poll_char entry, but the associated routine, ehci_kdb_poll_char()
   is not yet implemented (and just returns -1 for now). I plan to work
   on the EHCI poll code next. I hope to have a subsequent patch for this
   very soon.
 
Issues:

   While testing I noticed some issues when using hubs to attach
   USB keyboards. When multiple keyboards are attached via a USB1.1
   hub, only one of the keyboards is operational from kdb - not sure
   why. It's probably a shortcoming of the OHCI poll character code.
   Also, it appears hotplug of USB1.1 hubs doesn't work right in Linux
   and the HID hotplug interfaces are not called for the attached keyboards.
   Hotplug does work correctly with USB2.0 hubs however.

   When keyboard(s) are attached directly to USB ports (with no hubs), I
   could find no issues - hotplug/unplug, mulitplexing all appear to work
   properly.

Testing:

   These changes have only been tested on a ia64 machine containing
   OHCI/EHCI style USB controllers. Additional testing on other archs
   and USB configs by others would be appreciated.


Patch is against 2.6.23-rc8 (should be applied after kdb-4.4-2.6.23-*.1 patch 
set)

Signed-off-by:  Aaron Young ([EMAIL PROTECTED])

---

diff -pNaru linux.orig/arch/i386/kdb/kdba_io.c linux/arch/i386/kdb/kdba_io.c
--- linux.orig/arch/i386/kdb/kdba_io.c  2007-11-09 11:37:45.000000000 -0800
+++ linux/arch/i386/kdb/kdba_io.c       2007-11-08 14:26:07.710994431 -0800
@@ -29,9 +29,10 @@
 #endif
 
 #ifdef CONFIG_KDB_USB
-struct kdb_usb_exchange kdb_usb_infos;
 
-EXPORT_SYMBOL(kdb_usb_infos);
+/* support up to 8 USB keyboards (probably excessive, but...) */
+#define KDB_USB_NUM_KEYBOARDS   8
+struct kdb_usb_kbd_info kdb_usb_kbds[KDB_USB_NUM_KEYBOARDS];
 
 static unsigned char kdb_usb_keycode[256] = {
          0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
@@ -52,77 +53,161 @@ static unsigned char kdb_usb_keycode[256
        150,158,159,128,136,177,178,176,142,152,173,140
 };
 
-/* get_usb_char
- * This function drives the UHCI controller,
- * fetch the USB scancode and decode it
+/*
+ * kdb_usb_keyboard_attach()
+ * Attach a USB keyboard to kdb.
  */
-static int get_usb_char(void)
+int
+kdb_usb_keyboard_attach(struct urb *urb, unsigned char *buffer, void 
*poll_func)
 {
-       static int usb_lock;
-       unsigned char keycode, spec;
-       extern u_short plain_map[], shift_map[], ctrl_map[];
+        int     i;
+        int     rc = -1;
 
-       /* Is USB initialized ? */
-       if(!kdb_usb_infos.poll_func || !kdb_usb_infos.urb)
-               return -1;
+        /*
+         * Search through the array of KDB USB keyboards (kdb_usb_kbds)
+         * looking for a free index. If found, assign the keyboard to
+         * the array index.
+         */
+
+        for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) {
+                if (kdb_usb_kbds[i].urb) /* index is already assigned */
+                        continue;
+
+                /* found a free array index */
+                kdb_usb_kbds[i].urb = urb;
+                kdb_usb_kbds[i].buffer = buffer;
+                kdb_usb_kbds[i].poll_func = poll_func;
 
-       /* Transfer char if they are present */
-       (*kdb_usb_infos.poll_func)(kdb_usb_infos.uhci, (struct urb 
*)kdb_usb_infos.urb);
+                rc = 0; /* success */
 
-       spec = kdb_usb_infos.buffer[0];
-       keycode = kdb_usb_infos.buffer[2];
-       kdb_usb_infos.buffer[0] = (char)0;
-       kdb_usb_infos.buffer[2] = (char)0;
+                break;
+        }
 
-       if(kdb_usb_infos.buffer[3])
-               return -1;
+        return rc;
+}
+EXPORT_SYMBOL_GPL (kdb_usb_keyboard_attach);
 
-       /* A normal key is pressed, decode it */
-       if(keycode)
-               keycode = kdb_usb_keycode[keycode];
-
-       /* 2 Keys pressed at one time ? */
-       if (spec && keycode) {
-               switch(spec)
-               {
-                       case 0x2:
-                       case 0x20: /* Shift */
-                               return shift_map[keycode];
-                       case 0x1:
-                       case 0x10: /* Ctrl */
-                               return ctrl_map[keycode];
-                       case 0x4:
-                       case 0x40: /* Alt */
-                               break;
-               }
-       }
-       else {
-               if(keycode) { /* If only one key pressed */
-                       switch(keycode)
-                       {
-                               case 0x1C: /* Enter */
-                                       return 13;
-
-                               case 0x3A: /* Capslock */
-                                       usb_lock ? (usb_lock = 0) : (usb_lock = 
1);
-                                       break;
-                               case 0x0E: /* Backspace */
-                                       return 8;
-                               case 0x0F: /* TAB */
-                                       return 9;
-                               case 0x77: /* Pause */
-                                       break ;
-                               default:
-                                       if(!usb_lock) {
-                                               return plain_map[keycode];
-                                       }
-                                       else {
-                                               return shift_map[keycode];
-                                       }
-                       }
-               }
-       }
-       return -1;
+/*
+ * kdb_usb_keyboard_detach()
+ * Detach a USB keyboard from kdb.
+ */
+int
+kdb_usb_keyboard_detach(struct urb *urb)
+{
+        int     i;
+        int     rc = -1;
+
+        /*
+         * Search through the array of KDB USB keyboards (kdb_usb_kbds)
+         * looking for the index with the matching URB. If found,
+         * clear the array index.
+         */
+
+        for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) {
+                if (kdb_usb_kbds[i].urb != urb)
+                        continue;
+
+                /* found it, clear the index */
+                kdb_usb_kbds[i].urb = NULL;
+                kdb_usb_kbds[i].buffer = NULL;
+                kdb_usb_kbds[i].poll_func = NULL;
+                kdb_usb_kbds[i].caps_lock = 0;
+
+                rc = 0; /* success */
+
+                break;
+        }
+
+        return rc;
+}
+EXPORT_SYMBOL_GPL (kdb_usb_keyboard_detach);
+
+/*
+ * get_usb_char
+ * This function drives the USB attached keyboards.
+ * Fetch the USB scancode and decode it.
+ */
+static int
+get_usb_char(void)
+{
+        int     i;
+        int     ret;
+        unsigned char keycode, spec;
+        extern u_short plain_map[], shift_map[], ctrl_map[];
+
+        /*
+         * Loop through all the USB keyboard(s) and return
+         * the first character obtained from them.
+         */
+
+        for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) {
+                /* skip uninitialized keyboard array entries */
+                if (!kdb_usb_kbds[i].urb || !kdb_usb_kbds[i].buffer ||
+                    !kdb_usb_kbds[i].poll_func)
+                        continue;
+
+                /* Transfer char */
+                ret = (*kdb_usb_kbds[i].poll_func)(kdb_usb_kbds[i].urb);
+                if (ret == -1) /* error or no characters, try the next kbd */
+                        continue;
+
+                spec = kdb_usb_kbds[i].buffer[0];
+                keycode = kdb_usb_kbds[i].buffer[2];
+                kdb_usb_kbds[i].buffer[0] = (char)0;
+                kdb_usb_kbds[i].buffer[2] = (char)0;
+
+                if(kdb_usb_kbds[i].buffer[3]) {
+                        kdb_usb_kbds[i].buffer[3] = (char)0;
+                        continue;
+                }
+
+                /* A normal key is pressed, decode it */
+                if(keycode)
+                        keycode = kdb_usb_keycode[keycode];
+
+                /* 2 Keys pressed at one time ? */
+                if (spec && keycode) {
+                        switch(spec)
+                        {
+                        case 0x2:
+                        case 0x20: /* Shift */
+                                return shift_map[keycode];
+                        case 0x1:
+                        case 0x10: /* Ctrl */
+                                return ctrl_map[keycode];
+                        case 0x4:
+                        case 0x40: /* Alt */
+                                break;
+                        }
+                } else if (keycode) { /* If only one key pressed */
+                        switch(keycode)
+                        {
+                        case 0x1C: /* Enter */
+                                return 13;
+
+                        case 0x3A: /* Capslock */
+                                kdb_usb_kbds[i].caps_lock = 
!(kdb_usb_kbds[i].caps_lock);
+                                break;
+                        case 0x0E: /* Backspace */
+                                return 8;
+                        case 0x0F: /* TAB */
+                                return 9;
+                        case 0x77: /* Pause */
+                                break ;
+                        default:
+                                if(!kdb_usb_kbds[i].caps_lock) {
+                                        return plain_map[keycode];
+                                }
+                                else {
+                                        return shift_map[keycode];
+                                }
+                        }
+                }
+        }
+
+        /* no chars were returned from any of the USB keyboards */
+
+        return -1;
 }
 #endif /* CONFIG_KDB_USB */
 
diff -pNaru linux.orig/arch/ia64/kdb/kdba_io.c linux/arch/ia64/kdb/kdba_io.c
--- linux.orig/arch/ia64/kdb/kdba_io.c  2007-11-09 11:37:47.000000000 -0800
+++ linux/arch/ia64/kdb/kdba_io.c       2007-11-08 14:31:06.500022083 -0800
@@ -39,9 +39,10 @@
 #endif
 
 #ifdef CONFIG_KDB_USB
-struct kdb_usb_exchange kdb_usb_infos;
 
-EXPORT_SYMBOL(kdb_usb_infos);
+/* support up to 8 USB keyboards (probably excessive, but...) */
+#define KDB_USB_NUM_KEYBOARDS  8
+struct kdb_usb_kbd_info kdb_usb_kbds[KDB_USB_NUM_KEYBOARDS];
 
 static unsigned char kdb_usb_keycode[256] = {
          0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
@@ -62,39 +63,122 @@ static unsigned char kdb_usb_keycode[256
        150,158,159,128,136,177,178,176,142,152,173,140
 };
 
-/* get_usb_char
- * This function drives the UHCI controller,
- * fetch the USB scancode and decode it
+/*
+ * kdb_usb_keyboard_attach()
+ * Attach a USB keyboard to kdb.
  */
-static int get_usb_char(void)
+int
+kdb_usb_keyboard_attach(struct urb *urb, unsigned char *buffer, void 
*poll_func)
 {
-       static int usb_lock;
-       unsigned char keycode, spec;
-       extern u_short plain_map[], shift_map[], ctrl_map[];
+       int     i;
+       int     rc = -1;
 
-       /* Is USB initialized ? */
-       if (!kdb_usb_infos.poll_func || !kdb_usb_infos.urb || 
!kdb_usb_infos.buffer)
-               return -1;
+       /*
+        * Search through the array of KDB USB keyboards (kdb_usb_kbds)
+        * looking for a free index. If found, assign the keyboard to
+        * the array index.
+        */
 
-       /* Transfer char if they are present */
-       (*kdb_usb_infos.poll_func)(kdb_usb_infos.uhci, (struct urb 
*)kdb_usb_infos.urb);
+       for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) {
+               if (kdb_usb_kbds[i].urb) /* index is already assigned */
+                       continue;
+
+               /* found a free array index */
+               kdb_usb_kbds[i].urb = urb;
+               kdb_usb_kbds[i].buffer = buffer;
+               kdb_usb_kbds[i].poll_func = poll_func;
 
-       spec = kdb_usb_infos.buffer[0];
-       keycode = kdb_usb_infos.buffer[2];
-       kdb_usb_infos.buffer[0] = (char)0;
-       kdb_usb_infos.buffer[2] = (char)0;
+               rc = 0; /* success */
 
-       if(kdb_usb_infos.buffer[3])
-               return -1;
+               break;
+       }
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL (kdb_usb_keyboard_attach);
+
+/*
+ * kdb_usb_keyboard_detach()
+ * Detach a USB keyboard from kdb.
+ */
+int
+kdb_usb_keyboard_detach(struct urb *urb)
+{
+       int     i;
+       int     rc = -1;
+
+       /*
+        * Search through the array of KDB USB keyboards (kdb_usb_kbds)
+        * looking for the index with the matching URB. If found,
+        * clear the array index.
+        */
+
+       for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) {
+               if (kdb_usb_kbds[i].urb != urb)
+                       continue;
+
+               /* found it, clear the index */
+               kdb_usb_kbds[i].urb = NULL;
+               kdb_usb_kbds[i].buffer = NULL;
+               kdb_usb_kbds[i].poll_func = NULL;
+               kdb_usb_kbds[i].caps_lock = 0;
+
+               rc = 0; /* success */
+
+               break;
+       }
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL (kdb_usb_keyboard_detach);
+
+/*
+ * get_usb_char
+ * This function drives the USB attached keyboards.
+ * Fetch the USB scancode and decode it.
+ */
+static int
+get_usb_char(void)
+{
+       int     i;
+       int     ret;
+       unsigned char keycode, spec;
+       extern u_short plain_map[], shift_map[], ctrl_map[];
+
+       /*
+        * Loop through all the USB keyboard(s) and return
+        * the first character obtained from them.
+        */
 
-       /* A normal key is pressed, decode it */
-       if(keycode)
-               keycode = kdb_usb_keycode[keycode];
+       for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) {
+               /* skip uninitialized keyboard array entries */
+               if (!kdb_usb_kbds[i].urb || !kdb_usb_kbds[i].buffer ||
+                   !kdb_usb_kbds[i].poll_func)
+                       continue;
+
+               /* Transfer char */
+               ret = (*kdb_usb_kbds[i].poll_func)(kdb_usb_kbds[i].urb);
+               if (ret == -1) /* error or no characters, try the next kbd */
+                       continue;
+
+               spec = kdb_usb_kbds[i].buffer[0];
+               keycode = kdb_usb_kbds[i].buffer[2];
+               kdb_usb_kbds[i].buffer[0] = (char)0;
+               kdb_usb_kbds[i].buffer[2] = (char)0;
+
+               if(kdb_usb_kbds[i].buffer[3]) {
+                       kdb_usb_kbds[i].buffer[3] = (char)0;
+                       continue;
+               }
 
-       /* 2 Keys pressed at one time ? */
-       if (spec && keycode) {
-               switch(spec)
-               {
+               /* A normal key is pressed, decode it */
+               if(keycode)
+                       keycode = kdb_usb_keycode[keycode];
+
+               /* 2 Keys pressed at one time ? */
+               if (spec && keycode) {
+                       switch(spec)
+                       {
                        case 0x2:
                        case 0x20: /* Shift */
                                return shift_map[keycode];
@@ -104,34 +188,35 @@ static int get_usb_char(void)
                        case 0x4:
                        case 0x40: /* Alt */
                                break;
-               }
-       }
-       else {
-               if(keycode) { /* If only one key pressed */
+                       }
+               } else if (keycode) { /* If only one key pressed */
                        switch(keycode)
                        {
-                               case 0x1C: /* Enter */
-                                       return 13;
+                       case 0x1C: /* Enter */
+                               return 13;
 
-                               case 0x3A: /* Capslock */
-                                       usb_lock ? (usb_lock = 0) : (usb_lock = 
1);
-                                       break;
-                               case 0x0E: /* Backspace */
-                                       return 8;
-                               case 0x0F: /* TAB */
-                                       return 9;
-                               case 0x77: /* Pause */
-                                       break ;
-                               default:
-                                       if(!usb_lock) {
-                                               return plain_map[keycode];
-                                       }
-                                       else {
-                                               return shift_map[keycode];
-                                       }
+                       case 0x3A: /* Capslock */
+                               kdb_usb_kbds[i].caps_lock = 
!(kdb_usb_kbds[i].caps_lock);
+                               break;
+                       case 0x0E: /* Backspace */
+                               return 8;
+                       case 0x0F: /* TAB */
+                               return 9;
+                       case 0x77: /* Pause */
+                               break ;
+                       default:
+                               if(!kdb_usb_kbds[i].caps_lock) {
+                                       return plain_map[keycode];
+                               }
+                               else {
+                                       return shift_map[keycode];
+                               }
                        }
                }
        }
+
+       /* no chars were returned from any of the USB keyboards */
+
        return -1;
 }
 #endif /* CONFIG_KDB_USB */
diff -pNaru linux.orig/arch/x86_64/kdb/kdba_io.c linux/arch/x86_64/kdb/kdba_io.c
--- linux.orig/arch/x86_64/kdb/kdba_io.c        2007-11-09 11:37:46.000000000 
-0800
+++ linux/arch/x86_64/kdb/kdba_io.c     2007-11-08 14:28:31.507644333 -0800
@@ -29,9 +29,10 @@
 #endif
 
 #ifdef CONFIG_KDB_USB
-struct kdb_usb_exchange kdb_usb_infos;
 
-EXPORT_SYMBOL(kdb_usb_infos);
+/* support up to 8 USB keyboards (probably excessive, but...) */
+#define KDB_USB_NUM_KEYBOARDS   8
+struct kdb_usb_kbd_info kdb_usb_kbds[KDB_USB_NUM_KEYBOARDS];
 
 static unsigned char kdb_usb_keycode[256] = {
          0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
@@ -52,77 +53,161 @@ static unsigned char kdb_usb_keycode[256
        150,158,159,128,136,177,178,176,142,152,173,140
 };
 
-/* get_usb_char
- * This function drives the UHCI controller,
- * fetch the USB scancode and decode it
+/*
+ * kdb_usb_keyboard_attach()
+ * Attach a USB keyboard to kdb.
  */
-static int get_usb_char(void)
+int
+kdb_usb_keyboard_attach(struct urb *urb, unsigned char *buffer, void 
*poll_func)
 {
-       static int usb_lock;
-       unsigned char keycode, spec;
-       extern u_short plain_map[], shift_map[], ctrl_map[];
+        int     i;
+        int     rc = -1;
 
-       /* Is USB initialized ? */
-       if(!kdb_usb_infos.poll_func || !kdb_usb_infos.urb)
-               return -1;
+        /*
+         * Search through the array of KDB USB keyboards (kdb_usb_kbds)
+         * looking for a free index. If found, assign the keyboard to
+         * the array index.
+         */
+
+        for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) {
+                if (kdb_usb_kbds[i].urb) /* index is already assigned */
+                        continue;
+
+                /* found a free array index */
+                kdb_usb_kbds[i].urb = urb;
+                kdb_usb_kbds[i].buffer = buffer;
+                kdb_usb_kbds[i].poll_func = poll_func;
 
-       /* Transfer char if they are present */
-       (*kdb_usb_infos.poll_func)(kdb_usb_infos.uhci, (struct urb 
*)kdb_usb_infos.urb);
+                rc = 0; /* success */
 
-       spec = kdb_usb_infos.buffer[0];
-       keycode = kdb_usb_infos.buffer[2];
-       kdb_usb_infos.buffer[0] = (char)0;
-       kdb_usb_infos.buffer[2] = (char)0;
+                break;
+        }
 
-       if(kdb_usb_infos.buffer[3])
-               return -1;
+        return rc;
+}
+EXPORT_SYMBOL_GPL (kdb_usb_keyboard_attach);
 
-       /* A normal key is pressed, decode it */
-       if(keycode)
-               keycode = kdb_usb_keycode[keycode];
-
-       /* 2 Keys pressed at one time ? */
-       if (spec && keycode) {
-               switch(spec)
-               {
-                       case 0x2:
-                       case 0x20: /* Shift */
-                               return shift_map[keycode];
-                       case 0x1:
-                       case 0x10: /* Ctrl */
-                               return ctrl_map[keycode];
-                       case 0x4:
-                       case 0x40: /* Alt */
-                               break;
-               }
-       }
-       else {
-               if(keycode) { /* If only one key pressed */
-                       switch(keycode)
-                       {
-                               case 0x1C: /* Enter */
-                                       return 13;
-
-                               case 0x3A: /* Capslock */
-                                       usb_lock ? (usb_lock = 0) : (usb_lock = 
1);
-                                       break;
-                               case 0x0E: /* Backspace */
-                                       return 8;
-                               case 0x0F: /* TAB */
-                                       return 9;
-                               case 0x77: /* Pause */
-                                       break ;
-                               default:
-                                       if(!usb_lock) {
-                                               return plain_map[keycode];
-                                       }
-                                       else {
-                                               return shift_map[keycode];
-                                       }
-                       }
-               }
-       }
-       return -1;
+/*
+ * kdb_usb_keyboard_detach()
+ * Detach a USB keyboard from kdb.
+ */
+int
+kdb_usb_keyboard_detach(struct urb *urb)
+{
+        int     i;
+        int     rc = -1;
+
+        /*
+         * Search through the array of KDB USB keyboards (kdb_usb_kbds)
+         * looking for the index with the matching URB. If found,
+         * clear the array index.
+         */
+
+        for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) {
+                if (kdb_usb_kbds[i].urb != urb)
+                        continue;
+
+                /* found it, clear the index */
+                kdb_usb_kbds[i].urb = NULL;
+                kdb_usb_kbds[i].buffer = NULL;
+                kdb_usb_kbds[i].poll_func = NULL;
+                kdb_usb_kbds[i].caps_lock = 0;
+
+                rc = 0; /* success */
+
+                break;
+        }
+
+        return rc;
+}
+EXPORT_SYMBOL_GPL (kdb_usb_keyboard_detach);
+
+/*
+ * get_usb_char
+ * This function drives the USB attached keyboards.
+ * Fetch the USB scancode and decode it.
+ */
+static int
+get_usb_char(void)
+{
+        int     i;
+        int     ret;
+        unsigned char keycode, spec;
+        extern u_short plain_map[], shift_map[], ctrl_map[];
+
+        /*
+         * Loop through all the USB keyboard(s) and return
+         * the first character obtained from them.
+         */
+
+        for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) {
+                /* skip uninitialized keyboard array entries */
+                if (!kdb_usb_kbds[i].urb || !kdb_usb_kbds[i].buffer ||
+                    !kdb_usb_kbds[i].poll_func)
+                        continue;
+
+                /* Transfer char */
+                ret = (*kdb_usb_kbds[i].poll_func)(kdb_usb_kbds[i].urb);
+                if (ret == -1) /* error or no characters, try the next kbd */
+                        continue;
+
+                spec = kdb_usb_kbds[i].buffer[0];
+                keycode = kdb_usb_kbds[i].buffer[2];
+                kdb_usb_kbds[i].buffer[0] = (char)0;
+                kdb_usb_kbds[i].buffer[2] = (char)0;
+
+                if(kdb_usb_kbds[i].buffer[3]) {
+                        kdb_usb_kbds[i].buffer[3] = (char)0;
+                        continue;
+                }
+
+                /* A normal key is pressed, decode it */
+                if(keycode)
+                        keycode = kdb_usb_keycode[keycode];
+
+                /* 2 Keys pressed at one time ? */
+                if (spec && keycode) {
+                        switch(spec)
+                        {
+                        case 0x2:
+                        case 0x20: /* Shift */
+                                return shift_map[keycode];
+                        case 0x1:
+                        case 0x10: /* Ctrl */
+                                return ctrl_map[keycode];
+                        case 0x4:
+                        case 0x40: /* Alt */
+                                break;
+                        }
+                } else if (keycode) { /* If only one key pressed */
+                        switch(keycode)
+                        {
+                        case 0x1C: /* Enter */
+                                return 13;
+
+                        case 0x3A: /* Capslock */
+                                kdb_usb_kbds[i].caps_lock = 
!(kdb_usb_kbds[i].caps_lock);
+                                break;
+                        case 0x0E: /* Backspace */
+                                return 8;
+                        case 0x0F: /* TAB */
+                                return 9;
+                        case 0x77: /* Pause */
+                                break ;
+                        default:
+                                if(!kdb_usb_kbds[i].caps_lock) {
+                                        return plain_map[keycode];
+                                }
+                                else {
+                                        return shift_map[keycode];
+                                }
+                        }
+                }
+        }
+
+        /* no chars were returned from any of the USB keyboards */
+
+        return -1;
 }
 #endif /* CONFIG_KDB_USB */
 
diff -pNaru linux.orig/drivers/hid/usbhid/hid-core.c 
linux/drivers/hid/usbhid/hid-core.c
--- linux.orig/drivers/hid/usbhid/hid-core.c    2007-11-09 11:37:44.000000000 
-0800
+++ linux/drivers/hid/usbhid/hid-core.c 2007-11-08 14:04:41.124958377 -0800
@@ -900,9 +900,12 @@ static void hid_disconnect(struct usb_in
        usbhid = hid->driver_data;
 
 #ifdef CONFIG_KDB_USB
-       /* Unlink the KDB USB struct */
-       if (usbhid->urbin == kdb_usb_infos.urb)
-               memset(&kdb_usb_infos, 0, sizeof(kdb_usb_infos));
+       /*
+        * If the URB was for a Keyboard, detach it from kdb.
+        * If the URB was for another type of device, just
+        * allow kdb_usb_keyboard_detach() to silently fail.
+        */
+       kdb_usb_keyboard_detach(usbhid->urbin);
 #endif
 
        spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
@@ -991,15 +994,20 @@ static int hid_probe(struct usb_interfac
        printk(": USB HID v%x.%02x %s [%s] on %s\n",
                hid->version >> 8, hid->version & 0xff, c, hid->name, path);
 
-#ifdef CONFIG_KDB_USB
-       /* Initialization of the KDB structure */
+#ifdef CONFIG_KDB_USB
+       /* Attach USB keyboards to kdb */
        if (!strcmp(c, "Keyboard")) {
+               int     ret;
                struct usbhid_device *usbhid = hid->driver_data;
-               kdb_usb_infos.urb = usbhid->urbin;
-               kdb_usb_infos.buffer = usbhid->inbuf;
-               kdb_usb_infos.reset_timer = NULL;
+               extern void * usb_hcd_get_kdb_poll_func(struct usb_device 
*udev);
+               ret = kdb_usb_keyboard_attach(usbhid->urbin, usbhid->inbuf,
+                   usb_hcd_get_kdb_poll_func(interface_to_usbdev(intf)));
+
+               if (ret == -1)
+                       printk(": FAILED to register keyboard (%s) "
+                              "with KDB\n", path);
        }
-#endif
+#endif /* CONFIG_KDB_USB */
 
        return 0;
 }
diff -pNaru linux.orig/drivers/hid/usbhid/usbkbd.c 
linux/drivers/hid/usbhid/usbkbd.c
--- linux.orig/drivers/hid/usbhid/usbkbd.c      2007-11-09 11:37:44.000000000 
-0800
+++ linux/drivers/hid/usbhid/usbkbd.c   2007-11-08 14:04:41.148957819 -0800
@@ -292,12 +292,15 @@ static int usb_kbd_probe(struct usb_inte
                         kbd->new, (maxp > 8 ? 8 : maxp),
                         usb_kbd_irq, kbd, endpoint->bInterval);
 
-#ifdef CONFIG_KDB_USB
-       /* Init the KDB structure */
-       kdb_usb_infos.urb = kbd->irq;
-       kdb_usb_infos.buffer = kbd->new;
-       kdb_usb_infos.reset_timer = NULL;
-#endif
+#ifdef CONFIG_KDB_USB
+       /* Attach keyboard to kdb */
+       extern void * usb_hcd_get_kdb_poll_func(struct usb_device *udev);
+
+       kdb_usb_keyboard_attach(kbd->irq, kbd->new,
+                               usb_hcd_get_kdb_poll_func(dev));
+
+#endif /* CONFIG_KDB_USB */
+
        kbd->irq->transfer_dma = kbd->new_dma;
        kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
@@ -334,12 +337,11 @@ static void usb_kbd_disconnect(struct us
        struct usb_kbd *kbd = usb_get_intfdata (intf);
 
        usb_set_intfdata(intf, NULL);
+       if (kbd) {
 #ifdef CONFIG_KDB_USB
-       /* Unlink the KDB USB struct */
-       if (kbd && kbd->irq == kdb_usb_infos.urb)
-               memset(&kdb_usb_infos, 0, sizeof(kdb_usb_infos));
+              /* Detach the keyboard from kdb */
+               kdb_usb_keyboard_detach(kbd->irq);
 #endif /* CONFIG_KDB_USB */
-       if (kbd) {
                usb_kill_urb(kbd->irq);
                input_unregister_device(kbd->dev);
                usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
diff -pNaru linux.orig/drivers/usb/core/hcd.c linux/drivers/usb/core/hcd.c
--- linux.orig/drivers/usb/core/hcd.c   2007-10-09 13:31:38.000000000 -0700
+++ linux/drivers/usb/core/hcd.c        2007-11-08 14:04:42.228932671 -0800
@@ -1718,6 +1718,20 @@ usb_hcd_platform_shutdown(struct platfor
 }
 EXPORT_SYMBOL (usb_hcd_platform_shutdown);
 
+#ifdef CONFIG_KDB_USB
+void *
+usb_hcd_get_kdb_poll_func(struct usb_device *udev)
+{
+       struct usb_hcd  *hcd = bus_to_hcd(udev->bus);
+
+       if (hcd && hcd->driver)
+               return (void *)(hcd->driver->kdb_poll_char);
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL (usb_hcd_get_kdb_poll_func);
+#endif /* CONFIG_KDB_USB */
+
 /*-------------------------------------------------------------------------*/
 
 #if defined(CONFIG_USB_MON)
diff -pNaru linux.orig/drivers/usb/core/hcd.h linux/drivers/usb/core/hcd.h
--- linux.orig/drivers/usb/core/hcd.h   2007-10-09 13:31:38.000000000 -0700
+++ linux/drivers/usb/core/hcd.h        2007-11-08 14:04:42.248932205 -0800
@@ -202,6 +202,10 @@ struct hc_driver {
        int             (*start_port_reset)(struct usb_hcd *, unsigned 
port_num);
        void            (*hub_irq_enable)(struct usb_hcd *);
                /* Needed only if port-change IRQs are level-triggered */
+#ifdef CONFIG_KDB_USB
+       /* KDB poll function for this HC */
+       int             (*kdb_poll_char)(struct urb *urb);
+#endif /* CONFIG_KDB_USB */
 };
 
 extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
diff -pNaru linux.orig/drivers/usb/host/ehci-hcd.c 
linux/drivers/usb/host/ehci-hcd.c
--- linux.orig/drivers/usb/host/ehci-hcd.c      2007-10-09 13:31:38.000000000 
-0700
+++ linux/drivers/usb/host/ehci-hcd.c   2007-11-08 14:04:42.272931646 -0800
@@ -916,6 +916,17 @@ static int ehci_get_frame (struct usb_hc
                ehci->periodic_size;
 }
 
+#ifdef CONFIG_KDB_USB
+
+int
+ehci_kdb_poll_char(struct urb *urb)
+{
+       /* routine not yet implemented */
+       return -1;
+}
+
+#endif /* CONFIG_KDB_USB */
+
 /*-------------------------------------------------------------------------*/
 
 #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
diff -pNaru linux.orig/drivers/usb/host/ehci-pci.c 
linux/drivers/usb/host/ehci-pci.c
--- linux.orig/drivers/usb/host/ehci-pci.c      2007-10-09 13:31:38.000000000 
-0700
+++ linux/drivers/usb/host/ehci-pci.c   2007-11-08 14:04:42.292931181 -0800
@@ -22,6 +22,10 @@
 #error "This file is PCI bus glue.  CONFIG_PCI must be defined."
 #endif
 
+#ifdef CONFIG_KDB_USB
+#include <linux/kdb.h>
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 /* called after powerup, by probe or system-pm "wakeup" */
@@ -367,6 +371,10 @@ static const struct hc_driver ehci_pci_h
        .hub_control =          ehci_hub_control,
        .bus_suspend =          ehci_bus_suspend,
        .bus_resume =           ehci_bus_resume,
+
+#ifdef CONFIG_KDB_USB
+       .kdb_poll_char =        ehci_kdb_poll_char,
+#endif
 };
 
 /*-------------------------------------------------------------------------*/
diff -pNaru linux.orig/drivers/usb/host/ohci-hcd.c 
linux/drivers/usb/host/ohci-hcd.c
--- linux.orig/drivers/usb/host/ohci-hcd.c      2007-11-09 11:37:44.000000000 
-0800
+++ linux/drivers/usb/host/ohci-hcd.c   2007-11-08 14:04:41.244955583 -0800
@@ -851,20 +851,14 @@ static void ohci_quirk_nec_worker(struct
 
 #ifdef CONFIG_KDB_USB
 
-static void
-ohci_kdb_poll (void * __ohci, struct urb *urb)
+int
+ohci_kdb_poll_char(struct urb *urb)
 {
        struct ohci_hcd *ohci;
        struct ohci_regs * regs;
 
-       /*
-        * NOTE - we use the ohci_hcd from the urb rather than the
-        * __ohci parameter (which is NULL anyway). This ensures
-        * that we will process the proper controller for the urb.
-        */
-
-       if (!urb) /* can happen if no keyboard attached */
-               return;
+       if (!urb)       /* should not happen */
+               return -1;
 
        ohci = (struct ohci_hcd *) hcd_to_ohci(bus_to_hcd(urb->dev->bus));
        regs = ohci->regs;
@@ -873,23 +867,27 @@ ohci_kdb_poll (void * __ohci, struct urb
        if (urb->status != -EINPROGRESS) {
 
                if (usb_submit_urb (urb, GFP_ATOMIC))
-                       return;
+                       return -1;
 
                /* make sure the HC registers are set correctly */
-               writel (OHCI_INTR_WDH, &regs->intrenable);
-               writel (OHCI_INTR_WDH, &regs->intrstatus);
-               writel (OHCI_INTR_MIE, &regs->intrenable);
+               ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrenable);
+               ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrstatus);
+               ohci_writel (ohci, OHCI_INTR_MIE, &regs->intrenable);
 
                // flush those pci writes
-               (void) readl (&ohci->regs->control);
+               (void) ohci_readl (ohci, &ohci->regs->control);
        }
 
        if (ohci->hcca->done_head) {
                dl_done_list_kdb (ohci, urb);
-               writel (OHCI_INTR_WDH, &regs->intrstatus);
+               ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrstatus);
                // flush the pci write
-               (void) readl (&ohci->regs->control);
+               (void) ohci_readl (ohci, &ohci->regs->control);
+
+               return 0;
        }
+
+       return -1;
 }
 
 #endif /* CONFIG_KDB_USB */
diff -pNaru linux.orig/drivers/usb/host/ohci-pci.c 
linux/drivers/usb/host/ohci-pci.c
--- linux.orig/drivers/usb/host/ohci-pci.c      2007-11-09 11:37:44.000000000 
-0800
+++ linux/drivers/usb/host/ohci-pci.c   2007-11-08 14:04:41.268955024 -0800
@@ -18,7 +18,7 @@
 #error "This file is PCI bus glue.  CONFIG_PCI must be defined."
 #endif
 
-#ifdef CONFIG_KDB_USB
+#ifdef CONFIG_KDB_USB
 #include <linux/kdb.h>
 #endif
 
@@ -219,12 +219,7 @@ static int __devinit ohci_pci_start (str
                ohci_err (ohci, "can't start\n");
                ohci_stop (hcd);
        }
-#ifdef CONFIG_KDB_USB
-       if (ret >= 0) {
-               kdb_usb_infos.poll_func = ohci_kdb_poll;
-               kdb_usb_infos.uhci = NULL; /* not used */
-       }
-#endif
+
        return ret;
 }
 
@@ -363,6 +358,9 @@ static const struct hc_driver ohci_pci_h
        .bus_resume =           ohci_bus_resume,
 #endif
        .start_port_reset =     ohci_start_port_reset,
+#ifdef CONFIG_KDB_USB
+       .kdb_poll_char =        ohci_kdb_poll_char,
+#endif
 };
 
 /*-------------------------------------------------------------------------*/
diff -pNaru linux.orig/include/linux/kdb.h linux/include/linux/kdb.h
--- linux.orig/include/linux/kdb.h      2007-11-09 11:37:44.000000000 -0800
+++ linux/include/linux/kdb.h   2007-11-08 14:04:41.420951485 -0800
@@ -140,16 +140,12 @@ extern void smp_kdb_stop(void);
 #endif /* CONFIG_SMP */
 
 #ifdef CONFIG_KDB_USB
+
 #include <linux/usb.h>
 
-struct kdb_usb_exchange {
-       void *uhci;                     /* pointer to the UHCI structure */
-       struct urb *urb;                /* pointer to the URB */
-       unsigned char *buffer;          /* pointer to buffer */
-       void (*poll_func)(void *, struct urb *); /* pointer to the polling 
function */
-       void (*reset_timer)(void);      /* pointer to the reset timer function 
*/
-};
-extern struct kdb_usb_exchange kdb_usb_infos; /* KDB common structure */
+extern int kdb_usb_keyboard_attach(struct urb *urb, unsigned char *buffer, 
void *poll_func);
+extern int kdb_usb_keyboard_detach(struct urb *urb);
+
 #endif /* CONFIG_KDB_USB */
 
 static inline
diff -pNaru linux.orig/include/linux/kdbprivate.h 
linux/include/linux/kdbprivate.h
--- linux.orig/include/linux/kdbprivate.h       2007-11-09 11:37:44.000000000 
-0800
+++ linux/include/linux/kdbprivate.h    2007-11-08 14:04:41.460950554 -0800
@@ -482,4 +482,15 @@ extern char kdb_prompt_str[];
 
 #define        KDB_WORD_SIZE   ((int)sizeof(kdb_machreg_t))
 
+#ifdef CONFIG_KDB_USB
+#include <linux/usb.h>
+
+struct kdb_usb_kbd_info {
+       struct urb *urb;                /* pointer to the URB */
+       unsigned char *buffer;          /* pointer to the kbd char buffer */
+       int (*poll_func)(struct urb *urb); /* poll function to retrieve chars */
+       int     caps_lock;      /* state of the caps lock for this keyboard */
+};
+#endif /* CONFIG_KDB_USB */
+
 #endif /* !_KDBPRIVATE_H */

---
---------------------------
Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe.

Reply via email to