#author("2016-09-14T17:30:56+09:00","default:afuruta","afuruta")
* Linux Kernel の見取り図 [#u00e790d]
#ref(Linux_bigmap_for_driver_developer.png);
**標準ライブラリ [#d6fdbada]
Linux Kernel で提供される標準ライブラリはおおよそアプリケーション向けの glibc に近い機能が提供されています。加えてビット操作と kernel 内ならではのアルゴリズム群があります。アルゴリズム群は「こんなのも有るのか」程度に知っておくと良いでしょう。アプリケーション向けに作られたライブラリが移植されていることもあるので、欲しいと思ったら &ogfile(Linux Kernel ソースコード検索,.); から探してみるのも良いでしょう。

要注意なことは、アプリケーションプログラムでは普通に除算 '/'、剰余 '%' 演算子を用いた式を long long 型に対して書けば計算可能なのに対し Linux Kernel 内では &ogfileone(linux/math64.h, include/linux/math64.h); からインクルードされる関数群を使用して関数呼び出し(あるいはマクロ呼び出し)の形で計算する必要があることです。

|機能単位|主なヘッダやソース|備考|h
|型定義|&ogfileone(linux/types.h,include/linux/types.h);&br;|コンパイラは inttypes.h, stdint.h を提供しています。|
|定数、最大、最小|&ogfileone(linux/kernel.h,include/linux/kernel.h);&br;&ogfileone(linux/stddef.h,include/linux/stddef.h);&br;&ogfileone(linux/limits.h,include/uapi/linux/limits.h);&br;&ogfileone(linux/sizes.h,include/linux/sizes.h);|uapi/linux/limits.h は linux/limits.h で include します。|
|構造体オフセット|&ogfileone(linux/stddef.h,include/linux/stddef.h);&br;&ogfileone(linux/kernel.h,include/linux/kernel.h);&br;|メンバーからそれを保持する構造体へ変換するマクロ &ogdefs(container_of(),container_of,include/linux/kernel.h); もここに含めます。|
|文字|&ogfileone(linux/ctype.h,include/linux/ctype.h);|linux/ctype.h は1バイト文字(いわゆるASCII)のみ対応です。|
|文字列・メモリ|&ogfileone(linux/string.h,include/linux/string.h);&br;&ogfileone(linux/glob.h,include/linux/glob.h);&br;&ogfileone(linux/string_helpers.h,include/linux/string_helpers.h);&br;&ogfileone(linux/textsearch.h,include/linux/textsearch.h);&br;&ogfileone(linux/textsearch_fsm.h,include/linux/textsearch_fsm.h);&br;&ogfileone(linux/ihex.h,include/linux/ihex.h);||
|文字列変換|&ogfileone(linux/kernel.h,include/linux/kernel.h);&br;&ogfileone(linux/parser.h,include/linux/parser.h);|linux/kernel.h の中で strtoxxx は kstrtoxxx という関数になっています。たとえば strtoul() は &ogdefs(kstrtoul(),kstrtoul,linux/kernel.h); という関数になっています。|
|書式フォーマット|&ogfileone(linux/kernel.h,include/linux/kernel.h);|&ogdefs(scnprintf(),scnprintf,linux/kernel.h); など|
|計算(数値)|&ogfileone(linux/kernel.h,include/linux/kernel.h);&br;&ogfileone(linux/math64.h,include/linux/math64.h);&br;&ogfile(asm/div64.h,div64.h);&br;&ogfileone(linux/gcd.h,include/linux/gcd.h);&br;&ogfileone(linux/lcm.h,include/linux/lcm.h);&br;&ogfileone(linux/log2.h,include/linux/log2.h);&br;&ogfileone(linux/mpi.h,include/linux/mpi.h);|asm/div64.h は linux/math64.h から include されます。プロセッサ語長が 32 bit の場合、64bit (long long) 型に対して除算または剰余演算子を使うとリンクに失敗します。64bit 除算ライブラリ &ogdefs(do_div(),do_div); などを使用して下さい。|
|計算(ビット)|&ogfileone(linux/bcd.h,include/linux/bcd.h);&br;&ogfile(linux/bitops.h,include/linux/bitops.h);&br;&ogfile(asm/bitops.h);&br;&ogfileone(linux/bitrev.h,include/linux/bitrev.h);&br;&ogfileone(linux/bitmap.h,include/linux/bitmap.h);&br;&ogfileone(asm-generic/bitops/const_hweight.h,include/asm-generic/bitops/const_hweight.h);&br;&ogfile(asm-generic/bitops/ffs.h,include/asm-generic/bitops/ffs.h);&br;&ogfile(asm-generic/bitops/fls.h,include/asm-generic/bitops/fls.h);&br;&ogfile(asm-generic/bitops/find.h,include/asm-generic/bitops/find.h);&hr;&ogfileone(linux/crc-ccitt.h,include/linux/crc-ccitt.h);&br;&ogfileone(linux/crc-itu-t.h,include/linux/crc-itu-t.h);&br;&ogfileone(linux/crc-t10dif.h,include/linux/crc-t10dif.h);&br;&ogfileone(linux/crc16.h,include/linux/crc16.h);&br;&ogfileone(linux/crc32.h,include/linux/crc32.h);&br;&ogfileone(linux/crc32c.h,include/linux/crc32c.h);&br;&ogfileone(linux/crc7.h,include/linux/crc7.h);&br;&ogfileone(linux/crc8.h,include/linux/crc8.h);|asm/bitops.h, asm-generic/bitops/const_hweight.h, asm-generic/bitops/ffs.h, asm-generic/bitops/fls.h, asm-generic/bitops/find.h は linux/bitops.h で include されます。直接 include しないで下さい。&br;bitops.h はプロセッサ毎に定義されています。&br;asm-generic/bitops/const_hweight.h はビットを数え上げる計算です。ファイル名に const がついていますが、即値と変数両方に使えるマクロです。gcc の組み込み関数 __builtin_constant_p() を使用して静的な定数と変数に対する計算をそれぞれ最適化しています。|
|エンディアン変換|&ogfileone(linux/byteorder/generic.h,include/linux/byteorder/generic.h);&br;&ogfileone(linux/swab.h,include/linux/swab.h);|linux/byteorder/generic.h は関数一覧として挙げてあります。実際は各アーキテクチャに最適な変換処理を利用するので &ogfile(asm/byteorder.h); をインクルードします。|
|アルゴリズム|&ogfileone(linux/average.h,include/linux/average.h);&br;&ogfileone(linux/bch.h,include/linux/bch.h);&br;&ogfileone(linux/bpf.h,include/linux/bpf.h);&br;&ogfileone(linux/bsearch.h,include/linux/bsearch.h);&br;&ogfileone(linux/btree.h,include/linux/btree.h);&br;&ogfileone(linux/circ_buf.h,include/linux/circ_buf.h);&br;&ogfileone(linux/cordic.h,include/linux/cordic.h);&br;&ogfileone(linux/kfifo.h,include/linux/kfifo.h);&br;&ogfileone(linux/plist.h,include/linux/plist.h);&br;&ogfileone(linux/range.h,include/linux/range.h);&br;&ogfileone(linux/rbtree.h,include/linux/rbtree.h);&br;&ogfileone(linux/rslib.h,include/linux/rslib.h);&br;&ogfileone(linux/sort.h,include/linux/sort.h);&hr;&ogfileone(linux/crypto.h,include/linux/crypto.h);&br;&ogfileone(linux/cryptohash.h,include/linux/cryptohash.h);&br;&ogfileone(linux/cryptouser.h,include/linux/cryptouser.h);&hr;&ogfileone(linux/hash.h,include/linux/hash.h);&br;&ogfileone(linux/hashtable.h,include/linux/hashtable.h);&br;&ogfileone(linux/jhash.h,include/linux/jhash.h);||
|圧縮|&ogfileone(linux/lz4.h,include/linux/lz4.h);&br;&ogfileone(linux/lzo.h,include/linux/lzo.h);&br;&ogfileone(linux/xz.h,include/linux/xz.h);&br;&ogfileone(linux/zlib.h,include/linux/zlib.h);|おそらくデバイスドライバで積極的に圧縮処理を使うことは無いと思います。圧縮処理が必要だったとして Kernel とアプリケーションの処理分担として適切か検討してみることを勧めます。|
**リンクリスト [#t0fd2a66]
双方向リンクリストを操作するマクロです。リストを辿るループ処理を構成する &ogdefs(list_for_each_entry(),list_for_each_entry,list.h); などの巧妙なマクロが定義されています。
|機能単位|主なヘッダやソース|備考|h
|リスト操作|&ogfileone(linux/list.h,include/linux/list.h);|リンクリストメンバーからそれを保持する構造体へ変換するマクロ &ogdefs(list_entry(),list_entry,include/linux/list.h); は &ogdefs(container_of(),container_of,include/linux/kernel.h); と同じです。リスト操作に関連するならば &ogdefs(list_entry(),list_entry,include/linux/list.h); を使用して下さい。|

**アトミック操作 [#r3bb15b5]
整数とビットに対するアトミック操作の機能群です。Tasklet, Work Queue などを含み、複数のスレッドや割り込みコンテキストと共有する変数、お互いの同期を取るための状態変数を操作するために使用します。ソースコード中で a++ や a |= FLAG_MASK といった式を書いたときに 変数 a は複数スレッドや割り込みコンテキストから参照・更新されるのか常に気にする必要が有ります。もし、参照・更新されるのなら spin_lock やアトミック操作が必要である可能性が高いです。
|機能単位|主なヘッダやソース|備考|h
|整数|&ogfileone(linux/atomic.h,include/linux/atomic.h);&br;&ogfile(asm/atomic.h);|asm/atomic.h はプロセッサ毎に定義されています。asm/atomic.h は linux/atomic.h で include されます。|
|ビット|&ogfile(asm/bitops.h,include/asm/bitops.h);|asm/bitops.h はプロセッサ毎に定義されています。ヘッダファイルに atomic かどうか書かれています。atomic な関数・マクロは &ogdefs(set_bit(),set_bit);, &ogdefs(clear_bit(),clear_bit);, &ogdefs(clear_bit_unlock(),clear_bit_unlock);, &ogdefs(change_bit(),change_bit);, &ogdefs(test_and_set_bit(),test_and_set_bit);, &ogdefs(test_and_set_bit_lock(),test_and_set_bit_lock);, &ogdefs(test_and_clear_bit(),test_and_clear_bit);, &ogdefs(test_and_change_bit(),test_and_change_bit);, &ogdefs(test_bit() atomic 関数と混在可,test_bit); です。asm/bitops.h は linux/bitops.h で include されます。|

**バリア指示・同期 [#u39f4313]
バリア指示 &ogdefs(barrier(),barrier); とバリア同期 &ogdefs(mb(),mb);, &ogdefs(rmb(),rmb);, &ogdefs(wmb(),wmb); の関数またはマクロ定義です。バリア指示はコンパイラに対して、&ogdefs(barrier(),barrier); を超えてメモリアクセス順を変更しないようにします。バリア同期は同期関数の前までに行ったメモリ操作 &ogdefs(mb(),mb);, メモリ読みだし &ogdefs(rmb(), rmb);, メモリ書き込み &ogdefs(wmb(), wmb); を済ませるよう指示します。インラインアセンブラなどによってロート・ストアキューまたはキャッシュに保留されたトランザクションをメモリに反映します。&ogfileone(Documentation/memory-barriers.txt); を参照して下さい。

プラットホーム(SoC 内部に構成された回路ブロックやバス、基板・バックプレーン・インターコネクトで接続されたプロセッサ、チップセット、バスブリッジなどで構成されるアーキテクチャ)によっては各回路(特にバスブリッジやインターコネクト)のリクエストキューにバストランザクションがバリア指示・同期を行っても滞留する場合もあります。プラットホームのデータシートを参照して意図通りにバリア指示・同期ができているか確認して下さい。

|機能単位|主なヘッダやソース|備考|h
|バリア|&ogfile(linux/compiler.h,include/linux/compiler.h);&br;&ogfile(asm/barrier.h,include/asm/barrier.h);|linux/compiler.h は linux/kernel.h より include されます。asm/barrier.h は linux/atomic.h から include されます。|
**排他制御 [#t1c4e07e]
複数の処理を一貫して行いたい場合に使う関数とマクロ群です。Spin Lock は複数のバリエーションがあり、割り込みコンテキストと共に使える機能もあります。ロックを獲得できるまで CPU が Spin (空走ループ)します。短時間で済む処理をロックして行うのに適しています。空走時間が長くなる場合 CPU の処理能力を無駄に消費します。

Semaphore, Mutex は呼び出したプロセスやスレッドなどを中断して他に実行を譲れる状況で使用します。割り込みコンテキストの中から使うことは出来ません。ロックを獲得できないならば、他に実行を譲ります。
|機能単位|主なヘッダやソース|備考|h
|Spin Lock|&ogfileone(linux/spinlock.h,include/linux/spinlock.h);|使い分けのドキュメントは &ogfiledirect(Documentation/locking/spinlocks.txt);, &ogfiledirect(Documentation/DocBook/kernel-locking/index.html); にあります。ドキュメントの冒頭にあるように &ogdefs(spin_lock_irqsave(),spin_lock_irqsave);, &ogdefs(spin_unlock_irqrestore(),spin_unlock_irqrestore); の組が最も汎用的にどんな場所でも使えます。使い分けが難しいと感じるならばこの組み合わせから使ってみて下さい。|
|Semaphore|&ogfileone(linux/semaphore.h,include/linux/semaphore.h);||
|Mutex|&ogfileone(linux/mutex.h,include/linux/mutex.h);|&ogfileone(Documentation/locking/mutex-design.txt);, &ogfileone(Documentation/locking/rt-mutex-design.txt); にドキュメントがあります。|

**同期制御、状態変化待ち [#ucd81709]
条件が成立するまで待つ機能、完了を待つ機能が Kernel にあります。別スレッドや work queue に処理を任せたあと完了を待ったり、割り込みが発生を条件に処理を進める場合に使用します。
|機能単位|主なヘッダやソース|備考|h
|Condition|&ogfileone(linux/wait.h,include/linux/wait.h);|ドキュメントは &ogfiledirect(Wait Queue, Documentation/DocBook/device-drivers/ch01s04.html); です。説明の中に Wait Queue を初期化する関数 &ogdefs(init_waitqueue_head(),init_waitqueue_head); の説明がありません。これはソースコードを見て用法を理解して下さい。初期化が済んだ後の典型的な流れは &ogdefs(wait_event_interruptible(), wait_event_interruptible); で条件待ちをし、条件成立をさせたならば &ogdefs(wake_up(),wake_up); で起床させます。wait_event_*, wake_up_* とも変化型が多くあります目的に合う関数またはマクロを選んで下さい。|
|Completion|&ogfileone(linux/completion.h,include/linux/completion.h);|ドキュメントは &ogfileone(Documentation/scheduler/completion.txt); です。古いドライバでは &ogfileone(linux/semaphore.h,include/linux/semaphore.h); にある &ogdefs(down(),down,semaphore);, &ogdefs(up(),up,semaphore); を使って完了待ち合わせを実現しています。今はこのような実装は書き直されているはずです。|

**割り込みハンドラ登録・設定 [#efcb2796]
デバイスから来る割り込みを受ける関数を登録するための定義群です。ドライバやデバイスが外された時は登録抹消します。割り込みコントローラの制御は SoC ベンダーあるいはボードベンダーによって実装されています。割り込みハンドラに必要最低限の処理は割り込み要因を解消することです。解消しない場合は割り込み処理が再割り込みによって永遠に継続したり、2 度目の割り込みが発生しないなどの事態になります。
|機能単位|主なヘッダやソース|備考|h
|IRQ class|&ogfileone(linux/interrupt.h,include/linux/interrupt.h);|ドキュメントは &ogfiledirect(Documentation/DocBook/genericirq/index.html); です。デバイスドライバでよく使われる &ogdefs(request_irq(),request_irq,interrupt.h); は &ogfileone(Documentation/driver-model/design-patterns.txt); にデザインパターンとして出ています。多くのドライバソースコードを読んで用法を習得できるでしょう。&br;割り込み番号(IRQ number)は SoC ベンダーが開発・実行環境を整備しているならば &ogdefs(gpio_to_irq(),gpio_to_irq); 関数を使ってチップのピン番号から IRQ 番号へ変換します。&ogfileone(linux/gpio.h,include/linux/gpio.h); をインクルードすれば &ogdefs(gpio_to_irq(),gpio_to_irq); を使えるようになります。GPIO (汎用入出力ピン)を識別するマクロ定義は各プラットホーム毎に違うので arch/&span(Alias){processor}; 以下の開発対象に関係したソースを読んでみてマクロ定義の一覧を含んだヘッダファイルあるいはデバイスのピン番号とソースコード中の GPIO ピン番号の対応を把握して下さい。|

**時間待ち、タイマー [#mea3030a]
制御対象のデバイスはプロセッサの処理速度に比べ動作が遅いことがあります。コマンド発行間隔、要求してから結果が得られるまでの待ち時間が必要な場合が有ります。Sleep, Delay, Timer はこれらのタイミングを合わせるための機能です。注意点はこれらの待ち時間は長くなる方向でぶれます。平行して隣接する機能ブロックを操作している場合、処理や制御の重なりで思わぬ挙動を示す場合が有ります。
|機能単位|主なヘッダやソース|備考|h
|Sleep|&ogfileone(linux/delay.h,include/linux/delay.h);|sleep の代表的な関数は &ogdefs(msleep(),msleep);, &ogdefs(usleep_range(),usleep_range); です。実行中のタスクを再スケジュールします。CPU 資源を無駄にしません。割り込み処理中では使えません。&br;単に別の task に実行を渡す(いわゆる 0 秒待ちをする)場合は &ogrefs(schedule(),schedule,linux/sched.h); を使用します。|
|Delay|&ogfileone(linux/delay.h,include/linux/delay.h);|delay 関数は &ogdefs(ndelay(),ndelay);, &ogdefs(udelay(),udelay);, &ogdefs(mdelay(),mdelay); があります。これらは CPU を空走させて時間待ちを実現します。割り込みハンドラの中でも使えます。しかし、割り込み応答性能を悪化させます。|
|Timer|&ogfileone(linux/timer.h,include/linux/timer.h);&br;&ogfileone(linux/hrtimer.h,include/linux/hrtimer.h);|ドキュメントは &ogfiledirect(Delaying, scheduling, and timer routines, Documentation/DocBook/device-drivers/ch01s03.html); です。代表的な関数は &ogdefs(add_timer(), add_timer);, &ogdefs(mod_timer(), mod_timer);, &ogdefs(del_timer_sync(), del_timer_sync); です。指定時間が経過した後に呼び出される関数の中で &ogdefs(msleep(),msleep); などのコンテキストスイッチの可能性を伴う関数を使用できる delayed work (&ogfileone(linux/workqueue.h,include/linux/workqueue.h);) の方が使い勝手が良い場合もあります。&ogdefs(INIT_DELAYED_WORK(),INIT_DELAYED_WORK);, &ogdefs(schedule_delayed_work(),schedule_delayed_work); などの用例も参考にして下さい。|

**時刻 [#zeb6d76b]
Kernel 内で刻まれている時刻を取得する機能群です。jiffies は 1/&ogdefs(HZ); 秒単位 で進む時刻です。ミリ秒オーダーの精度です。より高精度の時刻を必要とする場合は、&ogrefs(local_clock(),local_clock,sched.h);, &ogrefs(sched_clock(),sched_clock,sched.h); を使用して下さい。これらは Kernel が起動されてから刻まれる時刻です。現実世界の時刻と相対的な時間差があります。CPU が完全に停止した suspend 中には刻まれず止まっています。
|機能単位|主なヘッダやソース|備考|h
|jiffies|&ogfileone(linux/jiffies.h,include/linux/jiffies.h);|jiffies の時間的前後関係を判定する場合は、linux/jiffies.h に定義された比較関数・マクロを使用して下さい。jiffies と時間を変換するには HZ を直接使うより &ogdefs(msecs_to_jiffies(),msecs_to_jiffies);, &ogdefs(jiffies_to_msecs(),jiffies_to_msecs); などを使用することをお勧めします。マイクロ秒、ナノ秒単位への変換関数 &ogfileone(linux/jiffies.h,include/linux/jiffies.h);に定義されています。|
|Time|&ogfileone(linux/time.h,include/linux/time.h);&br;&ogfileone(linux/timekeeping.h,include/linux/timekeeping.h);&br;&ogfileone(linux/sched.h,include/linux/sched.h);|linux/sched.h の中に &ogrefs(local_clock(),local_clock,sched.h);, &ogrefs(sched_clock(),sched_clock,sched.h); などの時刻関数が入っています。|

メモリ確保
|機能単位|主なヘッダやソース|備考|h
|任意サイズ|&ogfileone(linux/slab.h,include/linux/slab.h);||
|ページ単位|&ogfileone(linux/gfp.h,include/linux/gfp.h);&br;&ogfileone(linux/mm.h,include/linux/mm.h);|ページ確保: linux/gfp.h:&ogdefs(alloc_page(),alloc_page,gfp.h); 、ページ・アドレス取得: linux/mm.h:&ogdefs(page_address(),page_address,mm.h); となっています。|

仮想-物理アドレス・マップ、DMA 転送、コピー
|機能単位|主なヘッダやソース|備考|h
|User - Kernel Copy|&ogfile(asm/uaccess.h);&br;&ogfile(linux/uaccess.h,include/linux/uaccess.h);|asm/uaccess.h は linux/uaccess.h で include されます。&ogdefs(copy_to_user(),copy_to_user);, &ogdefs(copy_from_user(),copy_from_user); などはアーキテクチャに最適な実装がされることがあります。|
|Virt - Phy map convert|&ogfile(asm/io.h);&br;&ogfile(linux/io.h,include/linux/io.h);&br;&ogfile(mach/hardware.h);|asm/io.h は linux/io.h で include されます。&ogdefs(virt_to_phys(),virt_to_phys);,&ogdefs(phys_to_virt(),phys_to_virt); などはアーキテクチャやプラットホームに最適な実装がされることがあります。一部のプラットホームでは周辺 IP block の仮想アドレス割り付けを単純化していて、軽量な実装の &ogdefs(IO_ADDRESS(),IO_ADDRESS);, &ogdefs(IOMEM(), IOMEM); マクロなどを経由して物理アドレスから仮想アドレスへ変換出来るよう便宜が図られています。|
|DMA mapping, Address convert, Scatter Gather|&ogfile(asm/dma-mapping.h);&br;&ogfileone(asm-generic/dma-mapping-common.h,include/asm-generic/dma-mapping-common.h);|asm/dma-mapping.h, asm-generic/dma-mapping-common.h は linux/dma-mapping.h で include されます。&br;アーキテクチャ、プラットホームによっては DMA アドレスと物理アドレスが違っています。&ogdefs(phys_to_dma(),phys_to_dma);, &ogdefs(dma_to_phys(),dma_to_phys); 関数が用意されています。|

メモリ・マップド・デバイス・アクセス
|機能単位|主なヘッダやソース|備考|h
|Read-Write|&ogfile(asm/io.h);|asm/io.h は linux/io.h で include されます。&ogdefs(readb(),readb);, &ogdefs(writeb(),writeb);, &ogdefs(readw(),readw);, &ogdefs(writew(),writew);, &ogdefs(readl(),readl);, &ogdefs(writel(),writel); などメモリにマップされたデバイスをアクセスするための関数がアーキテクチャやプラットホームに最適化されています。|

スレッド・軽量処理
|機能単位|主なヘッダやソース|備考|h
|kthread|&ogfileone(linux/kthread.h,include/linux/kthread.h);||
|work queue|&ogfileone(linux/workqueue.h,include/linux/workqueue.h);||
|tasklet|&ogfileone(linux/interrupt.h,include/linux/interrupt.h);|ヘッダファイルは linux/interrupt.h です。この中の &ogdefs(tasklet_init(),tasklet_init); をはじめとする関数群です。|

接続切断通知
|機能単位|主なヘッダやソース|備考|h
|UEvent|&ogfileone(linux/kobject.h,include/linux/kobject.h);|&ogdefs(kobject_uevent(),kobject_uevent);, &ogdefs(kobject_uevent_env(),kobject_uevent_env); 関数で kobject (ユーザー・ランド視点で /sys 以下のノード) から uevent を発行します。|
|External Connector (Switch)|&ogfileone(linux/extcon.h,include/linux/extcon.h);|Android で switch と呼ばれていた抽象化デバイスです。Android も extcon に移行しています。コネクタの接続切断、キーボードとして扱わないボタン押しなどを検出して通知します。|

リファレンスカウンタ
|機能単位|主なヘッダやソース|備考|h
|kref|&ogfileone(linux/kref.h,include/linux/kref.h);|Reference Counter を構成するライブラリです。生成したインスタンスの生存期間を参照の有無によって決定する場合に使います。&ogdefs(kref_init(),kref_init);, &ogdefs(kref_get(),kref_get);, &ogdefs(kref_put(),kref_put); が代表的関数です。|

Kernel Object
|機能単位|主なヘッダやソース|備考|h
|KObject, Kset|&ogfileone(linux/kobject.h,include/linux/kobject.h);|kobject(kernel object) のインスタンスを直接生成する機会は殆ど無いと思います。kobject を利用する場面は、kobject を参照するポインタを使って /sys (sysfs) の下にあるデバイスやドライバのノードに特殊なノードを作ったり、uevent を発行するのが主な場面になるでしょう。|

ノード形成
|機能単位|主なヘッダやソース|備考|h
|VFS(character)|&ogfileone(linux/fs.h,include/linux/fs.h);&br;&ogfileone(linux/cdev.h,include/linux/cdev.h);|&ogdefs(alloc_chrdev_region(),alloc_chrdev_region);, &ogdefs(register_chrdev(),register_chrdev);, &ogdefs(cdev_alloc(),cdev_alloc);, &ogdefs(cdev_init(),cdev_init);, &ogdefs(cdev_add(),cdev_add);  辺りから使用例を探ると良いでしょう。|
|VFS(block)|&ogfileone(linux/fs.h,include/linux/fs.h);&br;&ogfileone(linux/genhd.h,include/linux/genhd.h);|&ogdefs(register_blkdev(),register_blkdev);, &ogdefs(blk_register_region(),blk_register_region);, &ogdefs(alloc_disk(),alloc_disk);, &ogdefs(add_disk(),add_disk); 辺りから使用例を探ると良いでしょう。|
|SCSI|&ogfileone(scsi/scsi.h,include/scsi/scsi.h);&br;&ogfileone(scsi/scsi_host.h,include/scsi/scsi_host.h);&br;&ogfileone(scsi/scsi_driver.h,include/scsi/scsi_driver.h);&br;&ogfileone(scsi/scsi_device.h,include/scsi/scsi_device.h);|block device として登録するならば SCSI device として登録した方が良い場合もあります。SCSI 周りは記述が多くなるので別記検討中です。|
|procfs|&ogfileone(linux/proc_fs.h,include/linux/proc_fs.h);||
|sysfs|&ogfileone(linux/sysfs.h,include/linux/sysfs.h);&br;&ogfileone(linux/device.h,include/linux/device.h);&br;&ogfileone(linux/moduleparam.h,include/linux/moduleparam.h);|&ogdefs(DEVICE_ATTR(),DEVICE_ATTR,device.h); は linux/device.h にあります。&ogdefs(module_param(),module_param,moduleparam.h); は linux/moduleparam.h にあります。|
|debugfs|&ogfileone(linux/debugfs.h,include/linux/debugfs.h);||

モジュールロード、アンロード、シンボル解決
|機能単位|主なヘッダやソース|備考|h
|Module insmod rmmod|&ogfileone(kernel/module.c);|System Call として関数は実装されています。Kernel 内部から呼び出すには symbol を リンクできるように修正する必要が有ります。|
|Symbol lookup|&ogfileone(linux/kallsyms.h,include/linux/kallsyms.h);&br;&ogfileone(linux/license.h,include/linux/license.h);&br;&ogfileone(linux/module.h,include/linux/module.h);|シンボルのアドレスを取得する &ogdefs(symbol_get(),symbol_get); と &ogdefs(symbol_put(),symbol_put); は linux/module.h に有ります。シンボルの解決を使うと static link された Kernel からモジュールの関数を呼び出すことができるようになります。ただし、GPL の抜け穴になるような作り込みは慎みましょう。|

基本的なドライバ
|機能単位|主なヘッダやソース|備考|h
|Null, Zero, Full, Mem drivers|&ogfileone(drivers/char/mem.c);|/dev/null, /dev/zero, /dev/full, /dev/mem の実装です。単純なキャラクタ型デバイスを実装したドライバです。単純ながら興味深い実装になっています。|

基本的なファイルシステムノード
|機能単位|主なヘッダやソース|備考|h
|pipe|&ogfileone(fs/pipe.c);|&ogdefs(poll(select),pipe_poll);の実装、&ogdefs(ioctl FIONREAD の実装,pipe_ioctl); は単純な挙動で特別なデバイスも無い環境でも試せるので参考になるでしょう。|
|eventfd|&ogfileone(fs/eventfd.c);|eventfd, signalfd, timerfd それぞれで system call を実装し、file descriptor を API として提供しています。独自の Kernel API を必要としているならば読んでみるのも良いでしょう。|
|signalfd|&ogfileone(fs/signalfd.c);||
|timerfd|&ogfileone(fs/timerfd.c);||

デバイス登録
|機能単位|主なヘッダやソース|備考|h
|platform|&ogfileone(linux/platform_device.h,include/linux/platform_device.h);|&ogdefs(platform_device_register(),platform_device_register); にてプラットホーム・デバイスを登録します。プラットホームデバイスは SoC に内蔵された IP ブロックが主に対象となります。ただし、suspend、resume、接続、切断 動作に関して何らかの上流バスの支配あるいは管轄下にある場合は、そのバスのデバイスとして登録します。|
|HID|&ogfileone(linux/hid.h,include/linux/hid.h);|&ogdefs(hid_allocate_device(),hid_allocate_device);, &ogdefs(hid_add_device(),hid_add_device);|
|I2C|&ogfileone(linux/i2c.h,include/linux/i2c.h);|I2C 関連の基礎的な用語 Algorithm, Adapter, Driver, Client については &ogfiledirect(Documentation/i2c/summary); にて解説されています。全般的なドキュメントは &ogfileone(Documentation/i2c/); 以下のファイルと API の解説 &ogfiledirect(Documentation/DocBook/device-drivers/i2c.html); を参照してください。&br;多くの場合 &ogdefs(i2c_register_board_info(),i2c_register_board_info); を使ってプラットホームの初期化処理にてデバイスを登録します。動的な登録は &ogdefs(i2c_new_device(),i2c_new_device); で行います。|
|PCI|&ogfileone(linux/pci.h,include/linux/pci.h);|PCI 接続のデバイス登録は SoC メーカーあるいは開発環境を提供したメーカーがすでに初期化処理の中で行うよう実装しているはずです。&ogdefs(pci_common_init(),pci_common_init);, &ogdefs(pcibios_scan_root(),pcibios_scan_root);, &ogdefs(pci_bus_add_devices(),pci_bus_add_devices); 辺りからコードを追跡して確認してください。それでも意図して登録する場合は &ogdefs(pci_bus_add_device(),pci_bus_add_device); の用例を参考にしてください。|
|SDIO|&ogfileone(linux/mmc/host.h,include/linux/mmc/host.h);|SDIO デバイスは自動でデバイスが登録されます。登録の流れは &ogdefs(mmc_detect_change(),mmc_detect_change);, (delayed work を挟み) &ogdefs(mmc_rescan(), mmc_rescan);, &ogdefs(mmc_rescan_try_freq(),mmc_rescan_try_freq);, &ogdefs(mmc_attach_sdio(),mmc_attach_sdio);, &ogdefs(mmc_attach_sd(),mmc_attach_sd);, &ogdefs(mmc_attach_mmc(),mmc_attach_mmc);, &ogdefs(mmc_add_card(),mmc_add_card); の様になります。|
|SPI|&ogfileone(linux/spi/spi.h,include/linux/spi/spi.h);|&ogdefs(spi_register_board_info(), spi_register_board_info); を使ってプラットホームの初期化処理にてデバイスを登録します。動的な登録は &ogdefs(spi_alloc_device(),spi_alloc_device);, &ogdefs(spi_add_device(),spi_add_device); で行います。|
|USB|&ogfileone(linux/usb.h,include/linux/usb.h);&br;&ogfileone(linux/usb/hcd.h,include/linux/usb/hcd.h);|接続処理(デバイス登録)は自動で行われます。&ogdefs(usb_new_device(),usb_new_device);, &ogdefs(hub_port_connect(),hub_port_connect);, &ogdefs(usb_hub_create_port_device(),usb_hub_create_port_device); とその呼び出し元のコードを探索してみてください。|

ドライバ登録
|機能単位|主なヘッダやソース|備考|h
|platform|&ogfileone(linux/platform_device.h,include/linux/platform_device.h);|&ogdefs(platform_driver_register(),platform_driver_register);, &ogdefs(module_platform_driver(),module_platform_driver);|
|I2C|&ogfileone(linux/i2c.h,include/linux/pci.h);|&ogdefs(i2c_add_driver(),i2c_add_driver);, &ogdefs(module_i2c_driver(),module_i2c_driver);|
|PCI|&ogfileone(linux/pci.h,include/linux/pci.h);|&ogdefs(pci_register_driver(),pci_register_driver);, &ogdefs(module_pci_driver(),module_pci_driver);|
|SDIO|&ogfileone(linux/mmc/mmc.h,include/linux/mmc/mmc.h);&br;&ogfileone(linux/mmc/core.h,include/linux/mmc/core.h);&br;&ogfileone(linux/mmc/card.h,include/linux/mmc/card.h);&br;&ogfileone(linux/mmc/sdio.h,include/linux/mmc/sdio.h);&br;&ogfileone(linux/mmc/sdio_ids.h,include/linux/mmc/sdio_ids.h);&br;&ogfileone(linux/mmc/sdio_func.h,include/linux/mmc/sdio_func.h);|ドライバ登録は &ogdefs(sdio_register_driver(),sdio_register_driver); で行います。左の列に挙げたヘッダファイルは一部だけ使用する場合もあります。実装する機能と照らし合わせ &ogfile(include/linux/mmc); の下のヘッダファイル群を取り込んで下さい。|
|SPI|&ogfileone(linux/spi/spi.h,include/linux/spi/spi.h);|&ogdefs(spi_register_driver(),spi_register_driver);, &ogdefs(module_spi_driver(), module_spi_driver);|
|USB|&ogfileone(linux/usb.h,include/linux/usb.h);|&ogdefs(usb_register(),usb_register);, &ogdefs(module_usb_driver(),module_usb_driver);|

クラスデバイス登録
|機能単位|主なヘッダやソース|備考|h
|Input, HID|&ogfileone(linux/input.h,include/linux/input.h);&br;&ogfileone(linux/hid.h,include/linux/hid.h);|組み込みでは &ogdefs(input_allocate_device(),input_allocate_device);, &ogdefs(input_register_device(),input_register_device); のほうをよく使うと思います。&ogfiledirect(Documentation/DocBook/device-drivers/input_subsystem.html); を参照してください。関数名はデバイス登録を思わせる名前です。実質はドライバ登録に当たります。同じドライバソースの中にキー入力を報告(伝達)する関数 &ogdefs(input_report_key(),input_report_key);, &ogdefs(input_sync(),input_sync); が見つかると思います。&br;HID 系の API は &ogdefs(hid_allocate_device(),hid_allocate_device);, &ogdefs(hid_add_device(),hid_add_device); などです。&ogfiledirect(Documentation/hid/hid-transport.txt); を参照してください。&hr;&ogdefs(hid_register_driver(),hid_register_driver);, &ogdefs(module_hid_driver(),module_hid_driver);|

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS