寒假Linux学习笔记
2015年1月25日 晚 20:00
一、内核中断处理
进程上下文:应用程序主动调用内核驱动的程序的跳转
中断上下文:中断由硬件产生的,与应用程序无关
1、注册中断
Int request_irq(unsigned int irq, //中断号
void (*handler)(int ,void *, struct pt_regs*), //中断处理函数
unsigned long flags, //与中断处理管理相关的各种选项
const char * devname, //设备名
void * dev_id //共享中断时使用的id号,唯一
);
Flags参数:
IRQF_DISABLED(SA_INTERRUPT); //若设置此位,则是一个快速中断,即中断为原子操作,不会被打断;未设置该位,则是一个慢速中断
IRQF_SHARED(SA_SHIRQ); //中断可以在设备间共享,申请共享中断必须设置此位为IRQF_SHARED
注意:共享中断 不能使用 disable_irq(unsigned int irq),因为一旦使用该函数,则共享该中断线的全部都不能用
2、中断处理函数流程
Void short_sh_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
/*判断是否是本设备的中断,因为共享中断中使用的是同一个中断处理函数,此时内核就无法判断是哪一个设备发生的中断,可能产生误调用*/
Value = inb(short_base);
If(!value & 0x80) return;
/*清除中断标志位(若设备支持自动清除,则不需要此位)*/
Outb(value & 0x7f, short_base);
/* 中断处理函数,数据处理 */
……
/* 唤醒等待的进程 */
Wake_up_interrruptible(&short_quue);
}
中断处理程序:(运行环境为中断上下文)
1.不能向用户空间发送或接受数据,因为进程变了,用户就变了,中断不对应任何进程
2.不能使用可能引起阻塞的函数
3.不能使用可能引起调度的函数,中断中无进程,无法调度
3、释放中断
Void free_irq(unsigned int irq,void * dev_id);
当被释放的是共享中断时,必须设定dev_id位,否则共享中断全线不能用
二、按键驱动处理程序分析
分析实现流程:
//混杂设备结构体,主设备为10,次设备号不同的一类设备
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR, //次设备号
.name = DEVICE_NAME, //设备名
.fops = &dev_fops //字符设备的file_operation
};
1.初始化程序
Static int __init dev_init(void){
Int ret;
ret = misc_register(&misc); //注册混杂设备
……
return ret;
}
2.file_operations 按键实现的操作
static struct file_operations dev_fops = {
.owner = buttons_open, //打开操作
.release = buttons_close,
.poll = buttons_poll //select,多路监控
};
//open 函数实现
Static buttons_open(static inode *inode,struct(file *file)){
//为六个中断线分别注册驱动程序 总的大小/单个的大小=个数
For(I = 0, i<sizeof(button_irqs)/sizeof(button_irqs[0]);i++){
If(button_irqs[i].irq<0)
Continue;
//制定中断处理程序, IRQ_TYPE_EDGE_BOTH:双边沿产生中断
request_irq(button_irqs[i].irq,buttons_interrupt,IRQ_TYPE_EDGE_BOTH,button_irqs[i].name,(void *)&button_irqs[i]);
}
}
//poll 函数实现
static unsigned int buttons_poll(struct file *file,struct poll_table_struct *wait){
poll_wait(file,&button_waitq,wait); //指明要使用的等待队列
if(ev_press) //全局静态变量,初始值未按下为0,为1时按键按下
mask |= POLLIN | POLLRDNORM; //按键可读不可写
return mask; //返回掩码
}
//当按键按下,程序开始读,读函数实现
static unsigned int buttons_read(struct file * filp,char __user *buff,size_t count,loff_t *offp){
if(!ev_press) { //如果未按下
if(filp->f_flags & O_NONBLOCK) //O_NONBLOCK:用户通过此指定不阻塞
return –EAGAIN;
else
wait_event_interruptible(button_wait,ev_press);//阻塞在等待队列
}
ev_press = 0; //此行语句之前,ev_press其实是1的,中断程序里设置为1
//读取键值
err = copy_to_user(buff,(const void *)key_values,min(sizeof(key_values),count));
return err ? –EFAULT : min(sizeof(key_values),count);
}
3.中断处理程序
static irqreturn_t buttons_interrupt(int irq, void *dev_id){
//读取按键gpio的数据寄存器的值
down = !gpio_getpin(button_irqs->pin);//按下是值为0,而程序中1表示按下
//key_values初始全是为0的,按下时变为1,则不再运行,可防止抖动
if(down != (key_values[button_irqs->number] & 1)){
key_values[button_irqs->number] = '0' + down;
ev_press = 1; //有键按下
wake_up_interruptible(&button_waitq);
}
return IRQ_RETVAL(IRQ_HANDLED);
}