Ubuntuでデバイスドライバ開発するときの話。
最近のデバイスドライバ開発は、UEFIや度重なるアップデートにより、
何でもありという状況ではなくなっている。
USB-HIDを認識させるところまで、
結構苦労したのでまとめておく。
動作環境
いくつかPC依存の設定を弄るため、動作環境を並べておく。
なお、今回は仮想環境構築ではなく、デュアルブートでの再現である点に注意。
項目 | 説明 |
---|---|
PC | ASUS ExpertBook B1500CEAE(ノートPC) |
OS | Ubuntu 20.04(諸事情あり、最新ではありません) |
周辺機器の操作 | タッチパッド&組み込みキーボード(作業中はUSBを遮断するので、状況に応じてBluetoothなどを使う※1) |
接続するデバイス | LPC1343搭載ボード(※2) |
補足
※1:USBマウスを使える方法があれば教えてください(無線・有線問わず)
※2:この記事で使用したボードをそのまま分解して、USB接続しただけのものです。
セキュアブートに関すること
昨今のデバイスドライバでは、いわゆるバッタ物による情報漏えいやウイルス感染、なりすまし等を防ぐために、
BIOSには、セキュアブートという仕組みが動作している。
従って、通常の条件では、そもそもデバイスドライバの開発が出来ない点に注意しなくてはならない。
※プリントスクリーンではないので画質悪目
BIOSの設定に入り、セキュアブートをOFFにする。
ちなみに、この状態でWindowsやMacのデュアルブートを動かそうとすると、
無事に起動できない点は注意。
コーディング作業
lsusbによるVendorIDとProductIDの調査
基本的にはHIDデバイスとして認識するもの全般で同じことが言えると思います。
このボードは、ARMのCortexシリーズを搭載しているので、同系統であれば同じ動きをする可能性は高い。
なお、この記事では認識だけを試すので、idVendorとidProductだけわかればいい。
lsusb
lsusb -v -s 9
コーディング
デバイスドライバはここを参考に少し派生して組み直した。
私が勉強で使っているUSBデバイスカーネルモジュールのソースコード
Makefile、myBeuatoDriver.cが本体のディレクトリ。
myBeuatoDriver.cに、先程調べたVendorIdとProductIdを貼り付ける。
ビルドするときは、ワークディレクトリでcdで移動して
$ make
としてビルドすると、カーネルモジュールフォーマットファイル(.ko)が作成される。
パーミッション関連
myBeuatoDriver.cの一部に、
struct usb_class_driver skel_class = {
.name = "usb/BeuatoCtrl%d",
.fops = &skel_fops,
.minor_base = MINOR_BASE
};
という表記があり、ここにおける.nameはデバイス名を表す。
この状態でUSBが接続されると、/dev/BeuatoCtrl〜(〜:数字)として登録される(予定である)が、
実はこのままUSBをプラグインすると、パーミッションが600となってしまい、
開発ができなくなる。
そこで、接続されたときに
$ sudo chmod 777 /dev/BeuatoCtrl0
と書いてしまうのも手だが、いちいちこの設定をするのは面倒なので、udevの設定を変える。
/etc/udev/rules.dの設定
$ cd /etc/udev/rules.d
すると、いくつかのudevのデバイス登録時の管理ルールが規定されているのが分かる。
この管理ルールはすべてのファイルが非同期で設定されるが、ユーザの設定としてオリジナルの設定を作ることも可能。
ということで、
$ sudo vim 10-beuato.driver.rules
として、
ATTRS{idVendor}=="1962", ATTRS{idProduct}=="2080", KERNEL=="BeuatoCtrl*", (改行)
ENV{ID_MM_DEVICE_IGNORE}="1", MODE="777"
と追記することで、idVendor, idProductが一定の条件で、カーネルの名前として展開されるものがBeuatoCtrl〜のときは、常にパーミッションが777となるようになる。
なお、ID_MM_DEVICE_IGNOREというのも追加されているが、これはudevデーモンの管理対象外のモジュールとしてください、ということを表すものである。詳しくはこちらなど
HIDデバイスの認識に関すること
udevデーモンを遮断しない場合
普通に接続すると、自動でudevデーモンが働き、
カーネルにhiddevやhidrawと言った名前のデバイスが現れる。
このhiddevやhidrawはudevデーモンの認識機能(usbhid)が働いているために起きる。
このドライバはusbhid由来のものであり、直接ここからUSBでのデータ通信を行うことは出来ない。
udevの一部の動作(usbhid)の遮断
こうしたHIDデバイスの認識を抑制するためには、一時的にusbの自動認識(usbhid)を遮断する必要がある。
ただし、この操作自体はカーネルの動作に重篤な影響を及ぼしかねないので、開発中以外では多用することは望ましくない。
$ sudo rmmod usbhid # usbhidの遮断
※インストールする場合は、以下のサイトを参照にすると回答が書いてある・・・が、今回作ったMakefileがinstallに現状対応させていないので、参考までに・・・。
またこのコマンドを実行すると、HIDデバイスとして認識されているものも同時に停止する。
この例はマウスやキーボードなどであり、影響を及ぼすので注意が必要。
その設定を戻すには、
$ cd /lib/modules/$(uname -r)/kernel/drivers/hid/usbhid
$ sudo insmod usbmouse.ko # USBマウスの復活
$ sudo insmod usbkbd.ko # USBキーボードの復活
usbhidをリビルドしたあとのボードの認識状態(dmesg)
先程の勉強用ソースコードに戻り
$ sudo insmod myBeuatoDriver.ko
と入力し、
改めてUSB抜き差しする。そして、dmesgを使用すると
myBeuatoDriver.cの
skel_probe関数が実行されたことが確認できた。