由ARM-Linux中断知识的拓展

来源:互联网 发布:ubuntu 开不开机 编辑:程序博客网 时间:2024/05/24 06:48
1、Linux中断注册和中断处理
request_irq(IRQ_EINT0, key_interrupt, IRQ_TYPE_EDGE_FALLING, "KEY0", &keys_desc[0]);
该函数注册了一个中断,中断号为IRQ_EINT0,某个时刻中断发生,就调用中断处理函数key_interrupt(),顺带把数据keys_desc[0]传递给key_interrupt()的第二个入参。

自然,中断号IRQ_EINT0传递给了它的第一个入参。如下:



2、Linux驱动的poll机制
结合驱动和应用实现的代码,执行流程是:


poll(fds, 1, 5000)函数调用后,首先,程序进入内核调用poll_wait(),将对应的等待队列(button_waitq)加入到poll_table(wait)中,此过程对应上面的小箭头;
然后,返回是否能对设备进行读写的标志,存于fds.revents中,此过程对应下面的大箭头;

具体流程是:调用poll()完成函数内参数设置后,进程就在等指定的事件发生;事件发生前,进程进入睡眠,一旦关心的事件发生,进程就重新运行。
在此期间,如果出错,poll()调用返回值<0,如果没出错,我们利用返回值(fds.revents)查询是发生了哪个事件。

调用poll(fds, 1, 5000)函数时指定了等待的时值(5000ms),如果超时,进程就被唤醒,poll()调用返回值=0。


3、Linux驱动的异步通知

在某个时刻,我们关心的设备的某个动作准备好了,内核空间通过某种机制,把消息告知用户空间,好让应用层软件做必要的事情。这种机制,就是Linux驱动的异步通知机制。
通过异步通知机制,驱动把底层硬件发生的事主动“上报”,而不是应用层频繁地去查询驱动,这样可以大大提升系统的性能。
实现异步通知的流程是:
1、需要一个struct fasync_struct类型的指针:
static struct fasync_struct *ev_async;

struct fasync_struct {spinlock_tfa_lock;intmagic;intfa_fd;struct fasync_struct*fa_next; /* singly linked list */struct file*fa_file;struct rcu_headfa_rcu;};

2、实现struct file_operations中的fasync函数,其主体就是内核的fasync_helper()调用:
static int drv_fasync (int fd, struct file *filp, int on){return fasync_helper (fd, filp, on, &ev_async);}

3、在需要的地方,把内核的消息告知用户空间:
kill_fasync (&ev_async, SIGIO, POLL_IN);
该函数发送信号SIGIO信号给fasync_struct 结构体所描述的PID,触发应用程序的SIGIO信号处理函数。

上述流程的理论依据就是,内核的struct fasync_struct结构体保存了对应设备文件的信息(fd、filp等),然后交给内核管理。
一但收到信号,内核就会在异步队列头找到相应的文件(fd),并在filp->owner中找到对应的进程PID,这样就确定了向谁发。

不过,此时fd, filp都还不确定,这就需要借助fasync_helper(),将fd,filp和定义的结构体传给内核,这样就完成了fd、filp、结构体三者的衔接。
而fasync_helper则需要通过file_operations结构体的fasync成员被调用。

从这个过程中,也可以看到,哪个进程完成对ops成员fasync成员的调用,就会把fd、filp传给异步队列,kill_fasync发出信号就会到这个进程中。

0 0
原创粉丝点击