ChangeSet 1.1608.84.7, 2004/03/08 15:07:52-08:00, stern@rowland.harvard.edu [PATCH] USB UHCI: restore more state following PM resume Some systems don't save the internal state of the UHCI registers across a PM suspend/resume cycle very well. This patch saves & restores the Frame Number and the Framelist Base Address registers (in addition to the Interrupt Enable register, which was added separately in a recent patch.) drivers/usb/host/uhci-hcd.c | 14 ++++++++++---- drivers/usb/host/uhci-hcd.h | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c --- a/drivers/usb/host/uhci-hcd.c Tue Mar 16 15:03:34 2004 +++ b/drivers/usb/host/uhci-hcd.c Tue Mar 16 15:03:34 2004 @@ -2444,9 +2444,11 @@ struct uhci_hcd *uhci = hcd_to_uhci(hcd); /* Don't try to suspend broken motherboards, reset instead */ - if (suspend_allowed(uhci)) + if (suspend_allowed(uhci)) { suspend_hc(uhci); - else + uhci->saved_framenumber = + inw(uhci->io_addr + USBFRNUM) & 0x3ff; + } else reset_hc(uhci); return 0; } @@ -2460,9 +2462,13 @@ if (uhci->state == UHCI_SUSPENDED) { /* - * Some systems clear the Interrupt Enable register during - * PM suspend/resume, so reinitialize it. + * Some systems don't maintain the UHCI register values + * during a PM suspend/resume cycle, so reinitialize + * the Frame Number, the Framelist Base Address, and the + * Interrupt Enable registers. */ + outw(uhci->saved_framenumber, uhci->io_addr + USBFRNUM); + outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD); outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, uhci->io_addr + USBINTR); uhci->resume_detect = 1; diff -Nru a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h --- a/drivers/usb/host/uhci-hcd.h Tue Mar 16 15:03:34 2004 +++ b/drivers/usb/host/uhci-hcd.h Tue Mar 16 15:03:34 2004 @@ -350,6 +350,7 @@ enum uhci_state state; /* FIXME: needs a spinlock */ unsigned long state_end; /* Time of next transition */ int resume_detect; /* Need a Global Resume */ + unsigned int saved_framenumber; /* Save during PM suspend */ /* Main list of URB's currently controlled by this HC */ spinlock_t urb_list_lock;