HID のドキュメントは Documentation/hid 以下にあります。HID の全体図は Documentation/hid/hid-transport.txt にあります。

USB の場合で全体図のブロックとファイルの対応を見ていきます。"I/O Driver" が USB core drivers/usb/coredrivers/usb/core/message.c が主に該当します。"Transport Driver" が drivers/hid/usb/hid-core.c に該当します。"HID Core" が drivers/hid/hid-core.c (こちらも hid-core.c という名前なので要注意) に該当します。キーボードやマウスの場合は "Generic Driver" が drivers/hid/hid-generic.c に該当します。

drivers/hid/hid-generic.c の実装をみると殆ど何もしていません。Report Descriptor の解釈、Report を input event に変換する処理は "HID core" を構成する drivers/hid/hid-core.c, drivers/hid/hid-input.c で行われています。Application と直接 I/O する処理は drivers/hid/hidraw.c, drivers/hid/uhid.c で行われています。

ノート: USB HID device のうち Boot Interface Subclass デバイス専用のドライバ drivers/hid/usbhid/usbkbd.cdrivers/hid/usbhid/usbmouse.c があります。これらは input class device として動作します。Linux kernel 内では HID class device (あるいは driver) ではありません。

USB device の場合における HID class driver の機能ブロック

ブロック主なファイル機能
I/O Driverdrivers/usb/coredrivers/usb/core/message.cハードウエア入出力をする
Transport Driverdrivers/hid/usbhid/hid-core.cハードウエア入出力をデバイスのバスに依存しない様に抽象化する
HID Coredrivers/hid/hid-core.c
drivers/hid/hid-input.c
Report Descriptor を解釈する
Report を input event に変換する
HID class driver を登録・削除する
HID class device を登録・削除する
Generic Driverdrivers/hid/hid-generic.c殆ど何もしないドライバ、HID Core の機能で十分な場合に使う
Custom Driverdrivers/hid-*特別な対応が必要なデバイスのドライバ

HID class を扱う "HID core" drivers/hid/hid-core.c は HID class driver を登録・削除する機能、HID class device を登録・削除する機能も有しています。

HID class driver は 2 層に分かれています。一つは "Transport Driver" もう一つは "Custom Driver" です。

"Transport Driver" (struct hid_ll_driver)は I2C, bluetooth, USB の場合はあらかじめ用意されています。Hyper-V 仮想環境内の外界インターフェースドライバ、User space I/O driver (uhid) ドライバも存在します。

BUSstruct hid_ll_driver の実装
I2Ci2c_hid_ll_driver
bluetoothhidp_hid_driver
USBusb_hid_driver
Hyper-Vmousevsc_ll_driver
uhiduhid_hid_driver

struct hid_ll_driver のメンバとそのラッパー関数の関係は次のようになっています。詳細な調査は後回しにします。

メンバ(メソッド)説明ラッパ関数HID Core 内部使用
startstart underlaying HWhid_hw_start()hid_device_probe()
stopstop underlaying HWhid_hw_stop()hid_device_remove()
opensignal underlaying HW to start delivering eventshid_hw_open()hidinput_open()
closesignal underlaying HW to stop delivering eventshid_hw_close()hidinput_close()
powerrequests underlying HW to go into given power modehid_hw_power()
parsethis method is called only once to parse the device datahid_add_device()
requestsend report request to devicehid_hw_request()
waitwait for buffered io to completehid_hw_wait()
raw_requestsend report request to devicehid_hw_raw_request()hidinput_led_worker(), hidinput_led_worker()
output_reportsend output report to devicehid_hw_output_report()
idlesend idle request to devicehid_hw_idle()
hid_device メンバ(メソッド)機能
hiddev_connect
hiddev_disconnect
hiddev_hid_event
hiddev_report_event
メンバ (メソッド)説明HID Core 内部の呼び出し元(一部は Transport Driver)
probenew device insertedhid_device_probe()
removedevice removed (NULL if not a hot-plug capable driver)hid_device_remove()
report_tableon which reports to call raw_event (NULL means all)hid_match_report() hid_input_report() この中で raw_event の呼び出し判定をしている。
raw_eventif report in report_table, this hook is called (NULL means nop)hid_input_report()
usage_tableon which events to call event (NULL means all)hid_match_usage() &ogdef(hid_process_event(),hid_process_event); この中で event の呼び出しを判定している
eventif usage in usage_table, this hook is called (NULL means nop)hid_process_event()
reportthis hook is called after parsing a report (NULL means nop)hid_report_raw_event()
report_fixupcalled before report descriptor parsing (NULL means nop)hid_open_report()
input_mappinginvoked on input registering before mapping an usagehidinput_configure_usage()
input_mappedinvoked on input registering after mapping an usagehidinput_configure_usage()
input_configuredinvoked just before the device is registeredhidinput_connect()
feature_mappinginvoked on feature registeringreport_features()
suspendinvoked on suspend (NULL means nop)usbhid hid_suspend() i2c_hid_suspend()
resumeinvoked on resume if device was not reset (NULL means nop)hid_resume_common()
reset_resumeinvoked on resume if device was reset (NULL means nop)usbhid hid_reset_resume() i2c_hid_resume()

HID class device の登録と HID class driver の関係を見ていきましょう。

HID class driver struct hid_driver に probe 関数を指すメンバがあります。これは珍しいことです。しかも、実装は必須ではありません。USB, bluetooth, I2C, 他 接続にて HID device と認識し、HID class device として hid_allocate_device(), hid_add_device() にて登録すると、hid_ignore() によって振るい分けられます。

hid_bus_match() で細かく行います。

hid_ignore() は HID class device のうち HID として扱わないデバイスか照合し、hid_add_device() をエラーにします。

hid_device_probe() が呼ばれ、この中で driver が未対応ならば hid_match_device() を呼び出し適切なドライバと対応付け、probe を呼び出します。

ノート: hid_device_probe() が呼び出された時点でドライバが未対応なのが多くの場合です。対応済みなのは hyperv(drivers/hid/hid-hyperv.c) mouse ドライバの場合だけです。

クラスドライバは接続されたデバイスと通信する機能を struct hid_ll_driver に格納した関数ポインタを介して抽象化し、デバイスを probe する(デバイスの機能を確認して初期化し必要なメモリなどのリソースを確保する)役割を担っています。

USB HID デバイスを例として見ていきます。USB HID ドライバのコアは drivers/hid/usbhid/hid-core.c です。ここでは USB デバイスのドライバとして usb_register() (対は usb_deregister()) を使って登録します。struct usb_driver の id_table は HID interface です。USB デバイスを probe する処理 usbhid_probe() で、hid_allocate_device(), hid_add_device() (対は hid_destroy_device()) を使って USB デバイスを HID class デバイスとして登録します。

usbhid_probe() で行われる HID デバイス登録は巧妙です。struct hid_device 構造体の ll_driver メンバーに USB pipe 通信処理を抽象化する関数群を保持した構造体 struct hid_ll_driver を指すポインタを格納しています。

hid_bus_match() にて行われるデバイスとドライバの突き合わせ処理が行われません。

Game Controller や HID 様式の入出力デバイスは USB の VendorID, ProductID で識別します。HID_USB_DEVICE() マクロで識別用のテーブルを作成します。識別用のテーブルを伴った struct hid_driverhid_register_driver(), (対は hid_unregister_driver()) または module_hid_driver() で HID クラスドライバとして登録します。


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS