linux-2.5.40 and .41 got a kernel invalid page request
when using a USB keyboard. linux-2.5.34 worked fine.
The bug is an incompatibility between uhci_alloc_urb_priv and
uhci_destroy_urb_priv, at least as they are used by uhci_urb_enqueue.
uhci_alloc_urb_priv adds the urb_priv to uhci->urb_list, but
uhci_destroy_urb_priv does not remove it. However, uhci_urb_enqueue
ASSUMES that uhci_destroy_urb_priv will completeley undo the
uhci_alloc_urb_priv.
In particular, this occurs uhci_urb_enqeueue when is called on
a control pipe and uhci_find_urb_ep() returns non-NULL. This occurs
when I plug in a USB keyboard or boot with a USB keyboard plugged in,
presumably from some of the activity generated by the "hotplug"
scripts.
The following patch changes uhci_destroy_urb_priv to
remove the urb_priv from whatever list it is on if it has been
added. It works for me, although I am not sure do not think
this patch is completly optimal:
1. If it really is OK for uhci_destroy_urb_priv to be called
when urbp->urb_list is linked into a list, then the warning
message should be deleted.
2. If queuing of control and interrupt requests is not going
to be implemented, the check for eurb != NULL can be
made earlier and uhci_urb_enqueue can just abort before
uhci_alloc_urb_priv is ever called.
In the meantime, however, this patch fixes a real bug, so
I would encourage you to integrate and forward it until there is a
better fix.
--
Adam J. Richter __ ______________ 575 Oroville Road
[EMAIL PROTECTED] \ / Milpitas, California 95035
+1 408 309-6081 | g g d r a s i l United States of America
"Free Software For The Rest Of Us."
--- linux-2.5.41/drivers/usb/host/uhci-hcd.c 2002-10-07 11:24:51.000000000 -0700
+++ linux/drivers/usb/host/uhci-hcd.c 2002-10-09 07:16:43.000000000 -0700
@@ -691,20 +691,22 @@
static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
{
struct list_head *head, *tmp;
struct urb_priv *urbp;
urbp = (struct urb_priv *)urb->hcpriv;
if (!urbp)
return;
- if (!list_empty(&urbp->urb_list))
+ if (!list_empty(&urbp->urb_list)) {
warn("uhci_destroy_urb_priv: urb %p still on uhci->urb_list or
uhci->remove_list", urb);
+ list_del(&urbp->urb_list);
+ }
if (!list_empty(&urbp->complete_list))
warn("uhci_destroy_urb_priv: urb %p still on uhci->complete_list",
urb);
head = &urbp->td_list;
tmp = head->next;
while (tmp != head) {
struct uhci_td *td = list_entry(tmp, struct uhci_td, list);