Linux设备驱动程序--学习笔记(3)

来源:互联网 发布:c语言99乘法表全部 编辑:程序博客网 时间:2024/04/29 17:07

1.使用命令"cat /proc/interrupts"可以查看中断的中断号,中断次数,irq_desc.chip名,中断名。


2.sizeof()函数返回值是unsigned long int类型


3.假设int str[]={1,2,3,4,5};int *ptr=str;那么sizeof(str)的大小是20个字节,而sizeof(ptr)是8个字节(如果你的计算机是32位那么所有指针都是4byte,反之64位8byte)。这也从另一个方面说明了数组和指针的差别


4.命令:mknod 可以用来创建设备文件,例如:mknod console c 5 1 其中console是设备文件名,c是指字符设备,5是主设备号,1是次设备号;也可以进入/dev目录下,执行MAKEDEV命令,例如:MAKEDEV  snd0  其中snd0是设备文件名,同时还会创建这个设备文件依赖的其他设备文件,设备号由系统分配没有使用的设备号。


5.windows默认的中文编码是GB2312,linux默认的编码是UTF-8


6.在调用do_asm_IRQ之前,要先保存现场,中断完毕后恢复现场


7.中断发生后要清除中断


8.中断的触发方式有:高电平触发,低电平触发,边沿触发。其中边沿(edge)触发容易产生毛刺和误触发


9.通过request_irq函数可以设置action的中断处理函数,同时启动中断,之后中断就可以发生并且处理了


10.电平触发的中断处理函数入口是:handle_level_irq函数;边沿触发的中断处理函数入口是:handle_edge_irq函数。他们是irq_desc[irq].handle_irq的另一种解释,他们还要通过调用handle_IRQ_event(irq,action)来调用action的中断处理函数


11.中断处理流程:

(1)中断向量调用总入口函数asm_do_IRQ,传入中断号irq;(2)asm_do_IRQ函数根据中断号irq调用irq_desc[irq].hanle_irq,它是这个中断的处理函数入口。对于电平触发的中断,这个入口通常为handle_level_irq;对于边沿触发的中断,这个入口通常为handle_edge_irq;(3)入口函数首先清除中断,入口函数是handle_level_irq时还要屏蔽中断;(4)逐个调用用户在irq_desc[irq].action链表中注册的中断处理函数;(5)入口函数是handle_level_irq时还要重新开启中断


12.中断时一种很稀缺的资源,当不再使用一个设备时,应该通过free_irq函数释放它占据的中断,free_irq函数通过参数irq找到action链表,然后使用dev_id在action链表中找到要卸载的表项


13.通过free_irq()函数释放irqaction里的一个action表项,释放后action里面没有表项的话就会禁止中断,上面的这些都是中断的框架,系统帮我们写好的


14.32位的linux中,所有的指针都是4byte的,无类型指针void *ptr,可以强制转换为任何类型的指针,同时其他类型的指针也可以赋值给void 指针


15.发生中断时,内核并不判断究竟是共享中断线上的哪个设备产生了中断,它会循环执行所有该中断线上注册的中断处理函数(即irq->handler函数)。因此irqaction->handler函数有责任识别出是否是自己的硬件设备产生了中断,然后再执行该中断处理函数。通常是通过读取硬件设备提供的中断flag标志位(在用request_irq函数注册中断处理程序时传入)进行判断。


16.void *dev_id的作用:(1)判断从共享中断线上的多个中断处理程序中删除哪一个。(2)将设备结构体传递给该中断处理程序(通过request_irq注册中断处理程序时传递)


17.#include<xxx/xxx.h>或者#include<xxx.h>想要知道xxx.h具体在系统的哪个文件目录下,首先要知道gcc的编译时的搜索目录,可以在编译一个.c文件时加上"-v"就可以查看了(PS:gcc搜索路径往往不止一个),一般都是在/usr/include里啦


18.<windows.h> 这个头文件在linux里跟<unistd.h>有点像


19.在<unistd.h>中有Sleep():单位毫秒,sleep():单位秒,还有usleep()单位微秒。它们都可以让进程挂起(阻塞)一段时间


20.应用程序中的poll函数是这样的:int poll(struct pollfd *fds,nfds_t nfds, int timeout);Poll机制会判断fds中的文件是否可读,如果可读则会立即返回,返回的值就是可读fd的数量,如果不可读,那么就进程就会休眠timeout这么长的时间,然后再来判断是否有文件可读,如果有,返回fd的数量,如果没有,则返回0.


21.对于系统调用的poll或select,它们对应的内核函数都是sys_poll


22.驱动程序里的poll函数不会让用户程序进入休眠,poll_wait只是让进程填入等待队列中,让进程进入休眠的是do_sys_poll函数的schedule_timeout(__timeout)


23.在内核中大致上实现过程:当应用程序调用poll函数的时候,会调用到系统调用sys_poll函数,该函数最终调用do_poll函数,do_poll函数中有一个死循 环,在里面又会利用do_pollfd函数去调用驱动中的poll函数(fds中每个成员的字符驱动程序都会被扫描到),驱动程序中的Poll函数的工作 有两个,一个就是调用poll_wait 函数,把进程挂到等待队列中去(这个是必须的,你要睡眠,必须要在一个等待队列上面,否则到哪里去唤醒你呢??),另一个是确定相关的fd是否有内容可 读,如果可读,就返回1,否则返回0,如果返回1 ,do_poll函数中的count++,    然后  do_poll函数然后判断三个条件(if (count ||!timeout || signal_pending(current)))如果成立就直接跳出,如果不成立,就睡眠timeout个jiffes这么长的时间(调用schedule_timeout实现睡眠),如果在这段时间内没有其他进程去唤醒它,那么第二次执行判断的时候就会跳出死循环。如果在这段时间内有其他进程唤醒它,那么也可以跳出死循环返回(例如我们可以利用中断处理函数去唤醒它,这样的话一有数据可读,就可以让它立即返回)


24.现在来总结一下poll机制:
(1)poll > sys_poll > do_sys_poll >poll_initwait,poll_initwait函数注册一下回调函数__pollwait,它就是我们的驱动程序执行poll_wait时,真正被调用的函数。
(2)接下来执行do_sys_poll>do_poll>do_pollfd>file->f_op->poll,即我们驱动程序里自己实现的poll函数
   它会调用poll_wait把自己挂入某个队列,这个队列也是我们的驱动自己定义的;
   它还判断一下设备是否就绪。
(3) 如果设备未就绪,do_sys_poll里会让进程休眠一定时间,这个时间是应用提供的“超时时间”
(4)进程被唤醒的条件有2:一是上面说的“一定时间”到了,二是被驱动程序唤醒。驱动程序发现条件就绪时,就把“某个队列”上挂着的进程唤醒,这个队列,就是前面通过poll_wait把本进程挂过去的队列。

(5)如果驱动程序没有去唤醒进程,那么chedule_timeout(__timeou)超时后,会重复2、3动作1次,直到应用程序的poll调用传入的时间到达, 然后返回。


25.回调函数就是一个通过函数指针实现的函数,它通常由另一个函数通过函数指针去调用它而本身并不实现



0 0