Tech と Culture

テクノロジーとカルチャー

Writeハンドラ???

init, exit, open, close と実装ができたので、次は read, write だと思っていろいろ参考書を見ながら、コーディングを始めたのですが、どうも read, writeはバイト単位のアクセスであって、何バイト渡すかを指定するみたいです。
そこまでは、良かったのですが、nバイト渡された時にそのうちの何バイト処理できたかを返り値で返さねばならないようです。
ハードウェアは3バイト単位(Y,Cb,Cr)単位でしか処理ができませんので(もしくは0x00を付加した4バイト)、とりあえず3バイト決めうちのwriteハンドラを書いてみることにしました。
これが、正しいwriteハンドラと呼んでいいのか分かりません。最終的には、IOCTLという関数によって、まとまったデータを受け渡すようにするつもりですので、その前段階の実験のようなものです。
同様に、ハードウェアのレジスタ設定もとりあえず、initの中で決めうちにしました。これも後ほど関数をつくるつもりです。

とりあえず、デバイスドライバ越しに絵を出す実験です。

drv-write1.png

現在使用しているLeon processorはMMUが付いています(MMU無しにコンフィグレーションすることもできます。その場合は、uClinuxを動作させることができます)。
Linuxを動作させるためには、MMUは必須です。
MMU使用しているシステムにおいて、プログラムは仮想アドレスと呼ばれるアドレス上で動作します。これまでモジュールに付けてきたアドレスは物理アドレスと呼ばれるものです。
例: YCbCr-RGB変換モジュールのAHB slave側アドレス 0xA0000000
Linux上では、プログラムは仮想アドレスでやり取りしますが、それを物理アドレスに変換しているものがMMUです。
デバイスドライバはハードウェアとアプリケーションプログラムをつなぐものですので、何らかの方法で物理アドレスをマッピングしなければなりません。それが、 ioremap_nocache の部分で行われています。物理アドレスを変換してvolatile ポインタに渡しています。そしてそのポインタを用いてハードウェアにアクセスします。

drv-write2.png

writeハンドラでは、アプリケーション側から渡されたデータを、initのioremapで取得したvolatileポインタに渡します。その際に、copy_from_userという関数を用いてデータをカーネル空間に渡します。
先ほど述べたように、アプリケーションプログラムは個別の仮想アドレス上で動いています。カーネルも別のアドレス空間で動作しています。カーネルから直接アプリケーションプログラムのアドレスへアクセスすることはできません。この特別な関数によってカーネル空間へコピーします。

driver.jpg

例によって80x80の画像を表示するプログラムから、このデバイスドラバをピクセル毎にコールしてみました。無事に画像が表示されています。本来はreadハンドラも作り、FIFOあふれが無いことを確認してから書き込むつもりなのですが、問題なく表示されました。
その代わり、どうも動作が遅いようです。上から下に書き込まれているのがなんとなく目視で分かります。やっぱり性能的にきついかなー。

それでも、デバイスドライバが動き始めていることが確認できました。