1. Linux混杂设备驱动模型
① 在Linux系统中,存在一类字符设备,它们拥有相同的主设备号(10),但次设备号不同,我们称这类设备为混杂设备(miscdevice)。所有混杂设备形成一个链表,对设备访问时内核根据次设备号查找相应的混杂设备。
② Linux中使用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; };
③ Linux中使用misc_register函数来注册一个混杂设备驱动
int misc_register(struct miscdevice * misc)
④ Linux中使用misc_deregister函数来注销一个混杂设备驱动
int misc_deregister(struct miscdevice *misc)
2. Linux按键设备驱动
① request_irq函数用于注册中断
int request_irq(unsigned int irq, void(*handler)(int, void*, struct pt_reg*), unsigned long flags, const char* devname, void* dev_id);
(1)irq:中断号
(2)handler:中断处理函数
(3)flags:与中断管理有关的各种选项
(4)devname :设备名
(5)dev_id:共享中断是使用,区分不同中断
(6)返回0表示成功,或者返回一个错误码
② 在flags参数中,可以选择一些与中断管理有关的选项
(1)IRQF_DESABLED(SA_INTERRUPT):如果改位置位,表示是一个“快速”中断处理程序;如果没有置位该位,是一个“慢速”中断处理程序
(2)IRQF_SHARED(SA_SHIRQ):该位表明中断号是被多个中断源共享的
③ 快、慢速中断的主要区别在于:快速中断保证中断处理的原子性(不被打断),而慢速中断则不保证。换句话说,也就是“开启中断”标志位(处理器IF位)在运行快速中断处理程序时是关闭的,因此在服务该中断时,不会被其他类型的中断打断;而调用慢速中断处理时,其它类型的中断仍可以得到服务
④ 中断处理程序的特别之处是在中断上下文中运行的,它的行为受到某些限制:
(1)不能使用可能引起阻塞的函数
(2)不能使用可能引起调度的函数
⑤ 当设备不再需要使用中断时(通常在卸载驱动时),应当把它注销,使用函数:
void free_irq(unsigned int irq, void* dev_id);
⑥ 进程上下文和中断上下文
(1)进程上下文:用户空间的应用程序,通过系统调用,进入内核空间。这个时候用户空间的进程要传递很多变量、参数的值给内核,内核态运行的时候也要保存用户进程的一些寄存器的值、变量等。所谓的“进程上下文”,可以看做是用户传递给内核的这些参数以及内核要保存的那一整套变量和寄存器的值以及当时的环境。
(2)中断上下文:用户通过触发信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件的一些变量和参数也要传递给内核,内核通过这些参数进行中断处理。所谓的“中断上下文”,其实可以看做就是硬件传递过来的这些参数和内核需要保存的一些其他环境(主要是当前被打断执行的进程环境)
⑦ Linux按键设备驱动简单示例
#include <linux/module.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/io.h>
#define GPGCON 0x56000060
irqreturn_t key_int(int irq, void *dev_id)
{
//1. 检测是否发生了按键中断
//2. 清除已经发生的按键中断
//3. 打印按键值
printk("key down!
");
return 0;
}
void key_hw_init(void)
{
unsigned short data;
unsigned int *gpio_config;
gpio_config = ioremap(GPGCON, 4);
data = readw(gpio_config);
data &= ~0b11;
data |= 0b10;
writew(data, gpio_config);
}
int key_open(struct inode *node, struct file *filp)
{
return 0;
}
struct file_operations key_fops =
{
.open = key_open,
};
struct miscdevice key_miscdev = {
.minor = 200,
.name = "Mini2440Key",
.fops = &key_fops,
};
static int button_init(void)
{
misc_register(&key_miscdev);
//按键硬件初始化
key_hw_init();
//注册中断处理程序
request_irq(IRQ_EINT8, key_int, IRQF_TRIGGER_LOW, "Mini2440Key", 0);
return 0;
}
static void button_exit(void)
{
free_irq(IRQ_EINT8, 0);
misc_deregister(&key_miscdev);
}
module_init(button_init);
module_exit(button_exit);