Linux内核修炼之misc设备源码分析
2012-04-23 09:17
483 查看
====本文系本站原创,欢迎转载! 转载请注明出处:http://blog.csdn.net/yyplc====
前面分析了字符设备,接下来分析misc混杂设备。
混杂设备是字符设备的一种,算是字符设备的一种附加品吧。
混杂驱动程序是那些简单的字符驱动程序,它们拥有一些相同的特性。内核将这些性抽象至一个API中,这个API能简化驱动程序初始化的方式。所有的混杂设备的主设备号为10,每个设备可选择一个单独的次设备号。
混杂设备定义以下参数:
misc_minors[7]对应63,62,61,60,59,58,57,56 并且用misc_minors[7]的8位来标记:1表示已分配,0表是未分配
misc_minors[6]对应55,54,53,52,51,50,49,48 并且用misc_minors[6]的8位来标记:1表示已分配,0表是未分配
...
misc_minors[0]对应 7, 6, 5, 4, 3, 2, 1, 0 并且用misc_minors[0]的8位来标记:1表示已分配,0表示未分配
//内核初始化时,通过调用subsys_init()调用misc_init()形成misc子系统
测试例程:
前面分析了字符设备,接下来分析misc混杂设备。
混杂设备是字符设备的一种,算是字符设备的一种附加品吧。
混杂驱动程序是那些简单的字符驱动程序,它们拥有一些相同的特性。内核将这些性抽象至一个API中,这个API能简化驱动程序初始化的方式。所有的混杂设备的主设备号为10,每个设备可选择一个单独的次设备号。
混杂设备定义以下参数:
#define DYNAMIC_MINORS 64 /* like dynamic majors */ static unsigned char misc_minors[DYNAMIC_MINORS / 8];说明可以动态分配64个次设备号(0~63)对应8组misc_minors[]。每组的位对应表示64个次设备号.
misc_minors[7]对应63,62,61,60,59,58,57,56 并且用misc_minors[7]的8位来标记:1表示已分配,0表是未分配
misc_minors[6]对应55,54,53,52,51,50,49,48 并且用misc_minors[6]的8位来标记:1表示已分配,0表是未分配
...
misc_minors[0]对应 7, 6, 5, 4, 3, 2, 1, 0 并且用misc_minors[0]的8位来标记:1表示已分配,0表示未分配
//内核初始化时,通过调用subsys_init()调用misc_init()形成misc子系统
static int __init misc_init(void) { int err; #ifdef CONFIG_PROC_FS proc_create("misc", 0, NULL, &misc_proc_fops); #endif misc_class = class_create(THIS_MODULE, "misc"); //在/sys/class下生成misc目录 err = PTR_ERR(misc_class); if (IS_ERR(misc_class)) goto fail_remove; err = -EIO; if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) //根据主设备号10,注册字符设备 goto fail_printk; return 0; fail_printk: printk("unable to get major %d for misc devices\n", MISC_MAJOR); class_destroy(misc_class); fail_remove: remove_proc_entry("misc", NULL); return err; } subsys_initcall(misc_init); //系统在do_basic_setup()-->do_initcalls调用分析一下miscdevice结构
struct miscdevice { int minor; const char *name; //设备名 const struct file_operations *fops; //操作函数 struct list_head list; //链表 struct device *parent; //指向父设备 struct device *this_device; //指向设备本身 };//misc设备的注册API
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) { //遍历misc设备list if (c->minor == misc->minor) { //如果minor已被分配,则退出 mutex_unlock(&misc_mtx); return -EBUSY; } } if (misc->minor == MISC_DYNAMIC_MINOR) { //如果是动态分配minor则找出minor为相应位为0的次设备号 int i = DYNAMIC_MINORS; while (--i >= 0) if ( (misc_minors[i>>3] & (1 << (i&7))) == 0) break; if (i<0) { mutex_unlock(&misc_mtx); return -EBUSY; } misc->minor = i; } if (misc->minor < DYNAMIC_MINORS) misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7); //相应位置位 dev = MKDEV(MISC_MAJOR, misc->minor); //获取设备号(32位) misc->this_device = device_create(misc_class, misc->parent, dev, NULL, "%s", misc->name); //在/dev下生成设备节点 if (IS_ERR(misc->this_device)) { err = PTR_ERR(misc->this_device); goto out; } /* * Add it to the front, so that later devices can "override" * earlier defaults */ list_add(&misc->list, &misc_list); //将当前设备添加到misc_list设备链表表头之后 out: mutex_unlock(&misc_mtx); return err; }//misc设备的注销API
int misc_deregister(struct miscdevice *misc) { int i = misc->minor; if (list_empty(&misc->list)) return -EINVAL; mutex_lock(&misc_mtx); list_del(&misc->list); device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); if (i < DYNAMIC_MINORS && i>0) { misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); //相应位复位 } mutex_unlock(&misc_mtx); return 0; }
测试例程:
#include <linux/kernel.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/list.h> #include <asm/uaccess.h> #include <linux/delay.h> #include <linux/cdev.h> #include <linux/miscdevice.h> #define DEBUG #ifdef DEBUG #define dbg(fmt, arg...) printk(KERN_DEBUG "my_debug:%s," fmt "\n", __FUNCTION__, ##arg) #else #define dbg(fmt, arg...) (void)(0) #endif #define DEVICE_NAME "my_dev" static int my_misc_open(struct inode *inode, struct file *filp) { dbg("dev ok."); return 0; } static const struct file_operations my_fops = { .open = my_misc_open, }; struct miscdevice my_dev = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &my_fops, }; static int __init my_module_init(void) { int ret; ret = misc_register(&my_dev); if (ret) dbg("misc_register error."); else dbg("misc_register ok."); return 0; } static void __exit my_module_exit(void) { misc_deregister(&my_dev); } module_init(my_module_init); module_exit(my_module_exit); MODULE_AUTHOR("itspy.wei<itspy.wei@gmail.com"); MODULE_DESCRIPTION("my_misc demo"); MODULE_LICENSE("GPL");
相关文章推荐
- linux内核杂项设备驱动源码分析
- Linux驱动修炼之道-SPI驱动框架源码分析(中)
- Linux驱动修炼之道-SPI驱动框架源码分析(下)
- Linux设备模型分析之bus(基于3.10.1内核)
- Linux内核源码分析--文件系统(七、Namei.c)
- Linux_内核源码分析方法
- linux 内核源码分析 - 获取数组的大小
- Linux设备模型分析之kobject(基于3.10.1内核)
- Linux驱动修炼之道-SPI驱动框架源码分析(中)
- Linux设备模型分析之kobject(基于3.10.1内核)
- Linux-0.11内核源码分析系列:内存管理up_wp_page()与do_wp_page()函数分析
- Linux驱动修炼之道-RTC子系统框架与源码分析
- Linux内核部件分析 设备驱动模型的基石kobject
- Linux usb设备驱动(2)---> usbmouse.c 源码分析
- Linux驱动修炼之道-SPI驱动框架源码分析(下)
- Linux内核源码分析--内核启动命令行的传递过程(Linux-3.0 ARMv7)
- [精华]]Linux内核2.6.14源码分析-双向循环链表代码分析(转)
- linux内核部件分析(七)——设备驱动模型之driver
- Linux设备模型分析之device(基于3.10.1内核)
- Linux内核导出符号宏定义EXPORT_SYMBOL的源码分析