On Mon, 26 Nov 2007 13:39:41 -0800 (PST)
Aaron Young <[EMAIL PROTECTED]> wrote:

> 
> 
>  Konstantin, some comments:
> 
> 1. You added some USB specific code to kdba_io_32.c, namely
>    kdb_usb_fill_int_urb(), kdb_uhci_submit_urb().
> 
>    Would it be better to put this USB code into the kernel uhci
>    files (uhci-q.c, uhci-hcd.c or whatever) so kdb can remain unaware
> of USB specifics?
>    Also, I think if you did it this way, then it would remove the need
>    for the new interface routine kdb_usb_uhci_keyboard_attach(). You
>    should be able to just call kdb_usb_keyboard_attach() after you
> create and submit the new URB from hid_probe(). Just add 
>    a new parameter to kdb_usb_keyboard_attach() for the
>    complete_func and pass NULL for it for OHCI and EHCI.
>  
>    The USB infastructure is constantly being rewritten and
> structures/parameters changing around, so it would be best to keep
> those details over in the kernel and not in kdb IMO. 
> 
 - Got rid from kdb_usb_uhci_keyboard_attach()
 - Added "poll_func" argument to kdb_usb_keyboard_attach()
 - Moved kdb_usb_fill_int_urb() and kdb_uhci_submit_urb() to hid-core.c. That 
fixes compilation errors (problem reported by jidong xiao) when USB subsystem 
is compiled as kernel module.

> 2. What is the limiting factor preventing multiple keyboards? Is it
>    the use of the globals kdb_uhci_hid_qh and kdb_hid_event? Can this
>    be fixed somehow? Can they be put into the per device
> kdb_usb_kbd_info struct maybe?
> 
 - Moved kdb_uhci_hid_qh and hid_event to kdb_usb_kbd_info. Now multiple UHCI 
keyboards are supported.

> 4. I think you'll need to add your new interfaces to kdba_io_64.c
>    and arch/ia64/kdb/kdba_io.c. Otherwise, the USB modules will
> encounter link/build errors when they can't find
> kdb_usb_uhci_keyboard_attach() (and the other globals and such) on
> those builds/systems. It would be nice to have UHCI support on those
> archs too.
> 
 - Added x86_64 part.

> 5. I already submitted another patch for EHCI support which will
>    conflict with this one (kdba_io_32.c). Can you add your patch on
>    top of that one?
 - Done.

> 
> 
>  -Aaron
> 

 Patch against kernel 2.6.24-rc2. Was tested on i386 kernel with 2 UHCI 
keyboards.

Index: linux-2.6.24-rc2/drivers/usb/host/uhci-q.c
===================================================================
--- linux-2.6.24-rc2.orig/drivers/usb/host/uhci-q.c
+++ linux-2.6.24-rc2/drivers/usb/host/uhci-q.c
@@ -25,6 +25,18 @@
  * 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 */
+extern int kdb_uhci_keyboard_chech_uhci_qh(struct uhci_qh *qh);
+extern int kdb_uhci_keyboard_set_qh(struct urb *urb, struct uhci_qh *qh);
+extern struct uhci_qh *kdb_uhci_keyboard_get_qh(struct urb *urb);
+extern int kdb_uhci_keyboard_set_hid_event(struct urb *urb, int hid_event);
+extern int kdb_uhci_keyboard_get_hid_event(struct urb *urb);
+extern int kdb_uhci_keyboard_set_hid_event_qh(struct uhci_qh *qh, int 
hid_event);
+extern int kdb_uhci_keyboard_get_hid_event_qh(struct uhci_qh *qh);
+#endif
+
+
 static void uhci_set_next_interrupt(struct uhci_hcd *uhci)
 {
        if (uhci->is_stopped)
@@ -292,6 +304,58 @@ static struct uhci_qh *uhci_alloc_qh(str
        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);
@@ -1399,6 +1463,20 @@ static int uhci_urb_enqueue(struct usb_h
        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 {
@@ -1648,6 +1726,13 @@ static int uhci_advance_check(struct uhc
        int ret = 1;
        unsigned status;
 
+#ifdef CONFIG_KDB_USB
+       /* Don't manage KDB QH */
+       if(kdb_uhci_keyboard_chech_uhci_qh(qh) != -1){
+               ret = 0;
+               goto done;
+       }
+#endif
        if (qh->type == USB_ENDPOINT_XFER_ISOC)
                goto done;
 
@@ -1740,6 +1825,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_chech_uhci_qh(qh) != -1)
+                               continue;
+#endif
                        if (uhci_advance_check(uhci, qh)) {
                                uhci_scan_qh(uhci, qh);
                                if (qh->state == QH_STATE_ACTIVE) {
@@ -1766,3 +1856,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
Index: linux-2.6.24-rc2/drivers/hid/usbhid/hid-core.c
===================================================================
--- linux-2.6.24-rc2.orig/drivers/hid/usbhid/hid-core.c
+++ linux-2.6.24-rc2/drivers/hid/usbhid/hid-core.c
@@ -969,6 +969,86 @@ static void hid_disconnect(struct usb_in
        hid_free_device(hid);
 }
 
+#ifdef CONFIG_KDB_USB
+/* 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_submit_urb(struct usb_interface *intf, unsigned int 
usbhid_bufsize, struct urb *hid_inurb)
+{
+       struct urb *kdb_urb = NULL;
+       unsigned char *kdb_buffer;
+       dma_addr_t uhci_inbuf_dma;
+       int ret = -1;
+       extern void * usb_hcd_get_kdb_poll_func(struct usb_device *udev);
+       extern void * usb_hcd_get_kdb_completion_func(struct usb_device *udev);
+
+       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;
+
+       ret = kdb_usb_keyboard_attach(kdb_urb, kdb_buffer,
+           usb_hcd_get_kdb_poll_func(interface_to_usbdev(intf)),
+           usb_hcd_get_kdb_completion_func(interface_to_usbdev(intf)));
+
+       if (ret){
+               kdb_uhci_keyboard_clear(kdb_urb);
+               goto out;
+       }
+
+       if (usb_submit_urb(kdb_urb, GFP_ATOMIC))
+               goto out;
+
+       ret = 0;
+       return ret;
+out:
+       /* Some Error Cleanup */
+       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;
+}
+#endif
+
 static int hid_probe(struct usb_interface *intf, const struct usb_device_id 
*id)
 {
        struct hid_device *hid;
@@ -1045,8 +1125,15 @@ static int hid_probe(struct usb_interfac
                int     ret;
                struct usbhid_device *usbhid = hid->driver_data;
                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)));
+               extern void * usb_hcd_get_kdb_completion_func(struct usb_device 
*udev);
+               extern int usb_hcd_check_uhci(struct usb_device *udev);
+
+               if (usb_hcd_check_uhci(interface_to_usbdev(intf)))
+                       ret = kdb_uhci_submit_urb(intf, usbhid->bufsize, 
usbhid->urbin);
+               else
+                       ret = kdb_usb_keyboard_attach(usbhid->urbin, 
usbhid->inbuf,
+                           
usb_hcd_get_kdb_poll_func(interface_to_usbdev(intf)),
+                           
usb_hcd_get_kdb_completion_func(interface_to_usbdev(intf)));
 
                if (ret == -1)
                        printk(": FAILED to register keyboard (%s) "
Index: linux-2.6.24-rc2/include/linux/kdb.h
===================================================================
--- linux-2.6.24-rc2.orig/include/linux/kdb.h
+++ linux-2.6.24-rc2/include/linux/kdb.h
@@ -143,9 +143,17 @@ extern void smp_kdb_stop(void);
 
 #include <linux/usb.h>
 
-extern int kdb_usb_keyboard_attach(struct urb *urb, unsigned char *buffer, 
void *poll_func);
+extern int kdb_uhci_keyboard_urb(struct urb *urb);
+extern int kdb_uhci_keyboard_clear(struct urb *urb);
+extern int kdb_usb_keyboard_alloc(void);
+
+extern int kdb_usb_keyboard_attach(struct urb *urb, unsigned char *buffer, 
void *poll_func, void *compl_func);
 extern int kdb_usb_keyboard_detach(struct urb *urb);
 
+extern int
+kdb_usb_uhci_keyboard_attach(struct urb *urb, unsigned int usbhid_bufsize,
+                               void *poll_func, void *compl_func);
+
 #endif /* CONFIG_KDB_USB */
 
 static inline
Index: linux-2.6.24-rc2/drivers/usb/host/uhci-hcd.c
===================================================================
--- linux-2.6.24-rc2.orig/drivers/usb/host/uhci-hcd.c
+++ linux-2.6.24-rc2/drivers/usb/host/uhci-hcd.c
@@ -50,6 +50,10 @@
 #include "uhci-hcd.h"
 #include "pci-quirks.h"
 
+#ifdef CONFIG_KDB_USB
+#include <linux/kdb.h>
+#endif
+
 /*
  * Version Information
  */
@@ -430,6 +434,17 @@ static irqreturn_t uhci_irq(struct usb_h
        return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_KDB_USB
+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));
+}
+#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
@@ -888,6 +903,10 @@ static const struct hc_driver uhci_drive
 
        .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,
+#endif
 };
 
 static const struct pci_device_id uhci_pci_ids[] = { {
Index: linux-2.6.24-rc2/arch/x86/kdb/kdba_io_32.c
===================================================================
--- linux-2.6.24-rc2.orig/arch/x86/kdb/kdba_io_32.c
+++ linux-2.6.24-rc2/arch/x86/kdb/kdba_io_32.c
@@ -55,12 +55,146 @@ static unsigned char kdb_usb_keycode[256
        150,158,159,128,136,177,178,176,142,152,173,140
 };
 
+/* Check if URB is managed by KDB code */
+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;
+}
+EXPORT_SYMBOL_GPL (kdb_uhci_keyboard_urb);
+
+/* Check if UHCI QH is managed by KDB code */
+int kdb_uhci_keyboard_chech_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;
+}
+EXPORT_SYMBOL_GPL (kdb_uhci_keyboard_chech_uhci_qh);
+
+/* Clear keyboar entry */
+int kdb_uhci_keyboard_clear(struct urb *urb)
+{
+       int i;
+
+       i = kdb_uhci_keyboard_urb(urb);
+       if (i != -1){
+               /* found a free array index */
+               kdb_usb_kbds[i].urb = NULL;
+               kdb_usb_kbds[i].buffer = NULL;
+               kdb_usb_kbds[i].poll_func = NULL;
+               kdb_usb_kbds[i].urb_complete = NULL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL (kdb_uhci_keyboard_clear);
+
+/* Set UHCI QH using URB pointer */
+int kdb_uhci_keyboard_set_qh(struct urb *urb, struct uhci_qh *qh)
+{
+       int i;
+
+       i = kdb_uhci_keyboard_urb(urb);
+       if (i != -1){
+               /* found a free array index */
+               kdb_usb_kbds[i].qh = qh;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL (kdb_uhci_keyboard_set_qh);
+
+/* Get UHCI QH using URB pointer */
+struct uhci_qh *kdb_uhci_keyboard_get_qh(struct urb *urb)
+{
+       int i;
+
+       i = kdb_uhci_keyboard_urb(urb);
+       if (i != -1){
+               /* found a free array index */
+               return kdb_usb_kbds[i].qh;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL (kdb_uhci_keyboard_get_qh);
+
+/* Set UHCI hid_event using URB pointer */
+int kdb_uhci_keyboard_set_hid_event(struct urb *urb, int hid_event)
+{
+       int i;
+
+       i = kdb_uhci_keyboard_urb(urb);
+       if (i != -1){
+               /* found a free array index */
+               kdb_usb_kbds[i].kdb_hid_event = hid_event;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL (kdb_uhci_keyboard_set_hid_event);
+
+/* Get UHCI hid_event using URB pointer */
+int kdb_uhci_keyboard_get_hid_event(struct urb *urb)
+{
+       int i;
+
+       i = kdb_uhci_keyboard_urb(urb);
+       if (i != -1){
+               /* found a free array index */
+               return kdb_usb_kbds[i].kdb_hid_event;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL (kdb_uhci_keyboard_get_hid_event);
+
+/* Set UHCI hid_event using UHCI QH pointer */
+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;
+}
+EXPORT_SYMBOL_GPL (kdb_uhci_keyboard_set_hid_event_qh);
+
+/* Get UHCI hid_event using UHCI QH pointer */
+int kdb_uhci_keyboard_get_hid_event_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 kdb_usb_kbds[i].kdb_hid_event;
+       }
+
+       return -1;
+}
+EXPORT_SYMBOL_GPL (kdb_uhci_keyboard_get_hid_event_qh);
+
 /*
  * kdb_usb_keyboard_attach()
  * 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)
 {
         int     i;
         int     rc = -1;
@@ -82,6 +216,7 @@ kdb_usb_keyboard_attach(struct urb *urb,
                 kdb_usb_kbds[i].urb = urb;
                 kdb_usb_kbds[i].buffer = buffer;
                 kdb_usb_kbds[i].poll_func = poll_func;
+                kdb_usb_kbds[i].urb_complete = compl_func;
 
                 rc = 0; /* success */
 
@@ -142,6 +277,9 @@ get_usb_char(void)
         int     ret;
         unsigned char keycode, spec;
         extern u_short plain_map[], shift_map[], ctrl_map[];
+        int     poll_ret, i2, j, max;
+
+       ret = -1;
 
         if (kdb_no_usb)
                 return -1;
@@ -158,20 +296,27 @@ get_usb_char(void)
                         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 */
+                poll_ret = (*kdb_usb_kbds[i].poll_func)(kdb_usb_kbds[i].urb);
+                if (poll_ret == -1) /* 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];
+                keycode = kdb_usb_kbds[i].buffer[max];
                 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];
@@ -182,10 +327,12 @@ get_usb_char(void)
                         {
                         case 0x2:
                         case 0x20: /* Shift */
-                                return shift_map[keycode];
+                               ret = shift_map[keycode];
+                               break;
                         case 0x1:
                         case 0x10: /* Ctrl */
-                                return ctrl_map[keycode];
+                               ret = ctrl_map[keycode];
+                               break;
                         case 0x4:
                         case 0x40: /* Alt */
                                 break;
@@ -194,31 +341,45 @@ get_usb_char(void)
                         switch(keycode)
                         {
                         case 0x1C: /* Enter */
-                                return 13;
-
+                               ret = 13;
+                               break;
                         case 0x3A: /* Capslock */
                                 kdb_usb_kbds[i].caps_lock = 
!(kdb_usb_kbds[i].caps_lock);
                                 break;
                         case 0x0E: /* Backspace */
-                                return 8;
+                               ret = 8;
+                               break;
                         case 0x0F: /* TAB */
-                                return 9;
+                               ret = 9;
+                               break;
                         case 0x77: /* Pause */
                                 break ;
                         default:
                                 if(!kdb_usb_kbds[i].caps_lock) {
-                                        return plain_map[keycode];
+                                       ret = plain_map[keycode];
+                                       break;
                                 }
                                 else {
-                                        return shift_map[keycode];
+                                       ret = shift_map[keycode];
+                                       break;
                                 }
                         }
                 }
+               /* Key was pressed, return keycode */
+               break;
         }
 
-        /* no chars were returned from any of the USB keyboards */
+       for(i2=0; i2<8; i2++){
+               if (kdb_usb_kbds[i2].buffer)
+                       for(j=0; j<8; j++){
+                               kdb_usb_kbds[i2].buffer[j] = (char)0;
+                       }
+       }
+
+       if (kdb_usb_kbds[i].urb_complete)
+               (*kdb_usb_kbds[i].urb_complete)((struct urb 
*)kdb_usb_kbds[i].urb);
 
-        return -1;
+        return ret;
 }
 #endif /* CONFIG_KDB_USB */
 
Index: linux-2.6.24-rc2/arch/x86/kdb/kdba_io_64.c
===================================================================
--- linux-2.6.24-rc2.orig/arch/x86/kdb/kdba_io_64.c
+++ linux-2.6.24-rc2/arch/x86/kdb/kdba_io_64.c
@@ -55,12 +55,146 @@ static unsigned char kdb_usb_keycode[256
        150,158,159,128,136,177,178,176,142,152,173,140
 };
 
+/* Check if URB is managed by KDB code */
+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;
+}
+EXPORT_SYMBOL_GPL (kdb_uhci_keyboard_urb);
+
+/* Check if UHCI QH is managed by KDB code */
+int kdb_uhci_keyboard_chech_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;
+}
+EXPORT_SYMBOL_GPL (kdb_uhci_keyboard_chech_uhci_qh);
+
+/* Clear keyboar entry */
+int kdb_uhci_keyboard_clear(struct urb *urb)
+{
+       int i;
+
+       i = kdb_uhci_keyboard_urb(urb);
+       if (i != -1){
+               /* found a free array index */
+               kdb_usb_kbds[i].urb = NULL;
+               kdb_usb_kbds[i].buffer = NULL;
+               kdb_usb_kbds[i].poll_func = NULL;
+               kdb_usb_kbds[i].urb_complete = NULL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL (kdb_uhci_keyboard_clear);
+
+/* Set UHCI QH using URB pointer */
+int kdb_uhci_keyboard_set_qh(struct urb *urb, struct uhci_qh *qh)
+{
+       int i;
+
+       i = kdb_uhci_keyboard_urb(urb);
+       if (i != -1){
+               /* found a free array index */
+               kdb_usb_kbds[i].qh = qh;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL (kdb_uhci_keyboard_set_qh);
+
+/* Get UHCI QH using URB pointer */
+struct uhci_qh *kdb_uhci_keyboard_get_qh(struct urb *urb)
+{
+       int i;
+
+       i = kdb_uhci_keyboard_urb(urb);
+       if (i != -1){
+               /* found a free array index */
+               return kdb_usb_kbds[i].qh;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL (kdb_uhci_keyboard_get_qh);
+
+/* Set UHCI hid_event using URB pointer */
+int kdb_uhci_keyboard_set_hid_event(struct urb *urb, int hid_event)
+{
+       int i;
+
+       i = kdb_uhci_keyboard_urb(urb);
+       if (i != -1){
+               /* found a free array index */
+               kdb_usb_kbds[i].kdb_hid_event = hid_event;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL (kdb_uhci_keyboard_set_hid_event);
+
+/* Get UHCI hid_event using URB pointer */
+int kdb_uhci_keyboard_get_hid_event(struct urb *urb)
+{
+       int i;
+
+       i = kdb_uhci_keyboard_urb(urb);
+       if (i != -1){
+               /* found a free array index */
+               return kdb_usb_kbds[i].kdb_hid_event;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL (kdb_uhci_keyboard_get_hid_event);
+
+/* Set UHCI hid_event using UHCI QH pointer */
+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;
+}
+EXPORT_SYMBOL_GPL (kdb_uhci_keyboard_set_hid_event_qh);
+
+/* Get UHCI hid_event using UHCI QH pointer */
+int kdb_uhci_keyboard_get_hid_event_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 kdb_usb_kbds[i].kdb_hid_event;
+       }
+
+       return -1;
+}
+EXPORT_SYMBOL_GPL (kdb_uhci_keyboard_get_hid_event_qh);
+
 /*
  * kdb_usb_keyboard_attach()
  * 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)
 {
         int     i;
         int     rc = -1;
@@ -82,6 +216,7 @@ kdb_usb_keyboard_attach(struct urb *urb,
                 kdb_usb_kbds[i].urb = urb;
                 kdb_usb_kbds[i].buffer = buffer;
                 kdb_usb_kbds[i].poll_func = poll_func;
+                kdb_usb_kbds[i].urb_complete = compl_func;
 
                 rc = 0; /* success */
 
@@ -142,6 +277,9 @@ get_usb_char(void)
         int     ret;
         unsigned char keycode, spec;
         extern u_short plain_map[], shift_map[], ctrl_map[];
+        int     poll_ret, i2, j, max;
+
+       ret = -1;
 
         if (kdb_no_usb)
                 return -1;
@@ -158,20 +296,27 @@ get_usb_char(void)
                         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 */
+                poll_ret = (*kdb_usb_kbds[i].poll_func)(kdb_usb_kbds[i].urb);
+                if (poll_ret == -1) /* 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];
+                keycode = kdb_usb_kbds[i].buffer[max];
                 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];
@@ -182,10 +327,12 @@ get_usb_char(void)
                         {
                         case 0x2:
                         case 0x20: /* Shift */
-                                return shift_map[keycode];
+                               ret = shift_map[keycode];
+                               break;
                         case 0x1:
                         case 0x10: /* Ctrl */
-                                return ctrl_map[keycode];
+                               ret = ctrl_map[keycode];
+                               break;
                         case 0x4:
                         case 0x40: /* Alt */
                                 break;
@@ -194,31 +341,45 @@ get_usb_char(void)
                         switch(keycode)
                         {
                         case 0x1C: /* Enter */
-                                return 13;
-
+                               ret = 13;
+                               break;
                         case 0x3A: /* Capslock */
                                 kdb_usb_kbds[i].caps_lock = 
!(kdb_usb_kbds[i].caps_lock);
                                 break;
                         case 0x0E: /* Backspace */
-                                return 8;
+                               ret = 8;
+                               break;
                         case 0x0F: /* TAB */
-                                return 9;
+                               ret = 9;
+                               break;
                         case 0x77: /* Pause */
                                 break ;
                         default:
                                 if(!kdb_usb_kbds[i].caps_lock) {
-                                        return plain_map[keycode];
+                                       ret = plain_map[keycode];
+                                       break;
                                 }
                                 else {
-                                        return shift_map[keycode];
+                                       ret = shift_map[keycode];
+                                       break;
                                 }
                         }
                 }
+               /* Key was pressed, return keycode */
+               break;
         }
 
-        /* no chars were returned from any of the USB keyboards */
+       for(i2=0; i2<8; i2++){
+               if (kdb_usb_kbds[i2].buffer)
+                       for(j=0; j<8; j++){
+                               kdb_usb_kbds[i2].buffer[j] = (char)0;
+                       }
+       }
+
+       if (kdb_usb_kbds[i].urb_complete)
+               (*kdb_usb_kbds[i].urb_complete)((struct urb 
*)kdb_usb_kbds[i].urb);
 
-        return -1;
+        return ret;
 }
 #endif /* CONFIG_KDB_USB */
 
Index: linux-2.6.24-rc2/include/linux/kdbprivate.h
===================================================================
--- linux-2.6.24-rc2.orig/include/linux/kdbprivate.h
+++ linux-2.6.24-rc2/include/linux/kdbprivate.h
@@ -489,7 +489,10 @@ 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 (*urb_complete)(struct urb *urb); /* called when URB int is 
processed */
        int     caps_lock;      /* state of the caps lock for this keyboard */
+       struct uhci_qh *qh;
+       int kdb_hid_event;
 };
 #endif /* CONFIG_KDB_USB */
 
Index: linux-2.6.24-rc2/drivers/usb/core/hcd.c
===================================================================
--- linux-2.6.24-rc2.orig/drivers/usb/core/hcd.c
+++ linux-2.6.24-rc2/drivers/usb/core/hcd.c
@@ -1851,6 +1851,32 @@ usb_hcd_get_kdb_poll_func(struct usb_dev
        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);
 #endif /* CONFIG_KDB_USB */
 
 /*-------------------------------------------------------------------------*/
Index: linux-2.6.24-rc2/drivers/usb/core/hcd.h
===================================================================
--- linux-2.6.24-rc2.orig/drivers/usb/core/hcd.h
+++ linux-2.6.24-rc2/drivers/usb/core/hcd.h
@@ -213,6 +213,7 @@ 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);
 #endif /* CONFIG_KDB_USB */
 };
 
---------------------------
Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe.

Reply via email to