Linux USB:打开和关闭电源?

时间:2009-07-22 08:22:50

标签: linux macos usb

如何以编程方式启用和禁用Linux上特定USB端口的电源?这样的事情甚至可能吗? Mac的回答也很受欢迎!

我正在尝试BOC(不要假装你也没有尝试过一个!)并最终得到其中一个,并希望通过挂钩获得一些用处它取决于我们的服务器监视器。

13 个答案:

答案 0 :(得分:24)

Linux中有一个sys条目。来自Documentation/usb/power-management.txt

  

功率/水平

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.)

类似于:echo on > /sys/bus/usb/devices/usb5/power/level

您可能还需要使用自动暂停设置。在没有告诉内核停止尝试的情况下,它可能会自动挂起端口。

祝你好运!

答案 1 :(得分:15)

自从这个问题最初被回答以来,usbfs交互似乎已经改变了很多次。所以,这就是我如何从Bash shell循环Ubuntu Oneiric Ocelot上的集线器端口电源。

搜索总线和设备编号:

sudo lsusb -v|less

使用总线和设备编号在总线/集线器端口层次结构中找到设备:

sudo lsusb -t|less

语法似乎是'bus-port.port.port.port.port ...'例如,我的鼠标连接到外部集线器,该集线器连接到我的计算机集线器,该集线器内部连接到根集线器:< / p>

/:  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

所以,在上述情况下'2-1.1.1'。最后,循环端口电源:

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

我没有连接协议分析器来查看总线上实际发生了什么,但我知道当我取消绑定时我的鼠标指示灯会熄灭。我猜测在较低层,这与EHCI主机控制器交互,实际上关闭了端口上的电源。这对于嵌入式设备尤其有用,例如UVC网络摄像头,它似乎永远不会正常运行,否则需要重启系统才能重置。

另请参阅udevadm命令。

答案 2 :(得分:7)

通过书签进行挖掘

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

似乎您需要将其连接到集线器并控制集线器的电源。我见过的根集线器似乎都没有能够支持电源控制。

答案 3 :(得分:5)

您可以使用uhubctl - 命令行实用程序来控制兼容USB集线器的每端口USB电源。

它仅适用于支持每端口电源切换的集线器,但请注意,许多现代主板都具有支持此功能的USB集线器。此外,uhubctl的最新版本支持USB 3.0集线器,好消息是有相当多的新USB 3.0集线器支持此功能。

编译:

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

列出可由uhubctl控制的所有集线器和端口的状态:

uhubctl

要关闭单个兼容集线器的端口5的电源:

uhubctl -a 0 -p 5

打开所有兼容集线器的所有端口的电源:

uhubctl -a 1

关闭电源然后再打开:

uhubctl -a 2 -p 5

阅读more here

披露 - 我是uhubctl的作者。

答案 4 :(得分:4)

这是一个在Linux下使用Logitech USB无线鼠标的例子。

根据您的设备“供应商”(供应商ID)和“ProdID”(产品ID)阅读“/ proc / bus / usb / devices”的相关段落 或“制造商”和“产品”(所有这些值都是每个设备不变的。)

cat /proc/bus/usb/devices

(第一段设备已开启,第二段设备已关机,但仍然插入电源)

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

这里需要两个变量。 它们位于“T:”行(段落的第一行)。 这些变量是:   总线(本例中总线= 01)   Cnt(本例中Cnt = 01)

您需要将“1”(算术一)添加到“Cnt”才能获得排名   Rank = Cnt + 1(这是一个数学函数,在这个例子中Rank = 2)

所以您要查找的设备是以下字符串:   Bus-Rank(这不是数学函数,它是一个字符串,在本例中为1-2)

还要注意“C:”这一行。 它包含有关设备功率(电流)的信息。 如果“C:”中有星号(如我们的第一个示例中所示),则设备已通电。 如果不是(“C:”)那么设备“或多或少”断电意味着当设备被插入时总是有微小的电流,否则我们将无法读取所有这些信息。

最后记住“I:”行。 如果字段“I:*”包含星号(如我们的第一个示例中所示)那么输入,来自或来自设备,我不确定,也许两者都有。 最后一行字段包含使用的驱动程序(在我们的第一个示例中为“usbhid”)

我们已准备好切换设备的电源:

关闭电源

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

打开电源

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

以下是一个简单的bash脚本“USBMS”(USB鼠标切换),它控制上面示例中设备的电源。 它不是很动态,它使用“Product”和“Manufacturer”常量来定位“/ proc / bus / usb / devices”的相关段落 您应该使用“供应商”(供应商ID)和“ProdID”(产品ID)。 它还会检查设备的电源状态。 以超级用户身份运行。

命令:./ USBMS动作

参数:action =“off”或“0”关闭电源 - action =“on”或“1”开机(不带引号)

#!/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
                                             )

答案 5 :(得分:3)

@Kristian通常,您不会发现广告中受软件控制的端口电源控制,因为用户不应该意识到这一层。除了强迫行为不端的总线供电设备进入已知状态之外,我认为除此之外还有很多使用案例,并且作为仅使用USB供电的后置设备处理哑巴。也许Mark的设备属于后一类。这是一种原始的,不可靠的机制。

正如我所提到的,我没有查看解除绑定黑客的实现细节,我只在我主板上嵌入的EHCI主机控制器上试用了它,“英特尔公司6系列/ C200系列芯片组家族USB增强版主机控制器(rev 05)。“我猜这个主机控制器的PPC位设置为HCSPARAMS,表示根据EHCI规范对端口电源开关进行软件控制。

根据USB 2.0规范,如果您正在与外部集线器连接,“集线器通过设置wHubCharacteristics中的逻辑电源切换模式字段来指示它是否支持电源切换”。我不记得合规性测试是否确保了这项功能,但如果他们这样做,你只需找到一个带有USB 2.0徽标的集线器。我推测黑客会发送一个设置端口功能请求,但它可能不仅仅循环目标端口。同样,根据USB 2.0规范,“具有电源开关的集线器可以将电源切换到所有端口作为一个组/组,单独地切换到每个端口,或者具有任意数量的一个或多个端口的组合。”我不确定是否有一个很好的命令行工具来获得wHubCharacteristics。

简而言之,就我所知,没有一种很好的通用方法来处理这个问题。但是,可以询问内部或外部集线器以确定其支持级别,然后,如果支持,则使用它。这只是你想花多少时间这么做的问题。

答案 6 :(得分:2)

在OS X中,您可以从用户空间访问USB设备并请求其暂停。

您可以在USB Device Interface Guide中找到一般示例。您需要使用IOUSBDeviceInterface182(或更高版本)USBDeviceSuspend方法。

注意:集线器和控制器端口可能具有联动电源,这意味着同一个交换机由多个端口共享。如果是这种情况,并且您的设备与另一个有源设备位于同一组中,则不会断电。

答案 7 :(得分:2)

  

功率/水平

     

“on”表示应该恢复设备而不是自动暂停   允许。(当然,仍然允许系统暂停。)

     

“auto”是允许内核的正常状态   自动挂起并自动恢复设备。

     

“暂停”表示设备应保持暂停状态,并且   不允许autoresume。 (但仍可允许远程唤醒,   因为它是由power / wakeup属性单独控制的。)

第1步: 所以我有,usb1,usb2,usb3,usb4 ....

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

第2步: 我怎么知道哪一个是哪个? (

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

Optional 1: ,以防lsusb显示并需要找到特定的

#!/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

可选2: 以防万一找不到 - 重启无法重启电源使用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中继:

#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);
}

答案 8 :(得分:1)

我更倾向于切断电线并将其连接到一个串行端口w /某种类型的简单继电器运行其中一个'接收就绪'。然后你可以在每次有一些问题时将线路(信号'我准备好接收')拉到串口文件。当它完成后,只需发出信号'我已经满了'

然而,我对这些事情的理解是,它们在电容器完全充电之前会消耗大量电流,然后立即将其全部释放以闪烁灯泡。我无法想象这种突然放电对计算机的电路有利。您可能需要一些二极管电流陷阱来防止反馈到串口。

  

每次闹铃响起,电脑都会关闭!

答案 9 :(得分:1)

如{link}中所述,few usb hubs可以打开和关闭其端口。我还没有找到一个带USB端口的主板,可以启用或禁用。

答案 10 :(得分:1)

不要购买昂贵的智能集线器,只是为了打开和关闭USB小工具 您只需要一个微控制器。

Arduino Nano™ ATmega328 * 1 enter image description here

Nano是一款16MHz 8位计算机,具有2K RAM和32K闪存 它有22个programmable引脚(8个模拟引脚和14个数字引脚) 它可以read/write USB,并由5.0V microUSB端口(外部高达12.0V)供电。

// 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();         
         }
}


提供精美的小盒子(也是免费的3d printables)。

C4Labs Zebra Black Ice Case
6

*仅使用正版Arduino Nano™。小心counterfeits

更新:还可以使用小型ATtinywireless微型手枪。

答案 11 :(得分:0)

您只是以root身份运行“echo”,请尝试:

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

答案 12 :(得分:-2)

据我所知,您的设备由USB电源线VCC(~5V)供电。 问题在于,除非您将设备与启用了电源控制的集线器连接,否则无法在标准Linux框架中从用户空间控制此电源线。 Ony内核代码可以触及这条电源线。