aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/uhci-hub.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/uhci-hub.c')
-rw-r--r--drivers/usb/host/uhci-hub.c83
1 files changed, 79 insertions, 4 deletions
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
index 4c45ba8390f8..4eace2b19ddb 100644
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -33,9 +33,24 @@ static __u8 root_hub_hub_des[] =
33/* status change bits: nonzero writes will clear */ 33/* status change bits: nonzero writes will clear */
34#define RWC_BITS (USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC) 34#define RWC_BITS (USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC)
35 35
36static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) 36/* A port that either is connected or has a changed-bit set will prevent
37 * us from AUTO_STOPPING.
38 */
39static int any_ports_active(struct uhci_hcd *uhci)
40{
41 int port;
42
43 for (port = 0; port < uhci->rh_numports; ++port) {
44 if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) &
45 (USBPORTSC_CCS | RWC_BITS)) ||
46 test_bit(port, &uhci->port_c_suspend))
47 return 1;
48 }
49 return 0;
50}
51
52static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf)
37{ 53{
38 struct uhci_hcd *uhci = hcd_to_uhci(hcd);
39 int port; 54 int port;
40 55
41 *buf = 0; 56 *buf = 0;
@@ -44,8 +59,6 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
44 test_bit(port, &uhci->port_c_suspend)) 59 test_bit(port, &uhci->port_c_suspend))
45 *buf |= (1 << (port + 1)); 60 *buf |= (1 << (port + 1));
46 } 61 }
47 if (*buf && uhci->state == UHCI_SUSPENDED)
48 uhci->resume_detect = 1;
49 return !!*buf; 62 return !!*buf;
50} 63}
51 64
@@ -115,6 +128,11 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
115 set_bit(port, &uhci->resuming_ports); 128 set_bit(port, &uhci->resuming_ports);
116 uhci->ports_timeout = jiffies + 129 uhci->ports_timeout = jiffies +
117 msecs_to_jiffies(20); 130 msecs_to_jiffies(20);
131
132 /* Make sure we see the port again
133 * after the resuming period is over. */
134 mod_timer(&uhci_to_hcd(uhci)->rh_timer,
135 uhci->ports_timeout);
118 } else if (time_after_eq(jiffies, 136 } else if (time_after_eq(jiffies,
119 uhci->ports_timeout)) { 137 uhci->ports_timeout)) {
120 uhci_finish_suspend(uhci, port, port_addr); 138 uhci_finish_suspend(uhci, port, port_addr);
@@ -123,6 +141,60 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
123 } 141 }
124} 142}
125 143
144static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
145{
146 struct uhci_hcd *uhci = hcd_to_uhci(hcd);
147 unsigned long flags;
148 int status;
149
150 spin_lock_irqsave(&uhci->lock, flags);
151 if (uhci->hc_inaccessible) {
152 status = 0;
153 goto done;
154 }
155
156 uhci_check_ports(uhci);
157 status = get_hub_status_data(uhci, buf);
158
159 switch (uhci->rh_state) {
160 case UHCI_RH_SUSPENDING:
161 case UHCI_RH_SUSPENDED:
162 /* if port change, ask to be resumed */
163 if (status)
164 usb_hcd_resume_root_hub(hcd);
165 break;
166
167 case UHCI_RH_AUTO_STOPPED:
168 /* if port change, auto start */
169 if (status)
170 wakeup_rh(uhci);
171 break;
172
173 case UHCI_RH_RUNNING:
174 /* are any devices attached? */
175 if (!any_ports_active(uhci)) {
176 uhci->rh_state = UHCI_RH_RUNNING_NODEVS;
177 uhci->auto_stop_time = jiffies + HZ;
178 }
179 break;
180
181 case UHCI_RH_RUNNING_NODEVS:
182 /* auto-stop if nothing connected for 1 second */
183 if (any_ports_active(uhci))
184 uhci->rh_state = UHCI_RH_RUNNING;
185 else if (time_after_eq(jiffies, uhci->auto_stop_time))
186 suspend_rh(uhci, UHCI_RH_AUTO_STOPPED);
187 break;
188
189 default:
190 break;
191 }
192
193done:
194 spin_unlock_irqrestore(&uhci->lock, flags);
195 return status;
196}
197
126/* size of returned buffer is part of USB spec */ 198/* size of returned buffer is part of USB spec */
127static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, 199static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
128 u16 wIndex, char *buf, u16 wLength) 200 u16 wIndex, char *buf, u16 wLength)
@@ -134,6 +206,9 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
134 u16 wPortChange, wPortStatus; 206 u16 wPortChange, wPortStatus;
135 unsigned long flags; 207 unsigned long flags;
136 208
209 if (uhci->hc_inaccessible)
210 return -ETIMEDOUT;
211
137 spin_lock_irqsave(&uhci->lock, flags); 212 spin_lock_irqsave(&uhci->lock, flags);
138 switch (typeReq) { 213 switch (typeReq) {
139 214