Re: [PATCH] Add support for USB Keyboard attached to UHCI
Konstantin Baydarov <[email protected]> Fri, 30 Nov 2007 22:46:28 +0300
| Newsgroups | gmane.linux.kernel.debugging |
|---|---|
| Message-ID | <[email protected]> |
On Fri, 30 Nov 2007 08:43:07 -0800 (PST) Aaron Young <[email protected]> wrote: > > > > Also, should kdb_uhci_keyboard_chech_uhci_qh() be > kdb_uhci_keyboard_check_uhci_qh()? - Changed. > > > > > > > > > > Looking better! More comments: > > > > 1. I don't understand the need for the call to > > kdb_uhci_keyboard_clear(). It's only called if > > kdb_usb_keyboard_attach() fails and in that case we > > didn't add the urb to kdb_usb_kbds[]. So, I don't > > see the need to clear it out of kdb_usb_kbds[]... > > (I'm probably missing something here). - Now I call kdb_uhci_keyboard_clear() if usb_submit_urb() failed, that is called after kdb_usb_keyboard_attach(). > > > > 2. I probably would have made kdb_uhci_submit_urb() return > > the newly created kdb_urb (extra arg) on success and not call > > kdb_usb_keyboard_attach() directly from within. Then you can > > just make a single call to kdb_usb_keyboard_attach() for all three > > cases (OHCI, EHCI and UHCI) out of hid_probe(). But, not > > a *BIG* deal... - We should first fill kdb_usb_kbds[] before call of usb_submit_urb() because uhci_urb_enqueue() checks kdb_usb_kbds[] to find out if KDB URB is enqueued. So kdb_usb_keyboard_attach() should be called in the "middle" of the function kdb_uhci_submit_urb(). > > > > 3. We'll have to get updates to ia64 kdba_io.c as well, otherwise > > it will result in compile errors on ia64. i.e. > > kdb_usb_keyboard_attach() will have a number of args mismatch and > > all the routines you added to kdba_io_32.c and kdba_io_64.c will > > not be there. - Can't find any ia64 file... > > > > 4. You have the comment "/* found a free array index */" in several > > of the new kdba_io*.c routines when it really means you found > > a "match". - Fixed. > > > > 5. I just submitted another patch on Wed (Nov. 28th). That will > > conflict with this one again. Sorry - should be my last patch. - Done. > > > > > > Does hotplug/hotunplug of the keyboards work? > > Does it correctly remove the KDB URBs on hotunplug? - kdb_usb_keyboard_detach() is never called on my PC. So I tested only 1 case: attaching keyboard after kernel boot - works OK. > > > > Thanks, > > > > -Aaron > 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,87 @@ 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)), hid_inurb); + + if (ret) + goto out; + + if (usb_submit_urb(kdb_urb, GFP_ATOMIC)){ + kdb_uhci_keyboard_clear(kdb_urb); + 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 +1126,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)), NULL); 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, struct urb *hid_urb); 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,137 @@ 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_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; +} +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){ + 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) + 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) + 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) + 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) + 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, struct urb *hid_urb) { int i; int rc = -1; @@ -82,6 +207,8 @@ 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; + kdb_usb_kbds[i].hid_urb = hid_urb; rc = 0; /* success */ @@ -112,14 +239,20 @@ kdb_usb_keyboard_detach(struct urb *urb) */ for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { - if (kdb_usb_kbds[i].urb != urb) - continue; + if (kdb_usb_kbds[i].qh) { + /* UHCI keyboard */ + if (kdb_usb_kbds[i].hid_urb != urb) + continue; + } else + if (kdb_usb_kbds[i].urb != urb) + continue; /* found it, clear the index */ kdb_usb_kbds[i].urb = NULL; kdb_usb_kbds[i].buffer = NULL; kdb_usb_kbds[i].poll_func = NULL; kdb_usb_kbds[i].caps_lock = 0; + kdb_usb_kbds[i].hid_urb = NULL; rc = 0; /* success */ @@ -142,6 +275,9 @@ get_usb_char(void) int ret; unsigned char keycode, spec; extern u_short plain_map[], shift_map[], ctrl_map[]; + int ret_key = -1, i2, j, max; + + ret = -1; if (kdb_no_usb) return -1; @@ -169,15 +305,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]; + 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; - } + ret_key = -1; /* A normal key is pressed, decode it */ if(keycode) @@ -189,10 +334,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; @@ -201,31 +348,45 @@ 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]; + break; } else { - return shift_map[keycode]; + ret_key = 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_key; } #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,137 @@ 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_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; +} +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){ + 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) + 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) + 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) + 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) + 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, struct urb *hid_urb) { int i; int rc = -1; @@ -82,6 +207,8 @@ 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; + kdb_usb_kbds[i].hid_urb = hid_urb; rc = 0; /* success */ @@ -112,14 +239,20 @@ kdb_usb_keyboard_detach(struct urb *urb) */ for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { - if (kdb_usb_kbds[i].urb != urb) - continue; + if (kdb_usb_kbds[i].qh) { + /* UHCI keyboard */ + if (kdb_usb_kbds[i].hid_urb != urb) + continue; + } else + if (kdb_usb_kbds[i].urb != urb) + continue; /* found it, clear the index */ kdb_usb_kbds[i].urb = NULL; kdb_usb_kbds[i].buffer = NULL; kdb_usb_kbds[i].poll_func = NULL; kdb_usb_kbds[i].caps_lock = 0; + kdb_usb_kbds[i].hid_urb = NULL; rc = 0; /* success */ @@ -142,6 +275,9 @@ get_usb_char(void) int ret; unsigned char keycode, spec; extern u_short plain_map[], shift_map[], ctrl_map[]; + int ret_key = -1, i2, j, max; + + ret = -1; if (kdb_no_usb) return -1; @@ -169,15 +305,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]; + 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; - } + ret_key = -1; /* A normal key is pressed, decode it */ if(keycode) @@ -189,10 +334,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; @@ -201,31 +348,45 @@ 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]; + break; } else { - return shift_map[keycode]; + ret_key = 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_key; } #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,8 +489,12 @@ 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 poll_ret; /* return val from poll_func */ int caps_lock; /* state of the caps lock for this keyboard */ + struct uhci_qh *qh; + int kdb_hid_event; + struct urb *hid_urb; /* pointer to the HID URB */ }; #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.