On Tue, 16 May 2006, Ezequiel Valenzuela wrote:

> The question I have for the nice people here is: how do I force the
> kernel to use the uhci-hcd module instead of ehci-hcd *just for this
> device*, considering that I want to plug other USB 2.0 devices to the
> same machine? Is there any solution involving hotplug? (I think it's
> probably "too late" for hotplug to determine which host controller
> device to use). Can I edit some kernel source file (I haven't looked
> into that yet) to force the other host controller driver (uhci-hcd)
> instead of the automatically chosen one (ehci-hcd)?

Here's a patch for 2.6.17-rc4 (it also applies to 2.6.16) that does what 
you want.

Let's suppose you have a high-speed USB device, something like 1-4 (i.e.,
controller 1 port 4).  You can force it to run at full speed by doing:

        echo 1-4 >/sys/class/usb/usb_host/usb_host1/companion

(the "1" in "usb_host1" is also the controller number, the same as the "1" 
in "1-4").

Issuing the command a second time will switch the device back to high 
speed.

Alan Stern

P.S.: Dave, what do you think?  I'm not sure why the retry loop was 
necessary; perhaps the port has to be disabled first before PORT_OWNER can 
take effect.  Also, there ought to be a way to do this when there's an 
integrated TT, but I don't know how that would work.



Index: usb-2.6/drivers/usb/host/ehci-hub.c
===================================================================
--- usb-2.6.orig/drivers/usb/host/ehci-hub.c
+++ usb-2.6/drivers/usb/host/ehci-hub.c
@@ -173,6 +173,76 @@ static int ehci_bus_resume (struct usb_h
 
 /*-------------------------------------------------------------------------*/
 
+/* Toggle the state of the OWNER bit for the requested port */
+static ssize_t
+store_companion (struct class_device *class_dev, const char *buf, size_t count)
+{
+       struct usb_bus          *bus;
+       struct usb_hcd          *hcd;
+       struct ehci_hcd         *ehci;
+       int                     busnum, index, illegal;
+       int                     port_status, old_owner, try;
+
+       bus = class_get_devdata(class_dev);
+       hcd = bus->hcpriv;
+       ehci = hcd_to_ehci (hcd);
+
+       switch (sscanf (buf, "%d-%d.%d", &busnum, &index, &illegal)) {
+       case 1:
+               index = busnum;
+               break;
+       case 2:
+               if (busnum != bus->busnum)
+                       return -ENODEV;
+               break;
+       default:
+               return -EINVAL;
+       }
+       --index;
+       if (index < 0 || index >= HCS_N_PORTS (ehci->hcs_params))
+               return -ENOENT;
+
+       old_owner = readl (&ehci->regs->port_status [index]) & PORT_OWNER;
+       for (try = 5; try > 0; --try) {
+               spin_lock_irq (&ehci->lock);
+               port_status = readl (&ehci->regs->port_status [index]);
+               if ((port_status & PORT_OWNER) == old_owner) {
+                       port_status ^= PORT_OWNER;
+                       port_status &= ~(PORT_PE | PORT_RWC_BITS);
+                       writel (port_status, &ehci->regs->port_status [index]);
+               } else
+                       try = 0;
+               spin_unlock_irq (&ehci->lock);
+               if (try > 1)
+                       msleep(5);
+       }
+       return count;
+}
+static CLASS_DEVICE_ATTR (companion, S_IWUSR, NULL, store_companion);
+
+static inline void create_companion_file (struct ehci_hcd *ehci)
+{
+       struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev;
+
+       /* with integrated TT there is no companion! */
+       if (ehci_is_TDI(ehci))
+               return;
+       class_device_create_file(cldev, &class_device_attr_companion);
+}
+
+static inline void remove_companion_file (struct ehci_hcd *ehci)
+{
+       struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev;
+
+       /* with integrated TT there is no companion! */
+       if (ehci_is_TDI(ehci))
+               return;
+       class_device_create_file(cldev, &class_device_attr_companion);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
 static int check_reset_complete (
        struct ehci_hcd *ehci,
        int             index,
Index: usb-2.6/drivers/usb/host/ehci-hcd.c
===================================================================
--- usb-2.6.orig/drivers/usb/host/ehci-hcd.c
+++ usb-2.6/drivers/usb/host/ehci-hcd.c
@@ -384,6 +384,7 @@ static void ehci_stop (struct usb_hcd *h
        writel (0, &ehci->regs->configured_flag);
        unregister_reboot_notifier (&ehci->reboot_notifier);
 
+       remove_companion_file(ehci);
        remove_debug_files (ehci);
 
        /* root hub is shut down separately (first, when possible) */
@@ -560,6 +561,7 @@ static int ehci_run (struct usb_hcd *hcd
         * since the class device isn't created that early.
         */
        create_debug_files(ehci);
+       create_companion_file(ehci);
 
        return 0;
 }



-------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-users

Reply via email to