From jlan@sgi.com Fri Nov 2 11:59:21 2007 Received: with ECARTIS (v1.0.0; list kdb); Fri, 02 Nov 2007 11:59:28 -0700 (PDT) Received: from cthulhu.engr.sgi.com (cthulhu.engr.sgi.com [192.26.80.2]) by oss.sgi.com (8.12.11.20060308/8.12.10/SuSE Linux 0.7) with ESMTP id lA2IxKBl019154 for ; Fri, 2 Nov 2007 11:59:21 -0700 Received: from [134.15.0.136] (mtv-vpn-sw-corp-0-136.corp.sgi.com [134.15.0.136]) by cthulhu.engr.sgi.com (8.12.10/8.12.10/SuSE Linux 0.7) with ESMTP id lA2IxLke001308; Fri, 2 Nov 2007 11:59:22 -0700 Message-ID: <472B72B5.7020903@sgi.com> Date: Fri, 02 Nov 2007 11:55:49 -0700 From: Jay Lan User-Agent: Thunderbird 1.5 (X11/20060317) MIME-Version: 1.0 To: Konstantin Baydarov CC: kdb@oss.sgi.com, Aaron Young Subject: Re: [PATCH] Add support for USB Keyboard attached to UHCI References: <20071008210936.7eba734d@localhost.localdomain> In-Reply-To: <20071008210936.7eba734d@localhost.localdomain> X-Enigmail-Version: 0.94.0.0 Content-type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit X-archive-position: 1267 X-ecartis-version: Ecartis v1.0.0 Sender: kdb-bounce@oss.sgi.com Errors-to: kdb-bounce@oss.sgi.com X-original-sender: jlan@sgi.com Precedence: bulk X-list: kdb 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 Konstantin Baydarov wrote: > Patch adds support of USB keyboard attached to UHCI in KDB. > Whole UHCI irq handler(uhci_irq) is called > periodically by KDB poll code when irqs are disabled. > I've tested patch with em64t pentiumd. USB keyboard attached to UHCI > works OK except there is 1 issue: auto reply of pressed key doesn't > work, but I don't think that is a critical issue. > > Patch against 2.6.23-rc8. > > Signed-off-by: Konstantin Baydarov > > arch/i386/Kconfig.debug | 4 ++-- > drivers/char/keyboard.c | 11 +++++++++++ > drivers/usb/host/uhci-hcd.c | 36 ++++++++++++++++++++++++++++++++++++ > include/linux/kdb.h | 1 + > kdb/kdbmain.c | 1 + > 5 files changed, 51 insertions(+), 2 deletions(-) > > 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 > @@ -41,6 +41,10 @@ > #include > #include > > +#ifdef CONFIG_KDB_USB > +#include > +#endif > + > #include > #include > #include > @@ -427,9 +431,37 @@ static irqreturn_t uhci_irq(struct usb_h > spin_unlock_irqrestore(&uhci->lock, flags); > } > > +#ifdef CONFIG_KDB_USB > + if (kdb_kbd_delay_enter){ > + kdb_kbd_delay_enter = 0; > +#ifndef CONFIG_PREEMPT_HARDIRQS > + kdb(KDB_REASON_KEYBOARD, 0, get_irq_regs()); > +#else > + KDB_ENTER(); > +#endif > + } > +#endif > + > return IRQ_HANDLED; > } > > +#ifdef CONFIG_KDB_USB > +void > +uhci_kdb_poll (void * __uhci, struct urb *urb) > +{ > + /* > + * NOTE - we use the uhci_hcd from the urb rather than the > + * __uhci parameter (which is NULL anyway). This ensures > + * that we will process the proper controller for the urb. > + */ > + > + if (!urb) /* can happen if no keyboard attached */ > + return; > + > + uhci_irq(bus_to_hcd(urb->dev->bus)); > +} > +#endif /* CONFIG_KDB_USB */ > + > /* > * 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 +693,10 @@ static int uhci_start(struct usb_hcd *hc > configure_hc(uhci); > uhci->is_initialized = 1; > start_rh(uhci); > +#ifdef CONFIG_KDB_USB > + kdb_usb_infos.poll_func = uhci_kdb_poll; > + kdb_usb_infos.uhci = NULL; /* not used */ > +#endif > return 0; > > /* > Index: linux-2.6.23-rc8/drivers/char/keyboard.c > =================================================================== > --- linux-2.6.23-rc8.orig/drivers/char/keyboard.c > +++ linux-2.6.23-rc8/drivers/char/keyboard.c > @@ -43,6 +43,7 @@ > #include > #ifdef CONFIG_KDB > #include > +void uhci_kdb_poll (void * __uhci, struct urb *urb); > #endif /* CONFIG_KDB */ > > extern void ctrl_alt_del(void); > @@ -1149,6 +1150,16 @@ static void kbd_keycode(unsigned int key > > #ifdef CONFIG_KDB > if (down && !rep && keycode == KEY_PAUSE && kdb_on == 1) { > +#ifdef CONFIG_KDB_USB > + /* Is this USB keyboard attached to UHCI ? */ > + if ((kdb_usb_infos.poll_func == uhci_kdb_poll) > + && kdb_usb_infos.urb) > + /* uhci_irq should be completed before kernel > + * enters KDB > + */ > + kdb_kbd_delay_enter = 1; > + else > +#endif > kdb(KDB_REASON_KEYBOARD, 0, get_irq_regs()); > return; > } > 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 > @@ -162,5 +162,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/kdb/kdbmain.c > =================================================================== > --- linux-2.6.23-rc8.orig/kdb/kdbmain.c > +++ linux-2.6.23-rc8/kdb/kdbmain.c > @@ -53,6 +53,7 @@ > volatile int kdb_flags; > atomic_t kdb_event; > atomic_t kdb_8250; > +int kdb_kbd_delay_enter = 0; > > /* > * kdb_lock protects updates to kdb_initial_cpu. Used to > 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,8 +156,8 @@ 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 (OHCI and UHCI only)" > + 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 > say N then kdb can only be used from a PC (AT) keyboard or a serial > --------------------------- > Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe. --------------------------- Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe. From jlan@sgi.com Fri Nov 2 12:14:04 2007 Received: with ECARTIS (v1.0.0; list kdb); Fri, 02 Nov 2007 12:14:10 -0700 (PDT) Received: from cthulhu.engr.sgi.com (cthulhu.engr.sgi.com [192.26.80.2]) by oss.sgi.com (8.12.11.20060308/8.12.10/SuSE Linux 0.7) with ESMTP id lA2JE3GL020660 for ; Fri, 2 Nov 2007 12:14:04 -0700 Received: from [134.15.0.136] (mtv-vpn-sw-corp-0-136.corp.sgi.com [134.15.0.136]) by cthulhu.engr.sgi.com (8.12.10/8.12.10/SuSE Linux 0.7) with ESMTP id lA2Ibwke031847; Fri, 2 Nov 2007 11:37:58 -0700 Message-ID: <472B6DB1.5080904@sgi.com> Date: Fri, 02 Nov 2007 11:34:25 -0700 From: Jay Lan User-Agent: Thunderbird 1.5 (X11/20060317) MIME-Version: 1.0 To: jidong xiao CC: kdb@oss.sgi.com Subject: Re: Question on kdb_event References: <4104961b0710310358y58bc0e1bm797fe236c8feb409@mail.gmail.com> In-Reply-To: <4104961b0710310358y58bc0e1bm797fe236c8feb409@mail.gmail.com> X-Enigmail-Version: 0.94.0.0 Content-type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit X-archive-position: 1268 X-ecartis-version: Ecartis v1.0.0 Sender: kdb-bounce@oss.sgi.com Errors-to: kdb-bounce@oss.sgi.com X-original-sender: jlan@sgi.com Precedence: bulk X-list: kdb jidong xiao wrote: > Hi,all > > Can anyone kindly explain the usage of kdb_event?Thank you very much! > I saw this varible is used only in two places, inside kdb_printf() and > kdb(), kdb_event is incremented and decremented. But I have no idea > why do we need to use it in these two circumstance. KDB modifies in this way: #ifdef CONFIG_KDB #include #define WARN_CONSOLE_UNLOCKED() WARN_ON(!is_console_locked() && !oops_in_progress && !atomic_read(&kdb_event)) #else /* !CONFIG_KDB */ #define WARN_CONSOLE_UNLOCKED() WARN_ON(!is_console_locked() && !oops_in_progress) #endif /* CONFIG_KDB */ The counter of kdb_event affects the value of WARN_CONSOLE_UNLOCKED(). Thanks, - jay > > Regards > Jason > --------------------------- > Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe. --------------------------- Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe. From jidong.xiao@gmail.com Sun Nov 4 21:48:02 2007 Received: with ECARTIS (v1.0.0; list kdb); Sun, 04 Nov 2007 21:48:08 -0800 (PST) Received: from rv-out-0910.google.com (rv-out-0910.google.com [209.85.198.184]) by oss.sgi.com (8.12.11.20060308/8.12.10/SuSE Linux 0.7) with ESMTP id lA55m0CF011716 for ; Sun, 4 Nov 2007 21:48:02 -0800 Received: by rv-out-0910.google.com with SMTP id k20so1079640rvb for ; Sun, 04 Nov 2007 21:48:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=beta; h=domainkey-signature:received:received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references; bh=oGObvBh62PbDtd9jzyx0glPdin7S2P+2h2CJfHUCgQ4=; b=WjRIgMBtlnTkDugY2NTr9eheGuahep7k0e/4VQUTjM7GT4Tb02QOHgBSs9YQNLFhM/SIJ3j+b3YKDYmT5AcUm73L0BYZudzx9f4dRGIKxh/7bvkyYOQ9IxQJHDmT+0RmHG6wDWUo/EWVCBxF6qCxW65Or+dpjRePrlrMFuxETPw= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=beta; h=received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references; b=Nj6z6zmSa2RyPbJeRw2nLglentBc3a8UdMLnBfjzua9j/+VlUdZYgHByhFBce9IPJ6nbYEYWYYpwtGzIIFuEhzoh7J/5r+xI69ucYsPwNxA9ceXEO71jpHVhr4L+nk8Sc74X3zG6WF2cbNeUjqCZ1zD657hHso9sd67T7mYUz9s= Received: by 10.142.47.6 with SMTP id u6mr896189wfu.1194240110265; Sun, 04 Nov 2007 21:21:50 -0800 (PST) Received: by 10.142.162.16 with HTTP; Sun, 4 Nov 2007 21:21:50 -0800 (PST) Message-ID: <4104961b0711042121s9fa9054m496f33ad581a56a8@mail.gmail.com> Date: Mon, 5 Nov 2007 13:21:50 +0800 From: "jidong xiao" To: "Jay Lan" Subject: Re: Question on kdb_event Cc: kdb@oss.sgi.com In-Reply-To: <472B6DB1.5080904@sgi.com> MIME-Version: 1.0 Content-type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit Content-Disposition: inline References: <4104961b0710310358y58bc0e1bm797fe236c8feb409@mail.gmail.com> <472B6DB1.5080904@sgi.com> X-archive-position: 1269 X-ecartis-version: Ecartis v1.0.0 Sender: kdb-bounce@oss.sgi.com Errors-to: kdb-bounce@oss.sgi.com X-original-sender: jidong.xiao@gmail.com Precedence: bulk X-list: kdb On Nov 3, 2007 2:34 AM, Jay Lan wrote: > > jidong xiao wrote: > > Hi,all > > > > Can anyone kindly explain the usage of kdb_event?Thank you very much! > > I saw this varible is used only in two places, inside kdb_printf() and > > kdb(), kdb_event is incremented and decremented. But I have no idea > > why do we need to use it in these two circumstance. > > KDB modifies in this way: > #ifdef CONFIG_KDB > #include > #define WARN_CONSOLE_UNLOCKED() WARN_ON(!is_console_locked() && > !oops_in_progress && !atomic_read(&kdb_event)) > #else /* !CONFIG_KDB */ > #define WARN_CONSOLE_UNLOCKED() WARN_ON(!is_console_locked() && > !oops_in_progress) > #endif /* CONFIG_KDB */ > > The counter of kdb_event affects the value of WARN_CONSOLE_UNLOCKED(). > > Thanks, > - jay > Well yes I saw kdb modifies WARN_CONSOLE_UNLOCKED, and I can understand the reason that kdb_event is incremented/decremented in kdb_printf(), because kdb_printf() will finally invoke vt_console_print()->hide_cursor()->clear_selection()->highlight_pointer()->complement_pos(), inside complement_pos(), WARN_CONSOLE_UNLOCKED is called. so in kdb_printf() we should increment kdb_event to avoid the warning message,or in other words, to avoid deadlock. But what I can't understand is that why we increment kdb_event at the begining of kdb()?Is it neccessary? Thanks Jason --------------------------- Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe. From kbaidarov@ru.mvista.com Mon Nov 5 08:39:08 2007 Received: with ECARTIS (v1.0.0; list kdb); Mon, 05 Nov 2007 08:39:15 -0800 (PST) Received: from buildserver.ru.mvista.com (rtsoft3.corbina.net [85.21.88.6] (may be forged)) by oss.sgi.com (8.12.11.20060308/8.12.10/SuSE Linux 0.7) with ESMTP id lA5Gd46V024890 for ; Mon, 5 Nov 2007 08:39:07 -0800 Received: from medved (unknown [10.150.0.9]) by buildserver.ru.mvista.com (Postfix) with ESMTP id AF45C8810; Mon, 5 Nov 2007 20:39:07 +0400 (SAMT) Date: Mon, 5 Nov 2007 19:39:11 +0300 From: Konstantin Baydarov To: Jay Lan Cc: kdb@oss.sgi.com, Aaron Young Subject: Re: [PATCH] Add support for USB Keyboard attached to UHCI Message-ID: <20071105193911.303cc50b@medved> In-Reply-To: <472B72B5.7020903@sgi.com> References: <20071008210936.7eba734d@localhost.localdomain> <472B72B5.7020903@sgi.com> X-Mailer: Claws Mail 2.9.1 (GTK+ 2.10.4; i386-redhat-linux-gnu) Mime-Version: 1.0 Content-type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 8bit X-archive-position: 1270 X-ecartis-version: Ecartis v1.0.0 Sender: kdb-bounce@oss.sgi.com Errors-to: kdb-bounce@oss.sgi.com X-original-sender: kbaidarov@ru.mvista.com Precedence: bulk X-list: kdb On Fri, 02 Nov 2007 11:55:49 -0700 Jay Lan 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 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 + +#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 +#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 +#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. From kbaidarov@ru.mvista.com Mon Nov 5 10:17:09 2007 Received: with ECARTIS (v1.0.0; list kdb); Mon, 05 Nov 2007 10:17:14 -0800 (PST) Received: from buildserver.ru.mvista.com (rtsoft3.corbina.net [85.21.88.6] (may be forged)) by oss.sgi.com (8.12.11.20060308/8.12.10/SuSE Linux 0.7) with ESMTP id lA5IH7XD008923 for ; Mon, 5 Nov 2007 10:17:08 -0800 Received: from medved (unknown [10.150.0.9]) by buildserver.ru.mvista.com (Postfix) with ESMTP id 8BB7F8810; Mon, 5 Nov 2007 22:17:11 +0400 (SAMT) Date: Mon, 5 Nov 2007 21:17:16 +0300 From: Konstantin Baydarov To: Aaron Young Cc: jlan@sgi.com (Jay Lan), kdb@oss.sgi.com, ayoung@cthulhu.engr.sgi.com (Aaron Young) Subject: Re: [PATCH] Add support for USB Keyboard attached to UHCI Message-ID: <20071105211716.14674612@medved> In-Reply-To: <200711051724.lA5HOHMV4005128@kluge.engr.sgi.com> References: <20071105193911.303cc50b@medved> <200711051724.lA5HOHMV4005128@kluge.engr.sgi.com> X-Mailer: Claws Mail 2.9.1 (GTK+ 2.10.4; i386-redhat-linux-gnu) Mime-Version: 1.0 Content-type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 8bit X-archive-position: 1271 X-ecartis-version: Ecartis v1.0.0 Sender: kdb-bounce@oss.sgi.com Errors-to: kdb-bounce@oss.sgi.com X-original-sender: kbaidarov@ru.mvista.com Precedence: bulk X-list: kdb On Mon, 5 Nov 2007 09:24:17 -0800 (PST) Aaron Young wrote: > If a USB keyboard (a "low" speed device) is connected directly to > a EHCI port, the "companion" controller (i.e. uhci_hcd or ohc_hcd > driver) will take control of it (and work fine in kdb). However, if > the keyboard is connected through a USB2.0 > hub, the ehci_hcd driver will take control of it. Therefore, the > problem is that kdb will call a ohci or uhci driver "poll" function > when the ehci driver is managing the keyboard. This causes kdb itself > to crash on ohci/ehci based controllers... not sure about uhci, but > it doesn't seem like it would work right. > > I am working on a fix for this problem and also to provide support > for multiple USB keyboards - since right now kdb only makes use of > a single USB keyboard. It would be better if kdb would "multiplex" > the input of all connected USB keyboards. > > So, if any of your code below makes any of the assumptions I mention > above (such as there is only one kdb USB keyboard used for input or > the keyboard is using either the ohci_hcd or uhci_hcd driver and > not ehci_hcd), it will have to be changed/incorporated to work with > my new code... > > I hope to have this new code within a couple of weeks... > > -Aaron Young > Yes my code makes assumption that there is only one Kbd and it's attached to OHCI/UHCI so definitely should be changed/incorporated. Aaron, what about UHCI part of code, can you review this? --------------------------- Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe. From kbaidarov@ru.mvista.com Wed Nov 7 06:12:11 2007 Received: with ECARTIS (v1.0.0; list kdb); Wed, 07 Nov 2007 06:12:17 -0800 (PST) Received: from mail.dev.rtsoft.ru (rtsoft2.corbina.net [85.21.88.2] (may be forged)) by oss.sgi.com (8.12.11.20060308/8.12.10/SuSE Linux 0.7) with SMTP id lA7EC8jr004107 for ; Wed, 7 Nov 2007 06:12:10 -0800 Received: (qmail 8835 invoked from network); 7 Nov 2007 14:12:12 -0000 Received: from unknown (HELO localhost.localdomain) (192.168.1.130) by mail.dev.rtsoft.ru with SMTP; 7 Nov 2007 14:12:12 -0000 Date: Wed, 7 Nov 2007 17:11:37 +0300 From: Konstantin Baydarov To: Aaron Young Cc: ayoung@cthulhu.engr.sgi.com (Aaron Young), jlan@sgi.com (Jay Lan), kdb@oss.sgi.com Subject: Re: [PATCH] Add support for USB Keyboard attached to UHCI Message-ID: <20071107171137.792d0304@localhost.localdomain> In-Reply-To: <200711051854.lA5Isg1n4205041@kluge.engr.sgi.com> References: <20071105211716.14674612@medved> <200711051854.lA5Isg1n4205041@kluge.engr.sgi.com> X-Mailer: Sylpheed-Claws 2.6.0 (GTK+ 2.8.19; i386-redhat-linux-gnu) Mime-Version: 1.0 Content-type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 8bit X-archive-position: 1272 X-ecartis-version: Ecartis v1.0.0 Sender: kdb-bounce@oss.sgi.com Errors-to: kdb-bounce@oss.sgi.com X-original-sender: kbaidarov@ru.mvista.com Precedence: bulk X-list: kdb On Mon, 5 Nov 2007 10:54:42 -0800 (PST) Aaron Young wrote: > I've only dealt with OHCI driver code before, so I'm not qualified > to review the UHCI specific code for you. As you say, it looks like a > lot of your infastructure code introduces new globals (kdb_hcd_type) > and uses kdb_usb_infos a lot - which is going away with my new > implementation. > > Would it be possible for you to wait for my new kdb/usb > infastructure code and re-implement your UHCI code against it at that > time? I could attempt to take an in depth look at it at that time > perhaps... > > Thanks, > > -Aaron Yes I'll intergrate UCHI code to the new KDB. --------------------------- Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe. From ayoung@engr.sgi.com Fri Nov 9 13:38:58 2007 Received: with ECARTIS (v1.0.0; list kdb); Fri, 09 Nov 2007 13:39:06 -0800 (PST) Received: from kluge.engr.sgi.com (kluge.engr.sgi.com [192.102.96.102]) by oss.sgi.com (8.12.11.20060308/8.12.10/SuSE Linux 0.7) with ESMTP id lA9Lcvh8002593 for ; Fri, 9 Nov 2007 13:38:58 -0800 Received: from kluge.engr.sgi.com (localhost [127.0.0.1]) by kluge.engr.sgi.com (SGI-8.12.5/8.12.5) with ESMTP id lA9LdCK95151090 for ; Fri, 9 Nov 2007 13:39:12 -0800 (PST) Received: (from ayoung@localhost) by kluge.engr.sgi.com (SGI-8.12.5/8.12.5/Submit) id lA9LdBwF5074249 for kdb@oss.sgi.com; Fri, 9 Nov 2007 13:39:11 -0800 (PST) Date: Fri, 9 Nov 2007 13:39:11 -0800 (PST) From: Aaron Young Message-Id: <200711092139.lA9LdBwF5074249@kluge.engr.sgi.com> To: kdb@oss.sgi.com Subject: [PATCH] New USB Keyboard interface for KDB X-archive-position: 1273 X-ecartis-version: Ecartis v1.0.0 Sender: kdb-bounce@oss.sgi.com Errors-to: kdb-bounce@oss.sgi.com X-original-sender: ayoung@engr.sgi.com Precedence: bulk X-list: kdb This patch implements a new KDB interface for USB keyboards which fixes the following problems: 1. Currently KDB is only "OHCI" type USB aware. If a keyboard is attached via a USB2.0 hub, the Linux kernel EHCI driver is used instead of OHCI, but kdb will still attempt to use the OHCI driver poll interface to read a character from the keyboard - this results in a crash from within kdb and, hence, kdb is unuseable. This patch allows KDB to work with any Host Contoller driver and call the correct HC driver poll routine (as long as the HC driver provides a .kdb_poll_char routine via it's associated hc_driver struct). If a HC driver is managing a keyboard, but doesn't provide a valid .kdb_poll_char routine, the keyboard will be ignored by KDB. 2. Hotplug - currently, if a USB keyboard is unplugged and plugged back in, KDB loses track and no longer recognizes the keyboard for use from KDB. This is because the "kdb_usb_infos" struct was getting zeroed and the .poll_func field set to NULL on hotunplugs (and not set to something valid on hotplugs) Hotplugged keyboards are now recognized by KDB. 3. Currently KDB can only make use of 1 USB type keyboard. This is because of the single "kdb_usb_infos" structure interface - which can only describe a single keyboard/urb. New code can handle up to 8 attached keyboards - input is multiplexed from all of them while in kdb. The number of supported USB keyboards can easily be changed via the KDB_USB_NUM_KEYBOARDS def in appropriate arch/XXX/kdb//kdba_io.c file. General notes about the new code: The new USB interface is composed of two new routines which HID drivers need to call when configuring USB keyboards: kdb_usb_keyboard_attach() - to attach a USB keyboard to KDB kdb_usb_keyboard_detach() - to detach a USB keyboard from KDB These should be called from the hotplug interfaces so that hotplugs/ unplugs keep KDB up-to-date on what keyboards are on the system. Each USB Host Controller driver which could manage keyboards needs to add a .kdb_poll_char entry to it's associated hc_driver struct and and, of course, provide the routine to poll a keyboard's URB for characters. The OHCI implementation is complete and there. UHCI is completely missing at this point and EHCI is partially there - i.e. EHCI provides the .kdb_poll_char entry, but the associated routine, ehci_kdb_poll_char() is not yet implemented (and just returns -1 for now). I plan to work on the EHCI poll code next. I hope to have a subsequent patch for this very soon. Issues: While testing I noticed some issues when using hubs to attach USB keyboards. When multiple keyboards are attached via a USB1.1 hub, only one of the keyboards is operational from kdb - not sure why. It's probably a shortcoming of the OHCI poll character code. Also, it appears hotplug of USB1.1 hubs doesn't work right in Linux and the HID hotplug interfaces are not called for the attached keyboards. Hotplug does work correctly with USB2.0 hubs however. When keyboard(s) are attached directly to USB ports (with no hubs), I could find no issues - hotplug/unplug, mulitplexing all appear to work properly. Testing: These changes have only been tested on a ia64 machine containing OHCI/EHCI style USB controllers. Additional testing on other archs and USB configs by others would be appreciated. Patch is against 2.6.23-rc8 (should be applied after kdb-4.4-2.6.23-*.1 patch set) Signed-off-by: Aaron Young (ayoung@sgi.com) --- diff -pNaru linux.orig/arch/i386/kdb/kdba_io.c linux/arch/i386/kdb/kdba_io.c --- linux.orig/arch/i386/kdb/kdba_io.c 2007-11-09 11:37:45.000000000 -0800 +++ linux/arch/i386/kdb/kdba_io.c 2007-11-08 14:26:07.710994431 -0800 @@ -29,9 +29,10 @@ #endif #ifdef CONFIG_KDB_USB -struct kdb_usb_exchange kdb_usb_infos; -EXPORT_SYMBOL(kdb_usb_infos); +/* 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]; static unsigned char kdb_usb_keycode[256] = { 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, @@ -52,77 +53,161 @@ static unsigned char kdb_usb_keycode[256 150,158,159,128,136,177,178,176,142,152,173,140 }; -/* get_usb_char - * This function drives the UHCI controller, - * fetch the USB scancode and decode it +/* + * kdb_usb_keyboard_attach() + * Attach a USB keyboard to kdb. */ -static int get_usb_char(void) +int +kdb_usb_keyboard_attach(struct urb *urb, unsigned char *buffer, void *poll_func) { - static int usb_lock; - unsigned char keycode, spec; - extern u_short plain_map[], shift_map[], ctrl_map[]; + int i; + int rc = -1; - /* Is USB initialized ? */ - if(!kdb_usb_infos.poll_func || !kdb_usb_infos.urb) - return -1; + /* + * Search through the array of KDB USB keyboards (kdb_usb_kbds) + * looking for a free index. If found, assign the keyboard to + * the array index. + */ + + for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { + if (kdb_usb_kbds[i].urb) /* index is already assigned */ + continue; + + /* found a free array index */ + kdb_usb_kbds[i].urb = urb; + kdb_usb_kbds[i].buffer = buffer; + kdb_usb_kbds[i].poll_func = poll_func; - /* Transfer char if they are present */ - (*kdb_usb_infos.poll_func)(kdb_usb_infos.uhci, (struct urb *)kdb_usb_infos.urb); + rc = 0; /* success */ - spec = kdb_usb_infos.buffer[0]; - keycode = kdb_usb_infos.buffer[2]; - kdb_usb_infos.buffer[0] = (char)0; - kdb_usb_infos.buffer[2] = (char)0; + break; + } - if(kdb_usb_infos.buffer[3]) - return -1; + return rc; +} +EXPORT_SYMBOL_GPL (kdb_usb_keyboard_attach); - /* A normal key is pressed, decode it */ - if(keycode) - keycode = kdb_usb_keycode[keycode]; - - /* 2 Keys pressed at one time ? */ - if (spec && keycode) { - switch(spec) - { - case 0x2: - case 0x20: /* Shift */ - return shift_map[keycode]; - case 0x1: - case 0x10: /* Ctrl */ - return ctrl_map[keycode]; - case 0x4: - case 0x40: /* Alt */ - break; - } - } - else { - if(keycode) { /* If only one key pressed */ - switch(keycode) - { - case 0x1C: /* Enter */ - return 13; - - case 0x3A: /* Capslock */ - usb_lock ? (usb_lock = 0) : (usb_lock = 1); - break; - case 0x0E: /* Backspace */ - return 8; - case 0x0F: /* TAB */ - return 9; - case 0x77: /* Pause */ - break ; - default: - if(!usb_lock) { - return plain_map[keycode]; - } - else { - return shift_map[keycode]; - } - } - } - } - return -1; +/* + * kdb_usb_keyboard_detach() + * Detach a USB keyboard from kdb. + */ +int +kdb_usb_keyboard_detach(struct urb *urb) +{ + int i; + int rc = -1; + + /* + * Search through the array of KDB USB keyboards (kdb_usb_kbds) + * looking for the index with the matching URB. If found, + * clear the array index. + */ + + for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { + 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; + + rc = 0; /* success */ + + break; + } + + return rc; +} +EXPORT_SYMBOL_GPL (kdb_usb_keyboard_detach); + +/* + * get_usb_char + * This function drives the USB attached keyboards. + * Fetch the USB scancode and decode it. + */ +static int +get_usb_char(void) +{ + int i; + int ret; + unsigned char keycode, spec; + extern u_short plain_map[], shift_map[], ctrl_map[]; + + /* + * Loop through all the USB keyboard(s) and return + * the first character obtained from them. + */ + + for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { + /* skip uninitialized keyboard array entries */ + if (!kdb_usb_kbds[i].urb || !kdb_usb_kbds[i].buffer || + !kdb_usb_kbds[i].poll_func) + continue; + + /* Transfer char */ + ret = (*kdb_usb_kbds[i].poll_func)(kdb_usb_kbds[i].urb); + if (ret == -1) /* error or no characters, try the next kbd */ + continue; + + 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; + } + + /* A normal key is pressed, decode it */ + if(keycode) + keycode = kdb_usb_keycode[keycode]; + + /* 2 Keys pressed at one time ? */ + if (spec && keycode) { + switch(spec) + { + case 0x2: + case 0x20: /* Shift */ + return shift_map[keycode]; + case 0x1: + case 0x10: /* Ctrl */ + return ctrl_map[keycode]; + case 0x4: + case 0x40: /* Alt */ + break; + } + } else if (keycode) { /* If only one key pressed */ + switch(keycode) + { + case 0x1C: /* Enter */ + return 13; + + case 0x3A: /* Capslock */ + kdb_usb_kbds[i].caps_lock = !(kdb_usb_kbds[i].caps_lock); + break; + case 0x0E: /* Backspace */ + return 8; + case 0x0F: /* TAB */ + return 9; + case 0x77: /* Pause */ + break ; + default: + if(!kdb_usb_kbds[i].caps_lock) { + return plain_map[keycode]; + } + else { + return shift_map[keycode]; + } + } + } + } + + /* no chars were returned from any of the USB keyboards */ + + return -1; } #endif /* CONFIG_KDB_USB */ diff -pNaru linux.orig/arch/ia64/kdb/kdba_io.c linux/arch/ia64/kdb/kdba_io.c --- linux.orig/arch/ia64/kdb/kdba_io.c 2007-11-09 11:37:47.000000000 -0800 +++ linux/arch/ia64/kdb/kdba_io.c 2007-11-08 14:31:06.500022083 -0800 @@ -39,9 +39,10 @@ #endif #ifdef CONFIG_KDB_USB -struct kdb_usb_exchange kdb_usb_infos; -EXPORT_SYMBOL(kdb_usb_infos); +/* 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]; static unsigned char kdb_usb_keycode[256] = { 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, @@ -62,39 +63,122 @@ static unsigned char kdb_usb_keycode[256 150,158,159,128,136,177,178,176,142,152,173,140 }; -/* get_usb_char - * This function drives the UHCI controller, - * fetch the USB scancode and decode it +/* + * kdb_usb_keyboard_attach() + * Attach a USB keyboard to kdb. */ -static int get_usb_char(void) +int +kdb_usb_keyboard_attach(struct urb *urb, unsigned char *buffer, void *poll_func) { - static int usb_lock; - unsigned char keycode, spec; - extern u_short plain_map[], shift_map[], ctrl_map[]; + int i; + int rc = -1; - /* Is USB initialized ? */ - if (!kdb_usb_infos.poll_func || !kdb_usb_infos.urb || !kdb_usb_infos.buffer) - return -1; + /* + * Search through the array of KDB USB keyboards (kdb_usb_kbds) + * looking for a free index. If found, assign the keyboard to + * the array index. + */ - /* 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 < KDB_USB_NUM_KEYBOARDS; i++) { + if (kdb_usb_kbds[i].urb) /* index is already assigned */ + continue; + + /* found a free array index */ + kdb_usb_kbds[i].urb = urb; + kdb_usb_kbds[i].buffer = buffer; + kdb_usb_kbds[i].poll_func = poll_func; - spec = kdb_usb_infos.buffer[0]; - keycode = kdb_usb_infos.buffer[2]; - kdb_usb_infos.buffer[0] = (char)0; - kdb_usb_infos.buffer[2] = (char)0; + rc = 0; /* success */ - if(kdb_usb_infos.buffer[3]) - return -1; + break; + } + + return rc; +} +EXPORT_SYMBOL_GPL (kdb_usb_keyboard_attach); + +/* + * kdb_usb_keyboard_detach() + * Detach a USB keyboard from kdb. + */ +int +kdb_usb_keyboard_detach(struct urb *urb) +{ + int i; + int rc = -1; + + /* + * Search through the array of KDB USB keyboards (kdb_usb_kbds) + * looking for the index with the matching URB. If found, + * clear the array index. + */ + + for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { + 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; + + rc = 0; /* success */ + + break; + } + + return rc; +} +EXPORT_SYMBOL_GPL (kdb_usb_keyboard_detach); + +/* + * get_usb_char + * This function drives the USB attached keyboards. + * Fetch the USB scancode and decode it. + */ +static int +get_usb_char(void) +{ + int i; + int ret; + unsigned char keycode, spec; + extern u_short plain_map[], shift_map[], ctrl_map[]; + + /* + * Loop through all the USB keyboard(s) and return + * the first character obtained from them. + */ - /* A normal key is pressed, decode it */ - if(keycode) - keycode = kdb_usb_keycode[keycode]; + for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { + /* skip uninitialized keyboard array entries */ + if (!kdb_usb_kbds[i].urb || !kdb_usb_kbds[i].buffer || + !kdb_usb_kbds[i].poll_func) + continue; + + /* Transfer char */ + ret = (*kdb_usb_kbds[i].poll_func)(kdb_usb_kbds[i].urb); + if (ret == -1) /* error or no characters, try the next kbd */ + continue; + + 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; + } - /* 2 Keys pressed at one time ? */ - if (spec && keycode) { - switch(spec) - { + /* A normal key is pressed, decode it */ + if(keycode) + keycode = kdb_usb_keycode[keycode]; + + /* 2 Keys pressed at one time ? */ + if (spec && keycode) { + switch(spec) + { case 0x2: case 0x20: /* Shift */ return shift_map[keycode]; @@ -104,34 +188,35 @@ static int get_usb_char(void) case 0x4: case 0x40: /* Alt */ break; - } - } - else { - if(keycode) { /* If only one key pressed */ + } + } else if (keycode) { /* If only one key pressed */ switch(keycode) { - case 0x1C: /* Enter */ - return 13; + case 0x1C: /* Enter */ + return 13; - case 0x3A: /* Capslock */ - usb_lock ? (usb_lock = 0) : (usb_lock = 1); - break; - case 0x0E: /* Backspace */ - return 8; - case 0x0F: /* TAB */ - return 9; - case 0x77: /* Pause */ - break ; - default: - if(!usb_lock) { - return plain_map[keycode]; - } - else { - return shift_map[keycode]; - } + case 0x3A: /* Capslock */ + kdb_usb_kbds[i].caps_lock = !(kdb_usb_kbds[i].caps_lock); + break; + case 0x0E: /* Backspace */ + return 8; + case 0x0F: /* TAB */ + return 9; + case 0x77: /* Pause */ + break ; + default: + if(!kdb_usb_kbds[i].caps_lock) { + return plain_map[keycode]; + } + else { + return shift_map[keycode]; + } } } } + + /* no chars were returned from any of the USB keyboards */ + return -1; } #endif /* CONFIG_KDB_USB */ diff -pNaru linux.orig/arch/x86_64/kdb/kdba_io.c linux/arch/x86_64/kdb/kdba_io.c --- linux.orig/arch/x86_64/kdb/kdba_io.c 2007-11-09 11:37:46.000000000 -0800 +++ linux/arch/x86_64/kdb/kdba_io.c 2007-11-08 14:28:31.507644333 -0800 @@ -29,9 +29,10 @@ #endif #ifdef CONFIG_KDB_USB -struct kdb_usb_exchange kdb_usb_infos; -EXPORT_SYMBOL(kdb_usb_infos); +/* 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]; static unsigned char kdb_usb_keycode[256] = { 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, @@ -52,77 +53,161 @@ static unsigned char kdb_usb_keycode[256 150,158,159,128,136,177,178,176,142,152,173,140 }; -/* get_usb_char - * This function drives the UHCI controller, - * fetch the USB scancode and decode it +/* + * kdb_usb_keyboard_attach() + * Attach a USB keyboard to kdb. */ -static int get_usb_char(void) +int +kdb_usb_keyboard_attach(struct urb *urb, unsigned char *buffer, void *poll_func) { - static int usb_lock; - unsigned char keycode, spec; - extern u_short plain_map[], shift_map[], ctrl_map[]; + int i; + int rc = -1; - /* Is USB initialized ? */ - if(!kdb_usb_infos.poll_func || !kdb_usb_infos.urb) - return -1; + /* + * Search through the array of KDB USB keyboards (kdb_usb_kbds) + * looking for a free index. If found, assign the keyboard to + * the array index. + */ + + for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { + if (kdb_usb_kbds[i].urb) /* index is already assigned */ + continue; + + /* found a free array index */ + kdb_usb_kbds[i].urb = urb; + kdb_usb_kbds[i].buffer = buffer; + kdb_usb_kbds[i].poll_func = poll_func; - /* Transfer char if they are present */ - (*kdb_usb_infos.poll_func)(kdb_usb_infos.uhci, (struct urb *)kdb_usb_infos.urb); + rc = 0; /* success */ - spec = kdb_usb_infos.buffer[0]; - keycode = kdb_usb_infos.buffer[2]; - kdb_usb_infos.buffer[0] = (char)0; - kdb_usb_infos.buffer[2] = (char)0; + break; + } - if(kdb_usb_infos.buffer[3]) - return -1; + return rc; +} +EXPORT_SYMBOL_GPL (kdb_usb_keyboard_attach); - /* A normal key is pressed, decode it */ - if(keycode) - keycode = kdb_usb_keycode[keycode]; - - /* 2 Keys pressed at one time ? */ - if (spec && keycode) { - switch(spec) - { - case 0x2: - case 0x20: /* Shift */ - return shift_map[keycode]; - case 0x1: - case 0x10: /* Ctrl */ - return ctrl_map[keycode]; - case 0x4: - case 0x40: /* Alt */ - break; - } - } - else { - if(keycode) { /* If only one key pressed */ - switch(keycode) - { - case 0x1C: /* Enter */ - return 13; - - case 0x3A: /* Capslock */ - usb_lock ? (usb_lock = 0) : (usb_lock = 1); - break; - case 0x0E: /* Backspace */ - return 8; - case 0x0F: /* TAB */ - return 9; - case 0x77: /* Pause */ - break ; - default: - if(!usb_lock) { - return plain_map[keycode]; - } - else { - return shift_map[keycode]; - } - } - } - } - return -1; +/* + * kdb_usb_keyboard_detach() + * Detach a USB keyboard from kdb. + */ +int +kdb_usb_keyboard_detach(struct urb *urb) +{ + int i; + int rc = -1; + + /* + * Search through the array of KDB USB keyboards (kdb_usb_kbds) + * looking for the index with the matching URB. If found, + * clear the array index. + */ + + for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { + 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; + + rc = 0; /* success */ + + break; + } + + return rc; +} +EXPORT_SYMBOL_GPL (kdb_usb_keyboard_detach); + +/* + * get_usb_char + * This function drives the USB attached keyboards. + * Fetch the USB scancode and decode it. + */ +static int +get_usb_char(void) +{ + int i; + int ret; + unsigned char keycode, spec; + extern u_short plain_map[], shift_map[], ctrl_map[]; + + /* + * Loop through all the USB keyboard(s) and return + * the first character obtained from them. + */ + + for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { + /* skip uninitialized keyboard array entries */ + if (!kdb_usb_kbds[i].urb || !kdb_usb_kbds[i].buffer || + !kdb_usb_kbds[i].poll_func) + continue; + + /* Transfer char */ + ret = (*kdb_usb_kbds[i].poll_func)(kdb_usb_kbds[i].urb); + if (ret == -1) /* error or no characters, try the next kbd */ + continue; + + 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; + } + + /* A normal key is pressed, decode it */ + if(keycode) + keycode = kdb_usb_keycode[keycode]; + + /* 2 Keys pressed at one time ? */ + if (spec && keycode) { + switch(spec) + { + case 0x2: + case 0x20: /* Shift */ + return shift_map[keycode]; + case 0x1: + case 0x10: /* Ctrl */ + return ctrl_map[keycode]; + case 0x4: + case 0x40: /* Alt */ + break; + } + } else if (keycode) { /* If only one key pressed */ + switch(keycode) + { + case 0x1C: /* Enter */ + return 13; + + case 0x3A: /* Capslock */ + kdb_usb_kbds[i].caps_lock = !(kdb_usb_kbds[i].caps_lock); + break; + case 0x0E: /* Backspace */ + return 8; + case 0x0F: /* TAB */ + return 9; + case 0x77: /* Pause */ + break ; + default: + if(!kdb_usb_kbds[i].caps_lock) { + return plain_map[keycode]; + } + else { + return shift_map[keycode]; + } + } + } + } + + /* no chars were returned from any of the USB keyboards */ + + return -1; } #endif /* CONFIG_KDB_USB */ diff -pNaru linux.orig/drivers/hid/usbhid/hid-core.c linux/drivers/hid/usbhid/hid-core.c --- linux.orig/drivers/hid/usbhid/hid-core.c 2007-11-09 11:37:44.000000000 -0800 +++ linux/drivers/hid/usbhid/hid-core.c 2007-11-08 14:04:41.124958377 -0800 @@ -900,9 +900,12 @@ static void hid_disconnect(struct usb_in usbhid = hid->driver_data; #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 the URB was for a Keyboard, detach it from kdb. + * If the URB was for another type of device, just + * allow kdb_usb_keyboard_detach() to silently fail. + */ + kdb_usb_keyboard_detach(usbhid->urbin); #endif spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ @@ -991,15 +994,20 @@ static int hid_probe(struct usb_interfac printk(": USB HID v%x.%02x %s [%s] on %s\n", hid->version >> 8, hid->version & 0xff, c, hid->name, path); -#ifdef CONFIG_KDB_USB - /* Initialization of the KDB structure */ +#ifdef CONFIG_KDB_USB + /* Attach USB keyboards to kdb */ if (!strcmp(c, "Keyboard")) { + int ret; struct usbhid_device *usbhid = hid->driver_data; - kdb_usb_infos.urb = usbhid->urbin; - kdb_usb_infos.buffer = usbhid->inbuf; - kdb_usb_infos.reset_timer = NULL; + 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))); + + if (ret == -1) + printk(": FAILED to register keyboard (%s) " + "with KDB\n", path); } -#endif +#endif /* CONFIG_KDB_USB */ return 0; } diff -pNaru linux.orig/drivers/hid/usbhid/usbkbd.c linux/drivers/hid/usbhid/usbkbd.c --- linux.orig/drivers/hid/usbhid/usbkbd.c 2007-11-09 11:37:44.000000000 -0800 +++ linux/drivers/hid/usbhid/usbkbd.c 2007-11-08 14:04:41.148957819 -0800 @@ -292,12 +292,15 @@ static int usb_kbd_probe(struct usb_inte kbd->new, (maxp > 8 ? 8 : maxp), usb_kbd_irq, kbd, endpoint->bInterval); -#ifdef CONFIG_KDB_USB - /* Init the KDB structure */ - kdb_usb_infos.urb = kbd->irq; - kdb_usb_infos.buffer = kbd->new; - kdb_usb_infos.reset_timer = NULL; -#endif +#ifdef CONFIG_KDB_USB + /* Attach keyboard to kdb */ + extern void * usb_hcd_get_kdb_poll_func(struct usb_device *udev); + + kdb_usb_keyboard_attach(kbd->irq, kbd->new, + usb_hcd_get_kdb_poll_func(dev)); + +#endif /* CONFIG_KDB_USB */ + kbd->irq->transfer_dma = kbd->new_dma; kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -334,12 +337,11 @@ static void usb_kbd_disconnect(struct us struct usb_kbd *kbd = usb_get_intfdata (intf); usb_set_intfdata(intf, NULL); + if (kbd) { #ifdef CONFIG_KDB_USB - /* Unlink the KDB USB struct */ - if (kbd && kbd->irq == kdb_usb_infos.urb) - memset(&kdb_usb_infos, 0, sizeof(kdb_usb_infos)); + /* Detach the keyboard from kdb */ + kdb_usb_keyboard_detach(kbd->irq); #endif /* CONFIG_KDB_USB */ - if (kbd) { usb_kill_urb(kbd->irq); input_unregister_device(kbd->dev); usb_kbd_free_mem(interface_to_usbdev(intf), kbd); diff -pNaru linux.orig/drivers/usb/core/hcd.c linux/drivers/usb/core/hcd.c --- linux.orig/drivers/usb/core/hcd.c 2007-10-09 13:31:38.000000000 -0700 +++ linux/drivers/usb/core/hcd.c 2007-11-08 14:04:42.228932671 -0800 @@ -1718,6 +1718,20 @@ usb_hcd_platform_shutdown(struct platfor } EXPORT_SYMBOL (usb_hcd_platform_shutdown); +#ifdef CONFIG_KDB_USB +void * +usb_hcd_get_kdb_poll_func(struct usb_device *udev) +{ + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + + if (hcd && hcd->driver) + return (void *)(hcd->driver->kdb_poll_char); + + return NULL; +} +EXPORT_SYMBOL_GPL (usb_hcd_get_kdb_poll_func); +#endif /* CONFIG_KDB_USB */ + /*-------------------------------------------------------------------------*/ #if defined(CONFIG_USB_MON) diff -pNaru linux.orig/drivers/usb/core/hcd.h linux/drivers/usb/core/hcd.h --- linux.orig/drivers/usb/core/hcd.h 2007-10-09 13:31:38.000000000 -0700 +++ linux/drivers/usb/core/hcd.h 2007-11-08 14:04:42.248932205 -0800 @@ -202,6 +202,10 @@ struct hc_driver { int (*start_port_reset)(struct usb_hcd *, unsigned port_num); void (*hub_irq_enable)(struct usb_hcd *); /* Needed only if port-change IRQs are level-triggered */ +#ifdef CONFIG_KDB_USB + /* KDB poll function for this HC */ + int (*kdb_poll_char)(struct urb *urb); +#endif /* CONFIG_KDB_USB */ }; extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); diff -pNaru linux.orig/drivers/usb/host/ehci-hcd.c linux/drivers/usb/host/ehci-hcd.c --- linux.orig/drivers/usb/host/ehci-hcd.c 2007-10-09 13:31:38.000000000 -0700 +++ linux/drivers/usb/host/ehci-hcd.c 2007-11-08 14:04:42.272931646 -0800 @@ -916,6 +916,17 @@ static int ehci_get_frame (struct usb_hc ehci->periodic_size; } +#ifdef CONFIG_KDB_USB + +int +ehci_kdb_poll_char(struct urb *urb) +{ + /* routine not yet implemented */ + return -1; +} + +#endif /* CONFIG_KDB_USB */ + /*-------------------------------------------------------------------------*/ #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC diff -pNaru linux.orig/drivers/usb/host/ehci-pci.c linux/drivers/usb/host/ehci-pci.c --- linux.orig/drivers/usb/host/ehci-pci.c 2007-10-09 13:31:38.000000000 -0700 +++ linux/drivers/usb/host/ehci-pci.c 2007-11-08 14:04:42.292931181 -0800 @@ -22,6 +22,10 @@ #error "This file is PCI bus glue. CONFIG_PCI must be defined." #endif +#ifdef CONFIG_KDB_USB +#include +#endif + /*-------------------------------------------------------------------------*/ /* called after powerup, by probe or system-pm "wakeup" */ @@ -367,6 +371,10 @@ static const struct hc_driver ehci_pci_h .hub_control = ehci_hub_control, .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, + +#ifdef CONFIG_KDB_USB + .kdb_poll_char = ehci_kdb_poll_char, +#endif }; /*-------------------------------------------------------------------------*/ diff -pNaru linux.orig/drivers/usb/host/ohci-hcd.c linux/drivers/usb/host/ohci-hcd.c --- linux.orig/drivers/usb/host/ohci-hcd.c 2007-11-09 11:37:44.000000000 -0800 +++ linux/drivers/usb/host/ohci-hcd.c 2007-11-08 14:04:41.244955583 -0800 @@ -851,20 +851,14 @@ static void ohci_quirk_nec_worker(struct #ifdef CONFIG_KDB_USB -static void -ohci_kdb_poll (void * __ohci, struct urb *urb) +int +ohci_kdb_poll_char(struct urb *urb) { struct ohci_hcd *ohci; struct ohci_regs * regs; - /* - * NOTE - we use the ohci_hcd from the urb rather than the - * __ohci parameter (which is NULL anyway). This ensures - * that we will process the proper controller for the urb. - */ - - if (!urb) /* can happen if no keyboard attached */ - return; + if (!urb) /* should not happen */ + return -1; ohci = (struct ohci_hcd *) hcd_to_ohci(bus_to_hcd(urb->dev->bus)); regs = ohci->regs; @@ -873,23 +867,27 @@ ohci_kdb_poll (void * __ohci, struct urb if (urb->status != -EINPROGRESS) { if (usb_submit_urb (urb, GFP_ATOMIC)) - return; + return -1; /* make sure the HC registers are set correctly */ - writel (OHCI_INTR_WDH, ®s->intrenable); - writel (OHCI_INTR_WDH, ®s->intrstatus); - writel (OHCI_INTR_MIE, ®s->intrenable); + ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable); + ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrstatus); + ohci_writel (ohci, OHCI_INTR_MIE, ®s->intrenable); // flush those pci writes - (void) readl (&ohci->regs->control); + (void) ohci_readl (ohci, &ohci->regs->control); } if (ohci->hcca->done_head) { dl_done_list_kdb (ohci, urb); - writel (OHCI_INTR_WDH, ®s->intrstatus); + ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrstatus); // flush the pci write - (void) readl (&ohci->regs->control); + (void) ohci_readl (ohci, &ohci->regs->control); + + return 0; } + + return -1; } #endif /* CONFIG_KDB_USB */ diff -pNaru linux.orig/drivers/usb/host/ohci-pci.c linux/drivers/usb/host/ohci-pci.c --- linux.orig/drivers/usb/host/ohci-pci.c 2007-11-09 11:37:44.000000000 -0800 +++ linux/drivers/usb/host/ohci-pci.c 2007-11-08 14:04:41.268955024 -0800 @@ -18,7 +18,7 @@ #error "This file is PCI bus glue. CONFIG_PCI must be defined." #endif -#ifdef CONFIG_KDB_USB +#ifdef CONFIG_KDB_USB #include #endif @@ -219,12 +219,7 @@ static int __devinit ohci_pci_start (str ohci_err (ohci, "can't start\n"); ohci_stop (hcd); } -#ifdef CONFIG_KDB_USB - if (ret >= 0) { - kdb_usb_infos.poll_func = ohci_kdb_poll; - kdb_usb_infos.uhci = NULL; /* not used */ - } -#endif + return ret; } @@ -363,6 +358,9 @@ static const struct hc_driver ohci_pci_h .bus_resume = ohci_bus_resume, #endif .start_port_reset = ohci_start_port_reset, +#ifdef CONFIG_KDB_USB + .kdb_poll_char = ohci_kdb_poll_char, +#endif }; /*-------------------------------------------------------------------------*/ diff -pNaru linux.orig/include/linux/kdb.h linux/include/linux/kdb.h --- linux.orig/include/linux/kdb.h 2007-11-09 11:37:44.000000000 -0800 +++ linux/include/linux/kdb.h 2007-11-08 14:04:41.420951485 -0800 @@ -140,16 +140,12 @@ extern void smp_kdb_stop(void); #endif /* CONFIG_SMP */ #ifdef CONFIG_KDB_USB + #include -struct kdb_usb_exchange { - void *uhci; /* pointer to the UHCI structure */ - struct urb *urb; /* pointer to the URB */ - unsigned char *buffer; /* pointer to buffer */ - void (*poll_func)(void *, struct urb *); /* pointer to the polling function */ - void (*reset_timer)(void); /* pointer to the reset timer function */ -}; -extern struct kdb_usb_exchange kdb_usb_infos; /* KDB common structure */ +extern int kdb_usb_keyboard_attach(struct urb *urb, unsigned char *buffer, void *poll_func); +extern int kdb_usb_keyboard_detach(struct urb *urb); + #endif /* CONFIG_KDB_USB */ static inline diff -pNaru linux.orig/include/linux/kdbprivate.h linux/include/linux/kdbprivate.h --- linux.orig/include/linux/kdbprivate.h 2007-11-09 11:37:44.000000000 -0800 +++ linux/include/linux/kdbprivate.h 2007-11-08 14:04:41.460950554 -0800 @@ -482,4 +482,15 @@ extern char kdb_prompt_str[]; #define KDB_WORD_SIZE ((int)sizeof(kdb_machreg_t)) +#ifdef CONFIG_KDB_USB +#include + +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 caps_lock; /* state of the caps lock for this keyboard */ +}; +#endif /* CONFIG_KDB_USB */ + #endif /* !_KDBPRIVATE_H */ --- --------------------------- Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe. From jlan@sgi.com Fri Nov 9 14:19:26 2007 Received: with ECARTIS (v1.0.0; list kdb); Fri, 09 Nov 2007 14:19:33 -0800 (PST) Received: from cthulhu.engr.sgi.com (cthulhu.engr.sgi.com [192.26.80.2]) by oss.sgi.com (8.12.11.20060308/8.12.10/SuSE Linux 0.7) with ESMTP id lA9MJPXo009852 for ; Fri, 9 Nov 2007 14:19:26 -0800 Received: from [134.15.0.106] (mtv-vpn-sw-corp-0-106.corp.sgi.com [134.15.0.106]) by cthulhu.engr.sgi.com (8.12.10/8.12.10/SuSE Linux 0.7) with ESMTP id lA9MJSke027723; Fri, 9 Nov 2007 14:19:28 -0800 Message-ID: <4734DCFF.3000106@sgi.com> Date: Fri, 09 Nov 2007 14:19:43 -0800 From: Jay Lan User-Agent: Thunderbird 1.5 (X11/20060317) MIME-Version: 1.0 To: Aaron Young CC: kdb@oss.sgi.com Subject: Re: [PATCH] New USB Keyboard interface for KDB References: <200711092139.lA9LdBwF5074249@kluge.engr.sgi.com> In-Reply-To: <200711092139.lA9LdBwF5074249@kluge.engr.sgi.com> X-Enigmail-Version: 0.94.0.0 Content-type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit X-archive-position: 1274 X-ecartis-version: Ecartis v1.0.0 Sender: kdb-bounce@oss.sgi.com Errors-to: kdb-bounce@oss.sgi.com X-original-sender: jlan@sgi.com Precedence: bulk X-list: kdb Aaron Young wrote: > This patch implements a new KDB interface for USB keyboards > which fixes the following problems: > > 1. Currently KDB is only "OHCI" type USB aware. If a keyboard is attached > via a USB2.0 hub, the Linux kernel EHCI driver is used instead of OHCI, but > kdb will still attempt to use the OHCI driver poll interface to > read a character from the keyboard - this results in a crash from > within kdb and, hence, kdb is unuseable. > > This patch allows KDB to work with any Host Contoller driver > and call the correct HC driver poll routine (as long as the > HC driver provides a .kdb_poll_char routine via it's > associated hc_driver struct). > If a HC driver is managing a keyboard, but doesn't provide a > valid .kdb_poll_char routine, the keyboard will be ignored by KDB. > > 2. Hotplug - currently, if a USB keyboard is unplugged and plugged back > in, KDB loses track and no longer recognizes the keyboard for use from KDB. > This is because the "kdb_usb_infos" struct was getting zeroed and the > .poll_func field set to NULL on hotunplugs (and not set to something > valid on hotplugs) > > Hotplugged keyboards are now recognized by KDB. > > 3. Currently KDB can only make use of 1 USB type keyboard. This is because > of the single "kdb_usb_infos" structure interface - which can only describe > a single keyboard/urb. > > New code can handle up to 8 attached keyboards - input is multiplexed > from all of them while in kdb. The number of supported USB keyboards can > easily be changed via the KDB_USB_NUM_KEYBOARDS def in appropriate > arch/XXX/kdb//kdba_io.c file. > > > General notes about the new code: > > The new USB interface is composed of two new routines which > HID drivers need to call when configuring USB keyboards: > > kdb_usb_keyboard_attach() - to attach a USB keyboard to KDB > kdb_usb_keyboard_detach() - to detach a USB keyboard from KDB > > These should be called from the hotplug interfaces so that hotplugs/ > unplugs keep KDB up-to-date on what keyboards are on the system. > > Each USB Host Controller driver which could manage keyboards needs > to add a .kdb_poll_char entry to it's associated hc_driver struct and > and, of course, provide the routine to poll a keyboard's URB for characters. > The OHCI implementation is complete and there. UHCI is completely > missing at this point and EHCI is partially there - i.e. EHCI provides > the .kdb_poll_char entry, but the associated routine, ehci_kdb_poll_char() > is not yet implemented (and just returns -1 for now). I plan to work > on the EHCI poll code next. I hope to have a subsequent patch for this > very soon. > > Issues: > > While testing I noticed some issues when using hubs to attach > USB keyboards. When multiple keyboards are attached via a USB1.1 > hub, only one of the keyboards is operational from kdb - not sure > why. It's probably a shortcoming of the OHCI poll character code. > Also, it appears hotplug of USB1.1 hubs doesn't work right in Linux > and the HID hotplug interfaces are not called for the attached keyboards. > Hotplug does work correctly with USB2.0 hubs however. > > When keyboard(s) are attached directly to USB ports (with no hubs), I > could find no issues - hotplug/unplug, mulitplexing all appear to work > properly. > > Testing: > > These changes have only been tested on a ia64 machine containing > OHCI/EHCI style USB controllers. Additional testing on other archs > and USB configs by others would be appreciated. > > > Patch is against 2.6.23-rc8 (should be applied after kdb-4.4-2.6.23-*.1 patch set) Well, actually i generated this patch for you against linux-2.6.23 and the 2.6.23 version of kdb patchset. I did basic testing on ia64, x86_64, and i386, but i did not have equipments to test new feature of USB keyboards/mice though. Thanks, - jay > > Signed-off-by: Aaron Young (ayoung@sgi.com) > > --- > > diff -pNaru linux.orig/arch/i386/kdb/kdba_io.c linux/arch/i386/kdb/kdba_io.c > --- linux.orig/arch/i386/kdb/kdba_io.c 2007-11-09 11:37:45.000000000 -0800 > +++ linux/arch/i386/kdb/kdba_io.c 2007-11-08 14:26:07.710994431 -0800 > @@ -29,9 +29,10 @@ > #endif > > #ifdef CONFIG_KDB_USB > -struct kdb_usb_exchange kdb_usb_infos; > > -EXPORT_SYMBOL(kdb_usb_infos); > +/* 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]; > > static unsigned char kdb_usb_keycode[256] = { > 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, > @@ -52,77 +53,161 @@ static unsigned char kdb_usb_keycode[256 > 150,158,159,128,136,177,178,176,142,152,173,140 > }; > > -/* get_usb_char > - * This function drives the UHCI controller, > - * fetch the USB scancode and decode it > +/* > + * kdb_usb_keyboard_attach() > + * Attach a USB keyboard to kdb. > */ > -static int get_usb_char(void) > +int > +kdb_usb_keyboard_attach(struct urb *urb, unsigned char *buffer, void *poll_func) > { > - static int usb_lock; > - unsigned char keycode, spec; > - extern u_short plain_map[], shift_map[], ctrl_map[]; > + int i; > + int rc = -1; > > - /* Is USB initialized ? */ > - if(!kdb_usb_infos.poll_func || !kdb_usb_infos.urb) > - return -1; > + /* > + * Search through the array of KDB USB keyboards (kdb_usb_kbds) > + * looking for a free index. If found, assign the keyboard to > + * the array index. > + */ > + > + for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { > + if (kdb_usb_kbds[i].urb) /* index is already assigned */ > + continue; > + > + /* found a free array index */ > + kdb_usb_kbds[i].urb = urb; > + kdb_usb_kbds[i].buffer = buffer; > + kdb_usb_kbds[i].poll_func = poll_func; > > - /* Transfer char if they are present */ > - (*kdb_usb_infos.poll_func)(kdb_usb_infos.uhci, (struct urb *)kdb_usb_infos.urb); > + rc = 0; /* success */ > > - spec = kdb_usb_infos.buffer[0]; > - keycode = kdb_usb_infos.buffer[2]; > - kdb_usb_infos.buffer[0] = (char)0; > - kdb_usb_infos.buffer[2] = (char)0; > + break; > + } > > - if(kdb_usb_infos.buffer[3]) > - return -1; > + return rc; > +} > +EXPORT_SYMBOL_GPL (kdb_usb_keyboard_attach); > > - /* A normal key is pressed, decode it */ > - if(keycode) > - keycode = kdb_usb_keycode[keycode]; > - > - /* 2 Keys pressed at one time ? */ > - if (spec && keycode) { > - switch(spec) > - { > - case 0x2: > - case 0x20: /* Shift */ > - return shift_map[keycode]; > - case 0x1: > - case 0x10: /* Ctrl */ > - return ctrl_map[keycode]; > - case 0x4: > - case 0x40: /* Alt */ > - break; > - } > - } > - else { > - if(keycode) { /* If only one key pressed */ > - switch(keycode) > - { > - case 0x1C: /* Enter */ > - return 13; > - > - case 0x3A: /* Capslock */ > - usb_lock ? (usb_lock = 0) : (usb_lock = 1); > - break; > - case 0x0E: /* Backspace */ > - return 8; > - case 0x0F: /* TAB */ > - return 9; > - case 0x77: /* Pause */ > - break ; > - default: > - if(!usb_lock) { > - return plain_map[keycode]; > - } > - else { > - return shift_map[keycode]; > - } > - } > - } > - } > - return -1; > +/* > + * kdb_usb_keyboard_detach() > + * Detach a USB keyboard from kdb. > + */ > +int > +kdb_usb_keyboard_detach(struct urb *urb) > +{ > + int i; > + int rc = -1; > + > + /* > + * Search through the array of KDB USB keyboards (kdb_usb_kbds) > + * looking for the index with the matching URB. If found, > + * clear the array index. > + */ > + > + for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { > + 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; > + > + rc = 0; /* success */ > + > + break; > + } > + > + return rc; > +} > +EXPORT_SYMBOL_GPL (kdb_usb_keyboard_detach); > + > +/* > + * get_usb_char > + * This function drives the USB attached keyboards. > + * Fetch the USB scancode and decode it. > + */ > +static int > +get_usb_char(void) > +{ > + int i; > + int ret; > + unsigned char keycode, spec; > + extern u_short plain_map[], shift_map[], ctrl_map[]; > + > + /* > + * Loop through all the USB keyboard(s) and return > + * the first character obtained from them. > + */ > + > + for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { > + /* skip uninitialized keyboard array entries */ > + if (!kdb_usb_kbds[i].urb || !kdb_usb_kbds[i].buffer || > + !kdb_usb_kbds[i].poll_func) > + continue; > + > + /* Transfer char */ > + ret = (*kdb_usb_kbds[i].poll_func)(kdb_usb_kbds[i].urb); > + if (ret == -1) /* error or no characters, try the next kbd */ > + continue; > + > + 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; > + } > + > + /* A normal key is pressed, decode it */ > + if(keycode) > + keycode = kdb_usb_keycode[keycode]; > + > + /* 2 Keys pressed at one time ? */ > + if (spec && keycode) { > + switch(spec) > + { > + case 0x2: > + case 0x20: /* Shift */ > + return shift_map[keycode]; > + case 0x1: > + case 0x10: /* Ctrl */ > + return ctrl_map[keycode]; > + case 0x4: > + case 0x40: /* Alt */ > + break; > + } > + } else if (keycode) { /* If only one key pressed */ > + switch(keycode) > + { > + case 0x1C: /* Enter */ > + return 13; > + > + case 0x3A: /* Capslock */ > + kdb_usb_kbds[i].caps_lock = !(kdb_usb_kbds[i].caps_lock); > + break; > + case 0x0E: /* Backspace */ > + return 8; > + case 0x0F: /* TAB */ > + return 9; > + case 0x77: /* Pause */ > + break ; > + default: > + if(!kdb_usb_kbds[i].caps_lock) { > + return plain_map[keycode]; > + } > + else { > + return shift_map[keycode]; > + } > + } > + } > + } > + > + /* no chars were returned from any of the USB keyboards */ > + > + return -1; > } > #endif /* CONFIG_KDB_USB */ > > diff -pNaru linux.orig/arch/ia64/kdb/kdba_io.c linux/arch/ia64/kdb/kdba_io.c > --- linux.orig/arch/ia64/kdb/kdba_io.c 2007-11-09 11:37:47.000000000 -0800 > +++ linux/arch/ia64/kdb/kdba_io.c 2007-11-08 14:31:06.500022083 -0800 > @@ -39,9 +39,10 @@ > #endif > > #ifdef CONFIG_KDB_USB > -struct kdb_usb_exchange kdb_usb_infos; > > -EXPORT_SYMBOL(kdb_usb_infos); > +/* 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]; > > static unsigned char kdb_usb_keycode[256] = { > 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, > @@ -62,39 +63,122 @@ static unsigned char kdb_usb_keycode[256 > 150,158,159,128,136,177,178,176,142,152,173,140 > }; > > -/* get_usb_char > - * This function drives the UHCI controller, > - * fetch the USB scancode and decode it > +/* > + * kdb_usb_keyboard_attach() > + * Attach a USB keyboard to kdb. > */ > -static int get_usb_char(void) > +int > +kdb_usb_keyboard_attach(struct urb *urb, unsigned char *buffer, void *poll_func) > { > - static int usb_lock; > - unsigned char keycode, spec; > - extern u_short plain_map[], shift_map[], ctrl_map[]; > + int i; > + int rc = -1; > > - /* Is USB initialized ? */ > - if (!kdb_usb_infos.poll_func || !kdb_usb_infos.urb || !kdb_usb_infos.buffer) > - return -1; > + /* > + * Search through the array of KDB USB keyboards (kdb_usb_kbds) > + * looking for a free index. If found, assign the keyboard to > + * the array index. > + */ > > - /* 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 < KDB_USB_NUM_KEYBOARDS; i++) { > + if (kdb_usb_kbds[i].urb) /* index is already assigned */ > + continue; > + > + /* found a free array index */ > + kdb_usb_kbds[i].urb = urb; > + kdb_usb_kbds[i].buffer = buffer; > + kdb_usb_kbds[i].poll_func = poll_func; > > - spec = kdb_usb_infos.buffer[0]; > - keycode = kdb_usb_infos.buffer[2]; > - kdb_usb_infos.buffer[0] = (char)0; > - kdb_usb_infos.buffer[2] = (char)0; > + rc = 0; /* success */ > > - if(kdb_usb_infos.buffer[3]) > - return -1; > + break; > + } > + > + return rc; > +} > +EXPORT_SYMBOL_GPL (kdb_usb_keyboard_attach); > + > +/* > + * kdb_usb_keyboard_detach() > + * Detach a USB keyboard from kdb. > + */ > +int > +kdb_usb_keyboard_detach(struct urb *urb) > +{ > + int i; > + int rc = -1; > + > + /* > + * Search through the array of KDB USB keyboards (kdb_usb_kbds) > + * looking for the index with the matching URB. If found, > + * clear the array index. > + */ > + > + for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { > + 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; > + > + rc = 0; /* success */ > + > + break; > + } > + > + return rc; > +} > +EXPORT_SYMBOL_GPL (kdb_usb_keyboard_detach); > + > +/* > + * get_usb_char > + * This function drives the USB attached keyboards. > + * Fetch the USB scancode and decode it. > + */ > +static int > +get_usb_char(void) > +{ > + int i; > + int ret; > + unsigned char keycode, spec; > + extern u_short plain_map[], shift_map[], ctrl_map[]; > + > + /* > + * Loop through all the USB keyboard(s) and return > + * the first character obtained from them. > + */ > > - /* A normal key is pressed, decode it */ > - if(keycode) > - keycode = kdb_usb_keycode[keycode]; > + for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { > + /* skip uninitialized keyboard array entries */ > + if (!kdb_usb_kbds[i].urb || !kdb_usb_kbds[i].buffer || > + !kdb_usb_kbds[i].poll_func) > + continue; > + > + /* Transfer char */ > + ret = (*kdb_usb_kbds[i].poll_func)(kdb_usb_kbds[i].urb); > + if (ret == -1) /* error or no characters, try the next kbd */ > + continue; > + > + 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; > + } > > - /* 2 Keys pressed at one time ? */ > - if (spec && keycode) { > - switch(spec) > - { > + /* A normal key is pressed, decode it */ > + if(keycode) > + keycode = kdb_usb_keycode[keycode]; > + > + /* 2 Keys pressed at one time ? */ > + if (spec && keycode) { > + switch(spec) > + { > case 0x2: > case 0x20: /* Shift */ > return shift_map[keycode]; > @@ -104,34 +188,35 @@ static int get_usb_char(void) > case 0x4: > case 0x40: /* Alt */ > break; > - } > - } > - else { > - if(keycode) { /* If only one key pressed */ > + } > + } else if (keycode) { /* If only one key pressed */ > switch(keycode) > { > - case 0x1C: /* Enter */ > - return 13; > + case 0x1C: /* Enter */ > + return 13; > > - case 0x3A: /* Capslock */ > - usb_lock ? (usb_lock = 0) : (usb_lock = 1); > - break; > - case 0x0E: /* Backspace */ > - return 8; > - case 0x0F: /* TAB */ > - return 9; > - case 0x77: /* Pause */ > - break ; > - default: > - if(!usb_lock) { > - return plain_map[keycode]; > - } > - else { > - return shift_map[keycode]; > - } > + case 0x3A: /* Capslock */ > + kdb_usb_kbds[i].caps_lock = !(kdb_usb_kbds[i].caps_lock); > + break; > + case 0x0E: /* Backspace */ > + return 8; > + case 0x0F: /* TAB */ > + return 9; > + case 0x77: /* Pause */ > + break ; > + default: > + if(!kdb_usb_kbds[i].caps_lock) { > + return plain_map[keycode]; > + } > + else { > + return shift_map[keycode]; > + } > } > } > } > + > + /* no chars were returned from any of the USB keyboards */ > + > return -1; > } > #endif /* CONFIG_KDB_USB */ > diff -pNaru linux.orig/arch/x86_64/kdb/kdba_io.c linux/arch/x86_64/kdb/kdba_io.c > --- linux.orig/arch/x86_64/kdb/kdba_io.c 2007-11-09 11:37:46.000000000 -0800 > +++ linux/arch/x86_64/kdb/kdba_io.c 2007-11-08 14:28:31.507644333 -0800 > @@ -29,9 +29,10 @@ > #endif > > #ifdef CONFIG_KDB_USB > -struct kdb_usb_exchange kdb_usb_infos; > > -EXPORT_SYMBOL(kdb_usb_infos); > +/* 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]; > > static unsigned char kdb_usb_keycode[256] = { > 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, > @@ -52,77 +53,161 @@ static unsigned char kdb_usb_keycode[256 > 150,158,159,128,136,177,178,176,142,152,173,140 > }; > > -/* get_usb_char > - * This function drives the UHCI controller, > - * fetch the USB scancode and decode it > +/* > + * kdb_usb_keyboard_attach() > + * Attach a USB keyboard to kdb. > */ > -static int get_usb_char(void) > +int > +kdb_usb_keyboard_attach(struct urb *urb, unsigned char *buffer, void *poll_func) > { > - static int usb_lock; > - unsigned char keycode, spec; > - extern u_short plain_map[], shift_map[], ctrl_map[]; > + int i; > + int rc = -1; > > - /* Is USB initialized ? */ > - if(!kdb_usb_infos.poll_func || !kdb_usb_infos.urb) > - return -1; > + /* > + * Search through the array of KDB USB keyboards (kdb_usb_kbds) > + * looking for a free index. If found, assign the keyboard to > + * the array index. > + */ > + > + for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { > + if (kdb_usb_kbds[i].urb) /* index is already assigned */ > + continue; > + > + /* found a free array index */ > + kdb_usb_kbds[i].urb = urb; > + kdb_usb_kbds[i].buffer = buffer; > + kdb_usb_kbds[i].poll_func = poll_func; > > - /* Transfer char if they are present */ > - (*kdb_usb_infos.poll_func)(kdb_usb_infos.uhci, (struct urb *)kdb_usb_infos.urb); > + rc = 0; /* success */ > > - spec = kdb_usb_infos.buffer[0]; > - keycode = kdb_usb_infos.buffer[2]; > - kdb_usb_infos.buffer[0] = (char)0; > - kdb_usb_infos.buffer[2] = (char)0; > + break; > + } > > - if(kdb_usb_infos.buffer[3]) > - return -1; > + return rc; > +} > +EXPORT_SYMBOL_GPL (kdb_usb_keyboard_attach); > > - /* A normal key is pressed, decode it */ > - if(keycode) > - keycode = kdb_usb_keycode[keycode]; > - > - /* 2 Keys pressed at one time ? */ > - if (spec && keycode) { > - switch(spec) > - { > - case 0x2: > - case 0x20: /* Shift */ > - return shift_map[keycode]; > - case 0x1: > - case 0x10: /* Ctrl */ > - return ctrl_map[keycode]; > - case 0x4: > - case 0x40: /* Alt */ > - break; > - } > - } > - else { > - if(keycode) { /* If only one key pressed */ > - switch(keycode) > - { > - case 0x1C: /* Enter */ > - return 13; > - > - case 0x3A: /* Capslock */ > - usb_lock ? (usb_lock = 0) : (usb_lock = 1); > - break; > - case 0x0E: /* Backspace */ > - return 8; > - case 0x0F: /* TAB */ > - return 9; > - case 0x77: /* Pause */ > - break ; > - default: > - if(!usb_lock) { > - return plain_map[keycode]; > - } > - else { > - return shift_map[keycode]; > - } > - } > - } > - } > - return -1; > +/* > + * kdb_usb_keyboard_detach() > + * Detach a USB keyboard from kdb. > + */ > +int > +kdb_usb_keyboard_detach(struct urb *urb) > +{ > + int i; > + int rc = -1; > + > + /* > + * Search through the array of KDB USB keyboards (kdb_usb_kbds) > + * looking for the index with the matching URB. If found, > + * clear the array index. > + */ > + > + for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { > + 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; > + > + rc = 0; /* success */ > + > + break; > + } > + > + return rc; > +} > +EXPORT_SYMBOL_GPL (kdb_usb_keyboard_detach); > + > +/* > + * get_usb_char > + * This function drives the USB attached keyboards. > + * Fetch the USB scancode and decode it. > + */ > +static int > +get_usb_char(void) > +{ > + int i; > + int ret; > + unsigned char keycode, spec; > + extern u_short plain_map[], shift_map[], ctrl_map[]; > + > + /* > + * Loop through all the USB keyboard(s) and return > + * the first character obtained from them. > + */ > + > + for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { > + /* skip uninitialized keyboard array entries */ > + if (!kdb_usb_kbds[i].urb || !kdb_usb_kbds[i].buffer || > + !kdb_usb_kbds[i].poll_func) > + continue; > + > + /* Transfer char */ > + ret = (*kdb_usb_kbds[i].poll_func)(kdb_usb_kbds[i].urb); > + if (ret == -1) /* error or no characters, try the next kbd */ > + continue; > + > + 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; > + } > + > + /* A normal key is pressed, decode it */ > + if(keycode) > + keycode = kdb_usb_keycode[keycode]; > + > + /* 2 Keys pressed at one time ? */ > + if (spec && keycode) { > + switch(spec) > + { > + case 0x2: > + case 0x20: /* Shift */ > + return shift_map[keycode]; > + case 0x1: > + case 0x10: /* Ctrl */ > + return ctrl_map[keycode]; > + case 0x4: > + case 0x40: /* Alt */ > + break; > + } > + } else if (keycode) { /* If only one key pressed */ > + switch(keycode) > + { > + case 0x1C: /* Enter */ > + return 13; > + > + case 0x3A: /* Capslock */ > + kdb_usb_kbds[i].caps_lock = !(kdb_usb_kbds[i].caps_lock); > + break; > + case 0x0E: /* Backspace */ > + return 8; > + case 0x0F: /* TAB */ > + return 9; > + case 0x77: /* Pause */ > + break ; > + default: > + if(!kdb_usb_kbds[i].caps_lock) { > + return plain_map[keycode]; > + } > + else { > + return shift_map[keycode]; > + } > + } > + } > + } > + > + /* no chars were returned from any of the USB keyboards */ > + > + return -1; > } > #endif /* CONFIG_KDB_USB */ > > diff -pNaru linux.orig/drivers/hid/usbhid/hid-core.c linux/drivers/hid/usbhid/hid-core.c > --- linux.orig/drivers/hid/usbhid/hid-core.c 2007-11-09 11:37:44.000000000 -0800 > +++ linux/drivers/hid/usbhid/hid-core.c 2007-11-08 14:04:41.124958377 -0800 > @@ -900,9 +900,12 @@ static void hid_disconnect(struct usb_in > usbhid = hid->driver_data; > > #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 the URB was for a Keyboard, detach it from kdb. > + * If the URB was for another type of device, just > + * allow kdb_usb_keyboard_detach() to silently fail. > + */ > + kdb_usb_keyboard_detach(usbhid->urbin); > #endif > > spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ > @@ -991,15 +994,20 @@ static int hid_probe(struct usb_interfac > printk(": USB HID v%x.%02x %s [%s] on %s\n", > hid->version >> 8, hid->version & 0xff, c, hid->name, path); > > -#ifdef CONFIG_KDB_USB > - /* Initialization of the KDB structure */ > +#ifdef CONFIG_KDB_USB > + /* Attach USB keyboards to kdb */ > if (!strcmp(c, "Keyboard")) { > + int ret; > struct usbhid_device *usbhid = hid->driver_data; > - kdb_usb_infos.urb = usbhid->urbin; > - kdb_usb_infos.buffer = usbhid->inbuf; > - kdb_usb_infos.reset_timer = NULL; > + 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))); > + > + if (ret == -1) > + printk(": FAILED to register keyboard (%s) " > + "with KDB\n", path); > } > -#endif > +#endif /* CONFIG_KDB_USB */ > > return 0; > } > diff -pNaru linux.orig/drivers/hid/usbhid/usbkbd.c linux/drivers/hid/usbhid/usbkbd.c > --- linux.orig/drivers/hid/usbhid/usbkbd.c 2007-11-09 11:37:44.000000000 -0800 > +++ linux/drivers/hid/usbhid/usbkbd.c 2007-11-08 14:04:41.148957819 -0800 > @@ -292,12 +292,15 @@ static int usb_kbd_probe(struct usb_inte > kbd->new, (maxp > 8 ? 8 : maxp), > usb_kbd_irq, kbd, endpoint->bInterval); > > -#ifdef CONFIG_KDB_USB > - /* Init the KDB structure */ > - kdb_usb_infos.urb = kbd->irq; > - kdb_usb_infos.buffer = kbd->new; > - kdb_usb_infos.reset_timer = NULL; > -#endif > +#ifdef CONFIG_KDB_USB > + /* Attach keyboard to kdb */ > + extern void * usb_hcd_get_kdb_poll_func(struct usb_device *udev); > + > + kdb_usb_keyboard_attach(kbd->irq, kbd->new, > + usb_hcd_get_kdb_poll_func(dev)); > + > +#endif /* CONFIG_KDB_USB */ > + > kbd->irq->transfer_dma = kbd->new_dma; > kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; > > @@ -334,12 +337,11 @@ static void usb_kbd_disconnect(struct us > struct usb_kbd *kbd = usb_get_intfdata (intf); > > usb_set_intfdata(intf, NULL); > + if (kbd) { > #ifdef CONFIG_KDB_USB > - /* Unlink the KDB USB struct */ > - if (kbd && kbd->irq == kdb_usb_infos.urb) > - memset(&kdb_usb_infos, 0, sizeof(kdb_usb_infos)); > + /* Detach the keyboard from kdb */ > + kdb_usb_keyboard_detach(kbd->irq); > #endif /* CONFIG_KDB_USB */ > - if (kbd) { > usb_kill_urb(kbd->irq); > input_unregister_device(kbd->dev); > usb_kbd_free_mem(interface_to_usbdev(intf), kbd); > diff -pNaru linux.orig/drivers/usb/core/hcd.c linux/drivers/usb/core/hcd.c > --- linux.orig/drivers/usb/core/hcd.c 2007-10-09 13:31:38.000000000 -0700 > +++ linux/drivers/usb/core/hcd.c 2007-11-08 14:04:42.228932671 -0800 > @@ -1718,6 +1718,20 @@ usb_hcd_platform_shutdown(struct platfor > } > EXPORT_SYMBOL (usb_hcd_platform_shutdown); > > +#ifdef CONFIG_KDB_USB > +void * > +usb_hcd_get_kdb_poll_func(struct usb_device *udev) > +{ > + struct usb_hcd *hcd = bus_to_hcd(udev->bus); > + > + if (hcd && hcd->driver) > + return (void *)(hcd->driver->kdb_poll_char); > + > + return NULL; > +} > +EXPORT_SYMBOL_GPL (usb_hcd_get_kdb_poll_func); > +#endif /* CONFIG_KDB_USB */ > + > /*-------------------------------------------------------------------------*/ > > #if defined(CONFIG_USB_MON) > diff -pNaru linux.orig/drivers/usb/core/hcd.h linux/drivers/usb/core/hcd.h > --- linux.orig/drivers/usb/core/hcd.h 2007-10-09 13:31:38.000000000 -0700 > +++ linux/drivers/usb/core/hcd.h 2007-11-08 14:04:42.248932205 -0800 > @@ -202,6 +202,10 @@ struct hc_driver { > int (*start_port_reset)(struct usb_hcd *, unsigned port_num); > void (*hub_irq_enable)(struct usb_hcd *); > /* Needed only if port-change IRQs are level-triggered */ > +#ifdef CONFIG_KDB_USB > + /* KDB poll function for this HC */ > + int (*kdb_poll_char)(struct urb *urb); > +#endif /* CONFIG_KDB_USB */ > }; > > extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); > diff -pNaru linux.orig/drivers/usb/host/ehci-hcd.c linux/drivers/usb/host/ehci-hcd.c > --- linux.orig/drivers/usb/host/ehci-hcd.c 2007-10-09 13:31:38.000000000 -0700 > +++ linux/drivers/usb/host/ehci-hcd.c 2007-11-08 14:04:42.272931646 -0800 > @@ -916,6 +916,17 @@ static int ehci_get_frame (struct usb_hc > ehci->periodic_size; > } > > +#ifdef CONFIG_KDB_USB > + > +int > +ehci_kdb_poll_char(struct urb *urb) > +{ > + /* routine not yet implemented */ > + return -1; > +} > + > +#endif /* CONFIG_KDB_USB */ > + > /*-------------------------------------------------------------------------*/ > > #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC > diff -pNaru linux.orig/drivers/usb/host/ehci-pci.c linux/drivers/usb/host/ehci-pci.c > --- linux.orig/drivers/usb/host/ehci-pci.c 2007-10-09 13:31:38.000000000 -0700 > +++ linux/drivers/usb/host/ehci-pci.c 2007-11-08 14:04:42.292931181 -0800 > @@ -22,6 +22,10 @@ > #error "This file is PCI bus glue. CONFIG_PCI must be defined." > #endif > > +#ifdef CONFIG_KDB_USB > +#include > +#endif > + > /*-------------------------------------------------------------------------*/ > > /* called after powerup, by probe or system-pm "wakeup" */ > @@ -367,6 +371,10 @@ static const struct hc_driver ehci_pci_h > .hub_control = ehci_hub_control, > .bus_suspend = ehci_bus_suspend, > .bus_resume = ehci_bus_resume, > + > +#ifdef CONFIG_KDB_USB > + .kdb_poll_char = ehci_kdb_poll_char, > +#endif > }; > > /*-------------------------------------------------------------------------*/ > diff -pNaru linux.orig/drivers/usb/host/ohci-hcd.c linux/drivers/usb/host/ohci-hcd.c > --- linux.orig/drivers/usb/host/ohci-hcd.c 2007-11-09 11:37:44.000000000 -0800 > +++ linux/drivers/usb/host/ohci-hcd.c 2007-11-08 14:04:41.244955583 -0800 > @@ -851,20 +851,14 @@ static void ohci_quirk_nec_worker(struct > > #ifdef CONFIG_KDB_USB > > -static void > -ohci_kdb_poll (void * __ohci, struct urb *urb) > +int > +ohci_kdb_poll_char(struct urb *urb) > { > struct ohci_hcd *ohci; > struct ohci_regs * regs; > > - /* > - * NOTE - we use the ohci_hcd from the urb rather than the > - * __ohci parameter (which is NULL anyway). This ensures > - * that we will process the proper controller for the urb. > - */ > - > - if (!urb) /* can happen if no keyboard attached */ > - return; > + if (!urb) /* should not happen */ > + return -1; > > ohci = (struct ohci_hcd *) hcd_to_ohci(bus_to_hcd(urb->dev->bus)); > regs = ohci->regs; > @@ -873,23 +867,27 @@ ohci_kdb_poll (void * __ohci, struct urb > if (urb->status != -EINPROGRESS) { > > if (usb_submit_urb (urb, GFP_ATOMIC)) > - return; > + return -1; > > /* make sure the HC registers are set correctly */ > - writel (OHCI_INTR_WDH, ®s->intrenable); > - writel (OHCI_INTR_WDH, ®s->intrstatus); > - writel (OHCI_INTR_MIE, ®s->intrenable); > + ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable); > + ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrstatus); > + ohci_writel (ohci, OHCI_INTR_MIE, ®s->intrenable); > > // flush those pci writes > - (void) readl (&ohci->regs->control); > + (void) ohci_readl (ohci, &ohci->regs->control); > } > > if (ohci->hcca->done_head) { > dl_done_list_kdb (ohci, urb); > - writel (OHCI_INTR_WDH, ®s->intrstatus); > + ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrstatus); > // flush the pci write > - (void) readl (&ohci->regs->control); > + (void) ohci_readl (ohci, &ohci->regs->control); > + > + return 0; > } > + > + return -1; > } > > #endif /* CONFIG_KDB_USB */ > diff -pNaru linux.orig/drivers/usb/host/ohci-pci.c linux/drivers/usb/host/ohci-pci.c > --- linux.orig/drivers/usb/host/ohci-pci.c 2007-11-09 11:37:44.000000000 -0800 > +++ linux/drivers/usb/host/ohci-pci.c 2007-11-08 14:04:41.268955024 -0800 > @@ -18,7 +18,7 @@ > #error "This file is PCI bus glue. CONFIG_PCI must be defined." > #endif > > -#ifdef CONFIG_KDB_USB > +#ifdef CONFIG_KDB_USB > #include > #endif > > @@ -219,12 +219,7 @@ static int __devinit ohci_pci_start (str > ohci_err (ohci, "can't start\n"); > ohci_stop (hcd); > } > -#ifdef CONFIG_KDB_USB > - if (ret >= 0) { > - kdb_usb_infos.poll_func = ohci_kdb_poll; > - kdb_usb_infos.uhci = NULL; /* not used */ > - } > -#endif > + > return ret; > } > > @@ -363,6 +358,9 @@ static const struct hc_driver ohci_pci_h > .bus_resume = ohci_bus_resume, > #endif > .start_port_reset = ohci_start_port_reset, > +#ifdef CONFIG_KDB_USB > + .kdb_poll_char = ohci_kdb_poll_char, > +#endif > }; > > /*-------------------------------------------------------------------------*/ > diff -pNaru linux.orig/include/linux/kdb.h linux/include/linux/kdb.h > --- linux.orig/include/linux/kdb.h 2007-11-09 11:37:44.000000000 -0800 > +++ linux/include/linux/kdb.h 2007-11-08 14:04:41.420951485 -0800 > @@ -140,16 +140,12 @@ extern void smp_kdb_stop(void); > #endif /* CONFIG_SMP */ > > #ifdef CONFIG_KDB_USB > + > #include > > -struct kdb_usb_exchange { > - void *uhci; /* pointer to the UHCI structure */ > - struct urb *urb; /* pointer to the URB */ > - unsigned char *buffer; /* pointer to buffer */ > - void (*poll_func)(void *, struct urb *); /* pointer to the polling function */ > - void (*reset_timer)(void); /* pointer to the reset timer function */ > -}; > -extern struct kdb_usb_exchange kdb_usb_infos; /* KDB common structure */ > +extern int kdb_usb_keyboard_attach(struct urb *urb, unsigned char *buffer, void *poll_func); > +extern int kdb_usb_keyboard_detach(struct urb *urb); > + > #endif /* CONFIG_KDB_USB */ > > static inline > diff -pNaru linux.orig/include/linux/kdbprivate.h linux/include/linux/kdbprivate.h > --- linux.orig/include/linux/kdbprivate.h 2007-11-09 11:37:44.000000000 -0800 > +++ linux/include/linux/kdbprivate.h 2007-11-08 14:04:41.460950554 -0800 > @@ -482,4 +482,15 @@ extern char kdb_prompt_str[]; > > #define KDB_WORD_SIZE ((int)sizeof(kdb_machreg_t)) > > +#ifdef CONFIG_KDB_USB > +#include > + > +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 caps_lock; /* state of the caps lock for this keyboard */ > +}; > +#endif /* CONFIG_KDB_USB */ > + > #endif /* !_KDBPRIVATE_H */ > > --- > --------------------------- > Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe. --------------------------- Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe. From jlan@sgi.com Mon Nov 12 10:58:53 2007 Received: with ECARTIS (v1.0.0; list kdb); Mon, 12 Nov 2007 10:58:58 -0800 (PST) Received: from kluge.engr.sgi.com (kluge.engr.sgi.com [192.102.96.102]) by oss.sgi.com (8.12.11.20060308/8.12.10/SuSE Linux 0.7) with ESMTP id lACIwqlF013183 for ; Mon, 12 Nov 2007 10:58:53 -0800 Received: from [150.166.8.78] (aware.engr.sgi.com [150.166.8.78]) by kluge.engr.sgi.com (SGI-8.12.5/8.12.5) with ESMTP id lACIbpK95898926; Mon, 12 Nov 2007 10:37:51 -0800 (PST) Message-ID: <47389DA0.1000700@sgi.com> Date: Mon, 12 Nov 2007 10:38:24 -0800 From: Jay Lan User-Agent: Thunderbird 2.0.0.6 (X11/20070801) MIME-Version: 1.0 To: KDB Subject: kdb patchset for linux-2.6.24-rc1 Content-type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit X-archive-position: 1275 X-ecartis-version: Ecartis v1.0.0 Sender: kdb-bounce@oss.sgi.com Errors-to: kdb-bounce@oss.sgi.com X-original-sender: jlan@sgi.com Precedence: bulk X-list: kdb Hi, Sorry it took so long to get KDB upgrade to 2.6.24-rc1 out. The x86 merge was a big thing to KDB. I merged kdb-v4.4-2.6.23-i386-1 and kdb-v4.4-2.6.23-x86_64-1 into kdb-v4.4-2.6.24-rc1-x86-1. During the merge, if there are same file names under i386 and x86_64, these files are now saved as _32.[ch] and _64.[ch] respectively under arch/x86/kdb or include/asm-x86. There are a few files that are specific to x86 in general, but not specific to i386 or x86_64 in particular. Those files were placed at the common directory before. I kept them at the common directory for now trying to preserve old look in this first attempt of mering. Please report any problem or strange behavior to this mailing list. Thanks, - jay --------------------------- Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe. From jidong.xiao@gmail.com Mon Nov 12 21:47:14 2007 Received: with ECARTIS (v1.0.0; list kdb); Mon, 12 Nov 2007 21:47:20 -0800 (PST) Received: from rv-out-0910.google.com (rv-out-0910.google.com [209.85.198.190]) by oss.sgi.com (8.12.11.20060308/8.12.10/SuSE Linux 0.7) with ESMTP id lAD5lB7U029184 for ; Mon, 12 Nov 2007 21:47:14 -0800 Received: by rv-out-0910.google.com with SMTP id k20so1041420rvb for ; Mon, 12 Nov 2007 21:47:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=beta; h=domainkey-signature:received:received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references; bh=Scyc0S4J1SrLmeKi0Pmu7tDwVYmxxKR8VZFusroaPuM=; b=TN/S1Gno7upOC9HLsJZW3hh8mQU+TaC8nwpGNyFfJJdilgmrYaA7gt3C9rCXFpUaYhgKhVRYfHAe9afplf0z/YybZTI54Jv7XvqgVLsCURoyyuoa0On+q82/2c4yBrrQgwko2WPjg8o6cS1pz15QXITdXxl60AL6cqEzo7u4ogw= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=beta; h=received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references; b=q7YaZFcJAXeLFAeCvkNA87AM/nKGqoGI5nBkccIxF6nRjwNPcO7GMsYkLVglETP1lpiWpoiJRksZRbaouOSogBiq7b9J7CmZ2YtoT+IW25fbHhyjnz8Qe2aecO+z8ClLPCJxAMQTTcOWMecyqjvzWzj+Zz46OCH5zr+3M/ISBLA= Received: by 10.142.77.11 with SMTP id z11mr1092802wfa.1194932837245; Mon, 12 Nov 2007 21:47:17 -0800 (PST) Received: by 10.142.14.21 with HTTP; Mon, 12 Nov 2007 21:47:17 -0800 (PST) Message-ID: <4104961b0711122147o4913845fl4db7e188c1a94347@mail.gmail.com> Date: Tue, 13 Nov 2007 13:47:17 +0800 From: "jidong xiao" To: "Jay Lan" Subject: Re: kdb patchset for linux-2.6.24-rc1 Cc: KDB In-Reply-To: <47389DA0.1000700@sgi.com> MIME-Version: 1.0 Content-type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit Content-Disposition: inline References: <47389DA0.1000700@sgi.com> X-archive-position: 1276 X-ecartis-version: Ecartis v1.0.0 Sender: kdb-bounce@oss.sgi.com Errors-to: kdb-bounce@oss.sgi.com X-original-sender: jidong.xiao@gmail.com Precedence: bulk X-list: kdb On Nov 13, 2007 2:38 AM, Jay Lan wrote: > Hi, > > Sorry it took so long to get KDB upgrade to 2.6.24-rc1 out. > The x86 merge was a big thing to KDB. I merged kdb-v4.4-2.6.23-i386-1 > and kdb-v4.4-2.6.23-x86_64-1 into kdb-v4.4-2.6.24-rc1-x86-1. > Any benefit from the merging? Regards Jason --------------------------- Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe. From jlan@sgi.com Tue Nov 13 09:41:21 2007 Received: with ECARTIS (v1.0.0; list kdb); Tue, 13 Nov 2007 09:41:26 -0800 (PST) Received: from cthulhu.engr.sgi.com (cthulhu.engr.sgi.com [192.26.80.2]) by oss.sgi.com (8.12.11.20060308/8.12.10/SuSE Linux 0.7) with ESMTP id lADHfHOv009231 for ; Tue, 13 Nov 2007 09:41:20 -0800 Received: from [134.15.0.64] (mtv-vpn-sw-corp-0-64.corp.sgi.com [134.15.0.64]) by cthulhu.engr.sgi.com (8.12.10/8.12.10/SuSE Linux 0.7) with ESMTP id lADHfKke008919; Tue, 13 Nov 2007 09:41:21 -0800 Message-ID: <4739CC40.6010908@sgi.com> Date: Tue, 13 Nov 2007 08:09:36 -0800 From: Jay Lan User-Agent: Thunderbird 1.5 (X11/20060317) MIME-Version: 1.0 To: jidong xiao CC: KDB Subject: Re: kdb patchset for linux-2.6.24-rc1 References: <47389DA0.1000700@sgi.com> <4104961b0711122147o4913845fl4db7e188c1a94347@mail.gmail.com> In-Reply-To: <4104961b0711122147o4913845fl4db7e188c1a94347@mail.gmail.com> X-Enigmail-Version: 0.94.0.0 Content-type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit X-archive-position: 1277 X-ecartis-version: Ecartis v1.0.0 Sender: kdb-bounce@oss.sgi.com Errors-to: kdb-bounce@oss.sgi.com X-original-sender: jlan@sgi.com Precedence: bulk X-list: kdb jidong xiao wrote: > On Nov 13, 2007 2:38 AM, Jay Lan wrote: >> Hi, >> >> Sorry it took so long to get KDB upgrade to 2.6.24-rc1 out. >> The x86 merge was a big thing to KDB. I merged kdb-v4.4-2.6.23-i386-1 >> and kdb-v4.4-2.6.23-x86_64-1 into kdb-v4.4-2.6.24-rc1-x86-1. >> > > Any benefit from the merging? Well, linux 2.6.24-rc1 merged arch/i386 and arch/x86_64 into arch/x86. (The arch/i386 and arch/x86_64 are completely gone in 2.6.24-rc2.) As a result, arch/{i386,x86_64}/kdb need to merge. I think it looks cleaner to release a single KDB -x86 patch to reflect the changes. Thanks, - jay > > Regards > Jason --------------------------- Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe. From ayoung@engr.sgi.com Tue Nov 13 13:42:34 2007 Received: with ECARTIS (v1.0.0; list kdb); Tue, 13 Nov 2007 13:42:57 -0800 (PST) Received: from kluge.engr.sgi.com (kluge.engr.sgi.com [192.102.96.102]) by oss.sgi.com (8.12.11.20060308/8.12.10/SuSE Linux 0.7) with ESMTP id lADLgWA4013784 for ; Tue, 13 Nov 2007 13:42:33 -0800 Received: from kluge.engr.sgi.com (localhost [127.0.0.1]) by kluge.engr.sgi.com (SGI-8.12.5/8.12.5) with ESMTP id lADLgcK95841951 for ; Tue, 13 Nov 2007 13:42:38 -0800 (PST) Received: (from ayoung@localhost) by kluge.engr.sgi.com (SGI-8.12.5/8.12.5/Submit) id lADLgcie5542388 for kdb@oss.sgi.com; Tue, 13 Nov 2007 13:42:38 -0800 (PST) Date: Tue, 13 Nov 2007 13:42:38 -0800 (PST) From: Aaron Young Message-Id: <200711132142.lADLgcie5542388@kluge.engr.sgi.com> To: kdb@oss.sgi.com Subject: [PATCH] KDB USB EHCI Support X-archive-position: 1278 X-ecartis-version: Ecartis v1.0.0 Sender: kdb-bounce@oss.sgi.com Errors-to: kdb-bounce@oss.sgi.com X-original-sender: ayoung@engr.sgi.com Precedence: bulk X-list: kdb This patch adds support to KDB for USB keyboards attached via EHCI. This happens when USB keyboards are connected via a USB2.0 hub forcing the Linux kernel EHCI driver to take control instead of the "companion" OHCI or UHCI drivers. It also adds a new boot parameter, "kdbnousb", which when set will disable KDB from configuring and using USB keyboards. This may prove useful if someone experiences a problem with KDB and USB keyboards by allowing KDB to still be used via a serial attached keyboard. Patch is against 2.6.23 (and should be applied after kdb-v4.4-2.6.23-*-2 patch set) Signed-off-by: Aaron Young (ayoung@sgi.com) Index: linux/arch/i386/kdb/kdba_io.c =================================================================== --- linux.orig/arch/i386/kdb/kdba_io.c 2007-11-13 13:52:15.000000000 -0600 +++ linux/arch/i386/kdb/kdba_io.c 2007-11-13 14:08:36.856610202 -0600 @@ -34,6 +34,8 @@ #define KDB_USB_NUM_KEYBOARDS 8 struct kdb_usb_kbd_info kdb_usb_kbds[KDB_USB_NUM_KEYBOARDS]; +extern int kdb_no_usb; + static unsigned char kdb_usb_keycode[256] = { 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, @@ -63,6 +65,9 @@ int i; int rc = -1; + if (kdb_no_usb) + return 0; + /* * Search through the array of KDB USB keyboards (kdb_usb_kbds) * looking for a free index. If found, assign the keyboard to @@ -97,6 +102,9 @@ int i; int rc = -1; + if (kdb_no_usb) + return 0; + /* * Search through the array of KDB USB keyboards (kdb_usb_kbds) * looking for the index with the matching URB. If found, @@ -134,6 +142,9 @@ int ret; unsigned char keycode, spec; extern u_short plain_map[], shift_map[], ctrl_map[]; + + if (kdb_no_usb) + return -1; /* * Loop through all the USB keyboard(s) and return Index: linux/arch/ia64/kdb/kdba_io.c =================================================================== --- linux.orig/arch/ia64/kdb/kdba_io.c 2007-11-13 13:52:16.000000000 -0600 +++ linux/arch/ia64/kdb/kdba_io.c 2007-11-13 14:09:07.484469037 -0600 @@ -44,6 +44,8 @@ #define KDB_USB_NUM_KEYBOARDS 8 struct kdb_usb_kbd_info kdb_usb_kbds[KDB_USB_NUM_KEYBOARDS]; +extern int kdb_no_usb; + static unsigned char kdb_usb_keycode[256] = { 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, @@ -73,6 +75,9 @@ int i; int rc = -1; + if (kdb_no_usb) + return 0; + /* * Search through the array of KDB USB keyboards (kdb_usb_kbds) * looking for a free index. If found, assign the keyboard to @@ -107,6 +112,9 @@ int i; int rc = -1; + if (kdb_no_usb) + return 0; + /* * Search through the array of KDB USB keyboards (kdb_usb_kbds) * looking for the index with the matching URB. If found, @@ -144,6 +152,9 @@ int ret; unsigned char keycode, spec; extern u_short plain_map[], shift_map[], ctrl_map[]; + + if (kdb_no_usb) + return -1; /* * Loop through all the USB keyboard(s) and return Index: linux/arch/x86_64/kdb/kdba_io.c =================================================================== --- linux.orig/arch/x86_64/kdb/kdba_io.c 2007-11-13 13:52:15.000000000 -0600 +++ linux/arch/x86_64/kdb/kdba_io.c 2007-11-13 14:09:43.601018582 -0600 @@ -34,6 +34,8 @@ #define KDB_USB_NUM_KEYBOARDS 8 struct kdb_usb_kbd_info kdb_usb_kbds[KDB_USB_NUM_KEYBOARDS]; +extern int kdb_no_usb; + static unsigned char kdb_usb_keycode[256] = { 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, @@ -63,6 +65,9 @@ int i; int rc = -1; + if (kdb_no_usb) + return 0; + /* * Search through the array of KDB USB keyboards (kdb_usb_kbds) * looking for a free index. If found, assign the keyboard to @@ -97,6 +102,9 @@ int i; int rc = -1; + if (kdb_no_usb) + return 0; + /* * Search through the array of KDB USB keyboards (kdb_usb_kbds) * looking for the index with the matching URB. If found, @@ -134,6 +142,9 @@ int ret; unsigned char keycode, spec; extern u_short plain_map[], shift_map[], ctrl_map[]; + + if (kdb_no_usb) + return -1; /* * Loop through all the USB keyboard(s) and return Index: linux/drivers/usb/host/ehci-hcd.c =================================================================== --- linux.orig/drivers/usb/host/ehci-hcd.c 2007-11-13 13:52:15.000000000 -0600 +++ linux/drivers/usb/host/ehci-hcd.c 2007-11-13 14:10:30.446918384 -0600 @@ -921,7 +921,24 @@ int ehci_kdb_poll_char(struct urb *urb) { - /* routine not yet implemented */ + struct ehci_hcd *ehci; + + /* just to make sure */ + if (!urb || !urb->dev || !urb->dev->bus) + return -1; + + ehci = (struct ehci_hcd *) hcd_to_ehci(bus_to_hcd(urb->dev->bus)); + + /* make sure */ + if (!ehci) + return -1; + + if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) + return -1; + + if (qh_completions_kdb(ehci, urb->hcpriv, urb)) + return 0; + return -1; } Index: linux/drivers/usb/host/ehci-q.c =================================================================== --- linux.orig/drivers/usb/host/ehci-q.c 2007-10-09 15:31:38.000000000 -0500 +++ linux/drivers/usb/host/ehci-q.c 2007-11-13 14:11:02.490953190 -0600 @@ -444,6 +444,212 @@ return count; } +#ifdef CONFIG_KDB_USB +/* + * This routine is basically a copy of qh_completions() for use by KDB. + * It is modified to only work on qtds which are associated + * with 'kdburb'. Also, there are some fixups related to locking. + */ +unsigned +qh_completions_kdb(struct ehci_hcd *ehci, struct ehci_qh *qh, struct urb *kdburb) +{ + struct ehci_qtd *last = NULL, *end = qh->dummy; + struct list_head *entry, *tmp; + int stopped; + unsigned count = 0; + int do_status = 0; + u8 state; + u32 halt = HALT_BIT(ehci); + + /* verify params are valid */ + if (!qh || !kdburb) + return 0; + + if (unlikely (list_empty (&qh->qtd_list))) + return count; + + /* completions (or tasks on other cpus) must never clobber HALT + * till we've gone through and cleaned everything up, even when + * they add urbs to this qh's queue or mark them for unlinking. + * + * NOTE: unlinking expects to be done in queue order. + */ + state = qh->qh_state; + qh->qh_state = QH_STATE_COMPLETING; + stopped = (state == QH_STATE_IDLE); + + /* remove de-activated QTDs from front of queue. + * after faults (including short reads), cleanup this urb + * then let the queue advance. + * if queue is stopped, handles unlinks. + */ + list_for_each_safe (entry, tmp, &qh->qtd_list) { + struct ehci_qtd *qtd; + struct urb *urb; + u32 token = 0; + + qtd = list_entry (entry, struct ehci_qtd, qtd_list); + urb = qtd->urb; + + if (urb != kdburb) + continue; + + /* clean up any state from previous QTD ...*/ + if (last) { + if (likely (last->urb != urb)) { + ehci_urb_done (ehci, last->urb); + /* + * ehci_urb_done() makes the assumption + * that it's called with ehci->lock held and + * releases and then reacquires the lock. + * Thus, ehci_urb_done() returns with the lock + * held. We don't want to keep the lock + * held here, so release it. Check it first, + * just in case ehci_urb_done() is ever + * changed to not grab the lock. + */ + if (spin_is_locked(&ehci->lock)) + spin_unlock (&ehci->lock); + + count++; + } + ehci_qtd_free (ehci, last); + last = NULL; + } + + /* ignore urbs submitted during completions we reported */ + if (qtd == end) + break; + + /* hardware copies qtd out of qh overlay */ + rmb (); + token = hc32_to_cpu(ehci, qtd->hw_token); + + /* always clean up qtds the hc de-activated */ + if ((token & QTD_STS_ACTIVE) == 0) { + + if ((token & QTD_STS_HALT) != 0) { + stopped = 1; + + /* magic dummy for some short reads; qh won't advance. + * that silicon quirk can kick in with this dummy too. + */ + } else if (IS_SHORT_READ (token) + && !(qtd->hw_alt_next + & EHCI_LIST_END(ehci))) { + stopped = 1; + goto halt; + } + + /* stop scanning when we reach qtds the hc is using */ + } else if (likely (!stopped + && HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) { + break