Linux USB: turning the power on and off?

LinuxMacosUsb

Linux Problem Overview


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 trying for a BOC (don't pretend you weren't try to get one too!) and ended up with one of these, and would like to get some use out of the thing by hooking it up to our server monitor.

https://s3.amazonaws.com/wootsaleimages/USB_Powered_Woot-Off_Lights7x1Detail.jpg" width="256" title="stupid woot lights!">

Linux Solutions


Solution 1 - Linux

There is a sys entry for this in Linux. From Documentation/usb/power-management.txt:

> power/level > > This file contains one of three words: "on", "auto", > or "suspend". You can write those words to the file > to change the device's setting. > > "on" means that the device should be resumed and > autosuspend is not allowed. (Of course, system > suspends are still allowed.) > > "auto" is the normal state in which the kernel is > allowed to autosuspend and autoresume the device. > > "suspend" means that the device should remain > suspended, and autoresume is not allowed. (But remote > wakeup may still be allowed, since it is controlled > separately by the power/wakeup attribute.)

Something like: echo on > /sys/bus/usb/devices/usb5/power/level

You may need to play with the autosuspend setting as well. Without telling the kernel to stop trying, it may suspend the port automatically.

Good luck!

Solution 2 - Linux

The usbfs interaction seems to have changed a number of times since this question was originally answered. So, here's how I cycle hub port power on Ubuntu Oneiric Ocelot from a Bash shell.

Search for the bus and device number:

sudo lsusb -v|less

Locate the device in the bus / hub port hierarchy using the bus and device number:

sudo lsusb -t|less

The syntax seems to be 'bus-port.port.port.port.port...' For example, my mouse is connected to an external hub which connects to my computer's hub which internally connects to a root hub:

/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=ehci_hcd/2p, 480M
    |__ Port 1: Dev 2, If 0, Class=hub, Driver=hub/6p, 480M
        |__ Port 1: Dev 3, If 0, Class=hub, Driver=hub/3p, 480M
            |__ Port 1: Dev 6, If 0, Class=HID, Driver=usbhid, 1.5M

So, '2-1.1.1' in the above case. Finally, cycle the port power:

echo '2-1.1.1'|sudo tee /sys/bus/usb/drivers/usb/unbind
sleep 1
echo '2-1.1.1'|sudo tee /sys/bus/usb/drivers/usb/bind

I haven't hooked up a protocol analyzer to see what's actually happening on the bus, but I know my mouse light turns off when I unbind it. I'm guessing at a lower layer this is interacting with the EHCI host controller to actually shut power off on the port. This is particularly useful for embedded devices, such as a UVC webcams, which never seem to function properly and would otherwise require a system reboot to reset.

See also the udevadm command.

Solution 3 - Linux

You could use my tool uhubctl - command line utility to control USB power per port for compatible USB hubs.

It works only on hubs that support per-port power switching, but note that many modern motherboards have USB hubs that support this feature. Also, last version of uhubctl supports USB 3.0 hubs, and good news is that quite a few new USB 3.0 hubs are supporting this feature.

To compile:

git clone https://github.com/mvp/uhubctl
cd uhubctl
make

To install system wide as /usr/sbin/uhubctl:

sudo make install

To list status of all hubs and ports that can be controlled by uhubctl:

uhubctl

To turn off power on port 5 of single compatible hub:

uhubctl -a 0 -p 5

To toggle power off then on:

uhubctl -a 2 -p 5

Read more here.

Solution 4 - Linux

Digs through bookmarks

http://blog.andrew.net.au/2009/01/01#usb_power_control

Seems like you need to connect it to a hub and control the hub's power. None of the root hubs I have seen seems to be able to support power control.

Solution 5 - Linux

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
                                             )

Solution 6 - Linux

@Kristian Typically you won't find software controlled port power controlled advertised because users shouldn't be conscious of this layer. I don't think there's many use cases for it other than to force misbehaving bus powered devices into a known state, and handle dumb as a post devices that only use USB for power. Perhaps Mark's device falls into the latter category. It's a crude, last resort mechanism.

As I mentioned, I haven't looked into the implementation details for the unbinding hack and I've only tried it on the EHCI host controller embedded in my motherboard, an "Intel Corporation 6 Series/C200 Series Chipset Family USB Enhanced Host Controller (rev 05)." I would guess that this host controller has the PPC bit of HCSPARAMS set, indicating software control of port power switches, per EHCI spec.

If you're interfacing with an external hub, "a hub indicates whether or not it supports power switching by the setting of the Logical Power Switching Mode field in wHubCharacteristics," according to the USB 2.0 spec. I don't rememeber if the compliance tests ensure this functionality or not, but if they do, you'd need only find a hub with the USB 2.0 logo. I speculate the hack would send a set port feature request, but it may cycle more than just the target port. Again, per USB 2.0 spec, "a hub with power switches can switch power to all ports as a group/ gang, to each port individually, or have an arbitrary number of gangs of one or more ports." I'm not sure if there's a nice command line tool to get wHubCharacteristics.

In short, there's not a great generic way to handle this problem, as far as I know. However, it is possible to interrogate an internal or external hub to determine its level of support and then, if supported, use it. It's just a question of how much time you want to spend doing so.

Solution 7 - Linux

In OS X you can access a USB device from user space and request it to suspend.

You can find a general example in the USB Device Interface Guide. You will need to use the IOUSBDeviceInterface182 (or higher) USBDeviceSuspend method.

Note: Hubs and controller ports may have ganged power supplies, meaning the same switch is shared by multiple ports. if this is the case and your device is in the same group as another active device, it will not be powered down.

Solution 8 - Linux

A few usb hubs can switch their ports on and off, as explained in the link. I have yet to find a motherboard with usb ports which can be enabled or disabled.

Solution 9 - Linux

I'd be more inclined to cut the wire and hook it up to a serial port w/ some type of simple relay running ofF one of the 'recieve ready'pin. Then you could just pull the line down (signal 'i'm ready to receive') to the serial port file every time there is some isssue. When it's done, just signal 'i'm full'

My understanding of those things, however, is that they draw a lot of current until they fully charge the capacitor, then release it all at once to flash the bulb. I can't imagine such a sudden discharge is good for the circuitry of the computer. you may need some diode current traps to prevent feedback into the serial port.

> Every time my alarm goes off, the computer shuts down!

Solution 10 - Linux

> power/level > > "on" means that the device should be resumed and autosuspend is not > allowed.(Of course, system suspends are still allowed.) > > "auto" is the normal state in which the kernel is allowed to > autosuspend and autoresume the device. > > "suspend" means that the device should remain suspended, and > autoresume is not allowed. (But remote wakeup may still be allowed, > since it is controlled separaely by the power/wakeup attribute.)

Step 1: so i have, usb1, usb2, usb3, usb4 ....

$ cat /sys/bus/usb/devices/usb*/power/level
auto
auto
auto
auto

Step 2: how would i know which one is which? (

# echo "on" | tee /sys/bus/usb/devices/usb*/power/level
# cat /sys/bus/usb/devices/usb*/power/level
on
on
on
on

Optional 1: in case the lsusb shows and need to find specific one

#!/bin/bash
usb="046d:082d" # Find ME, Replace the ID 

cam=$(lsusb | awk "/$usb/ {print $6}")
echo $cam
if [ ! -z "$cam" -a "$cam" != " " ]; then
  for X in /sys/bus/usb/devices/*;
  do
    a=$(cat "$X/idVendor" 2>/dev/null)
    b=$(cat "$X/idProduct" 2>/dev/null)
    c="$a:$b"
    if [ ! -z "$c" -a "$c" != " " ] && [ "$c" == "$usb" ]; then
      d=$(echo $X | sed "s/\/sys\/bus\/usb\/devices\///g")
      echo "[FOUND] $d"

      #sudo sh -c "echo on > /sys/bus/usb/devices/$d/authorized"
      sleep 2
      #sudo sh -c "echo on > /sys/bus/usb/devices/$d/authorized"
      lsusb
      break

    fi
  done;
fi

Optional 2: in case none found - reboot fails to power cycle use Arduino relay over udp

#!/bin/bash

file="/var/www/html/video/now.jpeg"

function age() {
   local filename=$1
   local changed=`stat -c %Y "$filename"`
   local now=`date +%s`
   local elapsed
   let elapsed=now-changed
   echo $elapsed
}

while true
do
  target="/dev/video99"
  foundon="none"
  warn="[WARNING]:"
  ok="[OK]:"
  for i in 0 1 2 3 4
  do
    tmp="/dev/video$i"
    if [ -e $tmp ]; then
      foundon="/dev/video$i"
    #else
    #  echo "no $i"
    fi
  done

  b="none"
  if [ "$foundon" = "$b" ]; then
    echo "$warn No camera is found - inform reboot or arduino boot"

  else
    echo "$ok ln -s $foundon $target"

    ### Camera is available but something is not correct so ###
    file_age=$(age "$file")
    echo The age of $file is $file_age seconds.

    if [[ ! -f $file ]]; then
      echo "file is not found. Kernel sucks for 500mA USB's"
    else
      echo "found file: $file_age"
      if [[ $file_age -gt 240 ]]; then
        echo "$warn greater then 240 seconds"

      else
        echo "$ok - less then 240 seconds"

      fi
    fi
  fi

ls /dev/video*
sleep 5

done

Arduino relay:

#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>

byte mac[]={0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xAD};
IPAddress ip(10,109,4,166);
byte gateway[]= {10,109, 0, 1};
byte subnet[]= {255, 255, 248,0};

unsigned int localPort = 8888;

char packetBuffer[UDP_TX_PACKET_MAX_SIZE];
char  ReplyBuffer[] = "ackv1";
EthernetUDP Udp;
int led1 = 2;
int led2 = 3;

void setup() {
  Ethernet.begin(mac,ip);
  //Ethernet.begin(mac, ip, '8.8.8.8', gateway, subnet);
  Udp.begin(localPort);

  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);

  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);
}

void loop() {
  int packetSize = Udp.parsePacket();
  if(packetSize) {
    delay(1000);
    digitalWrite(led1, HIGH);    // turn the LED off by making the voltage LOW
    delay(3000);
    digitalWrite(led1, LOW);   // turn the LED on (HIGH is the voltage level)

    delay(1000);
    digitalWrite(led2, HIGH);    // turn the LED off by making the voltage LOW
    delay(3000);
    digitalWrite(led2, LOW);   // turn the LED on (HIGH is the voltage level)


    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    Udp.write(ReplyBuffer);
    Udp.endPacket();
  }
  delay(10);
}

Solution 11 - Linux

Don't buy an expensive smart hub just for turning USB gadgets on and off.
All you need is a microcontroller.

Arduino Nano™ ATmega328 * 1enter image description here

The Nano is a 16MHz 8-bit computer with 2K RAM and 32K of flash storage.
It has 22 programmable pins (8 analog and 14 digital).
It can read/write USB, and is powered by its 5.0V microUSB port (up to 12.0V external).

// USB Blinker
// Blink LED while receiving USB stream
//
// For Arduino Nano™

int LED = 13;

// setup() is run once at powerup or when reset button is pressed
//
void setup() {
        pinMode(LED, OUTPUT);   // Configure pin D13 as output 
        Serial.begin(9600);     // Open 9600bps USB stream
}

// loop() runs forever at 16Mhz, blinking the LED at 1Hz when receiving USB data.
// 
void loop() { 
        if (Serial.available() > 0) {           // When stream is buffering
                digitalWrite(LED, HIGH);        //   turn on LED 
                delay(500);                     //   wait half second
                digitalWrite(LED, LOW);         //   turn off LED
                delay(500);                     //   wait half second
                while (Serial.available() > 0)  //   drain the buffer
                        Serial.read();         
         }
}


Exquisite tiny cases are available (also free 3d printables).

C4Labs Zebra Black Ice Case
6

* Use Genuine Arduino Nano™ only. Beware of counterfeits.

UPDATE: Miniaturised ATtiny and wireless microcontollers are also available.

Solution 12 - Linux

Your are running just "echo" as root, try:

echo suspend | sudo tee /sys/bus/usb/devices/usb3/power/level

Solution 13 - Linux

As I understand, your devices are supplied by USB power line VCC(~5V). The problem is that this power-line can't be controlled from user-space in standard linux framework, unless you interface your device with the hubs enabled with power-control. Ony kernel code can touch this power-line.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMark HarrisonView Question on Stackoverflow
Solution 1 - LinuxmixonicView Answer on Stackoverflow
Solution 2 - LinuxStephen NiedzielskiView Answer on Stackoverflow
Solution 3 - LinuxmvpView Answer on Stackoverflow
Solution 4 - LinuxSavant DegreesView Answer on Stackoverflow
Solution 5 - LinuxRVF16View Answer on Stackoverflow
Solution 6 - LinuxStephen NiedzielskiView Answer on Stackoverflow
Solution 7 - LinuxHasturkunView Answer on Stackoverflow
Solution 8 - LinuxptonelliView Answer on Stackoverflow
Solution 9 - LinuxApe-inagoView Answer on Stackoverflow
Solution 10 - Linuxuser285594View Answer on Stackoverflow
Solution 11 - LinuxDominic CerisanoView Answer on Stackoverflow
Solution 12 - LinuxAdaśView Answer on Stackoverflow
Solution 13 - LinuxParikshit PareekView Answer on Stackoverflow