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.