Linux系统设备驱动程序概述word精品文档13页.docx
- 文档编号:27550355
- 上传时间:2023-07-02
- 格式:DOCX
- 页数:11
- 大小:25.17KB
Linux系统设备驱动程序概述word精品文档13页.docx
《Linux系统设备驱动程序概述word精品文档13页.docx》由会员分享,可在线阅读,更多相关《Linux系统设备驱动程序概述word精品文档13页.docx(11页珍藏版)》请在冰豆网上搜索。
Linux系统设备驱动程序概述word精品文档13页
Linux系统设备驱动程序概述
1.1Linux设备驱动程序分类Linux设备驱动程序在Linux的内核源代码中占有很大的比例,源代码的长度日益增加,主要是驱动程序的增加。
在Linux内核的不断升级过程中,驱动程序的结构还是相对稳定。
在2.0.xx到2.2.xx的变动里,驱动程序的编写做了一些改变,但是从2.0.xx的驱动到2.2.xx的移植只需做少量的工作。
Linux系统的设备分为字符设备(chardevice),块设备(blockdevice)和网络设备(networkdevice)三种。
字符设备是指存取时没有缓存的设备。
块设备的读写都有缓存来支持,并且块设备必须能够随机存取(randomaccess),字符设备则没有这个要求。
典型的字符设备包括鼠标,键盘,串行口等。
块设备主要包括硬盘软盘设备,CD-ROM等。
一个文件系统要安装进入操作系统必须在块设备上。
网络设备在Linux里做专门的处理。
Linux的网络系统主要是基于BSDunix的socket机制。
在系统和驱动程序之间定义有专门的数据结构(sk_buff)进行数据的传递。
系统里支持对发送数据和接收数据的缓存,提供流量控制机制,提供对多协议的支持。
1.2编写驱动程序的一些基本概念无论是什么操作系统的驱动程序,都有一些通用的概念。
操作系统提供给驱动程序的支持也大致相同。
下面简单介绍一下网络设备驱动程序的一些基本要求。
1.2.1发送和接收这是一个网络设备最基本的功能。
一块网卡所做的无非就是收发工作。
所以驱动程序里要告诉系统你的发送函数在哪里,系统在有数据要发送时就会调用你的发送程序。
还有驱动程序由于是直接操纵硬件的,所以网络硬件有数据收到最先能得到这个数据的也就是驱动程序,它负责把这些原始数据进行必要的处理然后送给系统。
这里,操作系统必须要提供两个机制,一个是找到驱动程序的发送函数,一个是驱动程序把收到的数据送给系统。
1.2.2中断中断在现代计算机结构中有重要的地位。
操作系统必须提供驱动程序响应中断的能力。
一般是把一个中断处理程序注册到系统中去。
操作系统在硬件中断发生后调用驱动程序的处理程序。
Linux支持中断的共享,即多个设备共享一个中断。
1.2.3时钟在实现驱动程序时,很多地方会用到时钟。
如某些协议里的超时处理,没有中断机制的硬件的轮询等。
操作系统应为驱动程序提供定时机制。
一般是在预定的时间过了以后回调注册的时钟函数。
在网络驱动程序中,如果硬件没有中断功能,定时器可以提供轮询(poll)方式对硬件进行存取。
或者是实现某些协议时需要的超时重传等。
二.Linux系统网络设备驱动程序2.1网络驱动程序的结构所有的Linux网络驱动程序遵循通用的接口。
设计时采用的是面向对象的方法。
一个设备就是一个对象(device结构),它内部有自己的数据和方法。
每一个设备的方法被调用时的第一个参数都是这个设备对象本身。
这样这个方法就可以存取自身的数据(类似面向对象程序设计时的this引用)。
一个网络设备最基本的方法有初始化、发送和接收。
------|deliverpackets||receivepacketsqueue||(dev_queue_xmit())||them(netif_rx())|------||//||---|methodsandvariables(initialize,open,close,hard_xmit,||interrupthandler,config,resources,status.)|---||//||-----|sendtohardware||receivcefromhardware|-----||//||---|hardwaremedia|---初始化程序完成硬件的初始化、device中变量的初始化和系统资源的申请。
发送程序是在驱动程序的上层协议层有数据要发送时自动调用的。
一般驱动程序中不对发送数据进行缓存,而是直接使用硬件的发送功能把数据发送出去。
接收数据一般是通过硬件中断来通知的。
在中断处理程序里,把硬件帧信息填入一个skbuff结构中,然后调用netif_rx()传递给上层处理。
2.2网络驱动程序的基本方法网络设备做为一个对象,提供一些方法供系统访问。
正是这些有统一接口的方法,掩蔽了硬件的具体细节,让系统对各种网络设备的访问都采用统一的形式,做到硬件无关性。
下面解释最基本的方法。
2.2.1初始化(initialize)驱动程序必须有一个初始化方法。
在把驱动程序载入系统的时候会调用这个初始化程序。
它做以下几方面的工作。
检测设备。
在初始化程序里你可以根据硬件的特征检查硬件是否存在,然后决定是否启动这个驱动程序。
配置和初始化硬件。
在初始化程序里你可以完成对硬件资源的配置,比如即插即用的硬件就可以在这个时候进行配置(Linux内核对PnP功能没有很好的支持,可以在驱动程序里完成这个功能)。
配置或协商好硬件占用的资源以后,就可以向系统申请这些资源。
有些资源是可以和别的设备共享的,如中断。
有些是不能共享的,如IO、DMA。
接下来你要初始化device结构中的变量。
最后,你可以让硬件正式开始工作。
2.2.2打开(open)open这个方法在网络设备驱动程序里是网络设备被激活的时候被调用(即设备状态由down--up)。
所以实际上很多在initialize中的工作可以放到这里来做。
比如资源的申请,硬件的激活。
如果dev-open返回非0(error),则硬件的状态还是down。
open方法另一个作用是如果驱动程序做为一个模块被装入,则要防止模块卸载时设备处于打开状态。
在open方法里要调用MOD_INC_USE_COUNT宏。
2.2.3关闭(stop)close方法做和open相反的工作。
可以释放某些资源以减少系统负担。
close是在设备状态由up转为down时被调用的。
另外如果是做为模块装入的驱动程序,close里应该调用MOD_DEC_USE_COUNT,减少设备被引用的次数,以使驱动程序可以被卸载。
另外close方法必须返回成功(0==success)。
2.2.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),确保其他程序不会存取它。
2.2.5接收(reception)驱动程序并不存在一个接收方法。
有数据收到应该是驱动程序来通知系统的。
一般设备收到数据后都会产生一个中断,在中断处理程序中驱动程序申请一块sk_buff(skb),从硬件读出数据放置到申请好的缓冲区里。
接下来填充sk_buff中的一些信息。
skb-dev=dev,判断收到帧的协议类型,填入skb-protocol(多协议的支持)。
把指针skb-mac.raw指向硬件数据然后丢弃硬件帧头(skb_pull)。
还要设置skb-pkt_type,标明第二层(链路层)数据类型。
可以是以下类型:
PACKET_BROADCAST:
链路层广播PACKET_MULTICAST:
链路层组播PACKET_SELF:
发给自己的帧PACKET_OTHERHOST:
发给别人的帧(监听模式时会有这种帧)最后调用netif_rx()把数据传送给协议层。
netif_rx()里数据放入处理队列然后返回,真正的处理是在中断返回以后,这样可以减少中断时间。
调用netif_rx()以后,驱动程序就不能再存取数据缓冲区skb。
2.2.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)。
数据长度不要使用sk_buff中的参数,因为调用hard_header时数据可能还没完全组织好。
saddr是NULL的话是使用缺省地址(default)。
daddr是NULL表明协议层不知道硬件目的地址。
如果hard_header完全填好了硬件帧头,则返回添加的字节数。
如果硬件帧头中的信息还不完全(比如daddr为NULL,但是帧头中需要目的硬件地址。
典型的情况是以太网需要地址解析(arp)),则返回负字节数。
hard_header返回负数的情况下,协议层会做进一步的buildheader的工作。
目前Linux系统里就是做arp(如果hard_header返回正,dev-arp=1,表明不需要做arp,返回负,dev-arp=0,做arp)。
对hard_header的调用在每个协议层的处理程序里。
如ip_output。
2.2.7地址解析(xarp)有些网络有硬件地址(比如Ethernet),并且在发送硬件帧时需要知道目的硬件地址。
这样就需要上层协议地址(ip、ipx)和硬件地址的对应。
这个对应是通过地址解析完成的。
需要做arp的的设备在发送之前会调用驱动程序的rebuild_header方法。
调用的主要参数包括指向硬件帧头的指针,协议层地址。
如果驱动程序能够解析硬件地址,就返回1,如果不能,返回0。
对rebuild_header的调用在net/core/dev.c的do_dev_queue_xmit()里。
2.2.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()里。
2.3网络驱动程序中用到的数据结构最重要的是网络设备的数据结构。
定义在include/linux/netdevice.h里。
它的注释已经足够详尽。
structdevice{/**Thisisthefirstfieldofthe"visible"partofthisstructure*(i.e.asseenbyusersinthe"Space.c"file).Itisthename*theinterface.*/char*name;/*I/Ospecificfields-FIXME:
Mergetheseandstructifmapintoone*/unsignedlongrmem_end;/*shmem"recv"end*/unsignedlongrmem_start;/*shmem"recv"start*/unsignedlongmem_end;/*sharedmemend*/unsignedlongmem_start;/*sharedmemstart*/unsignedlongbase_addr;/*deviceI/Oaddress*/unsignedcharirq;/*deviceIRQnumber*//*Low-levelstatusflags.*/volatileunsignedcharstart,/*startanoperation*/interrupt;/*interruptarrived*//*在处理中断时interrupt设为1,处理完清0。
*/unsignedlongtbusy;/*transmitterbusymustbelongforbitops*/structdevice*next;/*Thedeviceinitializationfunction.Calledonlyonce.*//*指向驱动程序的初始化方法。
*/int(*init)(structdevice*dev);/*Somehardwarealsoneedsthesefields,buttheyarenotpartoftheusualsetspecifiedinSpace.c.*//*一些硬件可以在一块板上支持多个接口,可能用到if_port。
*/unsignedcharif_port;/*SelectableAUI,TP,.*/unsignedchardma;/*DMAchannel*/structenet_statistics*(*get_stats)(structdevice*dev);/**Thismarkstheendofthe"visible"partofthestructure.All*fieldshereafterareinternaltothesystem,andmaychangeat*will(read:
maybecleanedupatwill).*//*Thesemaybeneededforfuturenetwork-power-downcode.*//*trans_start记录最后一次成功发送的时间。
可以用来确定硬件是否工作正常。
*/unsignedlongtrans_start;/*Time(injiffies)oflastTx*/unsignedlonglast_rx;/*TimeoflastRx*//*flags里面有很多内容,定义在include/linux/if.h里。
*/unsignedshortflags;/*interfaceflags(alaBSD)*/unsignedshortfamily;/*addressfamilyID(AF_INET)*/unsignedshortmetric;/*routingmetric(notused)*/unsignedshortmtu;/*interfaceMTUvalue*//*type标明物理硬件的类型。
主要说明硬件是否需要arp。
定义在include/linux/if_arp.h里。
*/unsignedshorttype;/*interfacehardwaretype*//*上层协议层根据hard_header_len在发送数据缓冲区前面预留硬件帧头空间。
*/unsignedshorthard_header_len;/*hardwarehdrlength*//*priv指向驱动程序自己定义的一些参数。
*/void*priv;/*pointertoprivatedata*//*Interfaceaddressinfo.*/unsignedcharbroadcast[MAX_ADDR_LEN];/*hwbcastadd*/unsignedcharpad;/*makedev_addralignedto8bytes*/unsignedchardev_addr[MAX_ADDR_LEN];/*hwaddress*/unsignedcharaddr_len;/*hardwareaddresslength*/unsignedlongpa_addr;/*protocoladdress*/unsignedlongpa_brdaddr;/*protocolbroadcastaddr*/unsignedlongpa_dstaddr;/*protocolP-Pothersideaddr*/unsignedlongpa_mask;/*protocolnetmask*/unsignedshortpa_alen;/*protocoladdresslength*/structdev_mc_list*mc_list;/*Multicastmacaddresses*/intmc_count;/*Numberofinstalledmcasts*/structip_mc_list*ip_mc_list;/*IPmulticastfilterchain*/__u32tx_queue_len;/*Maxframesperqueueallowed*//*Forloadbalancingdriverpairsupport*/unsignedlongpkt_queue;/*Packetsqueued*/structdevice*slave;/*Slavedevice*/structnet_alias_info*alias_info;/*maindevaliasinfo*/structnet_alias*my_alias;/*aliasdevs*//*Pointertotheinterfacebuffers.*/structsk_buff_headbuffs[DEV_NUMBUFFS];/*Pointerstointerfaceserviceroutines.*/int(*open)(structdevice*dev);int(*stop)(structdevice*dev);int(*hard_start_xmit)(structsk_buff*skb,structdevice*dev);int(*hard_header)(structsk_buff*skb,structdevice*dev,unsignedshorttype,void*daddr,void*saddr,unsignedlen);int(*rebuild_header)(void*eth,structdevice*dev,unsignedlongraddr,structsk_buff*skb);#defineHAVE_MULTICASTvoid(*set_multicast_list)(structdevice*dev);#defineHAVE_SET_MAC_ADDRint(*set_mac_address)(structdevice*dev,void*addr);#defineHAVE_PRIVATE_IOCTLint(*do_ioctl)(structdevice*dev,structifreq*ifr,intcmd);#defineHAVE_SET_CONFIGint(*set_config)(structdevice*dev,structifmap*map);#defineHAVE_HEADER_CACHEvoid(*header_cache_bind)(structhh_cache*hhp,structdevice*dev,unsignedshorthtype,__u32daddr);void(*header_cache_update)(structhh_cache*hh,structdevice*dev,unsignedchar*haddr);#defineHAVE_CHANGE_MTUint(*change_mtu)(structdevice*dev,intnew_mtu);structiw_statistics*(*get_wireless_stats)(structdevice*dev);};2.4常用的系统支持2.4.1内存申请和释放include/linux/kernel.h里声明了kmalloc()和kfree()。
用于在内核模式下申请和释放内存。
void*kmalloc(unsignedintlen,intpriority);voidkfree(void*__ptr);与用户模式下的malloc()不同,kmalloc()申请空间有大小限制。
长度是2的整次方。
可以申请的最大长度也有限制。
另外kmalloc()有priority参数,通常使用时可以为GFP_KERNEL,如果在中断里调用用GFP_ATOMIC参数,因为使用GFP_KERNEL则调用者可能进入sleep状态,在处理中断时是不允许的。
kfree()释放的内存必须是kmalloc()申请的。
如果知道内存的大小,也可以用kfree_s()释放。
2.4.2request_irq()、free_irq()这是驱动程序申请中断和释放中断的调用。
在include/linux/sched.h里声明。
request_irq()调用的定义:
intrequest_irq(unsignedintirq,void(*handler)(intirq,void*dev_id,structpt_regs*regs),unsignedlongirqflags,constchar*devname,void*dev_id);irq是要申请的硬件中断号。
在Intel平台,范围0--15。
handler是向系统登记的中断处理函数。
这是一个回调函数,中断发生时,系统调用这个函数,传入的参数包括硬件中断号,deviceid,寄存器值。
dev_id就是下面的request_irq时传递给系统的参数dev_id。
irqflags是中断处理的一些属性。
比较重要的有SA_INTERRUPT,标明中断处理程序是快速处理程序(设置SA_INTERRUPT)还是慢速处理程序(不设置SA_INTERRUPT)。
快速处理程序被调用时屏蔽所有中断。
慢速处理程序不屏蔽。
还有一个SA_SHIRQ属性,设置了以后运行多个设备共享中断。
dev_id在中断共享时会用到。
一般设置为这个设备的device结构本身或者NULL。
中断处理程序可以用dev_id找到相应的控制这个中断的设备,或者用irq2dev_map找到中断对应的设备。
voidfree_irq(unsignedintirq
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Linux 系统 设备 驱动程序 概述 word 精品 文档 13