【问题标题】:Linux USB: turning the power on and off?Linux USB:打开和关闭电源?
【发布时间】:2010-11-12 22:11:50
【问题描述】:

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

我正在尝试BOC(不要假装你也没有尝试获得一个!)并最终获得了其中一个,并希望通过连接它来获得一些用途到我们的服务器监视器。

【问题讨论】:

  • 原谅我的无知,但是,BOC?
  • @JonHadley, BOC = Woot Bag of Crap。 en.wikipedia.org/wiki/Woot#Bag_of_Crap。在 youtube 上搜索一些非常有趣的拆箱。我每次都试了,一个都没有!
  • 答案似乎是关于 USB 电源管理的大量信息——ganged power switching 的第一个 Google 结果(不带引号)。
  • 你在哪里买的?找到替代品了吗?
  • 是的,有可能,检查github.com/mvp/uhubctl

标签: linux macos usb


【解决方案1】:

浏览书签

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

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

【讨论】:

【解决方案2】:

在 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

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

祝你好运!

【讨论】:

  • 根据我对 USB 2.0 规范的阅读,USB 端口的电源轨仍然可用。连接到端口的设备应将其功耗限制为低功耗 500uA 和高功率 2.5mA(通常为 5 个单位负载设备)。假设集线器允许禁用电源输出,通过集线器控制电源的建议看起来更有可能成功。
  • 自内核 v2.6.32 起,挂起选项已被删除 - 请参阅此答案中链接的文档
【解决方案3】:

我更倾向于切断电线并将其连接到带有某种简单继电器的串行端口,该继电器从“接收就绪”引脚之一运行。然后,每次出现问题时,您都可以将线路下拉(信号“我已准备好接收”)到串行端口文件。完成后,只需发出“我吃饱了”的信号

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

每次我的闹钟响起,电脑都会关机!

【讨论】:

    【解决方案4】:

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

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

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

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

        【解决方案6】:

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

        根据您的设备“Vendor”(供应商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”的相关段落 您应该改用“Vendor”(供应商 ID)和“ProdID”(产品 ID)。 它还检查设备的电源状态。 以超级用户身份运行。

        命令:./USBMS 操作

        参数:action = "off" or "0" to power off - action = "on" or "1" to power on(不带引号)

        #!/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,我的 Unbutu 11 版本中似乎没有 /proc/bus/usb/devices 文件...还有其他方法可以获取 USB 设备的“总线等级”吗?
        【解决方案7】:

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

        搜索总线和设备号:

        sudo lsusb -v|less
        

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

        sudo lsusb -t|less
        

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

        /:  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 命令。

        【讨论】:

        • 您使用哪个集线器?我目前正在寻找具有每个端口控制功能的集线器,但它似乎根本没有宣传为一项功能(实际芯片组制造商除外)。
        • @Kristian 请在下面查看我的评论。它不适合这里。
        • 另请参阅here,了解有关使用 udevadm 的一些注意事项。
        • 这不会关闭 USB 端口电源(5V 引脚始终打开)。这只会禁用操作系统中的 USB 端口,因此它们不再可用于连接。您的鼠标指示灯关闭是因为它失去了 USB 连接,而不是电源。您可以使用仅需要 5V USB 引脚的哑 USB 设备进行测试,例如台灯或风扇。解除绑定不会关闭此类设备,电源始终保持开启状态。
        【解决方案8】:

        @Kristian 通常你不会发现软件控制端口功率控制广告,因为用户不应该意识到这一层。我不认为它有很多用例,除了强制行为不端的总线供电设备进入已知状态,并将哑巴作为仅使用 USB 供电的后置设备处理。也许马克的设备属于后一类。这是一种粗糙的、不得已而为之的机制。

        正如我所提到的,我没有研究 unbinding hack 的实现细节,我只在我的主板中嵌入的 EHCI 主机控制器上进行了尝试,即“英特尔公司 6 系列/C200 系列芯片组系列 USB 增强主机控制器(修订版 05)。”我猜这个主机控制器设置了 HCSPARAMS 的 PPC 位,表示根据 EHCI 规范对端口电源开关进行软件控制。

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

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

        【讨论】:

        • 值得一提的是,有不少集线器报告支持此功能,但实际上并不支持。可悲的是,运行“sudo lsusb -v”来检查 wHubCharacteristics 并不能保证实际支持。这是实际支持此功能的最新 USB 集线器列表。 gniibe.org/development/ac-power-control-by-USB-hub/index.html 是 2011 年的,但这是我发现的最新...
        【解决方案9】:

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

        【讨论】:

          【解决方案10】:

          功率/等级

          “on”表示设备应该被恢复并且不自动挂起 允许。(当然,仍然允许系统挂起。)

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

          “挂起”表示设备应保持挂起状态,并且 不允许自动恢复。 (但可能仍然允许远程唤醒, 因为它是由 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 中继而不是 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);
          }
          

          【讨论】:

          • 这不会关闭 USB 端口电源(5V 引脚始终打开)。您可以使用只需要 5V USB 引脚的哑 USB 设备(例如台灯或风扇)进行测试。
          【解决方案11】:

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

          【讨论】:

          • 我不认为这是用户空间与内核空间的问题,而是硬件问题。这已经讨论过before
          【解决方案12】:

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

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

          编译:

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

          安装系统范围为/usr/sbin/uhubctl:

          sudo make install
          

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

          uhubctl
          

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

          uhubctl -a 0 -p 5
          

          关闭然后打开电源:

          uhubctl -a 2 -p 5
          

          阅读more here

          【讨论】:

            【解决方案13】:

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

            Arduino Nano™ ATmega328 *

            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


            * 使用正版 Arduino Nano™只要。当心counterfeits

            更新:小型ATtinywireless 微控制器也可用。

            【讨论】:

            • 反对票是怎么回事?这是一个全面的答案。请提供批评。
            • 可能的一个原因是您的回答似乎没有解决 OP 的问题。他没有问如何“让 LED 闪烁”——他问的是如何关闭 USB 端口。你的回答没有解决这个问题。
            • 答案是 - 您无法关闭 USB 端口。只有智能集线器允许您关闭 USB 引脚电源。 USB 供电的微控制器允许您拥有任意数量的 GPIO 开关。闪烁也只是反复切换电源(开/关)。
            猜你喜欢
            • 2014-07-25
            • 2020-05-03
            • 1970-01-01
            • 2010-12-27
            • 2018-03-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多