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
