Linux字符设备驱动基础(一)

Linux字符设备驱动基础(一)

1 Linux驱动分类

在这里插入图片描述

  • 字符设备:按照字节的顺序读写的设备,其不能随机的读取设备内存中的某一数据。字符设备是面向流的设备,常见的字符设备有串口、控制台、LED等。

  • 块设备:通常是指可从设备的任意位置读取到一定长度数据的设备。常见的块设备有:SD卡、U盘、磁盘等。

2 字符设备、字符设备驱动与用户空间三者之间的关系

在这里插入图片描述

1)在Linux内核中:

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

2) 在Linux字符设备驱动中:

  • a – 模块加载函数通过 register_chrdev_region( ) 或 alloc_chrdev_region( )来静态或者动态获取设备号;
  • b – 通过 cdev_init( ) 建立cdev与 file_operations之间的连接,通过 cdev_add( ) 向系统添加一个cdev以完成注册;
  • c – 模块卸载函数通过cdev_del( )来注销cdev,通过 unregister_chrdev_region( )来释放设备号;

3) 用户空间访问该设备的程序:

  • a – 通过Linux系统调用,如open( )、read( )、write( ),来“调用”file_operations来定义字符设备驱动提供给VFS的接口函数;

3 字符设备驱动模型

在这里插入图片描述

4 Cdev结构体解析

struct cdev {
	struct kobject kobj;		//内嵌的内核对象
	struct module *owner;	//该字符设备锁在的内核模块的对象指针
	const struct file_operations *ops;	//该字符设备的实现方法
	struct list_head list;		//链接已在内核注册的所有字符设备
	dev_t dev;			//该字符设备的设备号,由主设备号与次设备号构成
	unsigned int count;		//同一主设备号下的次设备号的个数
} __randomize_layout;

Cdev的相关操作接口:

1)cdev_init

/**
 * cdev_init() - initialize a cdev structure
 * @cdev: the structure to initialize
 * @fops: the file_operations for this device
 *
 * Initializes @cdev, remembering @fops, making it ready to add to the
 * system with cdev_add().
 */
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
	memset(cdev, 0, sizeof *cdev);	//将cdev清零
	INIT_LIST_HEAD(&cdev->list);		//初始化list链表,指向其本身
	kobject_init(&cdev->kobj, &ktype_cdev_default);	//初始化kobj成员
	cdev->ops = fops;				//初始化ops成员
}

2)cdev_alloc

/**
 * cdev_alloc() - allocate a cdev structure
 *
 * Allocates and returns a cdev structure, or NULL on failure.
 */
struct cdev *cdev_alloc(void)
{
	struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);	//动态申请cdev结构体
	if (p) {
		INIT_LIST_HEAD(&p->list);					//初始化list链表
		kobject_init(&p->kobj, &ktype_cdev_dynamic);	//初始化kobj成员
	}
	return p;
}

3)cdev_add

该函数向内核注册一个cdev结构体。

/**
 * cdev_add() - add a char device to the system
 * @p: the cdev structure for the device
 * @dev: the first device number for which this device is responsible
 * @count: the number of consecutive minor numbers corresponding to this
 *         device
 *
 * cdev_add() adds the device represented by @p to the system, making it
 * live immediately.  A negative error code is returned on failure.
 */
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{
	int error;

	p->dev = dev;
	p->count = count;

	error = kobj_map(cdev_map, dev, count, NULL,
			 exact_match, exact_lock, p);
	if (error)
		return error;

	kobject_get(p->kobj.parent);

	return 0;
}

4)cdev_del

该函数向内核注销一个cdev结构体。

/**
 * cdev_del() - remove a cdev from the system
 * @p: the cdev structure to be removed
 *
 * cdev_del() removes @p from the system, possibly freeing the structure
 * itself.
 *
 * NOTE: This guarantees that cdev device will no longer be able to be
 * opened, however any cdevs already open will remain and their fops will
 * still be callable even after cdev_del returns.
 */
void cdev_del(struct cdev *p)
{
	cdev_unmap(p->dev, p->count);
	kobject_put(&p->kobj);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值