一、字符设备基础知识
1、设备驱动分类
linux系统将设备分为3类:字符设备、块设备、网络设备。使用驱动程序:
字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据。字符设备是面向流的设备,常见的字符设备有鼠标、键盘、串口、控制台和LED设备等。
块设备:是指可以从设备的任意位置读取一定长度数据的设备。块设备包括硬盘、磁盘、U盘和SD卡等。
每一个字符设备或块设备都在/dev目录下对应一个设备文件。linux用户程序通过设备文件(或称设备节点)来使用驱动程序操作字符设备和块设备。
2、字符设备、字符设备驱动与用户空间访问该设备的程序三者之间的关系
如图,在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( )来释放设备号;
用户空间访问该设备的程序:
a -- 通过Linux系统调用,如open( )、read( )、write( ),来“调用”file_operations来定义字符设备驱动提供给VFS的接口函数;
3、字符设备驱动模型
二、cdev 结构体解析
在Linux内核中,使用cdev结构体来描述一个字符设备,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; //隶属于同一主设备号的次设备号的个数.
};
内核给出的操作struct cdev结构的接口主要有以下几个:
a -- void cdev_init(struct cdev *, const struct file_operations *);
其源代码如代码清单如下:
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
memset(cdev, 0, sizeof *cdev);
INIT_LIST_HEAD(&cdev->list);
kobject_init(&cdev->kobj, &ktype_cdev_default);
cdev->ops = fops;
}
该