Thanks Matthieu,

I'll give people a little longer to review.  I have never used the USB
keyboard support in KDB so I'm definitely not the best reviewer...

mh

On Tue, May 26, 2009 at 10:10:38AM +0200, Matthieu Fertré wrote:
> Building as a module has not been tested.
> 
> Update of patch from Konstantin Baydarov <[email protected]>.
> 
> The patch was originally posted here:
> http://oss.sgi.com/archives/kdb/2008-02/msg00006.html
> 
> Signed-off-by: Matthieu Fertré <[email protected]>
> ---
>  arch/x86/Kconfig.debug        |    4 +-
>  arch/x86/kdb/kdba_io.c        |   89 ++++++++++++++---
>  drivers/hid/usbhid/hid-core.c |   13 +++-
>  drivers/usb/core/hcd.c        |   60 +++++++++++-
>  drivers/usb/core/hcd.h        |    6 +
>  drivers/usb/host/uhci-hcd.c   |  218 
> +++++++++++++++++++++++++++++++++++++++++
>  drivers/usb/host/uhci-q.c     |  164 +++++++++++++++++++++++++++++++
>  7 files changed, 535 insertions(+), 19 deletions(-)
> 
> diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
> index c9216a7..51ed359 100644
> --- a/arch/x86/Kconfig.debug
> +++ b/arch/x86/Kconfig.debug
> @@ -342,8 +342,8 @@ config KDB_CONTINUE_CATASTROPHIC
>         setting to 2.
>  
>  config KDB_USB
> -     bool "Support for USB Keyboard in KDB (OHCI and/or EHCI only)"
> -     depends on KDB && (USB_OHCI_HCD || USB_EHCI_HCD)
> +     bool "Support for USB Keyboard in KDB"
> +     depends on KDB && (USB_OHCI_HCD || USB_EHCI_HCD || USB_UHCI_HCD)
>       help
>         If you want to use kdb from USB keyboards then say Y here.  If you
>         say N then kdb can only be used from a PC (AT) keyboard or a serial
> diff --git a/arch/x86/kdb/kdba_io.c b/arch/x86/kdb/kdba_io.c
> index 087d468..e754dd4 100644
> --- a/arch/x86/kdb/kdba_io.c
> +++ b/arch/x86/kdb/kdba_io.c
> @@ -30,9 +30,8 @@
>  
>  #ifdef       CONFIG_KDB_USB
>  
> -/* 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];
> +EXPORT_SYMBOL(kdb_usb_kbds);
>  
>  extern int kdb_no_usb;
>  
> @@ -60,7 +59,12 @@ static unsigned char kdb_usb_keycode[256] = {
>   * Attach a USB keyboard to kdb.
>   */
>  int
> -kdb_usb_keyboard_attach(struct urb *urb, unsigned char *buffer, void 
> *poll_func)
> +kdb_usb_keyboard_attach(struct urb *urb, unsigned char *buffer,
> +                     void *poll_func, void *compl_func,
> +                     kdb_hc_keyboard_attach_t kdb_hc_keyboard_attach,
> +                     kdb_hc_keyboard_detach_t kdb_hc_keyboard_detach,
> +                     unsigned int bufsize,
> +                     struct urb *hid_urb)
>  {
>          int     i;
>          int     rc = -1;
> @@ -83,6 +87,16 @@ kdb_usb_keyboard_attach(struct urb *urb, unsigned char 
> *buffer, void *poll_func)
>                  kdb_usb_kbds[i].buffer = buffer;
>                  kdb_usb_kbds[i].poll_func = poll_func;
>  
> +             kdb_usb_kbds[i].kdb_hc_urb_complete = compl_func;
> +             kdb_usb_kbds[i].kdb_hc_keyboard_attach = kdb_hc_keyboard_attach;
> +             kdb_usb_kbds[i].kdb_hc_keyboard_detach = kdb_hc_keyboard_detach;
> +
> +             /* USB Host Controller specific Keyboadr attach callback.
> +              * Currently only UHCI has this callback.
> +              */
> +             if (kdb_usb_kbds[i].kdb_hc_keyboard_attach)
> +                     kdb_usb_kbds[i].kdb_hc_keyboard_attach(i, bufsize);
> +
>                  rc = 0; /* success */
>  
>                  break;
> @@ -112,14 +126,23 @@ kdb_usb_keyboard_detach(struct urb *urb)
>           */
>  
>          for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) {
> -                if (kdb_usb_kbds[i].urb != urb)
> +             if ((kdb_usb_kbds[i].urb != urb) &&
> +                 (kdb_usb_kbds[i].hid_urb != urb))
>                          continue;
>  
>                  /* found it, clear the index */
> +
> +             /* USB Host Controller specific Keyboard detach callback.
> +              * Currently only UHCI has this callback.
> +              */
> +             if (kdb_usb_kbds[i].kdb_hc_keyboard_detach)
> +                     kdb_usb_kbds[i].kdb_hc_keyboard_detach(urb, i);
> +
>                  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;
> +             kdb_usb_kbds[i].hid_urb = NULL;
>  
>                  rc = 0; /* success */
>  
> @@ -142,6 +165,9 @@ get_usb_char(void)
>          int     ret;
>          unsigned char keycode, spec;
>          extern u_short plain_map[], shift_map[], ctrl_map[];
> +     int     ret_key = -1, j, max;
> +
> +     ret = 1;
>  
>          if (kdb_no_usb)
>                  return -1;
> @@ -168,15 +194,24 @@ get_usb_char(void)
>                  if (ret < 0) /* error or no characters, try the next kbd */
>                          continue;
>  
> +             /* If 2 keys was pressed simultaneously,
> +              * both keycodes will be in buffer.
> +              * Last pressed key will be last non
> +              * zero byte.
> +              */
> +             for (j=0; j<4; j++){
> +                     if (!kdb_usb_kbds[i].buffer[2+j])
> +                             break;
> +             }
> +             /* Last pressed key */
> +             max = j + 1;
> +
>                  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;
> -                }
> +             ret_key = -1;
>  
>                  /* A normal key is pressed, decode it */
>                  if(keycode)
> @@ -188,10 +223,12 @@ get_usb_char(void)
>                          {
>                          case 0x2:
>                          case 0x20: /* Shift */
> -                                return shift_map[keycode];
> +                                ret_key = shift_map[keycode];
> +                             break;
>                          case 0x1:
>                          case 0x10: /* Ctrl */
> -                                return ctrl_map[keycode];
> +                                ret_key = ctrl_map[keycode];
> +                             break;
>                          case 0x4:
>                          case 0x40: /* Alt */
>                                  break;
> @@ -200,28 +237,50 @@ get_usb_char(void)
>                          switch(keycode)
>                          {
>                          case 0x1C: /* Enter */
> -                                return 13;
> +                                ret_key = 13;
> +                             break;
>  
>                          case 0x3A: /* Capslock */
>                                  kdb_usb_kbds[i].caps_lock = 
> !(kdb_usb_kbds[i].caps_lock);
>                                  break;
>                          case 0x0E: /* Backspace */
> -                                return 8;
> +                                ret_key = 8;
> +                             break;
>                          case 0x0F: /* TAB */
> -                                return 9;
> +                                ret_key = 9;
> +                             break;
>                          case 0x77: /* Pause */
>                                  break ;
>                          default:
>                                  if(!kdb_usb_kbds[i].caps_lock) {
> -                                        return plain_map[keycode];
> +                                        ret_key = plain_map[keycode];
>                                  }
>                                  else {
> -                                        return shift_map[keycode];
> +                                        ret_key = shift_map[keycode];
>                                  }
>                          }
>                  }
> +
> +             if (ret_key != 1) {
> +                     /* Key was pressed, return keycode */
> +
> +                     /* Clear buffer before urb resending */
> +                     if (kdb_usb_kbds[i].buffer)
> +                             for(j=0; j<8; j++)
> +                                     kdb_usb_kbds[i].buffer[j] = (char)0;
> +
> +                     /* USB Host Controller specific Urb complete callback.
> +                      * Currently only UHCI has this callback.
> +                      */
> +                     if (kdb_usb_kbds[i].kdb_hc_urb_complete)
> +                             (*kdb_usb_kbds[i].kdb_hc_urb_complete)((struct 
> urb *)kdb_usb_kbds[i].urb);
> +
> +                     return ret_key;
> +             }
>          }
>  
> +
> +
>          /* no chars were returned from any of the USB keyboards */
>  
>          return -1;
> diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
> index 8c55733..8c342d1 100644
> --- a/drivers/hid/usbhid/hid-core.c
> +++ b/drivers/hid/usbhid/hid-core.c
> @@ -1195,9 +1195,20 @@ static int hid_probe(struct usb_interface *intf, const 
> struct usb_device_id *id)
>               int ret;
>               struct usbhid_device *usbhid = hid->driver_data;
>               extern void *usb_hcd_get_kdb_poll_func(struct usb_device *udev);
> +             extern void * usb_hcd_get_kdb_completion_func(struct usb_device 
> *udev);
> +             extern int usb_hcd_check_uhci(struct usb_device *udev);
> +             extern kdb_hc_keyboard_attach_t
> +                     usb_hcd_get_hc_keyboard_attach(struct usb_device *udev);
> +             extern kdb_hc_keyboard_detach_t
> +                     usb_hcd_get_hc_keyboard_detach(struct usb_device *udev);
>  
>               ret = kdb_usb_keyboard_attach(usbhid->urbin, usbhid->inbuf,
> -                 usb_hcd_get_kdb_poll_func(interface_to_usbdev(intf)));
> +                                           
> usb_hcd_get_kdb_poll_func(interface_to_usbdev(intf)),
> +                                           
> usb_hcd_get_kdb_completion_func(interface_to_usbdev(intf)),
> +                                           
> usb_hcd_get_hc_keyboard_attach(interface_to_usbdev(intf)),
> +                                           
> usb_hcd_get_hc_keyboard_detach(interface_to_usbdev(intf)),
> +                                           usbhid->bufsize,
> +                                           NULL);
>  
>               if (ret == -1)
>                       printk(": FAILED to register keyboard (%s) "
> diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
> index 5af2a35..f9d7c97 100644
> --- a/drivers/usb/core/hcd.c
> +++ b/drivers/usb/core/hcd.c
> @@ -38,6 +38,9 @@
>  #include <asm/unaligned.h>
>  #include <linux/platform_device.h>
>  #include <linux/workqueue.h>
> +#ifdef CONFIG_KDB_USB
> +#include <linux/kdb.h>
> +#endif
>  
>  #include <linux/usb.h>
>  
> @@ -2023,7 +2026,7 @@ EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown);
>  void *
>  usb_hcd_get_kdb_poll_func(struct usb_device *udev)
>  {
> -     struct usb_hcd  *hcd = bus_to_hcd(udev->bus);
> +     struct usb_hcd  *hcd = bus_to_hcd(udev->bus);
>  
>       if (hcd && hcd->driver)
>               return (void *)(hcd->driver->kdb_poll_char);
> @@ -2031,8 +2034,63 @@ usb_hcd_get_kdb_poll_func(struct usb_device *udev)
>       return NULL;
>  }
>  EXPORT_SYMBOL_GPL (usb_hcd_get_kdb_poll_func);
> +
> +void *
> +usb_hcd_get_kdb_completion_func(struct usb_device *udev)
> +{
> +     struct usb_hcd  *hcd = bus_to_hcd(udev->bus);
> +
> +     if (hcd && hcd->driver)
> +             return (void *)(hcd->driver->kdb_completion);
> +
> +     return NULL;
> +}
> +EXPORT_SYMBOL_GPL (usb_hcd_get_kdb_completion_func);
> +
> +int
> +usb_hcd_check_uhci(struct usb_device *udev)
> +{
> +     struct usb_hcd  *hcd = bus_to_hcd(udev->bus);
> +
> +     if (hcd && hcd->driver){
> +             if (!(strcmp(hcd->driver->description, "uhci_hcd")))
> +                     return 1;
> +     }
> +
> +     return 0;
> +}
> +EXPORT_SYMBOL_GPL (usb_hcd_check_uhci);
> +
> +kdb_hc_keyboard_attach_t
> +usb_hcd_get_hc_keyboard_attach(struct usb_device *udev)
> +{
> +     struct usb_hcd  *hcd = bus_to_hcd(udev->bus);
> +
> +     if (hcd && hcd->driver){
> +             return hcd->driver->kdb_hc_keyboard_attach;
> +     }
> +
> +     return 0;
> +}
> +EXPORT_SYMBOL_GPL (usb_hcd_get_hc_keyboard_attach);
> +
> +kdb_hc_keyboard_detach_t
> +usb_hcd_get_hc_keyboard_detach(struct usb_device *udev)
> +{
> +     struct usb_hcd  *hcd = bus_to_hcd(udev->bus);
> +
> +     if (hcd && hcd->driver){
> +             return hcd->driver->kdb_hc_keyboard_detach;
> +     }
> +
> +     return 0;
> +}
> +EXPORT_SYMBOL_GPL (usb_hcd_get_hc_keyboard_detach);
> +
> +
>  #endif /* CONFIG_KDB_USB */
>  
> +
>  /*-------------------------------------------------------------------------*/
>  
>  #if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
> diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
> index d2e9e35..65b4e96 100644
> --- a/drivers/usb/core/hcd.h
> +++ b/drivers/usb/core/hcd.h
> @@ -22,6 +22,9 @@
>  #ifdef __KERNEL__
>  
>  #include <linux/rwsem.h>
> +#ifdef CONFIG_KDB_USB
> +#include <linux/kdb.h>
> +#endif
>  
>  #define MAX_TOPO_LEVEL               6
>  
> @@ -222,6 +225,9 @@ struct hc_driver {
>  #ifdef CONFIG_KDB_USB
>       /* KDB poll function for this HC */
>       int     (*kdb_poll_char)(struct urb *urb);
> +     void    (*kdb_completion)(struct urb *urb);
> +     kdb_hc_keyboard_attach_t        kdb_hc_keyboard_attach;
> +     kdb_hc_keyboard_detach_t        kdb_hc_keyboard_detach;
>  #endif /* CONFIG_KDB_USB */
>  };
>  
> diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
> index cf5e4cf..3e52775 100644
> --- a/drivers/usb/host/uhci-hcd.c
> +++ b/drivers/usb/host/uhci-hcd.c
> @@ -50,6 +50,11 @@
>  #include "uhci-hcd.h"
>  #include "pci-quirks.h"
>  
> +#ifdef CONFIG_KDB_USB
> +#include <linux/kdb.h>
> +#include <linux/kdbprivate.h>
> +#endif
> +
>  /*
>   * Version Information
>   */
> @@ -461,6 +466,213 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd)
>       return IRQ_HANDLED;
>  }
>  
> +#ifdef CONFIG_KDB_USB
> +/* Unlink KDB QH from hardware and software scheduler */
> +static void kdb_unlink_uhci_qh(struct urb *urb, struct uhci_qh *qh)
> +{
> +     unsigned long flags;
> +     struct uhci_hcd *uhci;
> +
> +     uhci = (struct uhci_hcd *) hcd_to_uhci(bus_to_hcd(urb->dev->bus));
> +
> +     spin_lock_irqsave(&uhci->lock, flags);
> +     unlink_interrupt(NULL, qh);
> +     list_del(&(qh->node));
> +     spin_unlock_irqrestore(&uhci->lock, flags);
> +
> +}
> +
> +static int uhci_kdb_poll_char(struct urb *urb)
> +{
> +     if (!urb) /* can happen if no keyboard attached */
> +             return -1;
> +
> +     return uhci_check_kdb_uhci_qh(kdb_uhci_keyboard_get_qh(urb));
> +}
> +
> +/* Only 1 UHCI Keyboard supported */
> +static inline void kdb_usb_fill_int_urb (struct urb *urb,
> +                                      struct usb_device *dev,
> +                                      unsigned int pipe,
> +                                      void *transfer_buffer,
> +                                      int buffer_length,
> +                                      usb_complete_t complete_fn,
> +                                      void *context,
> +                                      int interval)
> +{
> +     urb->dev = dev;
> +     urb->pipe = pipe;
> +     urb->transfer_buffer = transfer_buffer;
> +     urb->transfer_buffer_length = buffer_length;
> +     urb->complete = complete_fn;
> +     urb->context = context;
> +     urb->interval = interval;
> +     urb->start_frame = -1;
> +}
> +
> +static int kdb_uhci_keyboard_attach(int i, unsigned int usbhid_bufsize)
> +{
> +     struct urb *kdb_urb;
> +     unsigned char *kdb_buffer;
> +     dma_addr_t uhci_inbuf_dma;
> +     struct urb *hid_inurb = kdb_usb_kbds[i].urb;
> +     int ret = -1;
> +
> +     kdb_usb_kbds[i].hid_urb = hid_inurb;
> +
> +     kdb_urb = NULL;
> +     kdb_buffer = NULL;
> +     if (!(kdb_buffer = usb_buffer_alloc(hid_inurb->dev,
> +                                         usbhid_bufsize, GFP_ATOMIC,
> +                                         &uhci_inbuf_dma)))
> +             goto out;
> +
> +     if (!(kdb_urb = usb_alloc_urb(0, GFP_KERNEL)))
> +             goto out;
> +
> +     kdb_usb_fill_int_urb(kdb_urb,
> +                          hid_inurb->dev,
> +                          hid_inurb->pipe,
> +                          kdb_buffer,
> +                          hid_inurb->transfer_buffer_length,
> +                          hid_inurb->complete,
> +                          hid_inurb->context,
> +                          hid_inurb->interval
> +             );
> +
> +     (kdb_urb)->transfer_dma = uhci_inbuf_dma;
> +     (kdb_urb)->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
> +
> +     kdb_usb_kbds[i].urb = kdb_urb;
> +     kdb_usb_kbds[i].buffer = kdb_buffer;
> +
> +     if (usb_submit_urb(kdb_urb, GFP_ATOMIC)){
> +             kdb_usb_keyboard_detach(hid_inurb);
> +             goto out;
> +     }
> +     /* Remove KDB special URB from endpoin queue to
> +      * prevent hang during hid_disconnect().
> +      */
> +     list_del(&(kdb_urb->urb_list));
> +
> +     ret = 0;
> +     return ret;
> +out:
> +     /* Some Error Cleanup */
> +     ret = -1;
> +     printk("KDB: Error, UHCI Keyboard HID won't work!\n");
> +
> +     if (kdb_buffer)
> +             usb_buffer_free(hid_inurb->dev,
> +                             usbhid_bufsize, kdb_buffer,
> +                             uhci_inbuf_dma);
> +
> +     if (kdb_urb)
> +             usb_free_urb(kdb_urb);
> +
> +     return ret;
> +}
> +
> +static int kdb_uhci_keyboard_detach(struct urb *urb, int i)
> +{
> +     int ret;
> +
> +     if (kdb_usb_kbds[i].qh && (kdb_usb_kbds[i].hid_urb == urb)) {
> +             /* UHCI keyboard */
> +             kdb_unlink_uhci_qh(kdb_usb_kbds[i].urb, kdb_usb_kbds[i].qh);
> +             ret = 0;
> +     }
> +     ret = -1;
> +
> +     return ret;
> +}
> +
> +/* Check if URB is managed by KDB code */
> +static int kdb_uhci_keyboard_urb(struct urb *urb)
> +{
> +     int i;
> +
> +     for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) {
> +             if (kdb_usb_kbds[i].urb && kdb_usb_kbds[i].urb == urb)
> +                     return i;
> +     }
> +     return -1;
> +}
> +
> +/* Check if UHCI QH is managed by KDB code */
> +static int kdb_uhci_keyboard_check_uhci_qh(struct uhci_qh *qh)
> +{
> +     int i;
> +
> +     for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) {
> +             if (kdb_usb_kbds[i].urb && kdb_usb_kbds[i].qh == qh)
> +                     return i;
> +     }
> +     return -1;
> +}
> +
> +/* Set UHCI QH using URB pointer */
> +static int kdb_uhci_keyboard_set_qh(struct urb *urb, struct uhci_qh *qh)
> +{
> +     int i;
> +
> +     i = kdb_uhci_keyboard_urb(urb);
> +     if (i != -1)
> +             kdb_usb_kbds[i].qh = qh;
> +
> +     return 0;
> +}
> +
> +/* Get UHCI QH using URB pointer */
> +static struct uhci_qh *kdb_uhci_keyboard_get_qh(struct urb *urb)
> +{
> +     int i;
> +
> +     i = kdb_uhci_keyboard_urb(urb);
> +     if (i != -1)
> +             return kdb_usb_kbds[i].qh;
> +
> +     return NULL;
> +}
> +
> +/* Set UHCI hid_event using URB pointer */
> +static int kdb_uhci_keyboard_set_hid_event(struct urb *urb, int hid_event)
> +{
> +     int i;
> +
> +     i = kdb_uhci_keyboard_urb(urb);
> +     if (i != -1)
> +             kdb_usb_kbds[i].kdb_hid_event = hid_event;
> +
> +     return 0;
> +}
> +/* Get UHCI hid_event using URB pointer */
> +static int kdb_uhci_keyboard_get_hid_event(struct urb *urb)
> +{
> +     int i;
> +
> +     i = kdb_uhci_keyboard_urb(urb);
> +     if (i != -1)
> +             return kdb_usb_kbds[i].kdb_hid_event;
> +
> +     return 0;
> +}
> +
> +/* Set UHCI hid_event using UHCI QH pointer */
> +static int kdb_uhci_keyboard_set_hid_event_qh(struct uhci_qh *qh, int 
> hid_event)
> +{
> +     int i;
> +
> +     for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) {
> +             if (kdb_usb_kbds[i].urb && kdb_usb_kbds[i].qh == qh){
> +                     kdb_usb_kbds[i].kdb_hid_event = hid_event;
> +                     return i;
> +             }
> +     }
> +     return -1;
> +}
> +#endif
> +
>  /*
>   * Store the current frame number in uhci->frame_number if the controller
>   * is runnning.  Expand from 11 bits (of which we use only 10) to a
> @@ -921,6 +1133,12 @@ static const struct hc_driver uhci_driver = {
>  
>       .hub_status_data =      uhci_hub_status_data,
>       .hub_control =          uhci_hub_control,
> +#ifdef CONFIG_KDB_USB
> +     .kdb_poll_char =        uhci_kdb_poll_char,
> +     .kdb_completion =       kdb_uhci_urb_complete,
> +     .kdb_hc_keyboard_attach =       kdb_uhci_keyboard_attach,
> +     .kdb_hc_keyboard_detach =       kdb_uhci_keyboard_detach,
> +#endif
>  };
>  
>  static const struct pci_device_id uhci_pci_ids[] = { {
> diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
> index 3e5807d..13def8f 100644
> --- a/drivers/usb/host/uhci-q.c
> +++ b/drivers/usb/host/uhci-q.c
> @@ -25,6 +25,17 @@
>   * games with the FSBR code to make sure we get the correct order in all
>   * the cases. I don't think it's worth the effort
>   */
> +#ifdef CONFIG_KDB_USB
> +/* KDB HID QH, managed by KDB code */
> +static int kdb_uhci_keyboard_check_uhci_qh(struct uhci_qh *qh);
> +static int kdb_uhci_keyboard_set_qh(struct urb *urb, struct uhci_qh *qh);
> +static struct uhci_qh *kdb_uhci_keyboard_get_qh(struct urb *urb);
> +static int kdb_uhci_keyboard_set_hid_event(struct urb *urb, int hid_event);
> +static int kdb_uhci_keyboard_get_hid_event(struct urb *urb);
> +static int kdb_uhci_keyboard_set_hid_event_qh(struct uhci_qh *qh, int 
> hid_event);
> +static int kdb_uhci_keyboard_urb(struct urb *urb);
> +#endif
> +
>  static void uhci_set_next_interrupt(struct uhci_hcd *uhci)
>  {
>       if (uhci->is_stopped)
> @@ -288,6 +299,58 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd 
> *uhci,
>       return qh;
>  }
>  
> +#ifdef CONFIG_KDB_USB
> +/*
> + * Same as uhci_alloc_qh execpt it doesn't change to hep->hcpriv
> + */
> +static struct uhci_qh *kdb_uhci_alloc_qh(struct uhci_hcd *uhci,
> +                                      struct usb_device *udev, struct 
> usb_host_endpoint *hep)
> +{
> +     dma_addr_t dma_handle;
> +     struct uhci_qh *qh;
> +
> +     qh = dma_pool_alloc(uhci->qh_pool, GFP_ATOMIC, &dma_handle);
> +     if (!qh)
> +             return NULL;
> +
> +     memset(qh, 0, sizeof(*qh));
> +     qh->dma_handle = dma_handle;
> +
> +     qh->element = UHCI_PTR_TERM;
> +     qh->link = UHCI_PTR_TERM;
> +
> +     INIT_LIST_HEAD(&qh->queue);
> +     INIT_LIST_HEAD(&qh->node);
> +
> +     if (udev) {             /* Normal QH */
> +             qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
> +             if (qh->type != USB_ENDPOINT_XFER_ISOC) {
> +                     qh->dummy_td = uhci_alloc_td(uhci);
> +                     if (!qh->dummy_td) {
> +                             dma_pool_free(uhci->qh_pool, qh, dma_handle);
> +                             return NULL;
> +                     }
> +             }
> +             qh->state = QH_STATE_IDLE;
> +             qh->hep = hep;
> +             qh->udev = udev;
> +
> +             if (qh->type == USB_ENDPOINT_XFER_INT ||
> +                 qh->type == USB_ENDPOINT_XFER_ISOC)
> +                     qh->load = usb_calc_bus_time(udev->speed,
> +                                                  
> usb_endpoint_dir_in(&hep->desc),
> +                                                  qh->type == 
> USB_ENDPOINT_XFER_ISOC,
> +                                                  
> le16_to_cpu(hep->desc.wMaxPacketSize))
> +                             / 1000 + 1;
> +
> +     } else {                /* Skeleton QH */
> +             qh->state = QH_STATE_ACTIVE;
> +             qh->type = -1;
> +     }
> +     return qh;
> +}
> +#endif
> +
>  static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
>  {
>       WARN_ON(qh->state != QH_STATE_IDLE && qh->udev);
> @@ -1394,6 +1457,21 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
>       if (!urbp)
>               goto done;
>  
> +#ifdef CONFIG_KDB_USB
> +     /* Always allocate new QH for KDB URB.
> +      * KDB HQ will be managed by KDB poll code not by
> +      * UHCI HCD Driver.
> +      */
> +     if (kdb_uhci_keyboard_urb(urb) != -1){
> +             /* KDB urb will be enqued only once */
> +             kdb_uhci_keyboard_set_qh(urb, NULL);
> +             qh = kdb_uhci_alloc_qh(uhci, urb->dev, urb->ep);
> +             if (!qh)
> +                     goto err_no_qh;
> +             kdb_uhci_keyboard_set_qh(urb, qh);
> +     } else
> +#endif
> +
>       if (urb->ep->hcpriv)
>               qh = urb->ep->hcpriv;
>       else {
> @@ -1642,6 +1720,14 @@ static int uhci_advance_check(struct uhci_hcd *uhci, 
> struct uhci_qh *qh)
>       int ret = 1;
>       unsigned status;
>  
> +#ifdef CONFIG_KDB_USB
> +     /* Don't manage KDB QH */
> +     if(kdb_uhci_keyboard_check_uhci_qh(qh) != -1){
> +             ret = 0;
> +             goto done;
> +     }
> +#endif
> +
>       if (qh->type == USB_ENDPOINT_XFER_ISOC)
>               goto done;
>  
> @@ -1734,6 +1820,11 @@ rescan:
>                       uhci->next_qh = list_entry(qh->node.next,
>                                       struct uhci_qh, node);
>  
> +#ifdef CONFIG_KDB_USB
> +                     /* Don't manage KDB QH */
> +                     if(kdb_uhci_keyboard_check_uhci_qh(qh) != -1)
> +                             continue;
> +#endif
>                       if (uhci_advance_check(uhci, qh)) {
>                               uhci_scan_qh(uhci, qh);
>                               if (qh->state == QH_STATE_ACTIVE) {
> @@ -1760,3 +1851,76 @@ rescan:
>       else
>               uhci_set_next_interrupt(uhci);
>  }
> +
> +#ifdef CONFIG_KDB_USB
> +/*
> + * Activate KDB UHCI QH, called by KDB poll code.
> + */
> +static void kdb_activate_uhci_qh(struct uhci_qh *qh)
> +{
> +     struct urb_priv *urbp;
> +     struct uhci_td *td;
> +     __le32 status, token;
> +
> +     urbp = list_entry(qh->queue.next, struct urb_priv, node);
> +
> +     list_for_each_entry(td, &urbp->td_list, list){
> +             status = td->status;
> +             token = td->token;
> +             barrier();
> +             /* Clear Status and ActLen */
> +             status &= cpu_to_le32(0xff000000);
> +             /* Make TD Active */
> +             status |= cpu_to_le32(TD_CTRL_ACTIVE);
> +             /* Clear TD Interrupt */
> +             status &= cpu_to_le32(~TD_CTRL_IOC);
> +             /* Toggle Data Sycronization Bit */
> +             if (token & cpu_to_le32(TD_TOKEN_TOGGLE))
> +                     token &= cpu_to_le32(~TD_TOKEN_TOGGLE);
> +             else
> +                     token |= cpu_to_le32(TD_TOKEN_TOGGLE);
> +
> +             td->token = token;
> +             td->status = status;
> +             barrier();
> +     }
> +     /* Activate KDB UHCI Keyboard HID QH */
> +     td = list_entry(urbp->td_list.next, struct uhci_td, list);
> +     qh->element = LINK_TO_TD(td);
> +     barrier();
> +}
> +
> +/*
> + * Called when KDB finishes process key press/release event.
> + */
> +static void
> +kdb_uhci_urb_complete (struct urb *urb)
> +{
> +     if (!kdb_uhci_keyboard_get_hid_event(urb))
> +             return;
> +
> +     /* Activate KDB TD */
> +     kdb_activate_uhci_qh(kdb_uhci_keyboard_get_qh(urb));
> +     kdb_uhci_keyboard_set_hid_event(urb, 0);
> +}
> +
> +/*
> + * Check if state of KDB URB changed (key was pressed/released).
> + */
> +static int uhci_check_kdb_uhci_qh(struct uhci_qh *qh)
> +{
> +     struct urb_priv *urbp = NULL;
> +     struct uhci_td *td;
> +     unsigned status;
> +
> +     urbp = list_entry(qh->queue.next, struct urb_priv, node);
> +     td = list_entry(urbp->td_list.next, struct uhci_td, list);
> +     status = td_status(td);
> +     if (!(status & TD_CTRL_ACTIVE)){
> +             /* We're okay, the queue has advanced */
> +             kdb_uhci_keyboard_set_hid_event_qh(qh, 1);
> +             return 0;
> +     }
> +     return -1;
> +}
> +#endif
> -- 
> 1.5.6.3
> 
> _______________________________________________
> kdb mailing list
> [email protected]
> http://oss.sgi.com/mailman/listinfo/kdb

_______________________________________________
kdb mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/kdb

Reply via email to