字符设备驱动相关函数

本文深入探讨了Linux字符设备驱动的实现原理,包括cdev结构体的使用、设备号的管理和分配、file_operations的定义,以及设备驱动的注册与注销过程。通过具体函数和操作流程,为读者提供了全面的技术指导。
摘要由CSDN通过智能技术生成

Linux内核中:

a -- 使用cdev结构体来描述字符设备;
b -- 通过其成员dev_t来定义设备号(分为主、次设备号)以确定字符设备的唯一性;
c -- 通过其成员file_operations来定义字符设备驱动提供给VFS的接口函数,如常见的open()、read()、write()等;

Linux字符设备驱动中:

a -- 模块加载函数通过 register_chrdev_region( )alloc_chrdev_region( )来静态或者动态获取设备号;

b -- 通过 cdev_init( ) 建立cdev与 file_operations之间的连接,通过 cdev_add( ) 向系统添加一个cdev以完成注册;

c -- 模块卸载函数通过cdev_del( )来注销cdev,通过 unregister_chrdev_region( )来释放设备号

实现字符设备驱动函数:

1、动态申请设备号 注意,申请的主设备号 是一致的
	int  alloc_chrdev_region(dev_t * dev,unsigned baseminor,
						unsigned count,const char * name);
2、定义并初始化 字符设备对象 [属性 方法]
	struct cdev {
		const struct file_operations *ops;	方法集合
		dev_t dev;							设备号
	};
3、在用户层创建一个字符设备文件
	1)创建一个内核的类
		struct class * class_create(owner,name);
			owner: THIS_MODULE
			name:  你给类起的名字
	2)创建节点, 在用户层/dev/目录下  创建一个 字符设备文件/节点
		struct device *device_create(struct class *class, 
				struct device *parent,
		    		 dev_t devt, void *drvdata, const char *fmt, ...)

实现字符设备驱动释放的函数:

1、/释放 文件节点/

	void device_destroy(struct class * class, dev_t devt)

2、/释放 字符设备驱动对象/

	void cdev_del(struct cdev *)

3、/释放设备号/

	void unregister_chrdev_region(dev_t from, unsigned count)

cdev 结构体解析

<include/linux/cdev.h>

struct cdev { 
	struct kobject kobj;                  //内嵌的内核对象.
	struct module *owner;                 //该字符设备所在的内核模块的对象指针.
	const struct file_operations *ops;    //该结构描述了字符设备所能实现的方法,是极为关键的一个结构体.
	struct list_head list;                //用来将已经向内核注册的所有字符设备形成链表.
	dev_t dev;                            //字符设备的设备号,由主设备号和次设备号构成.
	unsigned int count;                   //隶属于同一主设备号的次设备号的个数.
};

操作这个结构体的入口函数:
1、struct cdev结构体做初始化,最重要的就是建立cdev 和 file_operations之间的连接:

	void cdev_init(struct cdev *, const struct file_operations *);

2、分配一个struct cdev结构,动态申请一个cdev内存

	struct cdev *cdev_alloc(void);
	
3、向内核注册一个struct cdev结构,

	int cdev_add(struct cdev *p, dev_t dev, unsigned count);

4、注销一个struct cdev结构,

	void cdev_del(struct cdev *p);

设备号相应操作

1 – 主设备号和次设备号(二者一起为设备号):
1) -- 从设备号中提取major和minor
	MAJOR(dev_t dev);                              
	MINOR(dev_t dev);

2) -- 通过major和minor构建设备号
	MKDEV(int major,int minor);
2 – 分配设备号(动态和静态)
1)--静态申请
	int register_chrdev_region(dev_t from, unsigned count, const char *name);

2)--动态申请
	int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);

区别:
		register_chrdev_region直接将Majorregister_chrdev_region直接将Major 注册进入。alloc_chrdev_region从Major
		alloc_chrdev_region从Major = 0 开始,逐个查找设备号,直到找到一个闲置的设备号,并将其注册进去;

举例:
1)、静态
	devno = MKDEV(major,minor);
    ret = register_chrdev_region(devno, 1, "hello"); 
    cdev_init(&cdev,&hello_ops);
    ret = cdev_add(&cdev,devno,1);
2)、动态
	alloc_chrdev_region(&devno, minor, 1, "hello");
    major = MAJOR(devno);
    cdev_init(&cdev,&hello_ops);
    ret = cdev_add(&cdev,devno,1)

3)、注册了设备号,做了cdev 的初始化以及cdev 的注册
register_chrdev函数:  
	
	static inline int register_chrdev(unsigned int major, const char *name,
			  const struct file_operations *fops)
		{
			return __register_chrdev(major, 0, 256, name, fops);
		}
3、注销设备号:
void unregister_chrdev_region(dev_t from, unsigned count);
4、创建设备文件:
 利用cat /proc/devices查看申请到的设备名,设备号。

1)使用mknod手工创建:mknod filename type major minor

2)自动创建设备节点: (利用udev(mdev)来实现设备文件的自动创建)
	在驱动初始化的代码里调用class_create(...)为该设备创建一个class,再为每个设备调用device_create(...)创建对应的设备。
函数讲解

I)创建一个类  class_create(...)
	#define class_create(owner, name)		\
	({						\
		static struct lock_class_key __key;	\
		__class_create(owner, name, &__key);	\
	})
	销毁函数:void class_destroy(struct class *cls)
	
II)创建一个字符设备文件  device_create(类,NULL,设备号,NULL,名字) 

	struct device *device_create(struct class *class, struct device *parent,
             dev_t devt, void *drvdata, const char *fmt, ...)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值