LoginSignup
0
0

More than 5 years have passed since last update.

driver側でデバイス認識時にインターフェースを制御する

Posted at

はじめに

デバイス認識時になんやかんやしたい時。通常はudevで色々やればいい話なんですが搭載されていない環境(Androidとか)での制御方法について
せっかくdriverのコードを読んだので覚書

driver動作の流れをざっくり

  • module_initでdriverの処理を登録
  • module_exitでdriverの処理を削除(デストラクタのようなイメージ)
  • その他driverの種類や用途によって登録処理の内容が異なる
    • USBデバイスならmodule_usb_driverとか、module_XXX_driverが多そう
    • これらで関数ポインタを登録して、対応するドライバのアクセスがあったら関数が呼ばれる

特に登録する関数ポインタの中で.probeがデバイス認識時に呼ばれます。

オブジェクト指向の言葉で言い換えると、

module_init⇒コンストラクタ
module_exit⇒デストラクタ
module_XXX_driverで使う構造体(関数ポインタの定義)⇒インターフェースクラス
module_XXX_driver⇒インターフェースクラス実装

って感覚が近い気がします。例えばUSBデバイス系のdriverならusb_driverインターフェース(struct usb_driver)で、以下のように関数を代入することでメソッドを定義する感じ。

static struct usb_driver ax88179_178a_driver = {
        .name =         "ax88179_178a",
        .id_table =     products,
        .probe =        usbnet_probe,
        .suspend =      ax88179_suspend,
        .resume =       ax88179_resume,
        .reset_resume = ax88179_resume,
        .disconnect =   usbnet_disconnect,
        .supports_autosuspend = 1,
        .disable_hub_initiated_lpm = 1,
};

というわけで、デバイス認識時で何かしたい⇒デバイス認識時に呼ばれる.probeでなんやかんやすればいいというわけです。

デバイス認識時にインターフェース制御したい

netdevice.hのint dev_change_flags(struct net_device *, unsigned int);を使います。
第一引数はdriverの関数ポインタの引数で渡ってくるdev構造体を利用。USBデバイスドライバの場合の引数はstruct usb_interface *udevなので、中身を参照する必要があります。
usbnet.cを参考に、こんな感じでnet_deviceを取り出します。

struct usbnet *dev = usb_get_intfdata(intf);
struct net_device * net = dev->net;

後はflagを弄るだけ。flagの定義はioctl、netdeviceのflagと同じです。
今のflagはdev->flagsに詰まっているので、そちらにflag追加するだけ。例えばIFF_UPをor演算で追加すればデバイスがupします。

        unsigned int flags = dev->flags;
        int ret;
        ret = dev_change_flags(dev, flags | IFF_UP);

これで完了。と思いきや

何も考えずにこちらを実行するとこんなエラーログが出ます。RTNL: assertion failed at
ログの原因はASSERT_RTNL。!rtnl_is_locked()の条件に引っかかっています。エラー要因としてはrtnl_lockしてないから。rtnl_lockrtnl_unlockを実行してあげる必要があるようです。

        unsigned int flags = dev->flags;
        int ret;
        rtnl_lock();
        ret = dev_change_flags(dev, flags | IFF_UP);
        rtnl_unlock();

ただ他のdriverコードを見ると、例えばlinux-4.9/drivers/net/vrf.cなんかはrtnl_lock()呼んでないケースもあったり。
どこでlockを読んでるのか、コードを読んだ上で追加が必要ですね。

参考

linux-4.9 driverコード
linux-4.9.tar.gz、
kernelのdriverコード:linux-4.9/drivers/net/usb/usbnet.c, linux-4.9/drivers/net/vrf.c等

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0