[PATCH] New USB Keyboard interface for KDB

Jay Lan jlan at sgi.com
Fri Nov 9 14:19:43 PST 2007


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 (ayoung at sgi.com)
> 
> ---
> 
> 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.

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


More information about the kdb mailing list