diff options
Diffstat (limited to 'drivers/usb/host/ehci-hub.c')
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 98 |
1 files changed, 61 insertions, 37 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 735db4aec831..40e8240b7851 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c | |||
@@ -123,6 +123,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
123 | 123 | ||
124 | if (time_before (jiffies, ehci->next_statechange)) | 124 | if (time_before (jiffies, ehci->next_statechange)) |
125 | msleep(5); | 125 | msleep(5); |
126 | del_timer_sync(&ehci->watchdog); | ||
127 | del_timer_sync(&ehci->iaa_watchdog); | ||
126 | 128 | ||
127 | port = HCS_N_PORTS (ehci->hcs_params); | 129 | port = HCS_N_PORTS (ehci->hcs_params); |
128 | spin_lock_irq (&ehci->lock); | 130 | spin_lock_irq (&ehci->lock); |
@@ -134,7 +136,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
134 | } | 136 | } |
135 | ehci->command = ehci_readl(ehci, &ehci->regs->command); | 137 | ehci->command = ehci_readl(ehci, &ehci->regs->command); |
136 | if (ehci->reclaim) | 138 | if (ehci->reclaim) |
137 | ehci->reclaim_ready = 1; | 139 | end_unlink_async(ehci); |
138 | ehci_work(ehci); | 140 | ehci_work(ehci); |
139 | 141 | ||
140 | /* Unlike other USB host controller types, EHCI doesn't have | 142 | /* Unlike other USB host controller types, EHCI doesn't have |
@@ -170,8 +172,11 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
170 | } | 172 | } |
171 | } | 173 | } |
172 | 174 | ||
175 | /* Apparently some devices need a >= 1-uframe delay here */ | ||
176 | if (ehci->bus_suspended) | ||
177 | udelay(150); | ||
178 | |||
173 | /* turn off now-idle HC */ | 179 | /* turn off now-idle HC */ |
174 | del_timer_sync (&ehci->watchdog); | ||
175 | ehci_halt (ehci); | 180 | ehci_halt (ehci); |
176 | hcd->state = HC_STATE_SUSPENDED; | 181 | hcd->state = HC_STATE_SUSPENDED; |
177 | 182 | ||
@@ -291,14 +296,16 @@ static int ehci_bus_resume (struct usb_hcd *hcd) | |||
291 | /*-------------------------------------------------------------------------*/ | 296 | /*-------------------------------------------------------------------------*/ |
292 | 297 | ||
293 | /* Display the ports dedicated to the companion controller */ | 298 | /* Display the ports dedicated to the companion controller */ |
294 | static ssize_t show_companion(struct class_device *class_dev, char *buf) | 299 | static ssize_t show_companion(struct device *dev, |
300 | struct device_attribute *attr, | ||
301 | char *buf) | ||
295 | { | 302 | { |
296 | struct ehci_hcd *ehci; | 303 | struct ehci_hcd *ehci; |
297 | int nports, index, n; | 304 | int nports, index, n; |
298 | int count = PAGE_SIZE; | 305 | int count = PAGE_SIZE; |
299 | char *ptr = buf; | 306 | char *ptr = buf; |
300 | 307 | ||
301 | ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev))); | 308 | ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); |
302 | nports = HCS_N_PORTS(ehci->hcs_params); | 309 | nports = HCS_N_PORTS(ehci->hcs_params); |
303 | 310 | ||
304 | for (index = 0; index < nports; ++index) { | 311 | for (index = 0; index < nports; ++index) { |
@@ -312,40 +319,21 @@ static ssize_t show_companion(struct class_device *class_dev, char *buf) | |||
312 | } | 319 | } |
313 | 320 | ||
314 | /* | 321 | /* |
315 | * Dedicate or undedicate a port to the companion controller. | 322 | * Sets the owner of a port |
316 | * Syntax is "[-]portnum", where a leading '-' sign means | ||
317 | * return control of the port to the EHCI controller. | ||
318 | */ | 323 | */ |
319 | static ssize_t store_companion(struct class_device *class_dev, | 324 | static void set_owner(struct ehci_hcd *ehci, int portnum, int new_owner) |
320 | const char *buf, size_t count) | ||
321 | { | 325 | { |
322 | struct ehci_hcd *ehci; | ||
323 | int portnum, new_owner, try; | ||
324 | u32 __iomem *status_reg; | 326 | u32 __iomem *status_reg; |
325 | u32 port_status; | 327 | u32 port_status; |
328 | int try; | ||
326 | 329 | ||
327 | ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev))); | 330 | status_reg = &ehci->regs->port_status[portnum]; |
328 | new_owner = PORT_OWNER; /* Owned by companion */ | ||
329 | if (sscanf(buf, "%d", &portnum) != 1) | ||
330 | return -EINVAL; | ||
331 | if (portnum < 0) { | ||
332 | portnum = - portnum; | ||
333 | new_owner = 0; /* Owned by EHCI */ | ||
334 | } | ||
335 | if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params)) | ||
336 | return -ENOENT; | ||
337 | status_reg = &ehci->regs->port_status[--portnum]; | ||
338 | if (new_owner) | ||
339 | set_bit(portnum, &ehci->companion_ports); | ||
340 | else | ||
341 | clear_bit(portnum, &ehci->companion_ports); | ||
342 | 331 | ||
343 | /* | 332 | /* |
344 | * The controller won't set the OWNER bit if the port is | 333 | * The controller won't set the OWNER bit if the port is |
345 | * enabled, so this loop will sometimes require at least two | 334 | * enabled, so this loop will sometimes require at least two |
346 | * iterations: one to disable the port and one to set OWNER. | 335 | * iterations: one to disable the port and one to set OWNER. |
347 | */ | 336 | */ |
348 | |||
349 | for (try = 4; try > 0; --try) { | 337 | for (try = 4; try > 0; --try) { |
350 | spin_lock_irq(&ehci->lock); | 338 | spin_lock_irq(&ehci->lock); |
351 | port_status = ehci_readl(ehci, status_reg); | 339 | port_status = ehci_readl(ehci, status_reg); |
@@ -362,9 +350,39 @@ static ssize_t store_companion(struct class_device *class_dev, | |||
362 | if (try > 1) | 350 | if (try > 1) |
363 | msleep(5); | 351 | msleep(5); |
364 | } | 352 | } |
353 | } | ||
354 | |||
355 | /* | ||
356 | * Dedicate or undedicate a port to the companion controller. | ||
357 | * Syntax is "[-]portnum", where a leading '-' sign means | ||
358 | * return control of the port to the EHCI controller. | ||
359 | */ | ||
360 | static ssize_t store_companion(struct device *dev, | ||
361 | struct device_attribute *attr, | ||
362 | const char *buf, size_t count) | ||
363 | { | ||
364 | struct ehci_hcd *ehci; | ||
365 | int portnum, new_owner; | ||
366 | |||
367 | ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); | ||
368 | new_owner = PORT_OWNER; /* Owned by companion */ | ||
369 | if (sscanf(buf, "%d", &portnum) != 1) | ||
370 | return -EINVAL; | ||
371 | if (portnum < 0) { | ||
372 | portnum = - portnum; | ||
373 | new_owner = 0; /* Owned by EHCI */ | ||
374 | } | ||
375 | if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params)) | ||
376 | return -ENOENT; | ||
377 | portnum--; | ||
378 | if (new_owner) | ||
379 | set_bit(portnum, &ehci->companion_ports); | ||
380 | else | ||
381 | clear_bit(portnum, &ehci->companion_ports); | ||
382 | set_owner(ehci, portnum, new_owner); | ||
365 | return count; | 383 | return count; |
366 | } | 384 | } |
367 | static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion); | 385 | static DEVICE_ATTR(companion, 0644, show_companion, store_companion); |
368 | 386 | ||
369 | static inline void create_companion_file(struct ehci_hcd *ehci) | 387 | static inline void create_companion_file(struct ehci_hcd *ehci) |
370 | { | 388 | { |
@@ -372,16 +390,16 @@ static inline void create_companion_file(struct ehci_hcd *ehci) | |||
372 | 390 | ||
373 | /* with integrated TT there is no companion! */ | 391 | /* with integrated TT there is no companion! */ |
374 | if (!ehci_is_TDI(ehci)) | 392 | if (!ehci_is_TDI(ehci)) |
375 | i = class_device_create_file(ehci_to_hcd(ehci)->self.class_dev, | 393 | i = device_create_file(ehci_to_hcd(ehci)->self.dev, |
376 | &class_device_attr_companion); | 394 | &dev_attr_companion); |
377 | } | 395 | } |
378 | 396 | ||
379 | static inline void remove_companion_file(struct ehci_hcd *ehci) | 397 | static inline void remove_companion_file(struct ehci_hcd *ehci) |
380 | { | 398 | { |
381 | /* with integrated TT there is no companion! */ | 399 | /* with integrated TT there is no companion! */ |
382 | if (!ehci_is_TDI(ehci)) | 400 | if (!ehci_is_TDI(ehci)) |
383 | class_device_remove_file(ehci_to_hcd(ehci)->self.class_dev, | 401 | device_remove_file(ehci_to_hcd(ehci)->self.dev, |
384 | &class_device_attr_companion); | 402 | &dev_attr_companion); |
385 | } | 403 | } |
386 | 404 | ||
387 | 405 | ||
@@ -393,10 +411,8 @@ static int check_reset_complete ( | |||
393 | u32 __iomem *status_reg, | 411 | u32 __iomem *status_reg, |
394 | int port_status | 412 | int port_status |
395 | ) { | 413 | ) { |
396 | if (!(port_status & PORT_CONNECT)) { | 414 | if (!(port_status & PORT_CONNECT)) |
397 | ehci->reset_done [index] = 0; | ||
398 | return port_status; | 415 | return port_status; |
399 | } | ||
400 | 416 | ||
401 | /* if reset finished and it's still not enabled -- handoff */ | 417 | /* if reset finished and it's still not enabled -- handoff */ |
402 | if (!(port_status & PORT_PE)) { | 418 | if (!(port_status & PORT_PE)) { |
@@ -475,8 +491,6 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
475 | * controller by the user. | 491 | * controller by the user. |
476 | */ | 492 | */ |
477 | 493 | ||
478 | if (!(temp & PORT_CONNECT)) | ||
479 | ehci->reset_done [i] = 0; | ||
480 | if ((temp & mask) != 0 | 494 | if ((temp & mask) != 0 |
481 | || ((temp & PORT_RESUME) != 0 | 495 | || ((temp & PORT_RESUME) != 0 |
482 | && time_after_eq(jiffies, | 496 | && time_after_eq(jiffies, |
@@ -864,3 +878,13 @@ error: | |||
864 | spin_unlock_irqrestore (&ehci->lock, flags); | 878 | spin_unlock_irqrestore (&ehci->lock, flags); |
865 | return retval; | 879 | return retval; |
866 | } | 880 | } |
881 | |||
882 | static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum) | ||
883 | { | ||
884 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | ||
885 | |||
886 | if (ehci_is_TDI(ehci)) | ||
887 | return; | ||
888 | set_owner(ehci, --portnum, PORT_OWNER); | ||
889 | } | ||
890 | |||