/var/log/messages

Sep 30, 2014 - 6 minute read - Comments - Linux

bcm2708_gpio_probe 手続き (2)

自分がササッてる bus に接続されているデバイスを順にとりだして __device_attach 手続きを呼び出している、のかどうか。引数として手続きに渡されるのは

  • next_device から取得できる struct device オブジェクト
  • driver_attach に渡される struct device_driver オブジェクト

になっている模様。next_device という手続きによれば

  • klist_next により struct klist_iter 型の引数から struct klist_node オブジェクトを取得
  • to_device_private_bus により struct device_private オブジェクトを取得
  • struct device_private オブジェクトの device 属性を戻す

形になっています。container_of 使って struct device_private なオブジェクトのアドレスを引っ張ってきて、なのか。

この struct device_private は何なのか、ということでコメントを見てみるに以下とのこと。

  • struct device_private - structure to hold the private to the driver core portions of the device structure.

うーん、そもそもこの構造体の役割が理解できてないのでそっちから見てみます。

struct device_driver 型 と struct device 型

何が違うのか。struct device_driver は The basic device driver structure で struct device は The basic device structure とのこと。ぐぬぬ。

struct device_driver 型は

  • 関数ポインタな属性があります。
  • struct bus_type 型のポインタ
  • なんとなくリストとは無縁に見える

struct device 型は

  • 階層関係なポインタ
  • struct kobject 型の属性
  • struct device_driver 型のポインタ
  • struct bus_type 型のポインタ
  • struct klist_node 型の属性

デバイスは同じ型のソレが複数 attach されてることもあり得る、ということか。

それを踏まえて再度確認。

__driver_attach 手続きです。記述としては

  • driver_match_device が 0 を戻す場合は return 0
  • 引数で渡された struct device オブジェクトに親がいるようであれば親を device_lock
  • 引数で渡された struct device オブジェクトを device_lock
  • 引数で渡された struct device オブジェクトの driver 属性が未設定の場合は driver_probe_device 手続きを呼び出す
  • unlock 操作 (親含め)

で、driver_match_device 手続きの定義が以下になってまして

{% gist 360e94aba9277c3621db %}

drv->bus->match が NULL なら 1 が戻ります (return しない)。また、struct bus_type 型の bus ってポインタがさしてるオブジェクトの match 属性は手続きポインタになってますね。定義なコメントが以下です。

 * @match:	Called, perhaps multiple times, whenever a new device or driver
 *		is added for this bus. It should return a nonzero value if the
 *		given device can be handled by the given driver.

なんというかそのまんまですね。NULL 値だったとしても can be handled 認定なのがアレです。

もう一つは driver_probe_device です。ここから呼ばれてる really_probe が核心と見てここのみ掘削。

  • 引数で渡された struct device オブジェクトの driver 属性に引数で渡された struct device_driver オブジェクト設定
  • driver_sysfs_add 手続き呼び出し
  • 引数で渡された struct device オブジェクトの bus->probe が NULL でなければこちらを呼び出す
  • 上記関数ポインタが NULL 値で引数で渡された struct device_driver オブジェクトの probe が NULL でなければこちらを呼び出す

なのか。とりあえず driver_sysfs_add を見てみます。sysfs_create_link 手続きで

  • 引数 dev の kobj 属性
  • 引数 dev の driver 属性の p 属性の kobj 属性

を互いに link しあってるのか、あるいは片側から片輪へ、なのか。確認してみるに正常なら 0 を return なのでお互いに、なのかなぁ。実機で確認してみるに

  • /sys/bus/platform/devices/bcm2708_gpio は /sys/devices/platform/bcm2708_gpio への symlink
  • /sys/bus/platform/drivers/bcm2708_gpio/bcm2708_gpio は /sys/devices/platform/bcm2708_gpio への symlink

や、違うなこれ。お互いに、ではないぞ。よくよく見てみるに以下なのか。

  • /sys/devices/platform/bcm2708_gpio/driver は /sys/bus/platform/drivers/bcm2708_gpio への symlink
  • /sys/bus/platform/drivers/bcm2708_gpio/bcm2708_gpio は /sys/devices/platform/bcm2708_gpio への symlink

つうことは bcm2708_gpio の場合は

  • device の kobject は /sys/devices/platform/bcm2708_gpio で表現されている
  • driver の kobject (という言い方が正しいのかどうか) は /sys/bus/platform/drivers/bcm2708_gpio で表現されている

ということになるのかな。あら、そーゆー意味ではここに到達するまでに sysfs に登録してる手続きを呼び出してるはずなんだけど、おそらくスルーしてるのだな。

一旦戻って

driver を register してるあたりを確認してみます。

  • bus_add_event から呼び出される driver_create_file で drv->p->kobj で sysfs_create_file しているのを発見

これが /sys/bus/platform/drivers/bcm2708_gpio か。でも device はそれを probe しないと sysfs には登録はされないはずなのではないのかと。

あらら? と言いつつよくよく見てみるに bus_add_driver から呼び出されている kobject_init_and_add という手続きで struct driver_private なオブジェクトの kobj を渡しててその中で create_dir という手続きが呼ばれております。

ちょっとタイム

どうも道に迷いまくっているようです。仕切り直し必要。/sys 配下のファイルの確認から。

  • /sys/class/gpio はデバイスを認識してから作成されるという認識で良いのかどうか
  • /sys/bus/platform/devices/bcm2708_gpio は /sys/devices/platform/bcm2708_gpio への symlink
  • /sys/bus/platform/drivers/bcm2708_gpio/bcm2708_gpio は /sys/devices/platform/bcm2708_gpio への symlink
  • /sys 配下を bcm2708_gpio で grep すると以下なディレクトリが存在する模様
  • /sys/bus/platform/devices/bcm2708_gpio
  • /sys/bus/platform/drovers/bcm2708_gpio
  • /sys/devices/platform/bcm2708_gpio

実は /sys/devices/platform/bcm2708_gpio はデバイス認識していなくてもディレクトリだけは作られてしまうのかな、とか勝手に思っていたり。

sysfs 関連に焦点を当ててざっくり確認

まず、bus_add_driver の中の kboject_init_and_add で struct driver_private の kobj を初期化するのかどうか。その後、create_dir しています。

ここで作られているディレクトリは /sys/bus/platform/drivers/bcm2708_gpio という理解で良いのかな。

その後、bus_add_driver から driver_attach という手続きが呼び出されるが、これは autoprobe なスイッチが入ってる時 (?) のみなのかどうか。bus なリンクリストを手繰って __driver_attach をそれぞれの要素について呼び出している模様。

そしてその driver に match する device を見つけたら driver_probe_device 手続きを呼び出しています。この中で really_probe という手続きが呼び出されていてその中で driver_sysfs_add という手続きが呼び出されています。

ただ、ざっくりな確認だけなんですが bcm2708_gpio については

  • /sys/bus/platform/devices/bcm2708_gpio が /sys/devices/platform/bcm2708_gpio への symlink
  • /sys/bus/platform/drivers/bcm2708_gpio/bcm2708_gpio が /sys/devices/platform/bcm2708_gpio への symlink

という二つだけなんスけど、って思ったらリンクはもひとつありますな。driver という名前だ。二つめの symlink 作成な以下の手続き呼び出しで

        ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
                                "driver");

/sys/devices/platform/bcm2708_gpio/driver が作られるのか。これは /sys/bus/platform/drivers/bcm2708_gpio への symlink です。もう一つの /sys/bus/platform/drivers/bcm2708_gpio/bcm2708_gpio は /sys/devices/platform/bcm2708_gpio への symlink になっています。

成程、って思ったけれどここまでの流れを確認してみるに /sys/devices/platform/bcm2708_gpio を作っていないという認識です。

symlink だからスルーで良くって probe からはるか彼方で呼び出される device_add でファイルが作られて、ってことなのかなぁ。でも device_add で追加されるのって /sys/class/gpio/gpiochp0 とかなはず。

そういった意味では bcm2708_gpio 限定で言うと

  • /sys/bus/platform/devices/bcm2708_gpio
  • /sys/bus/platform/drivers/bcm2708_gpio
  • /sys/devices/platform/bcm2708_gpio

は driver が追加された時に作られないとまずいはず。暫く置いておいて再度確認入れる方向にて。

再開

ええと、driver_sysfs_add で symlink を二つ作っていますが、この時点で /sys/bus/platform/drivers/bcm2708_gpio (dev->bus->p->kobj) および /sys/devices/platform/bcm2708_gpio (dev->kobj) は作成済みになっていないとマズいはず。

この類推を前提に確認入れてみます。

ええと、bus_add_driver から呼び出されている kobject_init_and_add では 別途 dev->p に設定される priv->kobj を渡しているので dev->bus->p->kobj のソレですね。

あら、really_probe を呼び出す driver_probe_device 手続きで device は登録済み、が前提になっていますね。

    if (!device_is_registered(dev))
        return -ENODEV;

定義が以下。

static inline int device_is_registered(struct device *dev)
{
    return dev->kobj.state_in_sysfs;
}

ということはここよりももっと前で sysfs 配下にて create_dir されているのかどうか。それとも driver_attach では device_is_registerd ではないので、なのかどうか。

迷走中ですが Documentation/driver.txt に以下な記述を発見

sysfs


When a driver is registered, a sysfs directory is created in its
bus's directory. In this directory, the driver can export an interface
to userspace to control operation of the driver on a global basis;
e.g. toggling debugging output in the driver.

A future feature of this directory will be a 'devices' directory. This
directory will contain symlinks to the directories of devices it
supports.

/sys/bus および /sys/devices は自動なの? でも /sys/bus/platform/deivers/bcm2708gpio は自分で作ってるな。

そして inode 番号確認してみたら /sys/devices/platform/bcm2708_gpio は 100 番台で /sys/bus/platform/drivers/bcm2708_gpio は 1400 番台でした。

これ、かなり早い段階でデバイス見つけてなんちゃらしてますね。dmesg 見てみるに

bcm2708_gpio: bcm2708_gpio_probe c05cfed0

て何だろ。probe か。あと、inode 番号見てみたときにタイムスタンプも出てたのですが、16 分くらいタイムラグがある。115 ができた 16 分後に 1420 だかができてる的な。あ、これってディレクトリの中のファイルが追加されたりしたらディレクトリエントリも更新されるのだったか。むむむ。

備忘まで

理解しかねている部分を以下に列挙しておきます。

  • kobject_add していない
  • もしかすると kobject_init_and_add が、なのか
  • kobject_init_and_add は bus_add_driver が呼び出している
  • kobject_init_and_add は driver_private な kobj を渡している

なんか色々駄目なカンジなのでやり方を変えてみたいと思います。drivers/base/init.c から見てみるとか (ぇ