Linux设备中断程序编写
来源:互联网 发布:美国在台协会 知乎 编辑:程序博客网 时间:2024/06/07 06:02
一. 几个要点知识:
1. 睡眠
安全睡眠的要点:
<1> 当你运行在原子上下文时不能睡眠;
<2> 醒后必须通过检查来确你在等待的条件;
<3> 睡眠必须对应一个唤醒。
<注>: 代码针对于2.6的内核
等待队列: DECLARE_WAIT_QUEUE_HEAD(name);
睡眠函数: wait_event_interruptible (queue, condition)
(它可能被信号中断. 这个版本返回一个你应当检查的整数值; 一个非零值意味着你的睡眠被某些信号打断, 并且你的驱动可能当
返回 -ERESTARTSYS.)
唤醒函数: void wake_up_interruptible(wait_queue_head_t *queue);
2. poll, select
获取设备驱动的支持: unsigned int (*poll) (struct file *filp, poll_table *wait);
<1> 在一个或多个可指示查询状态变化的等待队列上调用 poll_wait
void poll_wait (struct file *, wait_queue_head_t *, poll_table *)
<2> 返回一个位掩码, 描述可能不必阻塞就立刻进行的操作.标志参见<linux/poll.h>
3. 中断
中断注册函数: int request_irq(unsigned int irq,
irqreturn_t (*handler)(int, void *, struct pt_regs *),
unsigned long flags,
const char *dev_name,
void *dev_id);
中断释放函数: void free_irq(unsigned int irq, void *dev_id);
request_irq 返回给请求函数的返回值或者是 0 指示成功, 或者是一个负的错误码, 如同平常. 函数返回 -EBUSY 来指示另一个驱
动已经使用请求的中断线是不寻常的. 函数的参数如下:
unsigned int irq 请求的中断号
irqreturn_t (*handler) 安装的处理函数指针
unsigned long flags 如你会希望的, 一个与中断管理相关的选项的位掩码(后面描述).
const char *dev_name 这个传递给 request_irq 的字串用在 /proc/interrupts 来显示中断的拥有者
void *dev_id 用作共享中断线的指针. 它是一个独特的标识, 用在当释放中断线时以及可能还被驱动用来指向它自己的私有
数据区(来标识哪个设备在中断).如果中断没有被共享, dev_id 可以设置为 NULL。
调用 request_irq 的正确位置是当设备第一次打开时, 在硬件被指示来产生中断前.
调用 free_irq 的位置是设备最后一次被关闭时, 在硬件被告知不要再中断处理器之后.
中断处理函数: irqreturn_t short_interrupt(int irq, void *dev_id, struct pt_regs *regs)
struct pt_regs *regs, 很少用到
二. TQ2440 irq 代码分析
1.驱动代码(不完整)
天嵌提供的实例代码并不复杂,但作为一个例程是非常合适的,代码具体的给出了如何注册,处理,释放中断。
/*必要的头文件,我只列出中断相关的*/
....
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
....
#define DEVICE_NAME "EmbedSky_buttons"
#define BUTTON_MAJOR 232 //设备号用自动获取方式更好!
/*等待队列*/
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
/*中断flag, 中断处理函数置1,read函数清0 */
static volatile int ev_press = 0;
/* 按钮被按下的回数(准确地说,是发生中断的回数) */
static volatile int press_cnt[] = {0,0,0,0};
static struct class *button_class;
/*中断信息结构,这个结构的设计很不错*/
struct button_irqs_desc {
int irq;
int pin;
int pin_setting;
int number;
char *name;
};
static struct button_irqs_desc button_irqs[] =
{
{IRQ_EINT1, S3C2410_GPF1, S3C2410_GPF1_ENT1, 0, "KEY1"},
{IRQ_EINT4, S3C2410_GPF4, S3C2410_GPF4_ENT4, 1, "KEY2"},
{IRQ_EINT2, S3C2410_GPF2, S3C2410_GPF2_ENT2, 2, "KEY3"},
{IRQ_EINT0, S3C2410_GPF0, S3C2410_GPF0_ENT0, 3, "KEY4"},
};
/*中断处理函数*/
static irqreturn_t buttons_interrupt(int irq,void *dev_id)
{
//读键值(略)
ev_press = 1; /*表示中断发生了*/
wake_up_interruptible(&button_waitq); /*唤醒休眠的进程*/
return IRQ_RETVAL(IRQ_HANDLED);
}
static int tq2440_buttons_open(struct inode *inode,structfile *file)
{
int i;
int err;
//中断注册
for(i =0;i<sizeof(button_irqs)/sizeof(button_irqs[0]);i++)
{
s3c2410_gpio+cfgpin( buttons_irqs[i].pin, buttons_irqs[i]_pin_setting );
err = request_irq ( buttons_irqs[i].irq, buttons_interrupt, NULL, buttons_irqs[i].name, (void *)&buttons_irqs[i]);
if(err)
break;
}
if(err)
{
i--;
for( ;i>=0;i-- )
free_irq(buttons_irqs[i].irq,(void *)&buttons_irq);
return -EBUSY;
}
return 0;
}
static int tq2440_buttons_close(struct inode *inode,structfile *file)
{
int i;
//中断释放
for(i=0;i<sizeof(button_irqs)/sizeof(button_irqs[0]);i++)
{
free_irq(button_irqs[i].irq,(void *)&buttons_irq]);
}
return 0;
}
static int tq2440_buttons_read(struct file *filp,char__user *buff,size_t count,loff_t *offp)
{
unsigned long err;
if(!ev_press)
{
if()
else
wait_event_interruptible(button_waitq,ev_press);
}
ev_press = 0;
err = copy_to_user(buff,(const void*)press_cnt,MIN(sizeof(press_cnt),count));
memset((void *)press_cnt,0,sizeof(press_cnt));
return err? -EFAULT:0;
}
static unsigned int EmbedSky_buttons_poll(struct file *filp, poll_table *wait)
{
....
poll_wait(...);
return mask;
}
static struct file_operations tq2440_buttons_fops =
{
.owner = THIS_MODULE,
.open = tq2440_buttons_open,
.release = tq2440_buttons_close,
.read = tq2440_buttons_read,
};
static int __init tq2440_buttons_init(void)
{
........
}
static void __exit tq2440_buttons_exit(void)
{
........
}
module_init(tq2440_buttons_init);
module_exit(tq2440_buttons_exit)
- Linux设备中断程序编写
- 《Linux设备驱动开发详解》-- Linux中断处理程序架构和Linux中断编程
- linux设备驱动中断程序深度完全解析
- 字符设备驱动----中断程序
- 中断服务程序的编写
- 中断服务程序的编写
- 中断服务程序编写规则
- [转]编写Linux下Input设备的检测程序
- 编写Linux下Input设备的检测程序
- 编写Linux下Input设备的检测程序
- 编写Linux下Input设备的检测程序
- 编写Linux下Input设备的检测程序 .
- 编写Linux设备驱动
- Linux设备驱动程序编写
- 编写linux设备驱动程序
- Linux设备驱动程序编写
- 编写linux设备驱动程序
- 编写linux设备驱动程序
- VIM配置文件
- 如何修改一个文件的内容。
- Xcode快捷键大全!
- Flex使用图片
- windows xp下直接写显示缓冲区显示bmp图片
- Linux设备中断程序编写
- .NET命名空间之三
- Android的animation
- 在安装Oracle9i 遇到OCS4J.properties 的解决办法
- Android入门第十一篇之TabHost,TabWidget
- 什么是Cocoa 什么是Xcode 什么是Framework?
- 网络邮箱中Base64编码问题
- 三网融合触发MeeGo风暴
- 面向服务(SO)和面向对象(OO)的比较