代码之家  ›  专栏  ›  技术社区  ›  Stéphane

关闭USB端口的电源

  •  4
  • Stéphane  · 技术社区  · 8 年前

    我在找一个转弯的方法 权力 关闭(然后再打开)USB端口。解决方案可以是C、bash等。我使用的BeagleBone运行的是32位Ubuntu 16.04,用于armhf。

    > uname -srvm
    Linux 4.4.6-ti-r15 #1 SMP Tue Apr 5 12:32:22 UTC 2016 armv7l
    

    我在StackOverflow和AskUbuntu上尝试了很多讨论过的东西,包括:

    #include <linux/usbdevice_fs.h>
    
    int main(void)
    {
        int fd = open( "/dev/bus/usb/001/002", O_WRONLY );
        if (fd < 0) return 1;
    
        int rc = ioctl( fd, USBDEVFS_RESET, 0 );
        if (rc < 0) return 2;
    
        close( fd );
        return 0;
    }
    

    我需要关闭(并最终重新打开)的USB设备是Champtek FS310条码读取器,当我运行lsusb时,它会显示为磁卡条读取器:

    > lsusb
    Bus 001 Device 002: ID 040b:6543 Weltrend Semiconductor Manhattan Magnetic Card Strip Reader
    Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
    
    > lsusb -t
    /:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=musb-hdrc/1p, 480M
        |__ Port 1: Dev 2, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M
        |__ Port 1: Dev 2, If 1, Class=Human Interface Device, Driver=usbhid, 1.5M
    

    我发现运行这两个命令会导致设备关闭:

    echo "1-1" > /sys/bus/usb/drivers/usb/unbind
    echo "1-1" > /sys/bus/usb/drivers/usb/bind
    

    奇怪的是,它只在“绑定”期间关闭,而不是“解除绑定”。但一旦它以这种方式关闭,我找到的唯一打开它的方法就是重新启动计算机,这不是一个可用的解决方案。

    1 回复  |  直到 8 年前
        1
  •  3
  •   Stéphane    8 年前

    事实上,另一个问题确实有一种技巧,可以解决我想要解决的问题。请注意,这不是一个通用的Linux解决方案,它只适用于BeagleBone Black和类似设备。(我在BeagleBone Green上测试)从 devmem2 例如,此C++代码块关闭USB电源,然后重新打开:

    const size_t page_size_in_bytes = getpagesize();
    const size_t address_gpio3_13   = 0x47401c60; // see comment below
    const size_t address_start      = address_gpio3_13 / page_size_in_bytes * page_size_in_bytes;
    const size_t address_offset     = address_gpio3_13 - address_start;
    
    int fd = open("/dev/mem", O_RDWR);
    void *addr = mmap( 0, page_size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, fd, address_start );
    
    uint8_t *byte_ptr = reinterpret_cast<uint8_t*>(addr);
    
    byte_ptr[address_offset] = 0x00;    // turn off USB
    std::this_thread::sleep_for( std::chrono::milliseconds(500) );
    byte_ptr[address_offset] = 0x01;    // turn on USB
    
    munmap( addr, page_size_in_bytes );
    
    close(fd);
    

    (不包括错误处理。)

    神奇的数字 0x47401c60 真的是一个神奇的数字。根据一些帖子,似乎需要签署NDA才能访问一些USB相关文档。在《ARM335X技术参考手册》中,第156页仅提及0x47401Cxx地址空间:

    Block Name    Start Address    End Address
    USB1 Core     0x4740_1C00      0x4740_1FFF