コマンドラインからUSBデバイスをリセットするにはどうすればいいですか?

PCから物理的に切り離したり接続したりすることなく、USBデバイスの接続をリセットすることはできますか?

具体的には、デジタルカメラを使用しています。gphoto2」を使用していますが、最近、「デバイスの読み取りエラー」が発生するので、ソフトウェア的に接続をリセットしたいと考えています。

調べてみると、カメラ用のカーネルモジュールは読み込まれていないようです。関連していそうなのは usbhid だけです。

ソリューション

以下を usbreset.c として保存します。

/* usbreset -- send a USB port reset to a USB device */

#include 
#include 
#include 
#include 
#include 

#include 

int main(int argc, char **argv)
{
    const char *filename;
    int fd;
    int rc;

    if (argc != 2) {
        fprintf(stderr, "Usage: usbreset device-filename\n");
        return 1;
    }
    filename = argv[1];

    fd = open(filename, O_WRONLY);
    if (fd < 0) {
        perror("Error opening output file");
        return 1;
    }

    printf("Resetting USB device %s\n", filename);
    rc = ioctl(fd, USBDEVFS_RESET, 0);
    if (rc < 0) {
        perror("Error in ioctl");
        return 1;
    }
    printf("Reset successful\n");

    close(fd);
    return 0;
}

ターミナルで以下のコマンドを実行します。

1.プログラムをコンパイルします。

    $ cc usbreset.c -o usbreset

2.リセットしたいUSBデバイスのBusとDevice IDを取得する。

    $ lsusb
    Bus 002 Device 003:ID 0fe9:9010 DVICO

3.コンパイルしたプログラムを実行可能な状態にします。

    $ chmod +x usbreset

4.sudo権限でプログラムを実行し、lsusbコマンドを実行して得られたのidを必要に応じて置換します。

    $ sudo ./usbreset /dev/bus/usb/002/003

上記プログラムのソース: http://marc.info/?l=linux-usb&m=121459435621262&w=2

解説 (8)

あなたのような状況に陥ったことがないので、十分な効果が得られるかどうかはわかりませんが、私が見つけたUSBデバイスをリセットする最もシンプルな方法は、このコマンドです。(外部アプリは必要ありません)

sudo sh -c "echo 0 > /sys/bus/usb/devices/1-4.6/authorized"
sudo sh -c "echo 1 > /sys/bus/usb/devices/1-4.6/authorized"

libfreenectにはKinectをスリープ状態に戻すためのAPIがないようなので、実際にKinectをリセットするのに使っているものです。これは私のGentooの箱に入っていますが、カーネルは十分に新しく、sysfsに同じパス構造を使用しているはずです。

1-4.6ではないことは明らかですが、デバイスのパスをカーネルのログ(dmesg)から取得するか、lsusb`のようなものを使ってベンダーとプロダクトIDを取得し、次のようなクイックコマンドを使ってパスが異なるベンダー/プロダクトIDのペアにどのように関連しているかをリストアップすることができます。

for X in /sys/bus/usb/devices/*; do 
    echo "$X"
    cat "$X/idVendor" 2>/dev/null 
    cat "$X/idProduct" 2>/dev/null
    echo
done
解説 (10)

これにより、USB1/2/3接続ポート[1]がすべてリセットされます。

for i in /sys/bus/pci/drivers/[uoex]hci_hcd/*:*; do
  [ -e "$i" ] || continue
  echo "${i##*/}" > "${i%/*}/unbind"
  echo "${i##*/}" > "${i%/*}/bind"
done

これで問題は解決すると思います。もし、全てのUSBエンドポイントをリセットしたくない場合は、/sys/bus/pci/drivers/ehci_hcdから適切なデバイスIDを使用することができます。


注意点 [1]: *hci_hcd カーネルドライバは通常、USB ポートを制御します。ohci_hcduhci_hcdは USB1.1 ポート用、ehci_hcdは USB2 ポート用、xhci_hcd` は USB3 ポート用です。(https://en.wikipedia.org/wiki/Host_controller_interface_(USB,_Firewire)参照)

解説 (11)