Aaron Young wrote:
> 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)
Well, actually i generated this patch for you against linux-2.6.23 and
the 2.6.23 version of kdb patchset.
I did basic testing on ia64, x86_64, and i386, but i did not have
equipments to test new feature of USB keyboards/mice though.
Thanks,
- jay
>
> 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.
---------------------------
Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe.