1字符设备及其驱动
1.1字符设备简介
字符设备是一种按串行顺序来访问的设备,如触摸屏,磁带驱动器,鼠标等。
1.2字符设备驱动
字符设备驱动负责驱动字符设备,通常实现由open,read,write,close,ioctl等函数。
1.3设备号
设备号分为主次设备号,主设备号标示设备与哪个驱动相连,次设备号标示同一个驱动下的具体设备。
1.4字符驱动编写相关结构
1)file结构体
File结构体代表一个打开的文件(设备也对应一个文件),在系统中,每打开一个文件都在内核存在一个对应的file结构体。
它在一个文件打开时有内核创建,关闭时由内核释放。在期间传递在文件上进行操作的函数。
Structfile的指针通常命名为filp。
structfile {
union{
structlist_head fu_list;
structrcu_head fu_rcuhead;
}f_u;
structpath f_path;
conststruct file_operations *f_op; /*和文件关联的操作*/
spinlock_t f_lock;
atomic_long_t f_count;
unsignedint f_flags; /*文件标志,如:O_RDONLY,O_NONBLOCK*/
fmode_tf_mode; /*文件读/写模块,FMODE_READFMODE_WRITE*/
loff_t f_pos; /*当前读写位置*/
structfown_struct f_owner;
conststruct cred *f_cred;
structfile_ra_state f_ra;
u64 f_version;
void *private_data; /*文件私有数据指针*/
2)inode结构
VFSinode包含文件访问权限,属主,组,大小,生成时间,访问时间,最后修改时间等信息。它是Linux管理文件系统的最基本单位,也是文件系统连接任何子目录,文件的桥梁。
struct inode {
…..
umode_ti_mode; /*inode的权限*/
uid_ti_uid; /*inode拥有都的id*/
gid_ti_gid; /*inode所属的群组id*/
dev_ti_rdev; /*若是设备文件,些字段将记录设备的设备号*/
……
}
3)cdev结构体
cdev结构体用于描述字符设备,可以理解为cdev就是设备。
structcdev {
struct kobjectkobj; /*内嵌的kobject对象*/
struct module*owner; /*所属模块*/
const structfile_operations *ops; /*文件操作结构体-字符设备驱动的核心*/
。。。。。
dev_tdev; /*设备号*/
unsigned intcount;
};
dev_t:其实质为unsignedint 32位整数,其中高12位为主设备号,低20
位为次设备号。使用下列宏可以从dev_t获得主设备号和次设备号:
MAJOR(dev_tdev);
MINOR(dev_tdev);
使用下列宏可以通过主设备号和次设备号生成dev_t
MKDEV(intmajor,int minor);
4)kobject结构体
5)file_operations结构体
file_operations结构体专门用来绑定操作函数,如read,write,ioctl等函数,
file_operations结构体中的成员函数是字符设备驱动程序设计的主体内容,这些函数实际会在应用程序进行linux的open(),write(),read(),close()等系统调用时最终被调用,file_operations结构体目前已经比较庞大。
2字符驱动的编写
2.1字符驱动编写的要义
加载函数
卸载函数
实现file_operations成员函数
其关系图如下:

-
代码编写
-
-
加载模板
structxxx_dev_t//设备结构体
{
structcdev cdev;
...
}xxx_dev;
staticint __init xxx_init(void) /*设备驱动模块加载函数*/
{ ...
cdev_init(&xxx_dev.cdev,&xxx_fops);//初始化cdev
xxx_dev.cdev.owner=THIS_MODULE;
if(xxx_major)
{
register_chrdev_region(xxx_dev_no,1,DEV_NAME);//申请字符设备号
}
else
{
alloc_chrdev_region(&xxx_dev_no,0,1,DEV_NAME);//申请字符设备号
}
ret=cdev_add(&xxx_dev.cdev,xxx_dev_no,1); //注册设备
...
}
-
卸载模板
staticvoid __exit xxx_exit(void) /*设备驱动模块卸载函数*/
{
unregister_chrdev_region(xxx_dev_no,1);//释放占用的设备号
cdev_del(&xxx_dev.cdev);//注销设备
}
-
file_operation成员函数实现模板
// file_operations结构体设置,该设备的所有对外接口在这里明确,此处只写出了几个常用的
staticstruct file_operations xxx_fops =
{
.owner= THIS_MODULE,
.open = xxx_open, //打开设备
.release =xxx_release, // 关闭设备
.read = xxx_read, //实现设备读功能
.write = xxx_write, // 实现设备写功能
.ioctl = xxx_ioctl, //实现设备控制功能
};
字符设备驱动程序设计的主体工作是:
初始化、添加和删除cdev结构体,申请和释放设备号,以及填充file_operations结构体中的操作函数,实现file_operations结构体中的read(),write(),ioctl()等函数。