linux驱动编写一个中断,有下面几步操作:
- 申请中断
- 注册的中断服务函数
- 卸载中断
申请中断使用的函数有
inline int __must_check request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)
int request_threaded_irq(unsigned int irq, irq_handler_t handler,
irq_handler_t thread_fn, unsigned long irqflags,
const char *devname, void *dev_id)
request_irq实际调用的是request_threaded_irq
static inline int __must_check
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
const char *name, void *dev)
{
return request_threaded_irq(irq, handler, NULL, flags, name, dev);
}
参数如下:
unsigned int irq:为要注册中断服务函数的中断号,定义在mach/irqs.h
irq_handler_t handler:为要注册的中断服务函数
unsigned long irqflags: 触发中断的参数,比如边沿触发, 定义在linux/interrupt.h。
const char *devname:中断程序的名字,使用cat /proc/interrupt 可以查看中断程序名字
void *dev_id:传入中断处理程序的参数,注册共享中断时不能为NULL,因为卸载时需要这个做参数,避免卸载其它中断服务函数
例如,我们要对GPIO35检查上拉中断,进行如下配置:
request_irq(gpio_to_irq(SABRESD_POWER_OFF), button_irq, IRQ_TYPE_EDGE_FALLING, "S1",(void *)&pin_desc[0]);
button_irq是中断服务函数
IRQ_TYPE_EDGE_FALLING //下降沿触发
#define IRQ_TYPE_NONE 0
#define IRQ_TYPE_EDGE_RISING 1//上升沿触发
#define IRQ_TYPE_EDGE_FALLING 2//下降沿触发
#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)//双边沿触发
#define IRQ_TYPE_LEVEL_HIGH 4//高电平触发
#define IRQ_TYPE_LEVEL_LOW 8//低电平触发
"S1":中断程序的名字
(void *)&pin_desc[0]:传入中断处理程序的参数,即button_irq的参数
/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
/* 主要是为了区分是按下还是松开 */
static unsigned char key_val = 0;
irqreturn_t button_irq(int irq, void *devid)
{
int pin_val;
struct pin_desc *pin_readed;
pin_readed = (struct pin_desc *)devid;
/* 1 获取当前引脚的电平值 */
pin_val = gpio_get_value(pin_readed->pin);
/* 2 根据电平值判断当前是按下还是松开 */
if (pin_val) /* 松开为高电平,返回0x8x */
{
key_val = 0x80 | pin_readed->key_val;
}
else /* 按下为低电平,返回0x0x */
{
//把当前按键的键值给一个全局静态变量,在read函数里给用户
key_val = pin_readed->key_val;
}
printk("%02x ", key_val);
wake_up(&Key_Status_Read_Wait);
wait_flag = 1;
/* 3 标记中断已经触发 */
return IRQ_RETVAL(IRQ_HANDLED);
}
/*退出函数*/
static void ButtonDriver_Exit(void)
{
free_irq(gpio_to_irq(SABRESD_POWER_OFF), (void *)&pin_desc[0]);
....
/* 释放注册的4个中断 */
/*********************************************************
free_irq(unsigned int irq, void *dev_id);
参数说明:
unsigned int irq:要卸载的中断号
void *dev_id:这个是要卸载的中断action下的哪个服务函数,
***********************************************************/
}