LinuxのUIO(User space I/O) その2

More than 1 year has passed since last update.

前回の続き


デバイスツリーを使わずにUIOを使用する方法

peri_pmcという名のレジスタを0x120a0000からの4KBをユーザー空間からアクセス可能にします。

その情報をセットしてuio_pdrv_genirqのドライバを登録するだけです。

そのコードの全体はgistに貼りました。ここ

要点は以下の部分です。

実質的にplatform_device_register()を呼びだすだけです。

static struct uio_info mydev_mem = {

.name = "my_device",
.version = "0.1",
.irq = UIO_IRQ_NONE,
};

static struct resource uio_resources[] = {
[0] = {
.name = "peri_pmc",
.start = 0x120a0000,
.end = 0x120a0fff,
.flags = IORESOURCE_MEM,
},
[1] = {
.name = "DUMMY",
.flags = IORESOURCE_IRQ,
},
};

static struct platform_device my_dev = {
.name = "uio_pdrv_genirq",
.id = -1,
.dev = {
.platform_data = &mydev_mem,
},
.resource = uio_resources,
.num_resources = ARRAY_SIZE(uio_resources),
};

static int __init uio_init(void)
{
printk(KERN_INFO "uio_init\n");
return platform_device_register(&my_dev);
}

実際に使用するときには、struct resourceの初期化のところだけを変更すればよいと思います。

このソースをビルドしてカーネルモジュールを作成し、それを insmodコマンドで登録すれば、/dev/uio0 のデバイスファイルが作成されます。

あとは前回の記事と同様です。


注意点


  • 割り込みを使用しない場合は、上記のようにstruct uio_info のirqにUIO_IRQ_NONEするとともに、struct resourceの方にもダミーのIORESOURCE_IRQのエントリが必要です。これが無いとinsmodしたときに、"failed to get IRQ" というメッセージでエラー終了してしまいます。


  • アクセス可能にするメモリ範囲の情報は struct uio_info ではなくて、struct resourceの方に書きます。


  • rmmodするとデバイスを削除することができますが、カーネルのログに"uio_pdrv_genirqのデバイスにreleaseの関数が実装されていない" という旨のエラーメッセージが出ます。



余談

私が最初にUIOを試してみたのは、数年前のカーネル3.0の頃でした。その当時はまだARMのデバイスドライバのデバイスツリー化が必須ではなかったので、この記事のカーネルモジュールの方式でやりました。

最近になって、またUIOを試してみようとしたのですが、当時のコードはもう紛失していて、かすかな記憶を頼りに思い出すのに苦労しました。やっぱりブログに書いておくのがいいですね。

UIOのカーネル内のドキュメント、The Userspace I/O HOWTOは最終更新が2006年12月になっていて、その後の更新が反映されていません。

このドキュメントによると、割り込みを使用せずにメモリのマッピングだけ行いたい場合には"uio_pdrv" というドライバを使用すればよいように書かれています。確かにカーネル3.0の当時はこのドライバは存在しました。

しかし、その後の変更で"uio_pdrv" は削除されてしまっています。おそらくは"uio_pdrv_genirq" でirq=UIO_IRQ_NONE にして使えばよいということだったのでしょう。

その後の変更の履歴は追えていませんが、ARMのデバイスツリーの対応が追加されています。

注意点のところにも書きましたが、uio_pdrv_genirqで割り込みを使用しない場合にはuioinfoのirqをUIO_IRQ_NONEにするだけでは足りなくて、struct resourceの方にもダミーのIORESOURCE_IRQのエントリが必要でした。とてもバグくさい挙動です。

UIO_IRQ_NONEの値は0なのですが、どうやらいろいろな人が建て増し的にコードを追加した結果、uio_infoのirqが0である場合に"割り込みは使用しない"という意味と"割り込みは未設定のため他の情報を参照せよ" の2つの意味がごちゃごちゃになってしまっているようです。

本来なら最新版カーネルでも同様の症状が出るかを確認して、バグをレポートしたいところですが、組み込みLinuxでは簡単に最新のカーネルを動かすことができないのがつらいところです。