字符设备驱动的学习
1.首先介绍几个重要的结构体:
1.1 cdev结构体描述字符设备
Struct cdev
{
struct kobject kobj; /*内嵌的kobject对象*/
sruct module *owner; /*所属模块*/
struct file_operations *ops; //文件操作结构体
Struct list_head list;
dev_t dev ; //设备号
unsigned int count;
}
其中file_operations定义了字符设备驱动提供给虚拟文件系统的接口函数,void cdev_init(struct cdev*, struct file_operations *);这个函数用于初始化cdev的成员,并且建立cdev和file_operations之间的链接。
void cdev_init(struct cdev *cdev,struct file_operations *fops)
{
memset(cdev, 0 , sizeof *cdev);
INIT_LIST_HEAD(&cdev->list);
cdev->kobj.ktype = &ktype_cdev_default;
kobject_init(&cdev->kobj);
cdev->ops = fops; //讲传入的文件操作结构体指针赋值给cdev的ops*
}
cdev_add()函数和cdev_del()函数用于向操作系统添加和删除一个cdev,完成字符设备的注册与注销。
注册字符设备之前,首先调用register_chardev_region()或者alloc_chrdev_region函数向系统申请设备号,这两个函数的原型如下:
int register_chardev_region(dev_t from ,unsigned int count ,const char *name);
int alloc_chrdev_region(dev_t *dev, unsigned int baseminor ,unsigned int count ,const char *name);
其中第二个函数用于向设备动态申请未被占用的设备号。
字符设备驱动的组成
2.1.定义一个xxx_dev_t结构体可以包含设备所涉及的cdev,私有数据以及信号量等信息。常见的设备结构体、模块加载和卸载函数形式如下所示
struct xxx_dev_t
{
struct cdev cdev;
、、、、、
} XXX_dev;
//获取字符设备号
static int __init xxx_init(void)
{
....
cdev_init(&xxx_dev.cdev, &xxx_fops)
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); //注册设备
.。。。。。
}
//设备驱动模块卸载函数
static void __exit xxx_exit(void )
{
unregister_chrdev_region(xxx_dev_ni, 1);//释放占用的设备号
cdev_del(&xxx_dev.cdev); //注销设备
}
2.2.file_operations结构体中的成员函数最常见的3个函数如下所示。
ssize_t xxx_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos )
{
.。。。
copy_to_user(buf , ... , ....);
。。。
}
//写设备
ssize_t xxx_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
。。。
copy_from_user(。。。, buf , 。。。);
}
int xxx_ioctl(stuect inode *inode ,struct file *filp ,unsigned int cmd ,unsigned int long arg)
{
.....
switch(cmd)
{
case XXX_CMD1:
.....
break;
case XXX_CMD2:
.....
break;
default:
return -ENOTTY;
}
return 0;
}
字符设备室3大类设备(字符设备、块设备和网络设备)中较简单的一类设备,其驱动程序中完成的主要工作是初始化、添加和删除cdev结构体,申请和释放设备号,以及填充file_operations结构体中的操作函数,实现file_operations结构体重的read()、write()和ioctl()等函数是驱动设计的主体工作。