Linuxキャラクタードライブの概念の紹介

1.キャラクター主導のフレームワーク

Q:アプリケーションはどのようにしてドライバーのオープン、読み取り、および書き込み関数を見つけ、読み取り、書き込みしますか?

回答:アプリケーションのオープン、読み取り、書き込みはCライブラリに実装されています。アプリケーションはswi val命令を使用して例外をトリガーします。この例外はカーネルスペースに入ります。カーネルの例外処理関数には、私たちに基づく入力があります。 system_open関数またはsystem_read関数、system_write関数のどちらを呼び出すかを決定するVal。これらの関数は、開いているさまざまなファイルに応じてさまざまなプロパティを持ち、さまざまなファイルにはさまざまな属性があります(デバイスタイプ(キャラクターデバイスまたはブロックデバイスまたはネットワークデバイス)、メインデバイス番号など)これらの属性は、下位レベルのドライバーを見つけます。

 

Q:メジャーデバイス番号とマイナーデバイス番号は何ですか?

回答:Linuxメジャーデバイス番号は、LEDとシリアルポートの違いなど、さまざまなハードウェアデバイスタイプを区別するために使用されます
。Linuxマイナーデバイス番号は、シリアルポート1とシリアルポート2の違いなど、さまざまなハードウェアデバイスを区別するために使用されます。

 

Q:ドライバーのオープン機能を見つけるためにどのような方法が使用されていますか?

回答:登録機能+デバイスノードを介して

登録機能は次のとおりです(古い登録機能、新しい登録機能については後で説明します)。

register_chrdev(unsigned int major、const char * name、const struct file_operations * fops)

パラメータ1:メジャーデバイス番号(重要)

パラメータ2:名前(重要ではない)

パラメーター3:file_operations構造(重要)

デバイスノード:

手動でも自動でも作成できますが、当面は手動で作成する予定です。

mknod / dev / xxx c 252 0

/ dev / xxxという名前のデバイスノードを作成します。cはキャラクターデバイスノードを表し、252はメジャーデバイス番号、0はマイナーデバイス番号です。

 

Q:アプリケーションプログラムは通常メイン機能で実行されますが、最初に実行するドライバープログラムは何ですか?

回答:マクロを使用して、ドライバーの入り口関数を指定します。入り口関数は、ドライバーのロード時に実行されます。

例:module_init(first_drv_init); //エントリ関数を変更するために使用

当然、ドライバーがアンロードされると、ドライバーの終了関数が実行されます。

例:module_exit(first_drv_exit); //エクスポート関数を変更するために使用
 

 

ドライバのソースプログラムは次のとおりです。

#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/module.h>
 
 
int major;
static int first_drv_open(struct inode * inode, struct file * filp)
{
	printk("first_drv_open\n");
	return 0;
}
static int first_drv_write(struct file * file, const char __user * buffer, size_t count, loff_t * ppos)
{
	printk("first_drv_write\n");
	return 0;
}
 
/* File operations struct for character device */
static const struct file_operations first_drv_fops = {
	.owner		= THIS_MODULE,
	.open		= first_drv_open,
	.write      = first_drv_write,
};
 
/* 驱动入口函数 */
static int first_drv_init(void)
{
	/* 主设备号设置为0表示由系统自动分配主设备号 */
	major = register_chrdev(0, "first_drv", &first_drv_fops);
	return 0;
}
 
/* 驱动出口函数 */
static void first_drv_exit(void)
{
	unregister_chrdev(major, "first_drv");
}
 
module_init(first_drv_init);  //用于修饰入口函数
module_exit(first_drv_exit);  //用于修饰出口函数	
 
MODULE_AUTHOR("LWJ");
MODULE_DESCRIPTION("Just for Demon");
MODULE_LICENSE("GPL");  //遵循GPL协议

Makefileのソースコードは次のとおりです。

ifneq ($(KERNELRELEASE),)
 
obj-m := first_drv.o
 
else
	
KDIR := /home/opt/EmbedSky/linux-2.6.30.4
 
all:
	make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
	rm -f *.ko *.o *.mod.o *.mod.c *.symvers
 
endif

テスト手順は次のとおりです。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
 
int main(void)
 
{
	int fd;
	int val = 1;
	fd = open("/dev/xxx",O_RDWR);    //打开名为  /dev/xxx  的设备节点
	if(fd < 0)
	{
		printf("open error\n");
	}
	
	write(fd,&val,4);
	
	return 0;
}

開発ボードでのテスト手順は次のとおりです。

[WJ2440]# insmod first_drv.ko 
[WJ2440]# ./first_test 
open error                    //没有创建设备节点
[WJ2440]# cat proc/devices 
Character devices:
  1 mem
  4 /dev/vc/0
  4 tty
  5 /dev/tty
  5 /dev/console
  5 /dev/ptmx
  7 vcs
 10 misc
 13 input
 14 sound
 29 fb
 81 video4linux
 89 i2c
 90 mtd
116 alsa
128 ptm
136 pts
180 usb
188 ttyUSB
189 usb_device
204 tq2440_serial
252 first_drv                //我们创建的字符设备,主设备号252
253 usb_endpoint
254 rtc
 
Block devices:
259 blkext
  7 loop
  8 sd
 31 mtdblock
 65 sd
 66 sd
 67 sd
 68 sd
 69 sd
 70 sd
 71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
179 mmc
[WJ2440]# mknod /dev/xxx c 252 0        //手动创建一个字符设备节点
[WJ2440]# ls -l /dev/xxx 
crw-r--r--    1 root     root      252,   0 Jan  1 20:49 /dev/xxx
[WJ2440]# ./first_test                 //有设备节点后成功我们的应用程序运行了
first_drv_open
first_drv_write
[WJ2440]# 

この記事は以下を参照しています。

https://blog.csdn.net/lwj103862095/article/details/17468587

42件のオリジナル記事を公開 いいね10 10,000人以上の訪問者

おすすめ

転載: blog.csdn.net/qq_37659294/article/details/104302700
おすすめ