組み込みLinuxデバイスドライバの作り方 (12)(完)

# 12回目: 作成したデバイスドライバを起動時にロードする

# 本連載について
組み込みLinuxのデバイスドライバをカーネルモジュールとして開発するためのHowTo記事です。本記事の内容は全てラズパイ(Raspberry Pi)上で動かせます。

- [1回目: ビルド環境準備と、簡単なカーネルモジュールの作成](https://qiita.com/take-iwiw/items/1fdd2e0faaaa868a2db2)
- [2回目: システムコールハンドラとドライバの登録(静的な方法)](https://qiita.com/take-iwiw/items/580ec7db2e88beeac3de)
- [3回目: システムコールハンドラとドライバの登録(動的な方法)](https://qiita.com/take-iwiw/items/6b02494a3668f79800e6)
- [4回目: read/writeの実装とメモリのお話](https://qiita.com/take-iwiw/items/26d5f7f4894ccc4ce227)
- [5回目: ラズパイ用のGPIOデバドラの実装](https://qiita.com/take-iwiw/items/cd1d7734c8911830386d)
- [6回目: ioctlの実装](https://qiita.com/take-iwiw/items/ade0a73d4c05fc7961d3)
- [7回目: procfs用インタフェース](https://qiita.com/take-iwiw/items/548444999d2dfdc06f46)
- [8回目: debugfs用インタフェース](https://qiita.com/take-iwiw/items/1ef4b629f9b9bab4d222)
- [9回目: 他のカーネルモジュールの関数を呼ぶ / GPIO制御関数を使う](https://qiita.com/take-iwiw/items/e92a950a2cf57d1a3ded)
- [10回目: I2Cを使ったデバイスドライバを作る](https://qiita.com/take-iwiw/items/dbc544864f0e9873270a)
- [11回目: デバイスツリーにI2Cデバイスを追加する](https://qiita.com/take-iwiw/items/0d13142863d9ed064e41)
- __[12回目: 作成したデバイスドライバを起動時にロードする](https://qiita.com/take-iwiw/items/b9dd02724e83e36dabc3)  <--------------------- 今回の内容__ 


## 今回の内容
これまで、デバイスドライバを作ってきましたが、毎回手動でinsmodしてきました。開発時はこれでもいいかもしれませんが、実際にプロダクトに組み込むときにはカーネル起動時に自動でロードしてもらうようにしたいです。

# 起動時に自動的にロードさせる
## デバイスドライバを正式(?)な場所に配置する
今まで、自分の開発用ディレクトリでビルドして、MyDeviceModule.koファイルを作ってきました。これを、カーネルモジュールの正式な置き場所にコピーします。この場所はカーネルのバージョンによって変わるので、`uname`によって取得します。その後、カーネルモジュールの依存関係情報を更新する必要があります。そのために、`depmod`コマンドを使います。

```bash
sudo cp MyDeviceModule.ko /lib/modules/$(uname -r)/kernel/drivers/.
sudo depmod -ae
```

## 起動時にロードするモジュールに登録する
先ほどのコピーと設定によって、どこからでも`modprobe MyDeviceModule`で作成したデバイスドライバをロードできるようになりました。これを、起動時に実行されるスクリプト(例えばrcスクリプト)に記載すればOKです。色々と環境依存はあると思いますが、ラズパイでは`/etc/modules-load.d/modules.conf`にモジュール名を記載すればいいようです。実際には、他のモジュールとの依存関係や、製品仕様上どれくらい早くロードしてほしいか、などを考慮して決めるのだと思います。

```
sudo bash -c 'echo MyDeviceModule >> /etc/modules-load.d/modules.conf'
```

## 確認する
再起動してdmesgでログを見ると、起動時に本デバイスドライバがロードされていることが分かります。

```
dmesg
[    7.595531] sd 0:0:0:0: Attached scsi generic sg0 type 0
[    7.955417] usb 1-1.3: reset high-speed USB device number 4 using dwc_otg
[    8.097012] ieee80211 phy0: rt2x00_set_rt: Info - RT chipset 5390, rev 0502 detected
[    8.124187] MyDeviceModule: loading out-of-tree module taints kernel.
[    8.131765] mydevice_i2c_probe
[    8.131785] slave address = 0x18
[    8.132270] id = 0x33
[    8.173190] ieee80211 phy0: rt2x00_set_rf: Info - RF chipset 5370 detected
[    8.224829] ieee80211 phy0: Selected rate control algorithm 'minstrel_ht'
[    8.231902] usbcore: registered new interface driver rt2800usb
[   11.534982] Adding 102396k swap on /var/swap.  Priority:-1 extents:1 
```

## デバイスツリー対応デバドラの場合
前回作成した、デバイスツリー対応したデバイスドライバの場合、`/etc/modules-load.d/modules.conf`を編集して明示的にロードしないでも、カーネルが自動でMyDeviceModule.koをロードしてくれます。これは、デバイスツリーに登録されたデバイスに対応するデバイスドライバを、カーネルが自動的に探してロードしてくれるためだと思われます。


# __本連載の__ おわりに
やっと、終わった！！ 今年中に終えられて良かった～

何故か急に思い立って、これまで約10日間、全12回でLinuxデバイスドライバについての記事を投稿してきました。自分を含めて、初心者の方が実際に試しながら理解できるような内容にしてきたつもりです。というか、初心者の自分がこの2週間で勉強してきた内容の記録です。

そのため、色々と抜けている部分があるかと思います。例えば、変数アクセスするときには排他制御をすべきですが、省略しました。また、アドレス変換する前には、そのアドレスにアクセスできるかどうかのチェックをすべきですが、それも省略しまいた。これらは、コードや説明を分かりやすくするために敢えて省略しました。しかしそれ以外にも、僕の知識力、理解力不足で抜けている、間違っている点も多々あると思います。コメントなどでどんどんご指摘いただければと思います。

本連載で説明してきた内容はLinuxデバイスドライバのほんの一部にすぎません。また、実装方法やルールは日々変わっています。最新情報を正しく理解するためには、やはりLinuxのソースコードやドキュメントを読む必要があります。本連載が、そういった次の一歩を踏み出すための足がかりになれば幸いです。

最後に、「Linuxデバイスドライバプログラミング」を執筆なさった 平田 豊 さんに深く感謝を申し上げます。ソースコード読め、ドキュメント読め、とはよく言われますが、最初のとっかかりには日本語で分かりやすく解説されている書籍は非常に重宝しました。

http://elixir.free-electrons.com/linux/v4.14/source 
https://people.freedesktop.org/~narmstrong/meson_drm_doc/index.html