Linux下文字デバイスドライバの構造
まず、概念を明確にしてほしい.
1、駆動とは、必ずカーネルと密接につながっている下位プログラムである.インタフェースはユーザーには表示されません.駆動とカーネルをどのように結びつけるかを考えてみましょう.最初はモジュール(modules)を考えています.モジュールはキャリアのようなもので、容器のようなもので、それを通じて、カーネルが見える領域に書き終わったプログラムを挿入(ロード)して、カーネルに駆動の存在を感知させ、ユーザー空間はシステム呼び出しの形式で駆動に結びつくことができます.そのタスクを完了するために、モジュールを最もよく理解します.
2、駆動はOSの下にあり、OSにハードウェア操作(もちろん駆動はハードウェアではない可能性もある)の論理と下位抽象のパッケージを提供するので、彼は上下を兼ねて、上はOSの駆動呼び出しインタフェースに合致し、下はハードウェアの操作を処理しなければならない.
3、Linuxは特殊で、すべてのデバイスを抽象的にファイルにすると、操作インタフェースが統一され、開発にも便利になります.Linuxのデバイスファイルには、文字デバイス、ブロックデバイス、ネットワークデバイスの3種類があります.
ドライバ(文字デバイスドライバ)を作成するには、次の手順に従います.
1、設備の存在を特徴付ける構造体cdev:
全体の過程はこの構造体をめぐって行われている.彼の各要素に値を割り当て、モジュールを介してカーネルにロードすればよい.私たちは一つ一つ説明します.
場合、kobjectの初期化はcdev_Initの中で完成しましたFs/Char_dev.c :
ここではkobject、list_head、file_operationsも値を付けたり初期化したりしました.パラメータとしてfileが必要ですoperationsは値を割り当てるために使用され、file_operationsには、文字デバイスを操作するために使用可能なすべての関数(インタフェース)が含まれています.ファイルを引き出しましたoperationsは、文字駆動全体のコアであり、すべての処理ロジックをバインドするオブジェクトでもあります.
ここでは簡単な例ですが、私たちがしなければならないのは、等号の後ろの関数を実現し、その値を割り当てることです.下はfile_operationsのプロトタイプ、完備したインタフェースは、あなたが使っているものを実現するだけでいいです(include/linux/fs.h):
ここで、cdevの初期化によって、私たちはあなたの書いた論理をcdevと結びつけました(file_operationsを通じて)、それから:
cdev.owner = THIS_MODULE;
直接レプリケーションはcdevと現在のモジュールを関連付けます.次に、
dev_tdevno =MKDEV(222,0);
MKDEPマクロを使用して、0のdev_であるプライマリデバイス番号222が生成されるtタイプのデバイス番号変数devnoは、その後、デバイス番号とデバイス構造体cdevを関連付けて、デバイスが間接的にその処理関数を見つけることができ、これを使用して関連を完了します.
cdev_add(&dev->cdev,devno,1);
well、デバイス構造体の準備ができていて、具体的なデバイス番号も約束されています(このタイプのデバイスが直接具体的な処理を行うことができます).また、現在のモジュールと接続されています.さらに、カーネルにその存在を知らせるには、次の関数を使用します.
register_chrdev_region(devno,1,"globalmem");
現在のデバイスをカーネルに登録します.これはcdevとは関係ありません.仮想デバイスglobalmemに対してカーネルの登録を行うだけです.彼らのつながりの絆はdevnoです.もちろん、ログアウト関数もあります.
unregister_chrdev_region(devno,1);
彼らは普通ペアで現れます.
このように差は多くなくて、全体の過程と原理はこのようにして、更に詳しくて、Linux駆動開発の詳しい6章をよく読むことができます.非常に詳しく話す.もう一つのblogを見てみると、【Linuxの次の最初のドライバ】は、一例であり、多くの説明が付いており、初歩的な概念を構築することができるはずです.それから漸進的になって、ははは.
【本書docドキュメントダウンロード】
.
.
1、駆動とは、必ずカーネルと密接につながっている下位プログラムである.インタフェースはユーザーには表示されません.駆動とカーネルをどのように結びつけるかを考えてみましょう.最初はモジュール(modules)を考えています.モジュールはキャリアのようなもので、容器のようなもので、それを通じて、カーネルが見える領域に書き終わったプログラムを挿入(ロード)して、カーネルに駆動の存在を感知させ、ユーザー空間はシステム呼び出しの形式で駆動に結びつくことができます.そのタスクを完了するために、モジュールを最もよく理解します.
2、駆動はOSの下にあり、OSにハードウェア操作(もちろん駆動はハードウェアではない可能性もある)の論理と下位抽象のパッケージを提供するので、彼は上下を兼ねて、上はOSの駆動呼び出しインタフェースに合致し、下はハードウェアの操作を処理しなければならない.
3、Linuxは特殊で、すべてのデバイスを抽象的にファイルにすると、操作インタフェースが統一され、開発にも便利になります.Linuxのデバイスファイルには、文字デバイス、ブロックデバイス、ネットワークデバイスの3種類があります.
ドライバ(文字デバイスドライバ)を作成するには、次の手順に従います.
1、設備の存在を特徴付ける構造体cdev:
struct cdev{
struct kobject kobj; /* kobject */
struct module *owner; /* */
struct file_operations *ops; /* */
struct list_head list;
dev_t dev; /* , 32 , 12 , 20 */
unsigned int count;
};
全体の過程はこの構造体をめぐって行われている.彼の各要素に値を割り当て、モジュールを介してカーネルにロードすればよい.私たちは一つ一つ説明します.
場合、kobjectの初期化はcdev_Initの中で完成しましたFs/Char_dev.c :
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
memset(cdev, 0, sizeof *cdev);
INIT_LIST_HEAD(&cdev->list);
kobject_init(&cdev->kobj, &ktype_cdev_default);
cdev->ops = fops;
}
ここではkobject、list_head、file_operationsも値を付けたり初期化したりしました.パラメータとしてfileが必要ですoperationsは値を割り当てるために使用され、file_operationsには、文字デバイスを操作するために使用可能なすべての関数(インタフェース)が含まれています.ファイルを引き出しましたoperationsは、文字駆動全体のコアであり、すべての処理ロジックをバインドするオブジェクトでもあります.
static const struct file_operations globalmem_fops={
.owner = THIS_MODULE,
.read = globalmem_read,
.write = globalmem_write,
.open = globalmem_open,
.release = globalmem_release,
};
ここでは簡単な例ですが、私たちがしなければならないのは、等号の後ろの関数を実現し、その値を割り当てることです.下はfile_operationsのプロトタイプ、完備したインタフェースは、あなたが使っているものを実現するだけでいいです(include/linux/fs.h):
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
};
ここで、cdevの初期化によって、私たちはあなたの書いた論理をcdevと結びつけました(file_operationsを通じて)、それから:
cdev.owner = THIS_MODULE;
直接レプリケーションはcdevと現在のモジュールを関連付けます.次に、
dev_tdevno =MKDEV(222,0);
MKDEPマクロを使用して、0のdev_であるプライマリデバイス番号222が生成されるtタイプのデバイス番号変数devnoは、その後、デバイス番号とデバイス構造体cdevを関連付けて、デバイスが間接的にその処理関数を見つけることができ、これを使用して関連を完了します.
cdev_add(&dev->cdev,devno,1);
well、デバイス構造体の準備ができていて、具体的なデバイス番号も約束されています(このタイプのデバイスが直接具体的な処理を行うことができます).また、現在のモジュールと接続されています.さらに、カーネルにその存在を知らせるには、次の関数を使用します.
register_chrdev_region(devno,1,"globalmem");
現在のデバイスをカーネルに登録します.これはcdevとは関係ありません.仮想デバイスglobalmemに対してカーネルの登録を行うだけです.彼らのつながりの絆はdevnoです.もちろん、ログアウト関数もあります.
unregister_chrdev_region(devno,1);
彼らは普通ペアで現れます.
このように差は多くなくて、全体の過程と原理はこのようにして、更に詳しくて、Linux駆動開発の詳しい6章をよく読むことができます.非常に詳しく話す.もう一つのblogを見てみると、【Linuxの次の最初のドライバ】は、一例であり、多くの説明が付いており、初歩的な概念を構築することができるはずです.それから漸進的になって、ははは.
【本書docドキュメントダウンロード】
.
.