一、混杂设备驱动模型
1.概念
在Linux系统中,存在一类
字符设备,它们
拥有相同的主设备号(10),但次设备号不同,我们称这类设备为混杂设备(miscdevice)。所有的混杂设备形成一个链表,对设备访问时内核根据次设备号查找到相应的混杂设备。
2.设备描述
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;
};
3.设备注册
Linux中使用misc_register函数来注册一个混杂设备驱动。
int misc_register(
struct miscdevice * misc);
二、 Linux中断处理程序
1.裸机中断处理流程回顾
①初始化寄存器设置,中断有一个统一的入口
②事先设置中断处理程序
③根据中断源编号,调用中断处理程序
2.Linux中断处理流程分析
中断入口:__irq_svc(entry-arm.S)
①拿到产生中断源的编号(中断号)
②根据中断号,找到相应的irq_desc结构
③取出事先注册好的处理函数运行
3.Linux中断处理程序设计
3.1 中断注册
request_irq函数用于注册中断。
int requset_irq(unsigned int irq, void (*handler)(int , void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
返回:0表示成功,失败返回错误码
unsigned int irq:中断号
void (*handler)(int , void *):中断处理函数。
unsigned long flags:与中断管理有关的各种选项。
const char *devname:设备名。
void *dev_id:共享中断时使用。
在flags参数中,可以选择一些与中断管理有关
的选项,如:
IRQF_DISABLED(SA_INTERRUPT)
如果设置该位,表示是一个“快速”中断处理程序;如果没有设置这位,那么是一个“慢速”中断处理程序。
IRQF_SHARED(SA_SHIRQ)
该位表明该中断号是多个设备共享的。
快/慢速中断的主要区别在于:
快速中断保证中
断处理的原子性(不被打断),而慢速中断则不保证。
换句话说,也就是“开启中断”标志位(处理器IF)在运行快速中断处理程序时是关闭的,因此在服务该中断时,不会被其他类型的中断打断;
而调用慢速中断处理时,其它类型的中断仍可以得到服务。
3.2 中断处理程序
中断处理程序的特别之处是在
中断上下文中运行的,它的行为受到某些限制:
1.不能使用可能引起阻塞的函数
2.不能使用可能引起调度的函数
3.3 注销中断
当设备不再需要使用中断时(通常在驱
动卸载时), 应当把它们注销, 使用函数:
void
free_irq(unsigned int irq, void *
dev_id);
四、按键驱动硬件操作实现
key.c
-
#include <linux/module.h>
-
#include <linux/init.h>
-
#include <linux/miscdevice.h>
-
#include <linux/fs.h>
-
#include <asm/uaccess.h>
-
#include <linux/io.h>
-
#include <linux/irqreturn.h>
-
#include <linux/interrupt.h>
-
-
#define GPFCON (volatile unsigned long*) 0x56000050
-
#define GPFDAT (volatile unsigned long*) 0x56000054
-
-
-
irqreturn_t key_int(int irq, void *dev_id)
-
{
-
//1.检测是否发生了按键中断
-
-
//2.清除已经发生的按键中断
-
-
//3.打印按键值
-
printk("key down!\n");
-
-
return 0;
-
}
-
-
void key_hw_init()
-
{
-
unsigned int *gpio_config;
-
unsigned short data;
-
-
gpio_config = ioremap(GPFCON,4);
-
data = readw(gpio_config);
-
data &= ~0b11;
-
data |= 0b10;
-
writew(data, gpio_config);
-
}
-
-
int key_open(struct inode *inode, struct file *filp)
-
{
-
return 0;
-
}
-
-
struct file_operations key_fops = {
-
.open = key_open,
-
};
-
-
struct miscdevice key_miscdev = {
-
.minor = 200,
-
.name = "tq2400key",
-
.fops = &key_fops,
-
};
-
-
static int button_init()
-
{
-
int ret;
-
ret = misc_register(&key_miscdev);
-
if(ret != 0)
-
{
-
printk(KERN_ERR"misc_register failed\n");
-
}
-
//按键初始化
-
key_hw_init();
-
//注册中断处理程序
-
ret = request_irq(IRQ_EINT0, &key_int, IRQF_TRIGGER_FALLING, "tq2440key", 0);
-
if(ret != 0)
-
{
-
printk(KERN_ERR"request_irq failed,ret is %d\n",ret);
-
}
-
return 0;
-
}
-
-
static void button_exit()
-
{
-
misc_deregister(&key_miscdev);
-
//注销中断处理函数
-
free_irq(IRQ_EINT0, 0);
-
}
-
-
module_init(button_init);
-
module_exit(button_exit);
4.2错误总结
一开始装在内核按键后一直没反应。连内核加载成功都没有提示,甚至应该提示没有GPL协议之类的都没有。才觉得可能出错了。
助手杨给的建议:
中断号对么
中断注册成功了么
中断程序进去了么
还能够再次进入中断么
于是加了ret看看有没有出错:果然提示request_irq failed,ret is -16
一查中断号冲突了
这个表明内核已经编译好了,去内核中用make menuconfig ARCH=arm去掉(用/button查到的)
Symbol: TQ2440_IRQ_BUTTON [=n] │
│ Prompt: EmbedSky TQ2440 Board user buttons │
│ Defined at drivers/input/keyboard/Kconfig:336 │
│ Depends on: !S390 && INPUT && INPUT_KEYBOARD && ARCH_S3C2440 │
│ Location: │
│ -> Device Drivers │
│ -> Input device support │
│ -> Generic input layer (needed for keyboard, mouse, ...) (INPUT [=y]) │
│ -> Keyboards (INPUT_KEYBOARD [=y])
然后就成功了
阅读(687) | 评论(0) | 转发(0) |