版权声明:本文为博主原创文章,未经博主允许不得转载。
https://blog.csdn.net/huangweiqing80/article/details/82768109
混杂设备miscdevice是字符设备的一种,它们共享一个主设备号MISC_MAJOR(即10),但次设备号不同,所有的miscdevice设备形成了一个链表,对设备访问时内核根据次设备号查找对应的miscdevice设备。这样做的好处,节约主设备号,将某些设备用链表的形式链接在一起,最后通过查找次设备区分。
miscdevice混杂设备用主设备号无法匹配出设备驱动,只能找到链表,再通过次设备号,才能找到设备驱动,而一般字符设备,通过主设备号,就能找到设备驱动了。然后调用其file_operations结构中注册的文件操作接口进行操作。 在内核中用struct miscdevice表示miscdevice设备,然后调用其file_operations结构中注册的文件操作接口进行操作。
描述结构
混杂设备在内核中用struct miscdevice 描述,其定义如下:
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次设备号、name设备名、fops 设备操作集
注册驱动
混杂设备驱动通过如下函数注册:
int misc_register(struct miscdevice *misc);
注销驱动
通过如下函数注销驱动:
int misc_deregister(struct miscdevice *misc);
驱动模型思维导图
通过如上知识并结合模块的知识可以画出混杂设备驱动的思维导图:
我们在上一篇字符设备驱动中知道字符设备驱动模型需要申请构建设备号、初始化字符设备、注册字符设备等相对比较繁琐的几个步骤。但是我们放到混杂设备中就相对简单了,只需要两步即可完成
1.初始化设备结构 struct miscdevice
2.注册设备结构 misc_register
下面是笔者实现的基于混杂设备驱动的LED设备驱动代码:
驱动代码:
#include
#inlude
#include
#include
/*打开函数*/
int misc_open(struct inode *inode,struct file *file){
led_con = ioremap(LEDCON,4);
led_dat = ioremap(lEDDAT,4);
writel(0x00000001,led_con);
return 0;
}
/*控制函数*/
long misc_ioctl(struct file *file,unsigned int cmd,unsigned long arg){
switch(cmd){
//点亮led
case 1: writel(0x01,led_dat);
break;
//熄灭led
case 0: writel(0x00000000,led_dat);
break;
default:
return -EINVAL;
}
return 0;
}
/*关闭函数*/
int misc_close(struct inode *inode, struct file *file){
return 0;
}
/*定义操作函数集*/
struct file_operations misc_fops = {
.open = misc_open,
.unlocked_ioctl = misc_ioctl,
.release = misc_close,
};
/*定义混杂设备驱动描述结构*/
struct miscdevice misc = {
.minor = 100,
.name = "misc",
.fops = misc_fops,
};
/*模块加载函数*/
static int misc_init(void){
misc_register(&misc);
return 0;
}
/*模块卸载函数*/
static void misc_exit(void){
misc_deregister(&misc);
}
MODULE_LICENSE("GPL");
module_init(misc_init);
module_exit(misc_exit);
调用驱动的应用程序测试代码:
#include
#include
#include
#include
#include
#include
int main(int argc,char *argv[]){
int fd;
int i=0;
//因为驱动直接在/dev/目录下生成了设备节点misc ,因此应用程序可以直接打开该文件。
fd = open("/dev/misc",O_RDWR);
if(fd<0){
printf("App open failed\n");
return 0;
}
while(i++ < 4){
ioctl(fd,0);
sleep(1);
ioctl(fd,1);
sleep(1);
}
return 0;
}
当然上面的驱动程序我们完全可以用字符设备驱动模型来写,但是这样会麻烦很多