混杂设备概念
在Linux驱动中把无法归类的五花八门的设备定义为混杂设备,所有混杂设备共享一个主设备号10,但次设备号不同。 所有的混杂设备形成了一个链表,对设备访问时内核根据次设备号查找对应的混杂设备,然后调用其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);
驱动模型思维导图
通过如上知识并结合模块的知识可以画出混杂设备驱动的思维导图:
驱动范例
下面是笔者实现的基于混杂设备驱动的LED设备驱动代码:
驱动代码:
#include <linux/init.h>
#inlude <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
/*打开函数*/
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 <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
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;
}