I happened across a problem that came up with modified OHCI
root hub code ... looks like hub probing has misbehaved for a
long time, this might affect other configs too.
Does this patch look good to you? If so, please merge.
- Dave
Fix the khubd probe logic so that when khubd wakes up, it will
actually look at all ports on the new hub. This resolved a root
hub enumeration issue.
The fix uses a new routine centralizing the logic to make khubd
look at a given hub ... two working copies, one (previously) not.
Signed-off-by: David Brownell <[EMAIL PROTECTED]>
--- 1.141/drivers/usb/core/hub.c Thu Aug 26 09:05:20 2004
+++ edited/drivers/usb/core/hub.c Tue Aug 31 19:49:43 2004
@@ -39,12 +39,13 @@
/* Protect struct usb_device state and children members */
static spinlock_t device_state_lock = SPIN_LOCK_UNLOCKED;
-/* Wakes up khubd */
+/* khubd's worklist and its lock */
static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
-
static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */
+/* Wakes up khubd */
static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
+
static pid_t khubd_pid = 0; /* PID of khubd */
static DECLARE_COMPLETION(khubd_exited);
@@ -226,6 +227,19 @@
data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT);
}
+static void kick_khubd(struct usb_hub *hub)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&hub_event_lock, flags);
+ if (list_empty(&hub->event_list)) {
+ list_add_tail(&hub->event_list, &hub_event_list);
+ wake_up(&khubd_wait);
+ }
+ spin_unlock_irqrestore(&hub_event_lock, flags);
+}
+
+
/* completion function, fires on port status changes and various faults */
static void hub_irq(struct urb *urb, struct pt_regs *regs)
{
@@ -261,12 +275,7 @@
hub->nerrors = 0;
/* Something happened, let khubd figure it out */
- spin_lock(&hub_event_lock);
- if (list_empty(&hub->event_list)) {
- list_add_tail(&hub->event_list, &hub_event_list);
- wake_up(&khubd_wait);
- }
- spin_unlock(&hub_event_lock);
+ kick_khubd(hub);
resubmit:
if (hub->quiescing)
@@ -579,6 +588,9 @@
dev_dbg(hub_dev, "%sover-current condition exists\n",
(hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
+ /* scan all ports ASAP on new hubs */
+ hub->change_bits[0] = ~0;
+
/* Start the interrupt endpoint */
pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));
@@ -604,7 +616,7 @@
}
/* Wake up khubd */
- wake_up(&khubd_wait);
+ kick_khubd(hub);
/* maybe start cycling the hub leds */
if (hub->has_indicators && blinkenlights) {
@@ -2813,13 +2825,7 @@
hub = usb_get_intfdata(parent->actconfig->interface[0]);
set_bit(port, hub->change_bits);
-
- spin_lock_irq(&hub_event_lock);
- if (list_empty(&hub->event_list)) {
- list_add_tail(&hub->event_list, &hub_event_list);
- wake_up(&khubd_wait);
- }
- spin_unlock_irq(&hub_event_lock);
+ kick_khubd(hub);
return -ENODEV;
}