嵌入式Linux驱动开发(三)新字符设备驱动

  前面字符设备用register_chrdev注册设备,用unregister_chrdev注销设备。新的字符设备驱动使用linux推荐的新API。此外,前面测试的时候要自己建立设备节点,本节学习如何在加载驱动的时候自动新建节点。

1. 新字符设备驱动原理

旧方法缺陷:
  register_chrdev注册只需要给一个主设备号,但是这样就导致该主设备号下的次设备号全都归属该设备,比如led,太浪费资源。

解决方案:

<未给定设备号,向内核申请并注册设备号  PARA:设备号指针,起始设备号,申请个数,设备名>
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
<给定主设备号,注册设备号 通常用这个 para:起始设备号(上一行给定的),申请个数,设备名>
int register_chrdev_region(dev_t from, unsigned count, const char *name)
<注销设备号>
void unregister_chrdev_region(dev_t from, unsigned count)
/---------------------------------------------------------------/
int major;        <主设备号>
int minor;        <次设备号>
dev_t devid;      <设备号>

if (major) {      <定义了主设备号>
	devid = MKDEV(major, 0);     <大部分驱动次设备号都选择 >
	register_chrdev_region(devid, 1, "test");
} else {          <没有定义设备号>
	alloc_chrdev_region(&devid, 0, 1, "test");    <申请设备号>
	major = MAJOR(devid);                <获取分配号的主设备号>
	minor = MINOR(devid);                <获取分配号的次设备号>
}

unregister_chrdev_region(devid, 1);      <注销设备号>

2. 新字符设备注册方法

2.1 新字符设备结构

使用cdev结构体表示一个字符设备。

struct cdev {
	struct kobject kobj;
	struct module *owner;
	const struct file_operations *ops;    <操作函数集合>
	struct list_head list;
	dev_t dev;       <设备号>
	unsigned int count;
};

struct cdev test_cdev  <定义了一个字符设备test_dev>

2.2 cdev_init

用于初始化字符设备。

<函数原型>
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
--------------------------------------------------------------------

struct cdev testcdev;
<设备操作函数>
static struct file_operations test_fops = {
	.owner = THIS_MODULE,
	/* 其他具体的初始项 */
};

testcdev.owner = THIS_MODULE;
cdev_init(&testcdev, &test_fops);   <初始化cdev结构体变量>

2.3 cdev_add

向linux系统添加字符设备。

<函数原型 Para:字符设备,设备号,添加个数>
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
-------------------------------------------------------

cdev_add(&testcdev, devid, 1);

2.4 cdev_del

卸载驱动时删除字符设备。
结合unregister_chrdev_region相当于unregister_chrdev。

<函数原型>
void cdev_del(struct cdev *p)
---------------------------------

cdev_del(&testcdev);

3. 自动创建设备节点

3.1 mdev机制

  前面使用modprobe加载模块之后会自动在/dev下创建设备节点文件,rmmod后就会删除文件。这其实是mdev用户程序完成的,该程序可以根据系统中硬件设备状态来创建或者删除设备文件。mdev是BusyBox根据Linux下的udev构建的简化版,用于嵌入式Linux。热插拔事件也是mdev管理的
  下面学习如何用mdev实现自动管理节点。

1)创建和删除类
位置:驱动入口函数,cdev_add之后。

<创建:>
<owner一般为THIS_MODULE,name是类名,返回值是指向结构体class的指针也就是创建的类>
struct class *class_create (struct module *owner, const char *name)

<删除:>
void class_destroy(struct class *cls);

2)创建设备
位置:驱动出口函数。

<创建:>
<class-要创建到哪个类下面;parent-父设备-一般为NULL;devt-设备号>
<drvdata-设备可能使用的数据,一般为NULL;fmt-设备名>
struct device *device_create(struct class *class, 
							 struct device *parent,
							 dev_t devt, 
							 void *drvdata, 
							 const char *fmt, ...)
<删除:>							 
void device_destroy(struct class *class, dev_t devt)

3)设置文件私有数据
其实就是写成结构体封装一下,再open函数中作为私有数据添加到设备文件:

<设备结构体>
struct test_dev{
	dev_t devid;            <设备号>
	struct cdev cdev;       <cdev>
	struct class *class;    <>
	struct device *device;  <设备>
	int major;              <主设备号>
	int minor;              <次设备号>
};

static int test_open(struct inode *inode, struct file *filp)
{
	filp->private_data = &testdev; /* 设置私有数据 */
	return 0;
}

你可能感兴趣的:(嵌入式,驱动开发,linux,运维)