hidrawとlibusbは何が違う?LinuxでHID機器を扱う仕組みを整理
Linux で USB 接続のキーボードやマウス、ゲームパッドなどを扱っていると、次のようなものが登場します。
/dev/hidraw0
/dev/bus/usb/001/005
libusb
HID Report
Interrupt Transfer
最初は、
hidrawと/dev/bus/usbは何が違うのか?
1台のUSB機器に対してどちらか一方が使われるのか?
という点が分かりにくいと思います。
結論からいうと、USB接続のHID機器では /dev/bus/usb/... と /dev/hidrawX の両方が存在することがあります。
両者は競合する別方式というより、同じUSB機器を異なるレイヤーから扱うための入口です。
この記事では、HID、HIDレポート、hidraw、/dev/bus/usb、libusb、USBの転送方式について整理します。
1. HID 機器とは
HID(Human Interface Device)は、主に人とコンピューターの間で操作情報などをやり取りするためのデバイス規格です。
代表的なものには次があります。
- キーボード
- マウス
- ゲームパッド
- タッチパッド
- ペンタブレット
「HID = 入力機器」と考えると大まかには分かりやすいですが、厳密には入力だけではありません。
HIDでは、デバイスからPCへ送られる情報だけでなく、PCからデバイスへ送る情報も扱えます。
たとえばキーボードの Caps Lock LED の制御なども、HIDの仕組みで行われることがあります。
2. HID レポートとは
HID機器では、機器の状態などを**HIDレポート(HID Report)**というバイナリデータでやり取りします。
たとえば、次のような情報です。
- 押されているキー
- マウスの移動量
- ボタンの状態
- ゲームパッドのスティックの傾き
- LED の状態
HIDレポートには主に次の3種類があります。
Input Report
デバイスからPCへ送られるデータです。
例:
キーボード → 押されているキー
マウス → 移動量、ボタン状態
ゲームパッド → スティックやボタンの状態
Output Report
PCからデバイスへ送るデータです。
たとえば、
PC → キーボード
に Caps Lock LED の状態を送る、といった用途があります。
Feature Report
デバイスの設定値などを読み書きするために利用されます。
通常のキー入力のように継続的に送られるデータとは少し性質が異なり、機器固有の設定などで利用されます。
3. hidraw とは
hidraw は、LinuxでHIDレポートをユーザー空間のプログラムから直接扱うためのインターフェースです。
たとえば次のようなデバイスファイルとして見えます。
/dev/hidraw0
/dev/hidraw1
/dev/hidraw2
アプリケーションはこれらを open() して、read() や write()、ioctl() などを使ってHID機器と通信できます。
hidraw の特徴
- HID機器を扱うためのインターフェース
- HIDレポートを直接読み書きできる
- Linuxの input subsystem によるキーイベントなどへの変換前のデータを扱える
たとえば通常のキーボードでは、LinuxがHIDレポートを解釈して、
HID Report
↓
Linux HID driver
↓
Linux input subsystem
↓
KEY_A が押された
といった入力イベントに変換します。
一方 hidraw を利用すると、
HID Report
↓
/dev/hidraw0
↓
アプリケーション
という形で、HIDレポートそのものをユーザー空間から扱えます。
4. /dev/bus/usb とは
LinuxではUSBデバイスが、次のようなパスでも見えます。
/dev/bus/usb/001/005
これは、
USBバス番号 001
USBデバイス番号 005
を意味します。
/dev/bus/usb は、HID専用ではありません。
USBデバイスそのものをUSBレベルで扱うための低レベルなインターフェースです。
そのため対象には、
- HID
- USBメモリ
- プリンター
- USBシリアル変換器
- 独自USBデバイス
など、USB機器全般が含まれます。
一般的なアプリケーションが /dev/bus/usb/... を直接操作することは少なく、通常は libusb などのライブラリを利用します。
5. hidraw と /dev/bus/usb はどちらか一方なのか
ここが重要なポイントです。
どちらか一方だけが作られる、という関係ではありません。
USB接続のHID機器の場合、同じ物理デバイスに対して両方が存在することがあります。
たとえばUSBマウスなら、概念的には次のようになります。
USBマウス
│
├─ /dev/bus/usb/001/005
│ USBデバイスとしての入口
│
└─ /dev/hidraw0
HIDとしての入口
つまり、
/dev/bus/usb/...
は、
この機器を「USBデバイス」として扱う入口
です。
一方、
/dev/hidrawX
は、
この機器を「HIDデバイス」として扱う入口
です。
同じ機器を、違うレイヤーから見ていると考えると分かりやすいです。
6. USB → HID → hidraw という関係
USB接続のHID機器は、概念的には次のような階層になっています。
物理USB機器
↓
USB
↓
USB Interface
↓
HID
↓
HID Report
↓
hidraw
↓
アプリケーション
一方、libusbを使う場合は、よりUSBに近いレイヤーから操作します。
物理USB機器
↓
USB
↓
/dev/bus/usb/...
↓
libusb
↓
アプリケーション
したがって、かなり大雑把に表現すれば、
USB機器
│
┌────────┴────────┐
│ │
USBとして扱う HIDとして扱う
│ │
/dev/bus/usb/... HID driver
│ │
libusb /dev/hidrawX
│ │
アプリケーション アプリケーション
という関係になります。
7. 1台のUSB機器から複数の hidraw が作られることもある
さらに、USBでは1台の物理デバイスが複数のインターフェースを持つことがあります。
これをUSB複合デバイス(Composite Device)と呼びます。
たとえば、1台のデバイスが、
Interface 0 : キーボード
Interface 1 : マウス
Interface 2 : 独自機能
を持っていることがあります。
この場合、概念的には、
USBデバイス
│
├─ Interface 0
│ └─ HID
│ └─ /dev/hidraw0
│
├─ Interface 1
│ └─ HID
│ └─ /dev/hidraw1
│
└─ Interface 2
└─ 独自USB通信
のようになります。
USBデバイス全体としては、
/dev/bus/usb/001/005
という1つのUSBデバイスとして見えていても、HID側では複数の hidraw デバイスとして見えることがあります。
そのため、
1 USBデバイス = 1 hidraw
とは限りません。
8. hidraw と libusb を同時に使えるのか
デバイスファイルとして、
/dev/hidraw0
と
/dev/bus/usb/001/005
の両方が存在していても、
同じUSBインターフェースを両方から自由に操作できるとは限りません。
理由は、LinuxのカーネルドライバがUSBインターフェースを使用していることがあるためです。
たとえばHID機器では、
USB Interface
↓
Linux HID driver
↓
hidraw
という状態になっています。
このとき hidraw からHIDレポートを扱うことはできます。
一方、libusbから同じインターフェースを直接操作しようとすると、LinuxのHIDドライバがすでにそのインターフェースを使用しているため、libusb側でインターフェースを claim できない場合があります。
概念的には、
USB Interface
│
┌─────────┴─────────┐
│ │
Linux HID driver libusb
│
hidraw
のような状態です。
libusbでそのインターフェースを占有して通信する必要がある場合は、カーネルドライバを一時的にdetachすることがあります。
ただし、カーネルドライバをdetachすると、そのドライバが提供していた通常のHID機能も利用できなくなる可能性があります。
そのため、HIDレポートを扱いたいだけであれば、一般的には hidraw のほうが扱いやすいケースがあります。
9. libusb とは
libusb は、ユーザー空間のプログラムからUSBデバイスを直接操作するための汎用ライブラリです。
Linuxでは /dev/bus/usb/... などを通してUSBデバイスへアクセスします。
libusbでは、たとえば次のような処理ができます。
- USBデバイスの列挙
- Vendor ID / Product ID の取得
- Descriptor の取得
- Configuration の操作
- Interface の claim
- 制御転送
- バルク転送
- インタラプト転送
- アイソクロナス転送
- 非同期I/O
libusbはHID専用ではありません。
USBプロトコルのレベルで通信したい場合に利用できる汎用ライブラリです。
10. hidraw と libusb の使い分け
単純化すると、次のように考えられます。
hidraw が向いている場合
HID機器のHIDレポートを扱いたい場合です。
HID機器
↓
HID Report
↓
hidraw
↓
アプリケーション
たとえば、
- 独自HIDデバイス
- ゲームパッド
- HIDベースの制御機器
- Feature Report の読み書き
などです。
libusb が向いている場合
USBプロトコルそのものを操作したい場合です。
USBデバイス
↓
USB Transfer
↓
libusb
↓
アプリケーション
たとえば、
- 独自USBプロトコルのデバイス
- USBインターフェースを直接操作したい
- Endpointを指定して通信したい
- HID以外のUSB機器を扱いたい
場合などです。
11. USB の転送方式とは
USBでは用途に応じて、4種類の転送方式が定義されています。
Control
Bulk
Interrupt
Isochronous
それぞれ用途が異なります。
制御転送(Control Transfer)
USBデバイスの設定や情報取得などに使われます。
主な用途は、
- Descriptor の取得
- Configuration の設定
- デバイスへの問い合わせ
- デバイス固有の制御
などです。
すべてのUSBデバイスが持つ Endpoint 0 を使って通信します。
USBデバイスを制御するための基本的な転送方式です。
バルク転送(Bulk Transfer)
比較的大量のデータを、正確に転送することを重視する場合に使用されます。
特徴は、
- 比較的大量のデータに向いている
- エラー時には再送される
- 転送時間の保証はない
という点です。
例として、
- USBストレージ
- プリンター
- USBシリアル機器
などがあります。
インタラプト転送(Interrupt Transfer)
少量のデータを、一定の応答性を確保しながら定期的にやり取りする用途に向いています。
代表例は、
- キーボード
- マウス
- ゲームパッド
です。
HID機器では特によく利用されます。
なお、「Interrupt」という名前ですが、
デバイスが好きなタイミングでCPUに割り込みを発生させる
という意味ではありません。
USBでは基本的にホスト側が通信を開始します。
ホストコントローラが一定間隔で対象Endpointに対して通信機会を与える仕組みになっています。
アイソクロナス転送(Isochronous Transfer)
一定時間内に継続的にデータを送ることを重視する転送方式です。
たとえば、
- USBオーディオ
- Webカメラ
- 動画ストリーミング
などで利用されます。
特徴は、
エラー時の再送よりもリアルタイム性を優先する
ことです。
音声や映像では、少し前のデータを再送するより、次のデータを時間どおり送ったほうが重要だからです。
12. 非同期 I/O はUSB転送方式ではない
libusbを調べていると「非同期転送」という言葉もよく登場します。
ただし、
Control
Bulk
Interrupt
Isochronous
と、
同期
非同期
は別の分類です。
Control / Bulk / Interrupt / Isochronous は、
USB上でどのような性質の通信をするか
を表します。
一方、同期 / 非同期は、
アプリケーションがその通信の完了をどのように待つか
という違いです。
同期処理
同期処理では、
転送開始
↓
完了するまで待機
↓
次の処理
となります。
転送が完了するまで、その処理は戻ってきません。
非同期処理
非同期処理では、
転送を要求
↓
別の処理を続ける
↓
転送完了
↓
コールバックなどで通知
という動作ができます。
libusbでは非同期APIも提供されており、複数のUSB転送を効率よく処理する場合などに利用できます。
全体の関係
ここまでをまとめると、次のようになります。
USBデバイス
│
├─ USBとして直接扱う
│ │
│ ├─ /dev/bus/usb/...
│ │
│ └─ libusb
│
└─ HIDとして扱う
│
├─ Linux HID driver
│
├─ HID Report
│
└─ /dev/hidrawX
さらにUSB通信そのものには、
Control
Bulk
Interrupt
Isochronous
という4種類の転送方式があります。
そして、
同期I/O
非同期I/O
は、それらの転送をアプリケーションからどのように実行・待機するかという別の概念です。
一言でまとめると
-
HID機器
人とコンピューターの操作・情報交換に利用されるデバイス規格 -
HIDレポート
HID機器とPCの間でやり取りされるバイナリデータ -
hidraw
LinuxでHIDレポートを直接扱うためのインターフェース -
/dev/bus/usb
LinuxでUSBデバイスをUSBレベルから扱うためのインターフェース -
libusb
USBデバイスをユーザー空間から扱うための汎用ライブラリ -
Control / Bulk / Interrupt / Isochronous
USBで定義されている4種類の転送方式 -
非同期I/O
USB転送の種類ではなく、転送完了を待たずに処理を進めるプログラミング方式
そして最も重要なのは、
hidrawと/dev/bus/usbは二者択一ではない
という点です。
USB接続のHID機器では、同じ物理デバイスに対して、
/dev/bus/usb/...
と
/dev/hidrawX
の両方が存在することがあります。
両者は、
USBとして見るか
HIDとして見るか
というレイヤーの違いだと理解すると、LinuxにおけるUSB/HID周りの仕組みがかなり整理しやすくなります。