Linux USB: turning the power on and off?

后端 未结 13 1339
遥遥无期
遥遥无期 2020-12-07 10:41

How can I programmatically enable and disable the power to a particular USB port on Linux? Is such a thing even possible? Mac answers appreciated as well!

I was tryi

13条回答
  •  旧巷少年郎
    2020-12-07 10:52

    This is an example with a Logitech USB wireless mouse under linux.

    Read relevant paragraph of "/proc/bus/usb/devices" according to your devices "Vendor" (vendor id) and "ProdID" (product id) or "Manufacturer" and "Product" (all these values are constant per device).

    cat /proc/bus/usb/devices
    

    (first paragraph with device powered on, second one with same device powered off but still pluged in)

    T:  Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  4 Spd=1.5 MxCh= 0
    D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
    P:  Vendor=046d ProdID=c50e Rev=25.10
    S:  Manufacturer=Logitech
    S:  Product=USB RECEIVER
    C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr= 70mA
    I:* If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=02 Driver=usbhid
    E:  Ad=81(I) Atr=03(Int.) MxPS=   8 Ivl=10ms
    
    T:  Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  4 Spd=1.5 MxCh= 0
    D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
    P:  Vendor=046d ProdID=c50e Rev=25.10
    S:  Manufacturer=Logitech
    S:  Product=USB RECEIVER
    C:  #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr= 70mA
    I:  If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=02 Driver=
    E:  Ad=81(I) Atr=03(Int.) MxPS=   8 Ivl=10ms
    

    You need two variables here. They are located in the "T:" line (first line of paragraph). These variables are : Bus (Bus=01 in this example) Cnt (Cnt=01 in this example)

    You will need to add "1" (arithmetic one) to "Cnt" to get the rank Rank=Cnt+1 (this is a mathematical function, Rank=2 in this example)

    So the device you are looking for is the following string : Bus-Rank (this is not a mathematical function, its a string, 1-2 in this example)

    Mind also the "C:" line. It contains info regarding the power (current) of the device. If there is an asterisk in "C:" (like in our 1st example) then the device is powered. If not ("C:") then the device is "more or less" powered off meaning there is always a tiny current when a device is pluged, otherwise we wouldn't be able to read all this info.

    Mind finaly the "I:" line. If the field "I:*" contains asterisk (like in our 1st example) then there is input, from or to the device, i am not sure, maybe both. The final line field contains the driver used ("usbhid" in our 1st example)

    We are ready to switch the power of our device :

    power off

    echo -n "Bus-Rank" > /sys/bus/usb/drivers/usb/unbind
    echo -n "1-2" > /sys/bus/usb/drivers/usb/unbind (in our example)
    

    power on

    echo -n "Bus-Rank" > /sys/bus/usb/drivers/usb/bind
    echo -n "1-2" > /sys/bus/usb/drivers/usb/bind (in our example)
    

    The following is a simple bash script "USBMS" (USB Mouse Switch) that controls the power of the device in our example above. It is not very dynamical and it uses the "Product" and "Manufacturer" constants to locate the relevant paragraph of "/proc/bus/usb/devices" You should use the "Vendor" (vendor id) and "ProdID" (product id) instead. It also checks the power state of the device. Run as superuser.

    Command : ./USBMS action

    parameter : action = "off" or "0" to power off - action = "on" or "1" to power on (without the quotes)

    #!/bin/bash
    
         USBmouseProduct="USB RECEIVER"
    USBmouseManufacturer="Logitech"
    
                  signal=$1
    
    nr3=$(awk '/Product='"$USBmouseProduct"'/ {print NR}' /proc/bus/usb/devices)
    nr3=$(expr $nr3 + 0)
    nr2=$(awk '/Manufacturer='"$USBmouseManufacturer"'/ {print NR}' /proc/bus/usb/devices)
    nr2=$(expr $nr2 + 0)
    nr1=$(expr $nr2 - 3)
    nr4=$(expr $nr3 + 1)
    nrdiff=$(expr $nr3 - $nr2)
    
    [ $nr3 != 0 -a $nr2 != 0 -a $nrdiff = 1 ] && (
                                                     usbmbus0=$(awk 'NR=='$nr1' {print $2}' /proc/bus/usb/devices | awk -F= '{print $2}')
                                                      usbmbus=$(expr $usbmbus0 + 0)
                                                      usbmdev=$(awk 'NR=='$nr1' {print $8}' /proc/bus/usb/devices)
                                                     usbmrank=$(awk 'NR=='$nr1' {print $5}' /proc/bus/usb/devices | awk -F= '{print $2}')
                                                     usbmrank=$(expr $usbmrank + 1)
                                                   usbmbusrank="$usbmbus""-""$usbmrank"
                                                    usbmpower=$(awk 'NR=='$nr4' {if ( $1=="C:" ) {print 0}; if ( $1=="C:*" ) {print 1}}' /proc/bus/usb/devices)
    
                                                   case $signal in
                                                                  off|0)
                                                                        [ $usbmpower = 1 ] && echo -n "$usbmbusrank" > /sys/bus/usb/drivers/usb/unbind
                                                                        ;;
                                                                   on|1)
                                                                        [ $usbmpower = 0 ] && echo -n "$usbmbusrank" > /sys/bus/usb/drivers/usb/bind
                                                                        ;;
                                                   esac
                                                 )
    

提交回复
热议问题