On Wednesday 08 September 2004 11:14 am, Greg KH wrote:
> 
> Care to re-diff it?  I can guess at what should be done...

Here you go!   The last chunk moved into Alan's new logical_disconnect()
routine.  I also added a FIXME there, capturing some of that discussion
about port power down ... it'd make PM_SUSPEND_DISK happier too.

- Dave
 
Fix the hub 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, and I expect the "boot from USB disk" folk will like this too.

The fix includes cleanup: centralizing the logic to make khubd look
at a given hub, instead of cloning it three times (or in the case of
hub probing, frankensteining it).

This also adds a FIXME to the new routine centralizing disconnect
processing:  we also want "power down port but don't wake khubd"
(for PM_SUSPEND_DISK as well as SRP).

Signed-off-by: David Brownell <[EMAIL PROTECTED]>


--- 1.132/drivers/usb/core/hub.c	Wed Sep  8 09:41:15 2004
+++ edited/drivers/usb/core/hub.c	Thu Sep  9 09:44:08 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) {
@@ -1407,15 +1419,18 @@
 	dev_dbg(hubdev(hdev), "logical disconnect on port %d\n", port + 1);
 	hub_port_disable(hdev, port);
 
+	/* FIXME let caller ask to power down the port:
+	 *  - some devices won't enumerate without a VBUS power cycle
+	 *  - SRP saves power that way
+	 *  - usb_suspend_device(dev,PM_SUSPEND_DISK)
+	 * That's easy if this hub can switch power per-port, and
+	 * khubd reactivates the port later (timer, SRP, etc).
+	 * Powerdown must be optional, because of reset/DFU.
+	 */
+
 	hub = usb_get_intfdata(hdev->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);
 }
 
 

Reply via email to