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, ®s->intrenable);
- writel (OHCI_INTR_WDH, ®s->intrstatus);
- writel (OHCI_INTR_MIE, ®s->intrenable);
+ ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable);
+ ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrstatus);
+ ohci_writel (ohci, OHCI_INTR_MIE, ®s->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, ®s->intrstatus);
+ ohci_writel (ohci, OHCI_INTR_WDH, ®s->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.