欢迎来到三一办公! | 帮助中心 三一办公31ppt.com(应用文档模板下载平台)
三一办公
全部分类
  • 办公文档>
  • PPT模板>
  • 建筑/施工/环境>
  • 毕业设计>
  • 工程图纸>
  • 教育教学>
  • 素材源码>
  • 生活休闲>
  • 临时分类>
  • ImageVerifierCode 换一换
    首页 三一办公 > 资源分类 > DOC文档下载  

    课程设计(论文)Linux网络设备驱动程序设计.doc

    • 资源ID:2393109       资源大小:80.50KB        全文页数:24页
    • 资源格式: DOC        下载积分:8金币
    快捷下载 游客一键下载
    会员登录下载
    三方登录下载: 微信开放平台登录 QQ登录  
    下载资源需要8金币
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    课程设计(论文)Linux网络设备驱动程序设计.doc

    1 引 言Linux网络设备驱动程序是Linux操作系统网络应用中的一个重要的组成部分,分析其运行机理,对于设计Linux网络应用程序是很有帮助的。我们可以在网络驱动程序这一级做一些与应用相关联的特殊事情,例如,在设计Linux防火墙和网络入侵检测系统时可以在网络驱动程序的基础上拦截网络数据包,继而对其进行分析。由于Linux是开放源代码的,这给我们提供了一个绝好的机会来分析和改造网络驱动程序使其满足自己的特殊应用。本文就Linux内核中的网络驱动程序部分进行了详细的讨论,并给出了实现Linux网络驱动程序的重要过程及一种实现模式和具体实例。随着当今世界经济的发展,计算机网络被广泛应用到各个领域,而网络设备的应用都必须要驱动程序来驱动,因而设计功能强大的网络设备驱动程序设计成为开发和设计的关键,而Linux 操作系统源代码的开放性和较强的可移植性味操作人员提供了一个分析和编写网络驱动程序的优越环境,可以达到特殊应用的要求。1.1 Linux设备驱动程序分类 Linux设备驱动程序在Linux的内核源代码中占有很大的比例,源代码的长度日益增加,主要是驱动程序的增加。在Linux内核的不断升级过程中,驱动程序的结构还是相对稳定。在2.0.xx到2.2.xx的变动里,驱动程序的编写做了一些改变,但是从2.0.xx的驱动到2.2.xx的移植只需做少量的工作。Linux系统的设备分为字符设备(char device),块设备(block device)和网络设备(net work device)三种。字符设备是指存取时没有缓存的设备。块设备的读写都有缓存来支持,并且块设备必须能够随机存取(random access),字符设备则没有这个要求。典型的字符设备包括鼠标,键盘,串行口等。块设备主要包括硬盘软盘设备,CD-ROM等。一个文件系统要安装进入操作系统必须在块设备上。网络设备在Linux里做专门的处理。Linux的网络系统主要是基于BSD unix的socket机制。在系统和驱动程序之间定义有专门的数据结构(sk_buff)进行数据的传递。系统里支持对发送数据和接收数据的缓存,提供流量控制机制,提供对多协议的支持【1】。 1.2 驱动程序的一些基本概念无论是什么操作系统的驱动程序,都有一些通用的概念。操作系统提供给驱动程序的支持也大致相同。下面简单介绍一下网络设备驱动程序的一些基本要求。(1)发送和接收这是一个网络设备最基本的功能。一块网卡所做的无非就是收发工作。所以驱动程序里要告诉系统你的发送函数在哪里,系统在有数据要发送时就会调用你的发 送程序。还有驱动程序由于是直接操纵硬件的,所以网络硬件有数据收到最先能得到这个数据的也就是驱动程序,它负责把这些原始数据进行必要的处理然后送给系统。这里,操作系统必须要提供两个机制,一个是找到驱动程序的发送函数,一个是驱动程序把收到的数据送给系统【2】。(2)中断中断在现代计算机结构中有重要的地位。操作系统必须提供驱动程序响应中断的能力。一般是把一个中断处理程序注册到系统中去。操作系统在硬件中断发生后 调用驱动程序的处理程序。Linux支持中断的共享,即多个设备共享一个中断。(3)时钟在实现驱动程序时,很多地方会用到时钟。如某些协议里的超时处理,没有中断机制的硬件的轮询等。操作系统应为驱动程序提供定时机制。一般是在预定的时 间过了以后回调注册的时钟函数。在网络驱动程序中,如果硬件没有中断功能,定时器可以提供轮询(poll)方式对硬件进行存取。或者是实现某些协议时需要的超时重传等【3】。2 驱动程序设计原理2.1 体系结构dev_queue_xmit()netif_rx() struct device数据包发送hard_start_xmit()网络物理设备媒介中断处理(数据包接收)网络协议接口层网络设备接口层设备驱动功能层设备媒介层图1 Linux网络驱动程序体系结构Linux网络驱动程序的体系结构如图1所示。可以划分为四层,从上到下分别为协议接口层,网络设备接口层,再就是提供实际功能的设备驱动功能层,以及网络设备和网络媒介层。我们在设计网络驱动程序时,最主要的工作就是完成设备驱动功能层,使其满足我们自己所需的功能。在Linux中对所有网络设备都抽象为一个接口,这个接口提供了对所有网络设备的操作集合。由数据结构struct device来表示网络设备在内核中的运行情况,即网络设备接口,它既包括纯软件网络设备接口,如环路(Loopback),也可以包括硬件网络设备接口,如以太网卡。而由以dev_base为头指针的设备链表来集体管理所有网络设备,该设备链表中的每个元素代表一个网络设备接口。数据结构device中有很多供系访问和协议层调用的设备方法,包括供设备初始化和往系统注册用的init函数,打开和关闭网络设备的open和stop函数,处理数据包发送的函数hard_start_xmit,以及中断处理函数等。有关device数据结构(在内核中也就是net_device)的详细内容,请参看/linux/include/linux/netdevice.h。2.2 初始化网络设备的初始化主要是由device数据结构中的init函数指针所指的初始化函数来完成的,当内核启动或加载网络驱动模块的时候,就会调用初始化过程。在这其中将首先检测网络物理设备是否存在,这是通过检测物理设备的硬件特征来完成,然后再对设备进行资源配置,这些完成之后就要构造设备的device数据结构,把检测到的数值来对device中的变量初始化,这一步很重要。最后向Linux内核中注册该设备并申请内存空间。2.3 数据包的发送与接收数据包的发送和接收是实现Linux网络驱动程序中两个最关键的过程,对这两个过程处理的好坏将直接影响到驱动程序的整体运行质量。图1中也很明确地说明了网络数据包的传输过程。首先在网络设备驱动加载时,通过device域中的init函数指针调用网络设备的初始化函数对设备进行初始化,如果操作成功就可以通过device域中的open函数指针调用网络设备的打开函数打开设备,再通过device域中的建立硬件包头函数指针hard_header来建立硬件包头信息。最后通过协议接口层函数dev_queue_xmit(详见/linux/net/core/dev.c)来调用device域中的hard_start_xmit函数指针来完成数据包的发送。该函数将把存放在套接字缓冲区中的数据发送到物理设备,该缓冲区是由数据结构sk_buff (详见/linux/include/linux/sk_buff.h)来表示的。数据包的接收是通过中断机制来完成的,当有数据到达时,就产生中断信号,网络设备驱动功能层就调用中断处理程序,即数据包接收程序来处理数据包的接收,然后网络协议接口层调用netif_rx函数(详见/linux/net/core/dev.c)把接收到的数据包传输到网络协议的上层进行处理。3 实现模式实现Linux网络设备驱动功能主要有两种形式,一是通过内核来进行加载,当内核启动的时候,就开始加载网络设备驱动程序,内核启动完成之后,网络驱动功能也随即实现了,再就是通过模块加载的形式。比较两者,第二种形式更加灵活,在此着重对模块加载形式进行讨论。模块设计是Linux中特有的技术,它使Linux内核功能更容易扩展。采用模块来设计Linux网络设备驱动程序会很轻松,并且能够形成固定的模式,任何人只要依照这个模式去设计,都能设计出优良的网络驱动程序。先简要概述一下基于模块加载的网络驱动程序的设计步骤,后面还结合具体实例来讲解。首先通过模块加载命令insmod来把网络设备驱动程序插入到内核之中。然后insmod将调用init_module()函数首先对网络设备的init函数指针初始化,再通过调用register_netdev()函数在Linux系统中注册该网络设备,如果成功,再调用init函数指针所指的网络设备初始化函数来对设备初始化,将设备的device数据结构插入到dev_base链表的末尾。最后可以通过执行模块卸栽命令rmmod 来调用网络驱动程序中的cleanup_module()函数来对网络驱动程序模块卸载。具体实现过程见图2所示。insmod命令init_module()打开网络接口设备init指针调用初始化函数register_netdev()关闭网络接口设备模块卸载数据包发送与接收操作图2 Linux网络设备驱动程序实现模式通过模块初始化网络接口是在编译内核时标记为编译为模块,系统在启动时并不知道该接口的存在,需要用户在/etc/rc.d/目录中定义的初始启动脚本中写入命令或手动将模块插入内核空间来激活网络接口。这也给我们在何时加载网络设备驱动程序提供了灵活性。4 详细设计4.1 网络驱动程序的结构所有的Linux网络驱动程序遵循通用的接口。设计时采用的是面向对象的方法。一个设备就是一个对象(device 结构),它内部有自己的数据和方法。每一个设备的方法被调用时的第一个参数都是这个设备对象本身。这样这个方法就可以存取自身的数据(类似面向对象程序设计时的this引用)。一个网络设备最基本的方法有初始化、发送和接收。- - |deliver packets | |receive packets queue| |(dev_queue_xmit() | |them(netif_rx() | - - | | / / | | -| methods and variables(initialize,open,close,hard_xmit,| | interrupt handler,config,resources,status.) | - | | / / | | - - |send to hardware | |receivce from hardware| - - | | / / | | - | hardware media | - 初始化程序完成硬件的初始化、device中变量的初始化和系统资源的申请。发送程序是在驱动程序的上层协议层有数据要发送时自动调用的。一般驱动程序中不对发送数据进行缓存,而是直接使用硬件的发送功能把数据发送出去。接收数据一般是通过硬件中断来通知的。在中断处理程序里,把硬件帧信息填入一skbuff结构中,然后调用netif_rx()传递给上层处理。4.2 网络驱动程序的基本方法网络设备做为一个对象,提供一些方法供系统访问。正是这些有统一接口的方法,掩蔽了硬件的具体细节,让系统对各种网络设备的访问都采用统一的形式,做到硬件无关性。下面解释最基本的方法。(1)初始化(initialize)驱动动程序必须有一个初始化方法。在把驱动程序载入系统的时候会调用这个初始化程序。它做以下几方面的工作。检测设备。在初始化程序里你可以根据硬件的特征检查硬件是否存在,然后决定是否启动这个驱动程序。配置和初始化硬件。在初始化程序里你可以完成对硬件资源的配置,比如即插即用的硬件就可以在这个时候进行配置(Linux内核对PnP功能没有很好的支持,可以在驱动程序里完成这个功能)。配置或协商好硬件占用的资源以后,就可以向系统申请这些资源。有些资源是可以和别的设备共享的,如中断。有些是不能共享的,如IO、DMA。接下来你要初始化device结构中的变量。最后,你可以让硬件正式开始工作。(2)打开(open)open这个方法在网络设备驱动程序里是网络设备被激活的时候被调用(即设备状态由dow n->up)。所以实际上很多在initialize中的工作可以放到这里来做。比如资源的申请,硬件的激活。如果dev->open返回非0(error),则硬件的状态还是down。open方法另一个作用是如果驱动程序做为一个模块被装入,则要防止模块卸载时设备处于打开状态。在open方法里要调用MOD_INC_USE_COUNT宏。(3)关闭(stop)close方法做和open相反的工作。可以释放某些资源以减少系统负担。close是在设备状态由up转为down时被调用的。另外如果是做为模块装入的驱动程序,close里应该调用M OD_DEC_USE_COUNT,减少设备被引用的次数,以使驱动程序可以被卸载。另外close方法必须返回成功(0=success)。(4)发送(hard_start_xmit)所有的网络设备驱动程序都必须有这个发送方法。在系统调用驱动程序的xmit时,发送的数据放在一个sk_buff结构中。一般的驱动程序把数据传给硬件发出去。也有一些特殊的设备比如loopback把数据组成一个接收数据再回送给系统,或者dummy设备直接丢弃数据。如果发送成功,hard_start_xmit方法里释放sk_buff,返回0(发送成功)。如果设备暂时无法处理,比如硬件忙,则返回1。这时如果dev->tbusy置为非0,则系统认为硬件忙,要等到dev->tbusy置0以后才会再次发送。tbusy的置0任务一般由中断完成。硬件在发送结束后产生中断,这时可以把tbusy置0,然后用mark_bh()调用通知系统可以再次发送。 在发送不成功的情况下,也可以不置dev->tbusy为非0,这样系统会不断尝试重发。如果hard_start_xmit发送不成功,则不要释放sk_buff。传送下来的sk_buff中的数据已经包含硬件需要的帧头。所以在发送方法里不需要再填充硬件帧头,数据可以直接提交给硬件发送。sk_buff是被锁住的(locked),确保其他程序不会存取它。(5)接收(reception)驱动程序并不存在一个接收方法。有数据收到应该是驱动程序来通知系统的。一般设备收到数据后都会产生一个中断,在中断处理程序中驱动程序申请一块sk_buff(skb),从硬件读出数据放置到申请好的缓冲区里。接下来填充sk_buff中 的一些信息。skb->dev = dev,判断收到帧的协议类型,填入skb->protocol(多协 议的支持)。把指针skb->m ac.raw指向硬件数据然后丢弃硬件帧头(skb_pull)。还要设置skb->pkt_type,标明第二层(链路层)数据类型。可以是以下类型: PACKET_BROADCAST : 链路层广播PACKET_MULTICAST : 链路层组播PACKET_SELF : 发给自己的帧PACKET_OTHERHOST : 发给别人的帧(监听模式时会有这种帧)最后调用netif_rx()把数据传送给协议层。netif_rx()里数据放入处理队列然后返回,真正的处理是在中断返回以后,这样可以减少中断时间。调用netif_rx()以后,驱动程序就不能再存取数据缓冲区skb。(6)硬件帧头(hard_header) 硬件一般都会在上层数据发送之前加上自己的硬件帧头,比如以太网(Ethernet)就有14字节的帧头。这个帧头是加在上层ip、ipx等数据包的前面的。驱动程序提供一个hard_ header方法,协议层(ip、ipx、arp等)在发送数据之前会调用这段程序。硬件帧头的长度必须填在dev->hard_header_len,这样协议层回在数据之前保留好硬件帧头的空间。这样hard_header程序只要调用skb_push然后正确填入硬件帧头就可以了。在协议层调用hard_header时,传送的参数包括(2.0.xx):数据的sk_buff,device指针,protocol,目的地址(daddr),源地址(saddr),数据长度(len)。数据长度不要使用s k_buff中的参数,因为调用hard_header时数据可能还没完全组织好。saddr是NULL的话是使用缺省地址(default)。daddr是NULL表明协议层不知道硬件目的地址。如果hard_header完全填好了硬件帧头,则返回添加的字节数。如果硬件帧头中的信息还不完全(比如daddr为NULL,但是帧头中需要目的硬件地址。典型的情况是以太网需要地址解析(arp),则返回负字节数。hard_header返回负数的情况下,协议层会做进一步的build header的工作。目前Linux系统里就是做arp (如果hard_header返回正,dev->arp=1,表明不需要做arp,返回负,dev->arp=0,做arp)。对hard_header的调用在每个协议层的处理程序里。如ip_output。(7)地址解析(xarp)有些网络有硬件地址(比如Ethernet),并且在发送硬件帧时需要知道目的硬件地址。这样就需要上层协议地址(ip、ipx)和硬件地址的对应。这个对应是通过地址解析完成的。需要做arp的的设备在发送之前会调用驱动程序的rebuild_header方法。调用的主要参数包括指向硬件帧头的指针,协议层地址。如果驱动程序能够解析硬件地址,就返回1,如果不能,返回0。对rebuild_header的调用在net/core/dev.c的do_dev_queue_xmit()里。(8)参数设置和统计数据在驱动程序里还提供一些方法供系统对设备的参数进行设置和读取信息。一般只有超级用户(root)权限才能对设备参数进行设置。设置方法有:.dev->set_mac_address()当用户调用ioctl类型为SIOCSIFHWADDR时是要设置这个设备的mac地址。一般对mac地址的设置没有太大意义的。.dev->set_config()当用户调用ioctl时类型为SIOCSIFMAP时,系统会调用驱动程序的set_config方法。用户会传递一个ifmap结构包含需要的I/O、中断等参数。.dev->do_ioctl()如果用户调用ioctl时类型在SIOCDEVPRIVATE和SIOCDEVPRIVATE+15之间,系统会调用驱动程序的这个方法。一般是设置设备的专用数据。读取信息也是通过ioctl调用进行。除次之外驱动程序还可以提供一个dev->get_stats方法,返回一个enet_statistics结构,包含发送接收的统计信息。ioctl的处理在net/core/dev.c的dev_ioctl()和dev_ifsioc()里。4.3 网络驱动程序中用到的数据结构最重要的是网络设备的数据结构。定义在include/linux/netdevice.h里。它的注释已经足够详尽。struct device /* * This is the first field of the "visible" part of this structure * (i.e. as seen by users in the "Space.c" file). It is the name * the interface. */ char *name; /* I/O specific fields - FIXME: Merge these and struct ifmap into one */ unsigned long rmem_end; /* shmem "recv" end */ unsigned long rmem_start; /* shmem "recv" start */ unsigned long mem_end; /* shared mem end */ unsigned long mem_start; /* shared mem start */ unsigned long base_addr; /* device I/O address */ unsigned char irq; /* device IRQ number */ /* Low-level status flags. */ volatile unsigned char start, /* start an operation */ interrupt; /* interrupt arrived */ /* 在处理中断时interrupt设为1,处理完清0。 */ unsigned long tbusy; /* transmitter busy must be long for bitops */ struct device *next; /* The device initialization function. Called only once. */ /* 指向驱动程序的初始化方法。 */ int (*init)(struct device *dev); /* Some hardware also needs these fields, but they are not part of the usual set specified in Space.c. */ /* 一些硬件可以在一块板上支持多个接口,可能用到if_port。 */ unsigned char if_port; /* Selectable AUI, TP,.*/ unsigned char dma; /* DMA channel */ struct enet_statistics* (*get_stats)(struct device *dev); /* * This marks the end of the "visible" part of the structure. All * fields hereafter are internal to the system, and may change at * will (read: may be cleaned up at will). */ /* These may be needed for future network-power-down code. */ /* trans_start记录最后一次成功发送的时间。可以用来确定硬件是否工作正常。*/ unsigned long trans_start; /* Time (in jiffies) of last Tx */ unsigned long last_rx; /* Time of last Rx */ /* flags里面有很多内容,定义在include/linux/if.h里。*/ unsigned short flags; /* interface flags (a la BSD) */ unsigned short family; /* address family ID (AF_INET) */ unsigned short metric; /* routing metric (not used) */ unsigned short mtu; /* interface MTU value */ /* type标明物理硬件的类型。主要说明硬件是否需要arp。定义在include/linux/if_arp.h里。 */ unsigned short type; /* interface hardware type */ /* 上层协议层根据hard_header_len在发送数据缓冲区前面预留硬件帧头空间。*/unsigned short hard_header_len; /* hardware hdr length */ /* priv指向驱动程序自己定义的一些参数。*/ void *priv; /* pointer to private data */ /* Interface address info. */ unsigned char broadcastMAX_ADDR_LEN; /* hw bcast add */ unsigned char pad; /* make dev_addr aligned to 8 bytes */ unsigned char dev_addrMAX_ADDR_LEN; /* hw address */ unsigned char addr_len; /* hardware address length */ unsigned long pa_addr; /* protocol address */ unsigned long pa_brdaddr; /* protocol broadcast addr */unsigned long pa_dstaddr; /* protocol P-P other side addr */ unsigned long pa_mask; /* protocol netmask */ unsigned short pa_alen; /* protocol address length */ struct dev_mc_list *mc_list; /* Multicast mac addresses */ int mc_count; /* Number of installed mcasts */ struct ip_mc_list *ip_mc_list; /* IP multicast filter chain */ _u32 tx_queue_len; /* Max frames per queue allowed */* For load balancing driver pair support */ unsigned long pkt_queue; /* Packets queued */ struct device *slave; /* Slave device */ struct net_alias_info *alias_info; /* main dev alias info */ struct net_alias *my_alias; /* alias devs */ /* Pointer to the interface buffers. */ struct sk_buff_head buffsDEV_NUMBUFFS; /* Pointers to interface service routines. */ int (*open)(struct device *dev); int (*stop)(struct device *dev); int (*hard_start_xmit) (struct sk_buff *skb, struct device *dev); int (*hard_header) (struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len); int (*rebuild_header)(void *eth, struct device *dev, unsigned long raddr, struct sk_buff *skb); #define HAVE_MULTICAST void (*set_multicast_list)(struct device *dev); #define HAVE_SET_MAC_ADDR int (*set_mac_address)(struct device *dev, void *addr); #define HAVE_PRIVATE_IOCTL int (*do_ioctl)(struct device *dev, struct ifreq *ifr, int cmd); #define HAVE_SET_CONFIG int (*set_config)(struct device *dev, struct ifmap *map); #define HAVE_HEADER_CACHE void (*header_cache_bind)(struct hh_cache *hhp, struct device *dev, unsigned short htype, _u32 daddr); void (*header_cache_update)(struct hh_cache *hh, struct device *dev, unsigned char * haddr); #define HAVE_CHANGE_MTU int (*change_mtu)(struct device *dev, int new_mtu); struct iw_statistics* (*get_wireless_stats)(struct device *dev); ; 4.4 常用的系统支持(1)内存申请和释放include/linux/kernel.h里声明了kmalloc()和kfree()。用于在内核模式下申请和释放内存。void *kmalloc(unsigned int len,int priority); void kfree(void *_ptr);与用户模式下的malloc()不同,kmalloc()申请空间有大小限制。长度是2的整次方。可以申请的最大长度也有限制。另外kmalloc()有priority参数,通常使用时可以为GFP_KERNEL,如果在中断里调用用GFP_ATOMIC参数,因为使用GFP_KERNEL 则调用者可能进入sleep状态,在处理中断时是不允许的。kfree()释放的内存必须是kmalloc()申请的。如果知道内存的大小,也可以用kfree_s( )释放。(2)request_irq()、free_irq()这是驱动程序申请中断和释放中断的调用。在include/linux/sched.h里声明。 request_irq()调用的定义: int request_irq(unsigned int irq, void (*handler)(int irq, void *dev_id, struct pt_regs *regs), unsigned long irqflags, const char * devname, void *dev_id); irq是要申请的硬件中断号。在Intel平台,范围0-15。handler是向系统登记的中断处理函数。这是一个回调函数,中断发生时,系统调用这个函数,传入的参 数包括硬件中断号,device id,寄存器值。dev_id就是下面的request_irq时传递 给系统的参数dev_id。irqflags是中断处理的一些属性。比较重要的有SA_INTERRUPT,标明中断处理程序是快速处理程序(设置SA_INTERRUPT)还是慢速处理程序(不设置SA_IN TERRUPT)。快速处理程序被调用时屏蔽所有中断。慢速处理程序不屏蔽。还有 一个SA_SHIRQ属性,设置了以后运行多个设备共享中断。dev_id在中断共享时会用到。一般设置为这个设备的device结构本身或者NULL。中断处理程序可以用dev_id 找到相应的控制这个中断的设备,或者用irq2dev_map找到中断对应的设备。void free_irq(unsigned int irq,void *dev_id); (3)时钟时钟的处理类似中断,也是登记一个时间处理函数,在预定的时间过后,系统会调用这个函数。在include/linux/timer.h里声明。struct timer_list struct timer_list *next; struct timer_list *prev; unsigned long expires; unsigned long data; void (*function)(unsigned long); ; void add_timer(struct timer_list * timer);int del_timer(struct timer_list * timer); void init_timer(struct timer_list * timer);使用时钟,先声明一个timer_list结构,调用init_timer对它进行初始化。time_list结构里expires是标明这个时钟的周期,单位采用jiffies的单位。jiffies是Linux一个全局变量,代表时间。它的单位随硬件平台的不同而不同。系统里定义了一个常数HZ,代表每秒种最小时间间隔的数目。这样jiffies的单位就是1/HZ。Intel平台jiffies的单位是1/100秒,这就是系统所能分辨的最小时间间隔了。所以expires/HZ就是以秒为单位的这个时钟的周期。function就是时间到了以后的回调函数,它的参数就是timer_list中的data。data这个参数在初始化时钟的时候赋值,一般赋给它设备的device结构指针。在预置时间到系统调用function,同时系统把这个time_list从定时队列里清除。所以如果需要一直使用定时函数,要在function里再次调用add_timer()把这个timer_list加进定时队列。(4)I/O端口 I/O端口的存取使用: inline unsigned int inb(unsigned short port); inline unsigned int inb_p(unsigned short port);inline void outb(char value, unsigned short port); inline void outb_p(char value, unsigned short port);在include/adm/io.h里定义。Inb_p()、outb_p()与inb()、o

    注意事项

    本文(课程设计(论文)Linux网络设备驱动程序设计.doc)为本站会员(文库蛋蛋多)主动上传,三一办公仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一办公(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    备案号:宁ICP备20000045号-2

    经营许可证:宁B2-20210002

    宁公网安备 64010402000987号

    三一办公
    收起
    展开