ここでキャラクタ(型)デバイスとはなんぞや、ということです。
Linux ではデバイスはキャラクタ型とブロック型があります。
キャラクタ型が1バイト単位の細かい読み書きが可能なのに対して、ブロック型はブロックというデータの塊を単位に読み書きします。
ブロック型のデバイスは
実行例のところで % で始まる行は一般ユーザでも実行可能、# で始まる行は root でなければ実行できないところです。
なお、とりあえず、メジャー番号(後述)を60にしていますが、もしかすると、ほかのデバイスがこの番号を使っているかも知れません。
念のため、
デバイスの識別にはメジャー番号・マイナー番号がつかわれます。
メジャー番号は登録されたドライバを区別する番号で、マイナー番号はそれぞれのドライバが使える番号です。
たとえば、IDEのデバイスは /dev/hda(ドライブ全部) /dev/hda1(第一パーティション)...
と幾つか種類がありますが、すべてメジャー番号3のデバイスでマイナー番号を0,1,2.. と区別することで、ドライバ側でどこが要求されたかを知ることができます。
マイナー番号を使う例はあとで述べることにします。
次に実行例の説明ですが、モジュールのところでの例に加え、
こまかいことをいうと、実際には read でエラーを起こした段階でrelease されてしまうようです。
また、いくらプロセス側からcloseが呼ばれても、release は一度しかよばれないように、設計されてます(そうでないと困ります:-))。
ここで MOD_INC_USE_COUNT するので、モジュールははずせなくなる。
(もちろん、ほかにもいろいろやってます)
すでに open して得たファイル記述子をつかって アクセスするとLinuxカーネルが read の機能があるかをチェック。
ないのでエラー(EINVAL)を返す。
同じく、close(release)の機能を探して実行。MOD_DEC_USE_COUNT してはずせるようになる。
Linux のバージョンによって微妙に動作が異なりますが、read のすべき仕事は
「コピーした量を return する」
そのようなわけで、データのコピーには特別な手順が必要です。それには以下の関数を使用します。
なお、return する値が 0 の場合、ふつうはデータの終点と見なします。
負の値を返した場合、その絶対値がC言語では errno に設定されます。
読み取りエラーなどの状況を EBUSY, EINVAL などで返すなどの応用が可能です。
あとは前の例とかわりません。つぎは write を組み込みます。
があります。後者のためには、いくつかの手段があります。
(ocrtest_open でフラグを立てて、ocrtest_close でフラグを寝せる)
file->f_posはもともと、ファイルの読み書き位置、すなわち
file->private_dataは自前の作業領域用構造体などを確保した場合に、それを保持しておくためなどに使うことの出来る汎用ポインタです。
これは3つめの対策案に使用できます。
ただ、ポインタとはいえ、所詮は数値なので:-) キャストして流用することは不可能じゃありません。
3つめの方法が正当な方法で、多くのドライバでみられる方法です。
大抵、file->private_dataで情報(へのポインタ)を保持しますが、適当に配列をつくる、という方法もあります。
そのときの目印として、file->f_versionを使用できます。この数字は open するたび異なる数値が設定されるので、識別子としてつかえます。
とりたてて、特別な点はありません。write の場合も受け取ったバイト数を返します。
今回解説した open, close, read, write はいわば、カーネル内部のデバイスドライバと それを利用するユーザ空間のプロセスとの通信手段、といえるでしょう。