字符设备驱动程序框架
设备驱动程序看起来十分的难一个主要的原因是,在写设备驱动程序的时候开发者要遵循的内核规则太多了。一个又一个的struc看得人的头大。因为一般的驱动程序都没不编译进内核的而时动态的加载和卸载的,所以驱动程序的编写一般是有规律可循的,一个固定的模板,这样内核才能认识新加入的驱动。下面就是字符设备的一般的框架:(自己总结的,老是转别人的不好,也要做点贡献吧,哈哈。)
注册与注销:
//设备结构体,里面还可以定义信号量sem,scull.C里这是要样做的(以后把这个代码分析一下)。这是一种良好的编程习惯
struct xxx_dev_t
{
struct cdev cdev;
.......
}xxx_dev; //设备对像
//设备驱动程序模块加载函数
static int __init xxx_init(void)
{
......
cdev_init(&xxx_dev.cdev,&xxx_fops); //和下面的add啊,dell一起定义在cdev.h里面
原型:
void cdev_init(struct cdev *cdev,struct file_operations fops)
{
memeset(cdev,0,sizeof*cdev);//这个嘛,初始化为0,bzero()好像也可以
INIT_LIST_HEAD(&cdev->list);//初始化队列
kobject_init(&cdev->kobj, &ktype_cdev_default);
cdev->ops = fops;//把两个传入的参数给关联起来,
} |
xxx_dev.cdev.owner=THIS_MODULE; //任何驱动代码都一样,但是少不了,照做,哈哈
//
if(xxx_major)
{
register_chrdev_region(xxx_dev_no,1,DEV_NAME);//如果自己定义了主设备号这个可能会成功
但是LDD3中是不推荐这种方法的,因为可能会产生冲突
}
else
{
alloc_chrdev_region(xxx_dev_no,0,1,DEV_NAME);//动态分配的,一般都要用这种方法,申请的主设备号在xxx_dev_no中了
}
ret=cdev_add(&xxx_dev.cdev,xxx_dev_no,1);//cdev.h
.....
}
//设置驱动模块卸载函数
static void __exit xxx_exit(void)
{
unregister_chrdev_region(xxx_dev_no,1);//释放设备
cdev_del(&xxx_dev.cdev); //cdev.h
.....
}
有关file operations:
ssize_t xxx_read(struct file *filp,char __user *buf ,size_t count, loff_t *f_pos)
{
.....
copy_to_user(); //完成内核空间与用户空间的数据交互,这个Copy的数据到底是从那里来到那里去呢?一功都从用户出发。(内核到用户)
.....
}
ssize_t xxx_write(struct file *filp,const char __user *buf ,size_t count, loff_t *f_pos)
{
.....
copy_from_user(); // THE SAME
.....
}
int xxx_ioctl(struct inode *inode ,struct file *filp,unsigned int cmd,unsigned long arg)
{
....
switch(cmd)// 这个嘛,一般要定义幻数(magic)。scull是定义在了本地的头文件中了,这是一个习惯哦,LDD3中定义了14个命令,my god!
{
case xxx_cmd1:
.....;
break;
case xxx_cmd2:
.....;
break;
default:
return -ENOTTY;//不支持的命令
}
return 0;
}
当然文件操作不止这么几个,在fs.h中可以看到里面的定义,本站也有有关三个数据结构的文章。
还可以多定义几个都没有问题的,看需要。
当然 open()
release()可不能少了。
把自己实现的函数关联起来:
strcut file_operations xxx_fops=
{
.owner=THIS_MODULE, //幸亏有了函数指针,不然一个一个对应写,累死人啊,
.read =xxx_read,
.write=xxx_write,
.ioctl=xxx_ioctl,
......
};
模块的入口,必须要使用这两个宏来加载初始化和卸载模块
module_init(xxx_init);
module_exit(xxx_exit);
MODULE_LICENSE("GPL");//这个得加上,不然内核认不了
阅读(1826) | 评论(0) | 转发(0) |