在Linux系统中,存在一类字符设备,他们共享一个主设备号(10),但此设备号不同,我们称这类设备为混杂设备(miscdeivce),查看/proc/device中可以看到一个名为misc的主设备号为10.所有的混杂设备形成一个链表,对设备访问时内核根据次设备号找到对应的miscdevice设备。
Linux内核使用struct miscdeivce来描述一个混杂设备
struct miscdevice {
int minor;
const char *name;
const struct file_operations *fops;
struct list_head list;
struct device *parent;
struct device *this_device;
const char *nodename;
mode_t mode;
};
minor是这个混杂设备的次设备号,若由系统自动配置,则可以设置为MISC_DYNANIC_MINOR,name是设备名.使用时只需填写minor次设备号,*name设备名,*fops文件操作函数集即可。
Linux内核使用misc_register函数注册一个混杂设备,使用misc_deregister移除一个混杂设备。注册成功后,内核为自动为该设备创建设备节点,在/dev/下会产生相应的节点。
注册函数:
int misc_register(struct miscdevice * misc)
输入参数:struct miscdevice
返回值:
表示注册成功。
负数 表示未成功。
卸载函数:
int misc_deregister(struct miscdevice *misc)
0 表示成功。
负数 表示失败。
下面是基于linux 混杂设备模型的一个简单示例:
#include#include #include #include #include #include #include #include #include #include #include #include #define DEVICE_NAME "BELL-Control"volatile unsigned long *gpbcon = NULL ;volatile unsigned long *gpbdat = NULL ; volatile unsigned long *gpbup = NULL ;static int bell_drv_open(struct inode *inode, struct file *file){ *gpbcon &= ~(0x3<<(0*2)); *gpbcon |= (0x1<<(0*2)) ; *gpbup = 0x0; printk("first_drv_open\n"); return 0;}static ssize_t bell_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos){ int val; copy_from_user(&val, buf, count) ; if (val == 1) { *gpbdat &= ~(1<<0); printk("first_drv_write 1111111\n"); } else { *gpbdat |= (1<<0); printk("first_drv_write 00000\n"); } return 0;}static struct file_operations bell_drv_fops = { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ .open = bell_drv_open, .write = bell_drv_write, }; //注册混杂设备,每一个misc驱动会自动出现在/sys/class/misc/下static struct miscdevice misc = { .minor =MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &bell_drv_fops,};static int bell_drv_init(void){ int result; result = misc_register(&misc); printk (""DEVICE_NAME" initialized\n"); gpbcon = (volatile unsigned long *)ioremap(0x56000010, 16); gpbdat = gpbcon + 1; gpbup = gpbcon + 2; return 0; }static void bell_drv_exit(void){ misc_deregister(&misc); iounmap(gpbcon);}module_init(bell_drv_init);module_exit(bell_drv_exit);MODULE_LICENSE("GPL");