1. Linuxのドライブの学習
駆動するために勉強したい学生のためのLinuxカーネルドライバの何百、およびその他の知識のポイントは、あなたがすぐに基本を把握する必要があります:基本的な使用を、このような開発ボード、ハードウェアの基本、開発環境を構築するよう、Linuxの一般的に使用されるツールは、カーネルのコンパイルとプログラミング、Linuxのシェルコマンド、C言語の基礎、Linuxカーネルの簡単なカットや設定、Linuxシステムのプログラミングなど
上記のいかなる基本的な知識、疑いは、空気中のビルド城に学んで駆動されていません。
Linuxオペレーティングシステム、「ボール」の同等は、プログラマやってきたが、ボールがどこかに行くためにどこから回転させて管理するのではない、特定の機能を実現するために、この分野でのドライブを追加することです。理解しやすくすることは車を運転することを学ぶように、何のコーチは「「右ハンドルの周りに回す」だけあなたのようないくつかの命令を与える、エンジンの原理を説明するために、ステアリングホイールの左を開始しません、単なるツールであり、それを使用することを学ぶ、Linuxのです革命「」ハンドブレーキ「」シフト「などが挙げられます。
もちろん学習するための最良の方法は、Linuxカーネルを読むことですが、何の根拠は、物事の核心を研究するも過言ではないの前には存在しません。
Linuxドライバを作業組込みエンジニアは、ドライバーが移植がスキルを習得する必要があり、後に、適切な仕事を見つけるために、ドライブに移植する方法を学びました、あなたはカーネルソース、だけでなく、時間の黒字に興味があるならば、あなたは見てみることができカーネル「絶妙」のコードが、それは缶限り、直接助け、読むために純粋に利益のために仕事をしません。
2. Linuxのデバイスドライバの分類
主に連続的にエンリッチドライバコードに、ソースコードの長さを増加させる大部分のためのLinuxカーネルのソースコードを所有するLinuxデバイスドライバ、。常にLinuxカーネルをアップグレードし、構造のドライバーは比較的安定しています。
キャラクタデバイス(チャー装置)、ブロックデバイス(ブロックデバイス)とネットワーク装置(ネットワーク機器)を3つのLinuxシステム装置。デバイスにアクセスする際にキャッシュされていない文字デバイス。ライトキャッシュブロックデバイスがサポートしており、デバイスは、ランダムアクセス(ランダムアクセス)をブロックすることができる必要があり、この要件はキャラクタデバイスではありません。典型的なキャラクタデバイスは、マウス、キーボード、シリアルポートなどを含みます。ハードディスク、フロッピーディスクデバイス、CD-ROMなどを含むブロックデバイス。ファイルシステムは、オペレーティングシステムに(マウント)ブロックデバイスをインストールします。
Linuxでの特別な取引を行うためのネットワーク機器。Linuxのネットワークシステムは、主にBSD Unixソケットメカニズムに基づいています。これは、データ転送のための特別なデータ構造(sk_buff)を有するシステムとドライバとの間に画定されます。データを送受信するデータをキャッシュするための支援システムは、複数のプロトコルのサポートを提供するために、フロー制御メカニズムを提供します。
3 駆動モジュールの形態では、コンパイル
ローディング関数モジュール「module_init(機能)」、正常に実行された場合、0が返され、整数型を返します。それ以外の場合は、エラーメッセージを返します。
時には、チップベンダーは、チップ駆動のソースコードを提供していないだけで、ドライブモジュールKOファイル、ドライバをロードするためにコールrequest_module(モジュール名)の必要性について、この時間を提供します。
Linuxでは、_initは、Linuxで起動または初期化モジュールがロードされた後、メモリスペースを取るの初期化機能がある_ラベルされた機能は、それが外に放出されます。機能に加えて、データはまた、「_ _データ」として定義することができ、データは、Linuxで起動またはロードまたは初期化モジュールの後に、また、リリースされます。背中のこの部分の知識は、徐々に使用します。
モジュールは、モジュールが比較的容易に理解するために、「逆のプロセスを」ロードされアンロードします。
アンインストール機能モジュール「module_init(機能)」は値を返しません。
一般的に、我々は反対の機能をアンインストール機能とロードの機能を完了する必要があり、例えば、アンインストール機能を使用する、その後、システムやハードウェアリソースを呼び出し、あなたは解放する必要があります。
Linuxのモジュールは、一般的にスクリプト言語の種類が非常に大きく、豊かな構文でコンパイルするスクリプト言語を使用しますが、我々はちょうど使用することを学ぶ必要があり、その上に書かれてモデル化することができ、これは我々の開発に影響を与えません。
、流れ図のブロックは、以下にまとめました。
図は、makeコマンドは、LinuxのモジュールをコンパイルするMakefileを呼び出して、実行した後、コンパイラで見ることができます。
Linuxのコンパイルされたモジュールは、2行に分割されます。
レッドライン:Linuxのソースコードを入力し、その上のヘッダファイルの一部としてだけでなく、バージョン情報を呼び出して。
これは全体のLinuxのソースコードファイルを通る線です。
オレンジライン:Linuxのソースツリー情報の収集を完了した後、Makefileのは続けて、ソースファイルを呼び出すには、ここでの.koファイルを、コンパイルされmini_linux_module.cこの「iTop4412_Kernel_3.0」ソースコード全体です。
彼らは、ソースが、このソースでもその源であるにもかかわらずこの行は、mini_linux_module.cを取っています。
二行上に行うことでMakefileは、情報を収集することにより、最終的なモジュールは、コンパイルの.ko
ここでの我々の焦点は、学び、理解し、カーネルモジュールのソースコードをコンパイルすることです彼らはカーネルのバージョン、およびヘッダに関連するとしても、使用する必要があります。間違ったバージョン場合は、モジュールがロードし、実行することができないことがありますヘッダーファイルならば、コンパイラは渡しません。
MCUまたはPCプログラミングでは、我々は、開発ツールを統合しています。ルール開発ツールとプログラマのに従って、指定された場所にコード、main.cのが.Cファイルの多くの通常のファイルは、コードは、自動的にあなたを与えるためにコンパイルされていること開発ツールボタンを書かバイナリファイル。
Linuxでは、そのような統合開発ツールが存在しない、コンパイル済みのファイルMakefileを書く必要もあります。
コンパイルされたファイルは、一般的に、スクリプトの何千ものスクリプト言語学の仕上げ、学習がどこで使用されている学習の最良のスクリプトを学び、スクリプトを使用しています。
次の書類をコンパイルするMakefileは、次のように次の「02_HelloDriverModule」を見つけるためにLinuxディレクトリにビデオファイルをドライブすることができます。
#!/ binに/ bashの
#私たちのモジュールをコンパイルするコンパイラに指示しますどのようなソース
ここでは、コンパイルitop4412_hello.c#このファイルは、中間ファイルmini_linux_module.oにコンパイルされています
OBJ-M + = mini_linux_module.o
ユーザーが実際の状況のパスを選択する必要があります#ソースディレクトリ変数、
Linuxのソースコードの#はディレクトリにコピーし、/home/topeet/android4.0を抽出しています
手段:= hometopeetandroid40iTop4412Kernel30
#変数のカレントディレクトリ
PWD?= $(シェルPWD)
最初の目標を探して#makeデフォルトの命名
-Cは、呼経路の実行を指す#make
#$(KDIR)、Linuxのソースコードディレクトリ、ここで著者は/home/topeet/android4.0/iTop4412_Kernel_3.0を指し、
#$(PWD)変数、現在のディレクトリ
#Modules動作が実行されます
すべて:
-C $(KDIR)M = $(PWD)モジュールを作ります
#Makeクリーン操作がo接尾辞ファイルを削除するために行われます
掃除:
RM -rf * .oの
上記のように、mini_linux_moduleスクリプトファイルをコンパイルされます。各文の意味の以下の詳細な説明。
#!/ binに/ bashの
このスクリプトを使用するようコンパイラーに指示すると、スクリプト言語です
OBJ-M + = mini_linux_module.o
これは、あなたが他のファイルをコンパイルする必要がある場合、その後、あなたが追加することができ、後でmini_linux_module.oファイルに変換mini_linux_module.c文書を表現したい、標準的な使用方法です。
手段:= hometopeetandroid40iTop4412Kernel30
この行には、カーネルのソースコードが存在しない場合は、ディレクトリのカーネルコードを表し、それはバージョンがサポートとヘッダファイルを欠いているため、モジュールは、することはできませんコンパイルします。KDIRは可変です。
PWD?= $(シェルPWD)
この文は、変数、この変数に渡され、現在のディレクトリに、パスです。PWDコマンドで、カレントディレクトリ、PWDは可変です。
すべて:
-C $(KDIR)M = $(PWD)モジュールを作ります
使用「メイク」コマンドのコンパイルスクリプトの実行時間、それはこの1つを見つけるためにデフォルト設定されます、変数は、カーネルのソースディレクトリにKDIRパスがあり、-Cは変数KDIRで実行を呼び出すためにパスを表します。
PWDは現在のディレクトリを表します。
ショーのモジュールとしてコンパイルドライブモジュール、KOは、最終的なファイルで生成されます。
掃除:
RM -rf * .oの
ソースコードを再変更した後、あなたは、いくつかの役に立たない中間ファイルを削除するには、コマンド「クリーンを作る」ことができ、ここでは、ファイル内の「o」サフィックスの明確な選択肢です。
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Hcamal");
int hello_init(void)
{
printk(KERN_INFO "Hello World\n");
return 0;
}
void hello_exit(void)
{
printk(KERN_INFO "Goodbye World\n");
}
module_init(hello_init);
module_exit(hello_exit);
しかし、C言語の開発を使用して、Linuxの下で運転し、私たちは通常、C言語を記述することは、我々は通常のlibcライブラリを使用してC言語を記述するためにも異なりますが、ドライブはプログラムのカーネルで実行されている、カーネルはしていませんライブラリが存在のlibcので、カーネルのライブラリ関数を使用します。
例えば、printk
libcの中に比較できるprintf
ので、カーネルで定義された出力機能ですが、私はロガー機能の内部でより多くのPythonのように感じており、printk
出力はカーネルログに出力され、使用できるdmesg
コマンドの表示を
ドライバコードは、ドライバがカーネル実行にロードされ、唯一の入口点と一つの出口点であるmodule_init
関数定義の機能は、上記のコードが入っているhello_init
機能。ドライブがカーネルからアンロードされたときに呼び出すmodule_exit
関数コードの関数定義は、上記にあるhello_exit
機能。
上記のコードは、ドライバがロードされたときに、非常に明確であり、出力Hello World
、搬出駆動出力Goodbye World
PSS: printk
結果の出力は、新しい行を追加する、または他のバッファをフラッシュしません。
ドライバのコンパイル
makeコマンドでコンパイルする必要が走行Makefile
次のように:
ifneq ($(KERNELRELEASE),)
obj-m := hello.o
else
KERN_DIR ?= /usr/src/linux-headers-$(shell uname -r)/
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERN_DIR) M=$(PWD) modules
endif
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
通常の状況下では、カーネルのソースコードが存在し、/usr/src/linux-headers-$(shell uname -r)/
ディレクトリ
例えば:
$ uname -r
4.4.0-135-generic
/usr/src/linux-headers-4.4.0-135/ --> 该内核源码目录
/usr/src/linux-headers-4.4.0-135-generic/ --> 该内核编译好的源码目录
そして、私たちはある、コンパイル後の良好なソースディレクトリである必要があります/usr/src/linux-headers-4.4.0-135-generic/
ヘッダー・コードは、ディレクトリ検索から駆動する必要があります
M=$(PWD)
このパラメータは、現在のディレクトリにドライブ出力コンパイル結果を示し、
最後に、コマンドをobj-m := hello.o
することを示すhello.o
コンパイルhello.ko
このファイルをカーネルモジュールファイルがkoです
カーネルにドライバをロードします
あなたは、いくつかのシステムコマンドを使用する必要があります。
lsmod
:現在のカーネルモジュールがロードされている見ますinsmod
:カーネルモジュールをロードするには、root権限が必要ですrmmod
:削除モジュール
例えば:
# insmod hello.ko // 把hello.ko模块加载到内核中
# rmmod hello // 把hello模块从内核中移除
知識ポイント1 - ドライバーの分類
駆動装置は、上記のコードの例については、文字デバイスである、三つのカテゴリー、キャラクタデバイス、ネットワークインターフェースデバイスとインターフェイスブロックに分割他の二つ、次いで繰り返します。
図の中に上記のようにbrw-rw----
権利フィールド、Bはブロックデバイス(ブロック)の始まりを示し、Cは、文字デバイス(チャー)の始まりを表します
知識ポイント2 - メジャー番号とマイナー番号
数は、一般的に、ドライバ制御と同じメジャー番号を付しメインドライブを区別するために使用されます。
ドライバは、区別するために、マイナー番号で、複数のデバイスを作成することができます。
メインとマイナー番号が一緒に駆動装置を決定します。
図に示すように。
brw-rw---- 1 root disk 8, 0 Dec 17 13:02 sda
brw-rw---- 1 root disk 8, 1 Dec 17 13:02 sda1
装置sda
及びsda1
主番号は、そのような数は、この数は1であり、8であり、0
知識ポイント3 - ドライバーは、APIを提供する方法です
私の考え方では、インターフェースのドライブが提供される/dev/xxx
Linuxでは、Everything is File
ドライバは、オープン/読み取り/書き込み/定義するために使用されるように、デバイスの動作は、実際には、ファイルを操作するように駆動されるように、...... A /dev/xxx
何が起こるか、APIは、ファイルの一連の操作を提供するように駆動されます。
どのようなファイル操作?これらは、カーネルで定義されている<linux/fs.h>
[5] 、ヘッダファイルにfile_operations
構造
私の例では上記のコード:
struct file_operations scull_fops = {
.owner = THIS_MODULE,
.llseek = scull_llseek,
.read = scull_read,
.write = scull_write,
.open = scull_open,
.release = scull_release,
};
私は宣言加え構造、割り当てとは、そのowner
関数ポインタの、全ての値が他のメンバー
私の後scull_setup_cdev
の機能、使用cdev_add
ファイル操作構造を登録し、各駆動装置
例えば、私が操作を実行するための駆動装置を開いて、それが実行に行くscull_open
システムコールフックに同等の機能をopen
機能を
知識4は - / devに対応デバイスを形成します
上記のコード、scull.koを与えるためにコンパイルされ、それが署名され、最後に使用されるinsmod
カーネルにロードします
正常にロードされた場合に参照するには、lsmodのを
ドライバが正常にロードされていますが、/ devディレクトリの中にデバイスファイルを作成しませんが、我々は、手動で使用する必要があるmknod
デバイスリンクについて
参考:
https://www.oschina.net/question/2371345_2186010