On Fri, 02 Nov 2007 11:55:49 -0700
Jay Lan <[EMAIL PROTECTED]> wrote:

> Hi Konstantin,
> 
> Thanks for your patch. It is in my queue.
> 
> In addition, there are other USB keyboard/mouse problems in
> current KDB code:
> 1) uhci and ohci keyboard would not work if connected through
>    a USB 2.0 hub,
> 2) hotplug USB keyboard does not work correctly.
> 
> Aaron Young is working to fix these problems and provide
> ehci support for KDB.
> 
> Thanks,
>  - jay
> 
> 

 Hi Jay.
You mean external 2.0 hub? I've attached keyboard to the EHCI
port of PC - I believe it works ok. AFAIK EHCI manages high speed
devices and it emulates OHCI or UHCI for low speed devices like keyboard,
so It should work with EHCI.

This is the new version of UHCI support in KDB. Because previous
version is unsafe. Previous fix issues:
- When CPU1 executes uhci_irq(), UHCI locks are acquired. If in the
same time KDB bp occurs on CPU2, KDB stops kernel and tries to acquire
the same UHCI spinlock in uhci_irq() called by KDB. That results in
deadlock, because KDB will never enable IRQ before it completes.
- Even if CPU1 executes uhci_irq() and lock is released KDB can't be
started untill uhci_irq() is finished, because uhci_irq() is not
reentrant function and probably UHCI scheduler can be broken by KDB.
- KDB code should manage only HID Keyboard URB. It can't be done if KDB
uses whole uhci_irq() handler. Because uhci_irq manages Queue
Heads(QH), not URBs, and in QH that contain KDB URB can be other URBs.

KDB UHCI poll driver requiremens based on issues:
- driver should not require any of UCHI kernel spinlocks.
- driver shouldn't require sync with kernel UHCI driver.
- driver should work with hardware UHCI scheduler and don't touch
software scheduler, because without sync with kernel driver sw
scheduler can be broken by KDB.
- driver should manage only KDB URB. As HW ans SW schedulers of UHCI
works with QH, not with URBs, special KDB QH should be allocated and
KDB URB shuld be added to this QH. KDB QH should contain only KDB urb.

Necessary changes of kernel UHCI driver:
- KDB QH and URB should not be managed.

Current version of KDB poll driver manages HW UHCI scheduler so it can
be executed even if kernel UHCI driver is stopped.
Main concepts KDB drivers:
  - Allocation of KDB QH and KDB URB
  Allocation of KDB URB occurs in HID driver, because only there we
know if keyboard is attached (see kdb_uhci_submit_urb()). HID core uses
Interrupt URB(inurb) to get keyboard codes. After urbin was sent, KDB
sends it's own interrupt urb with same parameters(DevAddr, Endpoint).
While KDB URB is sent, the brand new KDB QH(kdb_uhci_hid_qh) is
allocated and KDB URB transfer descriptors(TD) are linked into KDB QH.
KDB QH and KDB URB will never be managed by kernel driver so KDB QH
will always be in hardware scheduler of UHCI. When kernel enters KDB we
just need to reactivate KDB QH periodically without change software
scheduler of kernel driver and we don't need to free/allocate memory
for KDB QH and URB because whose will never be freed/unlinked by kernel
driver.
  - Reenabling of KDB QH
  KDB poll code periodically check if KDB QH was advanced(key was
pressed) in uhci_check_kdb_uhci_qh(). To reenable KDB QH
kdb_activate_uhci_qh() activate every TD linked in KDB QH except last
one that is dummy. Then, to reenable KDB QH, pointer to first TD is
written to element field of KDB QH.

Changes of KDB USB code:
  - kdb_hcd_type was added, it determines if Keyboard is attached to
OHCI or UCHI. Probably KDB should determine it without help of
kdb_hcd_type. kdb_hcd_type can be set by kernel config or in kernel
parameters(kdbohci/kdbuhci).
  - struct urb *hid_urbin was added to struct kdb_usb_exchange to
recognize HID keyboard used by KDB.
  - void (*urb_complete)(void *, struct urb *) was added to struct
kdb_usb_exchange. In UHCI case this callback is called from
get_usb_char(), when KDB URB is processed, to reenable KDB QH.

Known Issues of KDB driver:
  - Autoreply of pressed key doesn't work
  - When kernel enters KDB first pressed key doesn't appear on KDB
console, because it's caught by UHCI kernel driver.
  - Keyboard hotplug wasn't tested.

Patch is against 2.6.23-rc8.

Signed-off-by: Konstantin Baydarov <[EMAIL PROTECTED]>

Index: linux-2.6.23-rc8/drivers/usb/host/uhci-q.c
===================================================================
--- linux-2.6.23-rc8.orig/drivers/usb/host/uhci-q.c
+++ linux-2.6.23-rc8/drivers/usb/host/uhci-q.c
@@ -25,6 +25,11 @@
  * 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 struct uhci_qh *kdb_uhci_hid_qh;
+#endif
+
 static void uhci_set_next_interrupt(struct uhci_hcd *uhci)
 {
        if (uhci->is_stopped)
@@ -292,6 +297,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);
@@ -1396,6 +1453,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 (urb == kdb_usb_infos.urb && kdb_usb_infos.urb){
+               /* KDB urb will be enqued only once */
+               kdb_uhci_hid_qh = NULL;
+               qh = kdb_uhci_alloc_qh(uhci, urb->dev, hep);
+               if (!qh)
+                       goto err_no_qh;
+               kdb_uhci_hid_qh = qh;
+       } else
+#endif
        if (hep->hcpriv)
                qh = (struct uhci_qh *) hep->hcpriv;
        else {
@@ -1657,6 +1728,13 @@ static int uhci_advance_check(struct uhc
        int ret = 1;
        unsigned status;
 
+#ifdef CONFIG_KDB_USB
+       /* Don't manage KDB QH */
+       if (qh == kdb_uhci_hid_qh){
+               ret = 0;
+               goto done;
+       }
+#endif
        if (qh->type == USB_ENDPOINT_XFER_ISOC)
                goto done;
 
@@ -1749,6 +1827,11 @@ rescan:
                        uhci->next_qh = list_entry(qh->node.next,
                                        struct uhci_qh, node);
 
+#ifdef CONFIG_KDB_USB
+                       /* Don't manage KDB QH */
+                       if (qh == kdb_uhci_hid_qh)
+                               continue;
+#endif
                        if (uhci_advance_check(uhci, qh)) {
                                uhci_scan_qh(uhci, qh);
                                if (qh->state == QH_STATE_ACTIVE) {
@@ -1775,3 +1858,78 @@ rescan:
        else
                uhci_set_next_interrupt(uhci);
 }
+
+#ifdef CONFIG_KDB_USB
+static int kdb_hid_event = 0;  /* eq 1 when key was pressed/released */
+
+/*
+ * Activate KDB UHCI QH, called by KDB poll code.
+ */
+static void kdb_activate_uhci_qh(void)
+{
+       struct urb_priv *urbp;
+       struct uhci_td *td;
+       struct uhci_qh *qh = kdb_uhci_hid_qh;
+       __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 (void * __uhci, struct urb *urb)
+{
+
+       if (!kdb_hid_event)
+               return;
+
+       /* Activate KDB TD */
+       kdb_activate_uhci_qh();
+       kdb_hid_event = 0;
+}
+
+/*
+ * Check if state of KDB URB changed (key was pressed/released).
+ */
+static void uhci_check_kdb_uhci_qh(void)
+{
+       struct uhci_qh *qh = kdb_uhci_hid_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_hid_event = 1;
+}
+#endif
Index: linux-2.6.23-rc8/drivers/hid/usbhid/hid-core.c
===================================================================
--- linux-2.6.23-rc8.orig/drivers/hid/usbhid/hid-core.c
+++ linux-2.6.23-rc8/drivers/hid/usbhid/hid-core.c
@@ -45,6 +45,23 @@
 
 #ifdef CONFIG_KDB_USB
 #include <linux/kdb.h>
+
+#if defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE)
+struct urbin_saved_data {
+       /* Needed to fill KDB in URB */
+       struct usb_device *uhci_dev;
+       int uhci_pipe;
+       int uhci_insize;
+       int uhci_interval;
+       dma_addr_t uhci_inbuf_dma;
+};
+
+static struct urbin_saved_data kdb_urbin_param =
+       {0, 0, 0, 0, 0};
+
+static int kdb_uhci_hid_initialized = 0;
+#endif
+
 #endif
 
 static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick",
@@ -796,6 +813,20 @@ static struct hid_device *usb_hid_config
                                         hid_irq_in, hid, interval);
                        usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
                        usbhid->urbin->transfer_flags |= 
URB_NO_TRANSFER_DMA_MAP;
+
+#if (defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE)) && \
+       defined(CONFIG_KDB_USB)
+                       /* Save urbin parameters */
+                       if (!kdb_uhci_hid_initialized &&
+                               kdb_hcd_type == KDB_HCD_UHCI){
+                               kdb_usb_infos.hid_urbin = usbhid->urbin;
+                               kdb_urbin_param.uhci_dev = dev;
+                               kdb_urbin_param.uhci_pipe = pipe;
+                               kdb_urbin_param.uhci_insize = insize;
+                               kdb_urbin_param.uhci_interval = interval;
+                       }
+#endif
+
                } else {
                        if (usbhid->urbout)
                                continue;
@@ -901,8 +932,24 @@ static void hid_disconnect(struct usb_in
 
 #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 (usbhid->urbin == kdb_usb_infos.urb){
+#if defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE)
+               if (kdb_uhci_hid_initialized && kdb_hcd_type == KDB_HCD_UHCI){
+                       kdb_uhci_hid_initialized = 0;
+                       /* Cleanup */
+                       if (kdb_usb_infos.buffer)
+                               usb_buffer_free(kdb_urbin_param.uhci_dev,
+                               usbhid->bufsize, kdb_usb_infos.buffer,
+                               kdb_urbin_param.uhci_inbuf_dma);
+
+                       if (kdb_usb_infos.urb)
+                               usb_free_urb(kdb_usb_infos.urb);
+               }
+#endif
+               kdb_usb_infos.urb = NULL;
+               kdb_usb_infos.buffer = NULL;
+               kdb_usb_infos.hid_urbin = NULL;
+       }
 #endif
 
        spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
@@ -929,6 +976,60 @@ static void hid_disconnect(struct usb_in
        hid_free_device(hid);
 }
 
+#if (defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE)) && \
+       defined(CONFIG_KDB_USB)
+static void kdb_uhci_submit_urb(struct usbhid_device * usbhid)
+{
+       if (kdb_usb_infos.hid_urbin != usbhid->urbin ||
+                       !kdb_usb_infos.hid_urbin || kdb_uhci_hid_initialized)
+               return;
+
+       kdb_uhci_hid_initialized = 0;
+       if (!(kdb_usb_infos.buffer =
+                       usb_buffer_alloc(kdb_urbin_param.uhci_dev,
+                       usbhid->bufsize, GFP_ATOMIC,
+                       &kdb_urbin_param.uhci_inbuf_dma)))
+               goto out;
+
+       if (!(kdb_usb_infos.urb =
+                       usb_alloc_urb(0, GFP_KERNEL)))
+               goto out;
+
+       usb_fill_int_urb(kdb_usb_infos.urb,
+               kdb_urbin_param.uhci_dev,
+               kdb_urbin_param.uhci_pipe,
+               kdb_usb_infos.buffer,
+               kdb_urbin_param.uhci_insize,
+               hid_irq_in,
+               usbhid,
+               kdb_urbin_param.uhci_interval);
+
+       (kdb_usb_infos.urb)->transfer_dma = kdb_urbin_param.uhci_inbuf_dma;
+       (kdb_usb_infos.urb)->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       if (usb_submit_urb(kdb_usb_infos.urb, GFP_ATOMIC))
+               goto out;
+
+       kdb_uhci_hid_initialized = 1;
+out:
+       if (kdb_uhci_hid_initialized)
+               return;
+
+       /* Some Error Cleanup */
+       printk("\n\t\t KDB: Error, UHCI Keyboard HID won't work!");
+       if (kdb_usb_infos.buffer)
+               usb_buffer_free(kdb_urbin_param.uhci_dev,
+               usbhid->bufsize, kdb_usb_infos.buffer,
+               kdb_urbin_param.uhci_inbuf_dma);
+
+       if (kdb_usb_infos.urb)
+               usb_free_urb(kdb_usb_infos.urb);
+
+       kdb_usb_infos.buffer = NULL;
+       kdb_usb_infos.urb = NULL;
+}
+#endif
+
 static int hid_probe(struct usb_interface *intf, const struct usb_device_id 
*id)
 {
        struct hid_device *hid;
@@ -995,8 +1096,18 @@ static int hid_probe(struct usb_interfac
        /* Initialization of the KDB structure */
        if (!strcmp(c, "Keyboard")) {
                struct usbhid_device *usbhid = hid->driver_data;
-               kdb_usb_infos.urb = usbhid->urbin;
-               kdb_usb_infos.buffer = usbhid->inbuf;
+
+#if defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE)
+               if (kdb_hcd_type == KDB_HCD_UHCI){
+                       kdb_uhci_submit_urb(usbhid);
+               }
+#endif
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+               if (kdb_hcd_type == KDB_HCD_OHCI){
+                       kdb_usb_infos.urb = usbhid->urbin;
+                       kdb_usb_infos.buffer = usbhid->inbuf;
+               }
+#endif
                kdb_usb_infos.reset_timer = NULL;
        }
 #endif
Index: linux-2.6.23-rc8/include/linux/kdb.h
===================================================================
--- linux-2.6.23-rc8.orig/include/linux/kdb.h
+++ linux-2.6.23-rc8/include/linux/kdb.h
@@ -142,11 +142,18 @@ extern void smp_kdb_stop(void);
 #ifdef CONFIG_KDB_USB
 #include <linux/usb.h>
 
+#define KDB_HCD_OHCI 0
+#define KDB_HCD_UHCI 1
+
+extern int kdb_hcd_type;
+
 struct kdb_usb_exchange {
        void *uhci;                     /* pointer to the UHCI structure */
        struct urb *urb;                /* pointer to the URB */
        unsigned char *buffer;          /* pointer to buffer */
+       struct urb *hid_urbin;          /* pointer to HID URB */
        void (*poll_func)(void *, struct urb *); /* pointer to the polling 
function */
+       void (*urb_complete)(void *, struct urb *); /* pointer to the complete 
function */
        void (*reset_timer)(void);      /* pointer to the reset timer function 
*/
 };
 extern struct kdb_usb_exchange kdb_usb_infos; /* KDB common structure */
@@ -162,5 +169,6 @@ int kdb_process_cpu(const struct task_st
 }
 
 extern const char kdb_serial_str[];
+extern int kdb_kbd_delay_enter;
 
 #endif /* !_KDB_H */
Index: linux-2.6.23-rc8/drivers/usb/host/uhci-hcd.c
===================================================================
--- linux-2.6.23-rc8.orig/drivers/usb/host/uhci-hcd.c
+++ linux-2.6.23-rc8/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 void
+uhci_kdb_poll (void * __uhci, struct urb *urb)
+{
+       if (!urb) /* can happen if no keyboard attached */
+               return;
+
+       uhci_check_kdb_uhci_qh();
+}
+#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
@@ -661,6 +676,15 @@ static int uhci_start(struct usb_hcd *hc
        configure_hc(uhci);
        uhci->is_initialized = 1;
        start_rh(uhci);
+
+#ifdef CONFIG_KDB_USB
+       if (kdb_hcd_type == KDB_HCD_UHCI){
+               kdb_usb_infos.poll_func = uhci_kdb_poll;
+               kdb_usb_infos.uhci = NULL; /* not used */
+               kdb_usb_infos.urb_complete = kdb_uhci_urb_complete;
+       }
+#endif
+
        return 0;
 
 /*
Index: linux-2.6.23-rc8/arch/i386/kdb/kdba_io.c
===================================================================
--- linux-2.6.23-rc8.orig/arch/i386/kdb/kdba_io.c
+++ linux-2.6.23-rc8/arch/i386/kdb/kdba_io.c
@@ -61,22 +61,27 @@ static int get_usb_char(void)
        static int usb_lock;
        unsigned char keycode, spec;
        extern u_short plain_map[], shift_map[], ctrl_map[];
+       int ret, i, max;
 
+       ret = -1;
        /* Is USB initialized ? */
        if(!kdb_usb_infos.poll_func || !kdb_usb_infos.urb)
-               return -1;
+               return ret;
 
        /* 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<4; i++){
+               if (!kdb_usb_infos.buffer[2+i])
+                       break;
+       }
+       max = i + 1;
+
        spec = kdb_usb_infos.buffer[0];
-       keycode = kdb_usb_infos.buffer[2];
+       keycode = kdb_usb_infos.buffer[max];
        kdb_usb_infos.buffer[0] = (char)0;
        kdb_usb_infos.buffer[2] = (char)0;
 
-       if(kdb_usb_infos.buffer[3])
-               return -1;
-
        /* A normal key is pressed, decode it */
        if(keycode)
                keycode = kdb_usb_keycode[keycode];
@@ -87,10 +92,12 @@ static int 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;
@@ -101,28 +108,43 @@ static int get_usb_char(void)
                        switch(keycode)
                        {
                                case 0x1C: /* Enter */
-                                       return 13;
+                                       ret = 13;
+                                       break;
 
                                case 0x3A: /* Capslock */
                                        usb_lock ? (usb_lock = 0) : (usb_lock = 
1);
                                        break;
                                case 0x0E: /* Backspace */
-                                       return 8;
+                                       ret = 8;
+                                       break;
                                case 0x0F: /* TAB */
-                                       return 9;
+                                       ret = 9;
+                                       break;
                                case 0x77: /* Pause */
-                                       break ;
+                                       ret = -1;
+                                       break;
                                default:
                                        if(!usb_lock) {
-                                               return plain_map[keycode];
+                                               ret = plain_map[keycode];
+                                               break;
                                        }
                                        else {
-                                               return shift_map[keycode];
+                                               ret = shift_map[keycode];
+                                               break;
                                        }
                        }
                }
        }
-       return -1;
+
+       for(i=0; i<8; i++){
+               kdb_usb_infos.buffer[i] = (char)0;
+       }
+
+       if (kdb_usb_infos.urb_complete){
+               (*kdb_usb_infos.urb_complete)(kdb_usb_infos.uhci,
+                       (struct urb *)kdb_usb_infos.urb);
+       }
+       return ret;
 }
 #endif /* CONFIG_KDB_USB */
 
Index: linux-2.6.23-rc8/arch/i386/Kconfig.debug
===================================================================
--- linux-2.6.23-rc8.orig/arch/i386/Kconfig.debug
+++ linux-2.6.23-rc8/arch/i386/Kconfig.debug
@@ -156,11 +156,26 @@ config KDB_CONTINUE_CATASTROPHIC
          setting to 2.
 
 config KDB_USB
-       bool "Support for USB Keyboard in KDB (OHCI only)"
-       depends on KDB && USB_OHCI_HCD
+       bool "Support for USB Keyboard in KDB"
+       depends on KDB && (USB_OHCI_HCD || USB_UHCI_HCD)
        help
-         If you want to use kdb from a OHCI USB keyboard then say Y here.  If 
you
+         If you want to use kdb from a USB keyboard then say Y here.  If you
          say N then kdb can only be used from a PC (AT) keyboard or a serial
          console.
 
+choice
+       prompt "Keyboard HCD Type"
+       default KDB_UHCI
+       depends on KDB_USB
+
+config KDB_USB_UHCI
+       bool "Keyboard is attached to UHCI"
+       depends on USB_UHCI_HCD
+
+config KDB_USB_OHCI
+       bool "Keyboard is attached to OHCI"
+       depends on USB_OHCI_HCD
+
+endchoice
+
 endmenu
Index: linux-2.6.23-rc8/drivers/usb/host/ohci-pci.c
===================================================================
--- linux-2.6.23-rc8.orig/drivers/usb/host/ohci-pci.c
+++ linux-2.6.23-rc8/drivers/usb/host/ohci-pci.c
@@ -220,7 +220,7 @@ static int __devinit ohci_pci_start (str
                ohci_stop (hcd);
        }
 #ifdef CONFIG_KDB_USB
-       if (ret >= 0) {
+       if (ret >= 0 && kdb_hcd_type == KDB_HCD_OHCI) {
                kdb_usb_infos.poll_func = ohci_kdb_poll;
                kdb_usb_infos.uhci = NULL; /* not used */
        }
Index: linux-2.6.23-rc8/kdb/kdb_io.c
===================================================================
--- linux-2.6.23-rc8.orig/kdb/kdb_io.c
+++ linux-2.6.23-rc8/kdb/kdb_io.c
@@ -656,7 +656,43 @@ kdb_io_init(void)
        if (!vt_console)
                KDB_FLAG_SET(NO_VT_CONSOLE);
        kdb_input_flush();
+
+#ifdef CONFIG_KDB_USB
+       if (kdb_hcd_type == -1){
+#ifdef CONFIG_KDB_USB_OHCI
+       kdb_hcd_type = KDB_HCD_OHCI;
+#endif
+
+#ifdef CONFIG_KDB_USB_UHCI
+       kdb_hcd_type = KDB_HCD_UHCI;
+#endif
+       }
+#endif
+
        return;
 }
 
+#ifdef CONFIG_KDB_USB
+int kdb_hcd_type = -1;         /* undefined */
+
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+static int __init opt_kdbohci(char *str)
+{
+       kdb_hcd_type = KDB_HCD_OHCI;
+       return 0;
+}
+
+early_param("kdbohci", opt_kdbohci);
+#endif
+#if defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE)
+static int __init opt_kdbuhci(char *str)
+{
+       kdb_hcd_type = KDB_HCD_UHCI;
+       return 0;
+}
+
+early_param("kdbuhci", opt_kdbuhci);
+#endif
+#endif
+
 EXPORT_SYMBOL(kdb_read);
---------------------------
Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe.

Reply via email to