寒假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);
}
?
?
原文:http://www.cnblogs.com/lihaiyan/p/4274461.html