一,混杂设备的定义
在Linux中,存在这么一类字符设备,他们拥有相同的主设备号为10,但次设备号不同,这类设备就称为混杂设备(miscdevice).所有的混杂设备形成一个链表,对设备访问时内核根据次设备号查找到相应的混杂设备。
混杂设备定义头文件<linux/miscdevice.h>中
二,描述混杂设备的结构体
在这个结构体中我们只关心以下几个变量的初始化。
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;
};
三,混杂设备的注册与注销
注册:int misc_register(struct miscdevice *misc)
释放:int misc_deregister(struct miscdevice *misc)
四,驱动调用的实质
通过 设备文件找到与之对应设备号的设备,再通过设备初始化时绑定的操作函数对硬件进行控制的。
五,实例分析
下面这个例子是运行在tiny6410上的按键驱动程序。
//混杂设备驱动模型
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/hardware.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
#include <mach/gpio-bank-n.h>
#include <mach/gpio-bank-l.h>
#define DEVICE_NAME "keys" //定义设备名称
#define MISC_DYNAMIC_MINOR 200 //主设备号
#define GPNCON 0x7F008830
//中断函数
static irqreturn_t buttons_interrupt(int irq, void *dev_id)
{
//1检测设备中是否发生了中断
//2清楚中断产生的标准
//3相应的硬件操作——————在这里就是打印出那个按键被按下
printk(KERN_EMERG "key dowm\n"); //打印
return 0;
}
//初始化函数
static int s3c64xx_buttons_open(struct inode *inode, struct file *file)
{ //一般选择open()函数中完成按键的初始化
//但在这里单独定义一个函数进行初始化
return 0;
}
//按键初始化函数
static int int_key()
{
//初始化按键对应的GPIO引脚为中断功能
//K1 对应着 GPN0 对应的中断时EINT0
unsigned int *gpio_config;
unsigned short data;
gpio_config=ioremap(GPNCON,4); //物理地址转换为虚拟地址
data=readw(gpio_config); //readw()读取寄存器原来的值
data &= ~0b11;
data |= 0b10; //把GPN0设置为10
writew(data,gpio_config); //将data数值写入寄存器
printk(KERN_EMERG "function init\n");
return 0;
}
//操作函数集
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.open = s3c64xx_buttons_open,
};
static struct miscdevice misc = { //在Linux中使用struct miscdevice这个结构来描述混杂设备
.minor = MISC_DYNAMIC_MINOR, //次设备号
.name = DEVICE_NAME, //设备名,使用宏定义来定义设备名
.fops = &dev_fops, //file_operation操作函数集
};
static int __init dev_init() //注册混杂设备
{
int ret;
ret = misc_register(&misc);
request_irq(IRQ_EINT(0),buttons_interrupt,IRQF_TRIGGER_FALLING,"key",0); //注册中断函数
//注册中断函数有五个参数,中断号(与硬件相关),中断处理函数,与中断有关的各种选项
int_key(); //初始化按键函数 //设备名,共享中断时使用
//设置为下降沿触发中断 IRQF_TRIGGER_FALLING
printk (DEVICE_NAME"\tinitialized\n");
return ret;
}
static void __exit dev_exit() //注销混杂设备
{
misc_deregister(&misc);
}
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL"); //表明遵循GPL协议
MODULE_AUTHOR("FriendlyARM Inc.");