⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 00000004.htm

📁 一份很好的linux入门资料
💻 HTM
📖 第 1 页 / 共 5 页
字号:
kfree_s()释放。&nbsp;<BR>&nbsp;<BR>2.4.2&nbsp;request_irq()、free_irq()&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;这是驱动程序申请中断和释放中断的调用。在include/linux/sched.h里声明。&nbsp;<BR>request_irq()调用的定义:&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;request_irq(unsigned&nbsp;int&nbsp;irq,&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;(*handler)(int&nbsp;irq,&nbsp;void&nbsp;*dev_id,&nbsp;struct&nbsp;pt_regs&nbsp;*regs),&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;long&nbsp;irqflags,&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;char&nbsp;*&nbsp;devname,&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;*dev_id);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;irq是要申请的硬件中断号。在Intel平台,范围0--15。handler是向系统登记&nbsp;<BR>的中断处理函数。这是一个回调函数,中断发生时,系统调用这个函数,传入的参&nbsp;<BR>数包括硬件中断号,device&nbsp;id,寄存器值。dev_id就是下面的request_irq时传递&nbsp;<BR>给系统的参数dev_id。irqflags是中断处理的一些属性。比较重要的有SA_INTERRUPT,&nbsp;<BR>标明中断处理程序是快速处理程序(设置SA_INTERRUPT)还是慢速处理程序(不设置&nbsp;<BR>SA_INTERRUPT)。快速处理程序被调用时屏蔽所有中断。慢速处理程序不屏蔽。还有&nbsp;<BR>一个SA_SHIRQ属性,设置了以后运行多个设备共享中断。dev_id在中断共享时会用&nbsp;<BR>到。一般设置为这个设备的device结构本身或者NULL。中断处理程序可以用dev_id&nbsp;<BR>找到相应的控制这个中断的设备,或者用irq2dev_map找到中断对应的设备。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;free_irq(unsigned&nbsp;int&nbsp;irq,void&nbsp;*dev_id);&nbsp;<BR>&nbsp;<BR>2.4.3&nbsp;时钟&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;时钟的处理类似中断,也是登记一个时间处理函数,在预定的时间过后,系统&nbsp;<BR>会调用这个函数。在include/linux/timer.h里声明。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;timer_list&nbsp;{&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;timer_list&nbsp;*next;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;timer_list&nbsp;*prev;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;long&nbsp;expires;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;long&nbsp;data;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;(*function)(unsigned&nbsp;long);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;add_timer(struct&nbsp;timer_list&nbsp;*&nbsp;timer);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;del_timer(struct&nbsp;timer_list&nbsp;*&nbsp;timer);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;init_timer(struct&nbsp;timer_list&nbsp;*&nbsp;timer);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;使用时钟,先声明一个timer_list结构,调用init_timer对它进行初始化。&nbsp;<BR>time_list结构里expires是标明这个时钟的周期,单位采用jiffies的单位。&nbsp;<BR>jiffies是Linux一个全局变量,代表时间。它的单位随硬件平台的不同而不同。&nbsp;<BR>系统里定义了一个常数HZ,代表每秒种最小时间间隔的数目。这样jiffies的单位&nbsp;<BR>就是1/HZ。Intel平台jiffies的单位是1/100秒,这就是系统所能分辨的最小时间&nbsp;<BR>间隔了。所以expires/HZ就是以秒为单位的这个时钟的周期。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;function就是时间到了以后的回调函数,它的参数就是timer_list中的data。&nbsp;<BR>data这个参数在初始化时钟的时候赋值,一般赋给它设备的device结构指针。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;在预置时间到系统调用function,同时系统把这个time_list从定时队列里清&nbsp;<BR>除。所以如果需要一直使用定时函数,要在function里再次调用add_timer()把这&nbsp;<BR>&nbsp;<BR>------------------&nbsp;Linux操作系统网络驱动程序编写&nbsp;-------------------&nbsp;<BR>------------&nbsp;Contact&nbsp;the&nbsp;author&nbsp;by&nbsp;<A HREF="mailto:mailto:bordi@bordi.dhs.org">mailto:bordi@bordi.dhs.org</A>&nbsp;------&nbsp;<BR>&nbsp;<BR>个timer_list加进定时队列。&nbsp;<BR>&nbsp;<BR>2.4.4&nbsp;I/O&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;I/O端口的存取使用:&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;inline&nbsp;unsigned&nbsp;int&nbsp;inb(unsigned&nbsp;short&nbsp;port);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;inline&nbsp;unsigned&nbsp;int&nbsp;inb_p(unsigned&nbsp;short&nbsp;port);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;inline&nbsp;void&nbsp;outb(char&nbsp;value,&nbsp;unsigned&nbsp;short&nbsp;port);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;inline&nbsp;void&nbsp;outb_p(char&nbsp;value,&nbsp;unsigned&nbsp;short&nbsp;port);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;在include/adm/io.h里定义。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;inb_p()、outb_p()与inb()、outb_p()的不同在于前者在存取I/O时有等待&nbsp;<BR>(pause)一适应慢速的I/O设备。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;为了防止存取I/O时发生冲突,Linux提供对端口使用情况的控制。在使用端口&nbsp;<BR>之前,可以检查需要的I/O是否正在被使用,如果没有,则把端口标记为正在使用,&nbsp;<BR>使用完后再释放。系统提供以下几个函数做这些工作。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;check_region(unsigned&nbsp;int&nbsp;from,&nbsp;unsigned&nbsp;int&nbsp;extent);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;request_region(unsigned&nbsp;int&nbsp;from,&nbsp;unsigned&nbsp;int&nbsp;extent,const&nbsp;char&nbsp;*name);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;release_region(unsigned&nbsp;int&nbsp;from,&nbsp;unsigned&nbsp;int&nbsp;extent);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;其中的参数from表示用到的I/O端口的起始地址,extent标明从from开始的端&nbsp;<BR>口数目。name为设备名称。&nbsp;<BR>&nbsp;<BR>2.4.5&nbsp;中断打开关闭&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;系统提供给驱动程序开放和关闭响应中断的能力。是在include/asm/system.h&nbsp;<BR>中的两个定义。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;#define&nbsp;cli()&nbsp;__asm__&nbsp;__volatile__&nbsp;(&quot;cli&quot;::)&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;#define&nbsp;sti()&nbsp;__asm__&nbsp;__volatile__&nbsp;(&quot;sti&quot;::)&nbsp;<BR>&nbsp;<BR>2.4.6&nbsp;打印信息&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;类似普通程序里的printf(),驱动程序要输出信息使用printk()。在include&nbsp;<BR>/linux/kernel.h里声明。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;printk(const&nbsp;char*&nbsp;fmt,&nbsp;...);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;其中fmt是格式化字符串。...是参数。都是和printf()格式一样的。&nbsp;<BR>&nbsp;<BR>2.4.7&nbsp;注册驱动程序&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;如果使用模块(module)方式加载驱动程序,需要在模块初始化时把设备注册&nbsp;<BR>到系统设备表里去。不再使用时,把设备从系统中卸除。定义在drivers/net/net_init.h&nbsp;<BR>里的两个函数完成这个工作。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;register_netdev(struct&nbsp;device&nbsp;*dev);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;unregister_netdev(struct&nbsp;device&nbsp;*dev);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;dev就是要注册进系统的设备结构指针。在register_netdev()时,dev结构一&nbsp;<BR>般填写前面11项,即到init,后面的暂时可以不用初始化。最重要的是name指针和&nbsp;<BR>init方法。name指针空(NULL)或者内容为'\0'或者name[0]为空格(space),则系统&nbsp;<BR>把你的设备做为以太网设备处理。以太网设备有统一的命名格式,ethX。对以太网&nbsp;<BR>这么特别对待大概和Linux的历史有关。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;init方法一定要提供,register_netdev()会调用这个方法让你对硬件检测和&nbsp;<BR>设置。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;register_netdev()返回0表示成功,非0不成功。&nbsp;<BR>&nbsp;<BR>2.4.8&nbsp;sk_buff&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;Linux网络各层之间的数据传送都是通过sk_buff。sk_buff提供一套管理缓冲&nbsp;<BR>区的方法,是Linux系统网络高效运行的关键。每个sk_buff包括一些控制方法和一&nbsp;<BR>块数据缓冲区。控制方法按功能分为两种类型。一种是控制整个buffer链的方法,&nbsp;<BR>另一种是控制数据缓冲区的方法。sk_buff组织成双向链表的形式,根据网络应用&nbsp;<BR>的特点,对链表的操作主要是删除链表头的元素和添加到链表尾。sk_buff的控制&nbsp;<BR>方法都很短小以尽量减少系统负荷。(translated&nbsp;from&nbsp;article&nbsp;written&nbsp;by&nbsp;Alan&nbsp;<BR>Cox)&nbsp;<BR>常用的方法包括:&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;.alloc_skb()&nbsp;申请一个sk_buff并对它初始化。返回就是申请到的sk_buff。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;.dev_alloc_skb()类似alloc_skb,在申请好缓冲区后,保留16字节的帧头空&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;间。主要用在Ethernet驱动程序。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;.kfree_skb()&nbsp;释放一个sk_buff。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;.skb_clone()&nbsp;复制一个sk_buff,但不复制数据部分。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;.skb_copy()完全复制一个sk_buff。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;.skb_dequeue()&nbsp;从一个sk_buff链表里取出第一个元素。返回取出的sk_buff,&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果链表空则返回NULL。这是常用的一个操作。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;.skb_queue_head()&nbsp;在一个sk_buff链表头放入一个元素。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;.skb_queue_tail()&nbsp;在一个sk_buff链表尾放入一个元素。这也是常用的一个&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;操作。网络数据的处理主要是对一个先进先出队列的管理,skb_queue_tail()&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;和skb_dequeue()完成这个工作。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;.skb_insert()&nbsp;在链表的某个元素前插入一个元素。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;.skb_append()&nbsp;在链表的某个元素后插入一个元素。一些协议(如TCP)对没按&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;顺序到达的数据进行重组时用到skb_insert()和skb_append()。&nbsp;<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;.skb_reserve()&nbsp;在一个申请好的sk_buff的缓冲区里保留一块空间。这个空间&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一般是用做下一层协议的头空间的。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;.skb_put()&nbsp;在一个申请好的sk_buff的缓冲区里为数据保留一块空间。在&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alloc_skb以后,申请到的sk_buff的缓冲区都是处于空(free)状态,有一个&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tail指针指向free空间,实际上开始时tail就指向缓冲区头。skb_reserve()&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在free空间里申请协议头空间,skb_put()申请数据空间。见下面的图。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;.skb_push()&nbsp;把sk_buff缓冲区里数据空间往前移。即把Head&nbsp;room中的空间移&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一部分到Data&nbsp;area。&nbsp;<BR>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -