Oliver Neukum wrote:
> Am Dienstag, 26. Juni 2007 schrieb Jüri Reitel:
>   
>> Hello.
>> How to correctly turn off the port power of usb hub (assuming hub 
>> supports individual port power switching). Correctly means that all 
>> drivers using the device on that port are notified before the power is 
>> removed. Removed device could also be a usb hub.
>>     
>
> You'd have to use the code paths usbfs uses for disconnecting via+ioctl.
>   
Thank you for fast replay

Looked into drivers/usb/core/devio.c functions
usbdev_ioctl
  proc_ioctl_default
    proc_ioctl
      USBDEVFS_DISCONNECT branch calls usb_driver_release_interface

As i can understand i should obtain list of all interfaces registered to 
the port that i want to turn of the power and then call usbdev ioctl

drivers/usb/core/hub.c has function void usb_disconnect(struct 
usb_device **pdev)
I exported usb_disconnect function and use it in my own driver where i 
get struct usb_device * hub, because i know bus topology
static int set_usb_port_power_state(struct usb_device *hub, int port, 
int new_state)
{
    int ret;
    if (new_state) {
        ret = set_usb_hub_port_feature(hub, port, USB_PORT_FEAT_POWER);
    } else {
        //notify also children device drivers
        if (port > 0 && port <= USB_MAXCHILDREN && hub->children[port - 
1]) {
            usb_disconnect(&hub->children[port - 1]);
        }
        ret = clear_usb_hub_port_feature(hub, port, USB_PORT_FEAT_POWER);
    }
    return ret;
}

hub is obtained with usb_get_dev and later put with usb_put_dev

First tests have been successful, with usb to usb hub and with root hub 
althoug i had to change some files in usb/host/
The most hardest part to me is to understand the needed locks before 
calling kernel functions


Following patch is only tested with NEC uPD720101 usb 2.0 Host 
controller, this patch allows port power switching on nec root hub
diff -ruN linux-2.6.18/drivers/usb/host/ehci-hub.c 
linux-2.6.18-modified/drivers/usb/host/ehci-hub.c
--- linux-2.6.18/drivers/usb/host/ehci-hub.c    2006-09-20 
06:42:06.000000000 +0300
+++ linux-2.6.18-modified/drivers/usb/host/ehci-hub.c      2006-11-30 
13:12:01.000000000 +0200
@@ -344,7 +344,7 @@
                        goto error;
                wIndex--;
                temp = readl (&ehci->regs->port_status [wIndex]);
-               if (temp & PORT_OWNER)
+               if ((temp & PORT_OWNER) && wValue != USB_PORT_FEAT_POWER)
                        break;

                switch (wValue) {
@@ -510,7 +510,7 @@
                        goto error;
                wIndex--;
                temp = readl (&ehci->regs->port_status [wIndex]);
-               if (temp & PORT_OWNER)
+               if ((temp & PORT_OWNER) && wValue != USB_PORT_FEAT_POWER)
                        break;

                temp &= ~PORT_RWC_BITS;
diff -ruN linux-2.6.18/drivers/usb/host/ohci-hcd.c 
linux-2.6.18-modified/drivers/usb/host/ohci-hcd.c
--- linux-2.6.18/drivers/usb/host/ohci-hcd.c    2006-09-20 
06:42:06.000000000 +0300
+++ linux-2.6.18-modified/drivers/usb/host/ohci-hcd.c      2006-11-30 
13:05:27.000000000 +0200
@@ -666,6 +666,11 @@
                temp |= RH_A_NPS;
                ohci_writel (ohci, temp, &ohci->regs->roothub.a);
        }
+
+       temp &= ~(RH_A_NPS | RH_A_NOCP);
+       temp |= RH_A_PSM | RH_A_OCPM;
+       ohci_writel (ohci, temp, &ohci->regs->roothub.a);
+
        ohci_writel (ohci, RH_HS_LPSC, &ohci->regs->roothub.status);
        ohci_writel (ohci, (temp & RH_A_NPS) ? 0 : RH_B_PPCM,
                                                &ohci->regs->roothub.b);
diff -ruN linux-2.6.18/drivers/usb/host/ohci-hub.c 
linux-2.6.18-modified/drivers/usb/host/ohci-hub.c
--- linux-2.6.18/drivers/usb/host/ohci-hub.c    2006-09-20 
06:42:06.000000000 +0300
+++ linux-2.6.18-modified/drivers/usb/host/ohci-hub.c      2006-11-30 
13:16:25.000000000 +0200
@@ -559,6 +559,9 @@
                        break;
                case USB_PORT_FEAT_POWER:
                        temp = RH_PS_LSDA;
+                       ohci_writel (ohci, temp, 
&ohci->regs->roothub.portstatus[wIndex]);
+                       ohci_readl (ohci, 
&ohci->regs->roothub.portstatus[wIndex]);
+                       temp = RH_PS_CSC | RH_PS_PESC;
                        break;
                case USB_PORT_FEAT_C_CONNECTION:
                        temp = RH_PS_CSC;



JR

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to