aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-hub.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ehci-hub.c')
-rw-r--r--drivers/usb/host/ehci-hub.c68
1 files changed, 44 insertions, 24 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 1ad7a6572826..a165e0a0961c 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -314,41 +314,21 @@ static ssize_t show_companion(struct device *dev,
314} 314}
315 315
316/* 316/*
317 * Dedicate or undedicate a port to the companion controller. 317 * Sets the owner of a port
318 * Syntax is "[-]portnum", where a leading '-' sign means
319 * return control of the port to the EHCI controller.
320 */ 318 */
321static ssize_t store_companion(struct device *dev, 319static void set_owner(struct ehci_hcd *ehci, int portnum, int new_owner)
322 struct device_attribute *attr,
323 const char *buf, size_t count)
324{ 320{
325 struct ehci_hcd *ehci;
326 int portnum, new_owner, try;
327 u32 __iomem *status_reg; 321 u32 __iomem *status_reg;
328 u32 port_status; 322 u32 port_status;
323 int try;
329 324
330 ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); 325 status_reg = &ehci->regs->port_status[portnum];
331 new_owner = PORT_OWNER; /* Owned by companion */
332 if (sscanf(buf, "%d", &portnum) != 1)
333 return -EINVAL;
334 if (portnum < 0) {
335 portnum = - portnum;
336 new_owner = 0; /* Owned by EHCI */
337 }
338 if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
339 return -ENOENT;
340 status_reg = &ehci->regs->port_status[--portnum];
341 if (new_owner)
342 set_bit(portnum, &ehci->companion_ports);
343 else
344 clear_bit(portnum, &ehci->companion_ports);
345 326
346 /* 327 /*
347 * The controller won't set the OWNER bit if the port is 328 * The controller won't set the OWNER bit if the port is
348 * enabled, so this loop will sometimes require at least two 329 * enabled, so this loop will sometimes require at least two
349 * iterations: one to disable the port and one to set OWNER. 330 * iterations: one to disable the port and one to set OWNER.
350 */ 331 */
351
352 for (try = 4; try > 0; --try) { 332 for (try = 4; try > 0; --try) {
353 spin_lock_irq(&ehci->lock); 333 spin_lock_irq(&ehci->lock);
354 port_status = ehci_readl(ehci, status_reg); 334 port_status = ehci_readl(ehci, status_reg);
@@ -365,6 +345,36 @@ static ssize_t store_companion(struct device *dev,
365 if (try > 1) 345 if (try > 1)
366 msleep(5); 346 msleep(5);
367 } 347 }
348}
349
350/*
351 * Dedicate or undedicate a port to the companion controller.
352 * Syntax is "[-]portnum", where a leading '-' sign means
353 * return control of the port to the EHCI controller.
354 */
355static ssize_t store_companion(struct device *dev,
356 struct device_attribute *attr,
357 const char *buf, size_t count)
358{
359 struct ehci_hcd *ehci;
360 int portnum, new_owner;
361
362 ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
363 new_owner = PORT_OWNER; /* Owned by companion */
364 if (sscanf(buf, "%d", &portnum) != 1)
365 return -EINVAL;
366 if (portnum < 0) {
367 portnum = - portnum;
368 new_owner = 0; /* Owned by EHCI */
369 }
370 if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
371 return -ENOENT;
372 portnum--;
373 if (new_owner)
374 set_bit(portnum, &ehci->companion_ports);
375 else
376 clear_bit(portnum, &ehci->companion_ports);
377 set_owner(ehci, portnum, new_owner);
368 return count; 378 return count;
369} 379}
370static DEVICE_ATTR(companion, 0644, show_companion, store_companion); 380static DEVICE_ATTR(companion, 0644, show_companion, store_companion);
@@ -867,3 +877,13 @@ error:
867 spin_unlock_irqrestore (&ehci->lock, flags); 877 spin_unlock_irqrestore (&ehci->lock, flags);
868 return retval; 878 return retval;
869} 879}
880
881static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum)
882{
883 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
884
885 if (ehci_is_TDI(ehci))
886 return;
887 set_owner(ehci, --portnum, PORT_OWNER);
888}
889