27 miscdevice设备驱动应用及实现原理
2017-06-11 17:25
447 查看
miscdevice是字符设备驱动的简化版本,方便实现一个简单的字符设备驱动.
//只适用于没有同类型的设备驱动. 也就是一个驱动只对应一个硬件.
////////////////////////
测试代码, test.c:
//编译加载驱动后,设备文件会自动创建.
// miscdevice设备驱动实现起来比较简单,但无法实现一个设备驱动支持多个同类的设备.因miscdevice只能指定一个次设备号, 也就一个设备号。同类的设备是由不同的次设备号区分开的。所以miscdevice只适用于只有一个设备的设备驱动,例如: RTC, 看门狗.
//////////////////////////////////////////////////////////////////////
miscdevice的工作原理.
首先可修改file对象的f_op指针,指向另一个file_operations对象的地址。修改后,新的file_operations对象里的操作函数会得到调用.
测试代码:
////////////////////////////////////////////
miscdevice设备驱动的实现原理:
在内核源码drivers/char/misc.c文件里:
///////////////
当我们实现miscdevice设备驱动时,初始化一个miscdevice对象, 调用misc_register(对象的地址)注册.
misc_list是在misc.c文件里的一个全局内核链表头, 用于通过miscdevice对象的list成员,存放所有的miscdevice对象.
//////////////////
//只适用于没有同类型的设备驱动. 也就是一个驱动只对应一个硬件.
#include <linux/miscdevice.h> struct miscdevice { int minor; //指定次设备号,次设备号为255则会自分配空闲的次设备号. 主设备号已固定为10. //次设备号在(0~255)之间. const char *name; //名字, 指定的名字也是设备文件的名字.设备文件会在注册时自动创建 const struct file_operations *fops; //文件操作对象的地址 ... }; extern int misc_register(struct miscdevice * misc); //注册miscdevice对象 extern int misc_deregister(struct miscdevice *misc);//反注册
////////////////////////
测试代码, test.c:
#include <linux/init.h> #include <linux/module.h> #include <linux/miscdevice.h> #include <linux/fs.h> ssize_t myread(struct file *fl, char __user *buf, size_t len, loff_t *off) { printk("in myread ...\n"); return 0; } struct file_operations fops = { .read = myread, }; struct miscdevice mymdev = { .minor = MISC_DYNAMIC_MINOR, // 255 .name = "mymdev", .fops = &fops, }; static int __init test_init(void) { return misc_register(&mymdev); } static void __exit test_exit(void) { misc_deregister(&mymdev); } module_init(test_init); module_exit(test_exit); MODULE_LICENSE("GPL");
//编译加载驱动后,设备文件会自动创建.
// miscdevice设备驱动实现起来比较简单,但无法实现一个设备驱动支持多个同类的设备.因miscdevice只能指定一个次设备号, 也就一个设备号。同类的设备是由不同的次设备号区分开的。所以miscdevice只适用于只有一个设备的设备驱动,例如: RTC, 看门狗.
//////////////////////////////////////////////////////////////////////
miscdevice的工作原理.
首先可修改file对象的f_op指针,指向另一个file_operations对象的地址。修改后,新的file_operations对象里的操作函数会得到调用.
测试代码:
#include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #define MYMA 4095 ssize_t myread2(struct file *fl, char __user *buf, size_t len, loff_t *off) { printk("in myread2 ...\n"); return 0; } struct file_operations fops2 = { .read = myread2, }; int myopen(struct inod *ind, struct file *fl) { fl->f_op = &fops2; //在open函数里修改file对象的f_op成员,指向fops2对象的地址. //当read函数调用时,则fops2对象的read函数会得到调用. return 0; } ssize_t myread(struct file *fl, char __user *buf, size_t len, loff_t *off) { printk("in myread ...\n"); return 0; } struct file_operations fops = { .open = myopen, .read = myread, }; static int __init test_init(void) { int ret; ret = register_chrdev(MYMA, "mydev", &fops); return ret; } static void __exit test_exit(void) { unregister_chrdev(MYMA, "mydev"); }
////////////////////////////////////////////
miscdevice设备驱动的实现原理:
在内核源码drivers/char/misc.c文件里:
static int __init misc_init(void) { int err; ... misc_class = class_create(THIS_MODULE, "misc");//创建/sys/class/misc子目录,稍后创建设备信息用. ... if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) //当主设备号为10,次设备号(0~255)的所有设备文件打开操作时,会调用misc_fops对象里的open函数. goto fail_printk; ... } subsys_initcall(misc_init); //会在内核子系统初始化自动调用misc_init函数.
///////////////
当我们实现miscdevice设备驱动时,初始化一个miscdevice对象, 调用misc_register(对象的地址)注册.
misc_list是在misc.c文件里的一个全局内核链表头, 用于通过miscdevice对象的list成员,存放所有的miscdevice对象.
int misc_register(struct miscdevice * misc) { struct miscdevice *c; dev_t dev; int err = 0; INIT_LIST_HEAD(&misc->list); mutex_lock(&misc_mtx); //遍历链表,确认指定次设备号是否已用. list_for_each_entry(c, &misc_list, list) { if (c->minor == misc->minor) { mutex_unlock(&misc_mtx); return -EBUSY; } } if (misc->minor == MISC_DYNAMIC_MINOR) { //当需要动态分配空闲的次设备号时的操作 ... } //创建设备文件 dev = MKDEV(MISC_MAJOR, misc->m 4000 inor); misc->this_device = device_create(misc_class, misc->parent, dev, misc, "%s", misc->name); list_add(&misc->list, &misc_list); //通过list成员,把miscdevice对象加入misc_list链表. //也可以在misc_list链表里根据次设备号找到相应的miscdevice对象 out: mutex_unlock(&misc_mtx); return err; }
//////////////////
static const struct file_operations misc_fops = { .open = misc_open, ... }; //当主设备号为10,次设备号(0~255)的所有设备文件打开操作时,会调用misc_fops对象里的open函数. static int misc_open(struct inode * inode, struct file * file) { int minor = iminor(inode); //获取打开的设备文件的次设备号 struct miscdevice *c; int err = -ENODEV; const struct file_operations *old_fops, *new_fops = NULL; mutex_lock(&misc_mtx); //遍历misc_list链表, 根据次设备号minor找到对应的miscdevice对象 list_for_each_entry(c, &misc_list, list) { if (c->minor == minor) { new_fops = fops_get(c->fops); //找到后,则用new_fops指定存放miscdevice对象的fops成员存放file_operations对象的地址. 也就是我们自己miscdevice设备驱动里实现file_operatins对象的地址 break; } } err = 0; old_fops = file->f_op; file->f_op = new_fops; //把file对象的f_op成员指向我们的file_operations对象的地址, 以后我们的file_operations里实现的函数就会得到调用. //如果我们实现的file_operations对象里有open函数,则调用 if (file->f_op->open) { file->private_data = c; err=file->f_op->open(inode,file); if (err) { fops_put(file->f_op); file->f_op = fops_get(old_fops); } } fops_put(old_fops); fail: mutex_unlock(&misc_mtx); return err; }
相关文章推荐
- 25 驱动设备申请及源码实现设备文件创建一体函数(miscdevice)
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(一)
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(六)
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(七)
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(七) .
- 基于MTD的NANDFLASH设备驱动底层实现原理分析 一
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(二)
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(二)
- miscdevice混杂设备驱动
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(四)
- 基于MTD的NANDFLASH设备驱动底层实现原理分析 .
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(四)
- miscdevice.h----其它类型设备驱动的注册方式(转载)
- input子系统学习笔记三 驱动的分层及设备驱动层实现原理
- 设备驱动安装(从原理到实现)
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(五)
- linux高级字符设备驱动之 四 poll方法(select多路监控原理与实现)
- input子系统学习笔记三 驱动的分层及设备驱动层实现原理
- 基于MTD的NANDFLASH设备驱动底层实现原理分析 二
- 基于MTD的NANDFLASH设备驱动底层实现原理分析