Linux内核——字符设备.
- 设备相关点解
- 简述字符设备驱动的设计流程
- 编写对应Makefile
-
1 2 3 4 5 6 7 8 9 10obj-m += led_dev.o KERNEL_DIR := /home/bbigq/6818GEC/kernel CROSS_COMPILE := /home/bbigq/6818GEC/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi- PWD := $(shell pwd) default: $(MAKE) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNEL_DIR) M=$(PWD) modules clean: rm *.o *.order .*.cmd *.mod.c *.symvers .tmp_versions -rf
设备相关点解.
Linux驱动设备一共分为三种:字符设备、块设备、网络设备,其中只有网络设备比较特殊,其在/dev目录下是没有设备文件的。
区分文件类型:
| 符号 | 文件类型 |
|---|---|
| c | 字符设备 |
| b | 块设备 |
| d | 目录 |
| l | 符号链接 |
字符设备
该设备对数据的处理按照字节流的形式进行的,支持顺序访问(是有时间的概念),也可以支持随机访问。典型的字符设备:串口、键盘、触摸屏、摄像头、I2C、SPI、声卡、帧缓冲设备….顺序访问的设备:串口、键盘、触摸屏随机访问的设备:帧缓冲设备
应用程序,能够使用系统IO函数来就行访问:open、write、read、lseek、close…..
比如在根目录的/dev下我们能看到
其中第五第六列分别是主设备号和次设备号
如:fb0的主设备号为29,次设备号为0
| |
主设备号
主设备号主要用于区分某一类型的设备,比如显示器、鼠标、键盘、硬盘等
次设备号
次设备号用来区分同一类型设备的不同个体或者不同分区,比如显示器A.a、显示器A.b 或者硬盘的分区1~分区7;
简述字符设备驱动的设计流程.
- 首先定义一个字符设备
struct cdev - 申请设备号
a. 静态注册
b. 动态注册MKDEV register_chrdev_regionalloc_chrdev_region - 定义
file_operations,初始化打开、关闭、读、写等函数接口。 - cdev初始化
.cdev_init - 将cdev加入到内核
.cdev_add - 创建设备文件
.手动创建,去/dev目录进行创建
.自动创建
1)class_create
2)device_create
此处默认都能使用Source Insight来阅读内核源码了
定义一个字符设备.
使用到一个结构体,见include/linux/cdev.h –> cdev
| |
kobj:内核管理驱动的时候,自动管理的对象,自动链接调用(不需要我们管);*owner:属于哪一个内核模块,初始化一般默认编写值为THIS_MODULE,指向当前模块;(重点)*ops:字符设备文件操作集;(重点)list:内核自动管理字符设备的链表,内核自动调用;dev:设备号;count:对当前设备申请次设备号的数目;(重点)
定义并初始化一个文件操作集.
定义一个file_operations结构体,见/include/linux/fs.h –> file_operations
| |
当然很多时候我们用不到它结构体定义的这么多函数接口,只需保留最常用的即可;
每个字符设备都必须有一个文件操作集,文件操作集是驱动程序给应用程序访问硬件的一个接口,应用层与驱动程序函数接口的对应关系如下:
| 应用层 | 驱动层 |
|---|---|
| open | open |
| close | release |
| write | write |
| read | read |
| lseek | llseek |
| ioctl | unlocked_ioctl |
用法例子:(摘自源码bsg.c)
| |
对应的:
| |
当应用层的
open函数调用了xxx.ko的xxx_open函数
当应用层的write函数调用了xxx.ko的xxx_write函数
当应用层的close函数调用了xxx.ko的xxx_release函数
…
我们需要定义一个file_operations的结构体把自己编写的接口配置进去,以便后续cdev_init的初始化。
源码及详解.
led_dev.c
| |
要点详解
静态申请设备号 MKDEV
MKDEV 原型 参数1:主设备号,参数2:次设备号
| |
注册设备号
register_chrdev_region 原型 参数1:声明的设备号,参数2:注册的数量,参数3:注册的名字 返回值:成功为0,失败返回负数的错误码
| |
字符设备的初始化
cdev_init 原型 参数1:定义的字符设备,参数2:file_operations
| |
将设备加入内核
cdev_add 原型 参数1:定义的字符设备地址,参数2:声明的设备号,参数3:加入的数量,返回值:成功为0,失败为负数错误值
| |
设备号注销
unregister_chrdev_region 原型 参数1:声明的设备号,参数2:数量
| |
将字符设备从内核删除
cdev_del 原型 参数1:定义的字符设备地址
| |
编写对应Makefile.
| |
编译完成后,insmod到Linux系统中后,可以通过lsmod查看相关信息,也可以使用cat命令查看/proc/devices,能够找到注册成功的设备名字。
注意:由于没有这里只是小demo是需要手动创建设备节点的,如果配合应用程序使用时,需要为该设备在/dev目录下创建设备文件;
使用:
mknod /dev/led c 239 0mknod 设备文件 设备类型 主设备号 次设备号
后续的博客中将会加入自动创建设备节点的代码,和讲解!
注意
1.手动创建设备文件的时候,主设备号和次设备号不能写错;
2.若此前的设备文件已经存在,再次创建相同名字的设备文件,会出现错误;(解决方法:先使用rm命令删除原来的设备文件,再使用mknod命令重新创建。)
最后用ls -l /dev/xxx检查是否创建成功!
本文详细介绍了Linux字符设备驱动的设计流程,包括设备号的申请、文件操作集的定义与初始化,以及如何将设备加入内核。通过具体示例,解释了如何编写Makefile并编译字符设备驱动。
1278

被折叠的 条评论
为什么被折叠?



