Hi,

ehci_hub_resume() reads the hub port registers during resume. However, on S3 
or swsusp the root hub loses power, making read data invalid and forcing the 
user to replug all devices. Saving the data in memory during suspend helps - 
at least for my i855gm based notebook.

There are still issues. When uhci resumes before ehci, it reconnects all 
devices. Also, I need a rather bad hack that ignores pci_set_power_state() 
return values in usb_hcd_pci_suspend(), but that is all not directly related 
to my patch.

Signed-off-by: Stefan Rompf ([EMAIL PROTECTED])

Stefan
Files linux/drivers/usb/host.old/ehci-hcd.ko and linux/drivers/usb/host/ehci-hcd.ko differ
Files linux/drivers/usb/host.old/ehci-hcd.o and linux/drivers/usb/host/ehci-hcd.o differ
diff -purN linux/drivers/usb/host.old/ehci-hub.c linux/drivers/usb/host/ehci-hub.c
--- linux/drivers/usb/host.old/ehci-hub.c	2004-10-06 20:45:12.000000000 +0200
+++ linux/drivers/usb/host/ehci-hub.c	2004-10-07 22:43:15.562972960 +0200
@@ -43,6 +43,11 @@ static int ehci_hub_suspend (struct usb_
 		return -EAGAIN;
 
 	port = HCS_N_PORTS (ehci->hcs_params);
+
+	ehci->regs_suspend = kmalloc(sizeof(u32) * port, GFP_ATOMIC);
+	if (unlikely(ehci->regs_suspend == NULL))
+		return -EIO;
+
 	spin_lock_irq (&ehci->lock);
 
 	/* suspend any active/unsuspended ports, maybe allow wakeup */
@@ -62,6 +67,8 @@ static int ehci_hub_suspend (struct usb_
 				port + 1, t1, t2);
 			writel (t2, &ehci->regs->port_status [port]);
 		}
+
+		ehci->regs_suspend[port] = t1;
 	}
 
 	/* stop schedules, then turn off HC and clean any completed work */
@@ -109,7 +116,7 @@ static int ehci_hub_resume (struct usb_h
 	/* take ports out of suspend */
 	i = HCS_N_PORTS (ehci->hcs_params);
 	while (i--) {
-		temp = readl (&ehci->regs->port_status [i]);
+		temp = ehci->regs_suspend[i];
 		temp &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E);
 		if (temp & PORT_SUSPEND) {
 			ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
@@ -129,6 +136,9 @@ static int ehci_hub_resume (struct usb_h
 	}
 	(void) readl (&ehci->regs->command);
 
+	kfree(ehci->regs_suspend);
+	ehci->regs_suspend = NULL;
+
 	/* maybe re-activate the schedule(s) */
 	temp = 0;
 	if (ehci->async->qh_next.qh)
diff -purN linux/drivers/usb/host.old/ehci.h linux/drivers/usb/host/ehci.h
--- linux/drivers/usb/host.old/ehci.h	2004-10-06 20:45:12.000000000 +0200
+++ linux/drivers/usb/host/ehci.h	2004-10-07 22:25:27.047412016 +0200
@@ -73,6 +73,9 @@ struct ehci_hcd {			/* one per controlle
 	struct ehci_caps __iomem *caps;
 	struct ehci_regs __iomem *regs;
 	u32			hcs_params;	/* cached register copy */
+#ifdef CONFIG_PM
+	u32			*regs_suspend;
+#endif
 
 	/* per-HC memory pools (could be per-bus, but ...) */
 	struct dma_pool		*qh_pool;	/* qh per active urb */

Reply via email to