Linux USB: turning the power on and off?

Multi tool use
Linux USB: turning the power on and off?
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.
@JonHadley, BOC = Woot Bag of Crap. en.wikipedia.org/wiki/Woot#Bag_of_Crap. Search for it on youtube for some very entertaining unboxings. I try every time and haven't gotten one!
– Mark Harrison
Jan 4 '12 at 18:41
The answer seems a trove of information on USB power management — first Google result for
ganged power switching
(without quotes).– Blaisorblade
Dec 14 '13 at 21:29
ganged power switching
Where did you buy those? Found any alterntives?
– Kimble
Sep 26 '14 at 15:00
Yes, it is possible, check github.com/mvp/uhubctl
– mvp
Mar 17 '17 at 21:18
13 Answers
13
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.
It wasn't true in 2009, and it is not true now. Check this list of USB devices that support controlling power per port: github.com/mvp/uhubctl#compatible-usb-hubs
– mvp
Mar 17 '17 at 21:15
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
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!
By my reading of the USB 2.0 specification the power rails out of the USB port are still available. A device connected to the port should limit its power consumption to 500uA for low power and 2.5mA for high power (normally 5 unit load devices). The suggestion for controlling the power through a hub looks more likely to succeed, assuming that the hub allows the power output to be disabled.
– ʎəʞo uɐɪ
Jul 24 '09 at 11:10
+1 Works for suspending a USB stick.
– starblue
Jul 26 '09 at 11:27
Since kernel v2.6.32, the suspend option has been removed - see the documentation linked in this answer
– austinmarton
Jul 7 '15 at 3:13
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.
udevadm
Which hub do you use? I am currently looking for a hub with per port-control functionality, but it does not seem to advertised as a feature at all (except by the actual chipset manufactures).
– Kristian Evensen
Dec 8 '11 at 14:10
@Kristian please see my comment below. It wouldn't fit in here.
– Stephen Niedzielski
Dec 25 '11 at 22:57
Also see here for a couple notes on using udevadm.
– Stephen Niedzielski
May 13 '12 at 7:22
You could use 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 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 turn on power for all ports of all compatible hubs:
uhubctl -a 1
To toggle power off then on:
uhubctl -a 2 -p 5
Read more here.
Disclosure - I am the author of uhubctl.
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
)
@RVF16, it seems there's no
/proc/bus/usb/devices
file in my Unbutu 11 version... is there another approach to get the "Bus-Rank" of a usb device?– Siwei Shen申思维
Nov 9 '12 at 8:03
/proc/bus/usb/devices
@SiweiShen Try the command "sudo usb-devices".
– Martin J.H.
Sep 24 '13 at 22:03
@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.
It's worth mentioning that there are quite a few hubs that report to support this feature, while not actually supporting it. So sadly, running "sudo lsusb -v" to check wHubCharacteristics doesn't guarantee actual support. This is the latest list of usb hubs that actually support this. gniibe.org/development/ac-power-control-by-USB-hub/index.html It's from 2011, but that's the latest I found ...
– ZeDuS
Apr 2 '15 at 18:52
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.
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
Optional 1:
#!/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);
}
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!
Your are running just "echo" as root, try:
echo suspend | sudo tee /sys/bus/usb/devices/usb3/power/level
this no longer work in recent kernels
– socketpair
Dec 21 '15 at 18:09
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.
Don't buy an expensive smart hub just for turning USB gadgets on and off.
All you need is a microcontroller.
Arduino Nano™ ATmega328 *
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
* Use Genuine Arduino Nano™ only. Beware of counterfeits.
UPDATE: Miniaturised ATtiny and wireless microcontollers are also available.
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.
I don't think it's a user-space vs. kernel-space problem, but a hardware problem. This has been discussed before
– Johannes Jander
Jan 5 '16 at 10:28
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Exuse my ignorance, but, BOC?
– Jon Hadley
Jan 4 '12 at 13:12