Linux字符设备驱动模型

目录

一、简介

二、文件操作方法

1.open(应用端--接口函数)

2.pread() --read(系统调用的接口函数)

3.pwrite()

4.ioctl()

5.poll()

三、杂项字符设备驱动模型

1.特征

2.缺点

3.核心数据结构 

4.相关的函数和宏

四、驱动代码的实现

1.杂项设备驱动模型的实现

2.杂项设备驱动模型的实例代码

3.总结

五、早期经典字符设备驱动模型

1.特征

2.缺点

3.手动创建字符设备节点文件的命令

4.自动创建设备节点--内核kernel里面的API函数

4.1 class_create()

4.2 device_create

4.3 class_destroy()

4.4 device_destroy

六、Linux2.6标准字符设备模型

1.特征 

2.核心数据结构

3.相关函数或宏

3.1 cdev_alloc()

3.2 register_chrdev_region()

3.3 alloc_chrdev_region()

3.4 cdev_init()

3.5 cdev_add()

4.标准字符驱动模型

七、三种字符设备模型的比较

八、利用标准字符模型自动创建设备号及设备节点文件


一、简介

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)    

  • 11
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值