目录
一、简介
Linux字符设备驱动框架:主要服务于外设,或者硬件设备。例如:温度传感器、湿度传感器。
Linux系统有3种最基本的字符设备驱动模型(框架):
第一个:杂项设备驱动模型。
第二个:早期经典字符设备驱动模型(框架)。
第三个:Linux2.6标准字符设备驱动模型。它是在linux2.6版本之后发布的共同点:
都是需要一个struct file_operations类型文件操作方法的结构,里面包含了对设备的各种I/O操作。并且都需要在设备使用前进行注册(函数),不是使用的时候进行注销(函数)。
不同点:
注册的时候,它们使用的设备节点文件的主(驱动程序),次设备号(设备)不同,注销和注册方法不同。
好处:
可以只用加载一次驱动程序。
总结:
注册这些字符设备驱动的时候,本质上都是注册主设备号、次设备号和文件操作方法--struct file_operation,以及其他不重要都是一些属性信息(根据实际情况添加)。
二、文件操作方法
1.open(应用端--接口函数)
头文件:
#include<sys/types.h>
#include<sys/stat.h>
#include <fcntl.h>
原型 :
int open(const char *pathname , int flags, mode_t mode); (文件IO中对应的open函数)--最终对应到驱动程序里面的xxx_open
功能:
以指定的方式打开或创建一个文件
参数:
Pathname:路径
flags:打开方式
mode:权限
返回值:
成功:返回一个系统分配的文件描述符
失败:-1
2.pread() --read(系统调用的接口函数)
头文件:
#include <unistd.h>
原型:
ssize_t pread(int fd,void *buf,size_t count,off_t offset);
功能:
从指定文件中的位置开始读取count个字节到内存缓冲区buf
参数:
fd:表示文件描述符
buf:缓存的首地址
count:期望读取的字节数
offset:相对于文件头的偏移
返回值:
成功:实际读取到的字节数0
失败:-1
3.pwrite()
头文件:
#include <unistd.h>
原型:
ssize_t pwrite(int fd,const void *buf,size_t count,off_t offset)
功能:
从buf中取count个字节写入到指定的文件中--(驱动里面写入内容)的指定位置
参数:
Buf:缓存区的首地址
count:表示期望写入的字节数
offset:相对于文件头的偏移
返回值:
正常:count字节数
失败:-1
4.ioctl()
头文件:
#include <sys/ioctl.h>
原型:
int ioctl(int fd,unsigned long request,...)
功能:
通过命令码(系统定义,也可以自定义)来控制硬件设备,相当于Linux系统提供了一个扩展功能的一个接口,用户可以自定义命令码,让硬件执行不同的功能。
参数:
fd:待操作硬件设备的对应的文件描述符(设备文件节点的标识)
request:命令码,有些系统预定义 ,也可以用户自定义
返回值:
成功:0或正数
失败:-1
5.poll()
头文件:
#include <poll.h>
原型:
int poll(struct pollfd *fds,nfds_t nfds,int timeout)
功能:
监测一个或者多个指定文件描述符是否就绪,如果至少一个文件描述就绪,返回就绪文件描述符的数量
参数:
fds:待监测文件描述符的集合
struct pollfd{
int fd; //被监测的文件描述符
short evrnt; //期望的文件状态,POLLIN(读就绪) POLLOUT(写就绪)
short revent; //实际返回的文件
};
返回值:
>0 就是就绪的文件描述符数量
0:超时
-1:异常
三、杂项字符设备驱动模型
1.特征
(1)杂项字符设备的驱动通常服务一个杂项字符设备------一个驱动程序对应一个设备。
(2)主设备号固定10。一旦主设备固定了,只能对应一个设备。
(3)次设备号取值范围是0~255,每注册一个杂项设备需要占用一个次设备号。--device(只能接入256个设备)
(4)驱动加载成功之后,内核会在/dev/ 下自动创建设备节点文件
2.缺点
(1)主设备号固定10,无法选择其他的主设备号。(限定:一个驱动程序,在杂项设备驱动模型里面,占用了一个次设备号)
(2)次设备号有256个可用,资源紧张。(对未来来说,这个范围是比较小的)
(3)驱动加载时只能创建一个设备节点文件,因此只能服务一个设备,通用性差。
(4)驱动加载时内核自动创建设备节点文件,设备(device)可能不存在,应用层无法创建(硬件异常-杂项设备模型发现不了)
3.核心数据结构
第一个结构:
struct file_operations
杂项设备驱动模型的核心结构(重点):
#include <linux/miscdevice.h>
struct miscdevice{
int minor; //次设备号0~255 表示内核分配一个可用的次设备号--0,1,2
const char *name; //设备名--也是设备节点的名字,用:内核根据该名称自动在/dev/下 创建同名的设备节点文件
const struct file_operations *fops; //指向文件操作方法对应的指针
....//其他的参数是内核调用的
}
4.相关的函数和宏
包含的头文件:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
//linux内核里面的API函数
内核源码--查看:
int misc_register(struct miscdevice * misc)
{
dev_t dev;
int err = 0;
bool is_dynamic = (misc->minor == MISC_DYNAMIC_MINOR);
INIT_LIST_HEAD(&misc->list);
mutex_lock(&misc_mtx);
if (is_dynamic) {
int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);
if (i >= DYNAMIC_MINORS) {
err = -EBUSY;
goto out;
}
misc->minor = DYNAMIC_MINORS - i - 1;
set_bit(i, misc_minors);
} else {
struct miscdevice *c;
list_for_each_entry(c, &misc_list, list) {
if (c->minor == misc->minor) {
err = -EBUSY;
goto out;
}
}
}
头文件:
#include <linux/miscdevice.h>
原型:
int misc_register(struct miscdevice *misc)