您好,欢迎访问三七文档
1.Linux下驱动整体架构这个图我们从下面往上面看,linux驱动最底层是主机硬件,运行在主机硬件其上是驱动模块了,驱动模块直接对进行读写操作。驱动模块在内核是可以通过静态或者动态加载,来在内核中注册的。例如用insmodXXX.o模块,那么用limod就可以看到已经在内核中加载进来,设备文件是用mknod+新设备名+c/b+主设备号+次设备号来关联起来的。上层的应用程序仅仅对设备文件进行读写等操作。2.linuxUSB驱动层次应用程序设备文件驱动模块主机硬件kernelOpen/Read/Write命令操作Mknod通过主设备号关联通过模块中的Read/Write操作返回主设备号insmod向系统注册USB设备驱动usb-skeleton/Massstorage/AL576USB核心USB主机控制器驱动OHCI/EHCI/UHCIUSB控制器OHCI/EHCI/UHCIUSB控制器OHCI/EHCI/UHCI从运行Linux的主机侧看设备侧看上图可以说是前面第一部分的驱动模块的一个特写。从主机侧来看,在linux驱动中,USB驱动最底层的是USB主控制器硬件。在其上运行的是USB主机控制驱动。主机控制驱动之上为USB核心层,在往上层为USB设备驱动层了(与插入主机上的U盘、鼠标、AL576等对应的设备驱动)。Linux内核的USB核心负责USB驱动管理和协议处理的重要工作,其功能包括:通过定义一些数据结构、宏、和功能函数,向上为设备驱动提供编程接口,向下为USB主机控制器驱动提供编程接口:通过全部变量维护整个系统的USB设备信息;完成设备热插拔控制、总线数据传输控制等。3.USB骨架驱动usb-skeleton分析module_init(usb_skel_init);/*模块入口*/module_exit(usb_skel_exit);/*模块出口*/staticstructusb_driverskel_driver={name:skeleton,/*本驱动名*/probe:skel_probe,/*USB设备探测函数指针*/disconnect:skel_disconnect,/*USB设备断开函数指针*/fops:&skel_fops,/*对应的操作*/minor:USB_SKEL_MINOR_BASE,id_table:skel_table,/*本驱动支持的设备列里面对应设备VENDOR_ID,PRODUCT_ID*/};staticstructfile_operationsskel_fops={owner:THIS_MODULE,read:skel_read,write:skel_write,ioctl:skel_ioctl,open:skel_open,release:skel_release,};USB骨架程序的关键几点如下:USB驱动的注册和注销Usb驱动程序在注册时会发送一个命令给usb_register,通常在驱动程序的初始化函数里。当要从系统卸载驱动程序时,需要注销usb子系统。即需要usb_unregister函数处理:staticvoid__exitusb_skel_exit(void){/*deregisterthisdriverwiththeUSBsubsystem*/usb_deregister(&skel_driver);}module_exit(usb_skel_exit);当usb设备插入时,为了使linux-hotplug(Linux中PCI、USB等设备热插拔支持)系统自动装载驱动程序,你需要创建一个MODULE_DEVICE_TABLE。代码如下(这个模块仅支持某一特定设备):/*tableofdevicesthatworkwiththisdriver*/staticstructusb_device_idskel_table[]={{USB_DEVICE(USB_SKEL_VENDOR_ID,USB_SKEL_PRODUCT_ID)},{}/*Terminatingentry*/};MODULE_DEVICE_TABLE(usb,skel_table);USB_DEVICE宏利用厂商ID和产品ID为我们提供了一个设备的唯一标识。当系统插入一个ID匹配的USB设备到USB总线时,驱动会在USBcore中注册。驱动程序中probe函数也就会被调用。usb_device结构指针、接口号和接口ID都会被传递到函数中。staticvoid*skel_probe(structusb_device*dev,unsignedintifnum,conststructusb_device_id*id)驱动程序需要确认插入的设备是否可以被接受,如果不接受,或者在初始化的过程中发生任何错误,probe函数返回一个NULL值。否则返回一个含有设备驱动程序状态的指针。通过这个指针,就可以访问所有结构中的回调函数。在骨架驱动程序里,最后一点是我们要注册devfs。我们创建一个缓冲用来保存那些被发送给usb设备的数据和那些从设备上接受的数据,同时USBurb被初始化,并且我们在devfs子系统中注册设备,允许devfs用户访问我们的设备。注册过程如下:/*initializethedevfsnodeforthisdeviceandregisterit*/sprintf(name,skel%d,skel-minor);skel-devfs=devfs_register(usb_devfs_handle,name,DEVFS_FL_DEFAULT,USB_MAJOR,USB_SKEL_MINOR_BASE+skel-minor,S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH,&skel_fops,NULL);如果devfs_register函数失败,不用担心,devfs子系统会将此情况报告给用户。当然最后,如果设备从usb总线拔掉,设备指针会调用disconnect函数。驱动程序就需要清除那些被分配了的所有私有数据、关闭urbs,并且从devfs上注销调自己。/*removeourdevfsnode*/devfs_unregister(skel-devfs);现在,skeleton驱动就已经和设备绑定上了,任何用户态程序要操作此设备都可以通过file_operations结构所定义的函数进行了。首先,我们要open此设备。在open函数中MODULE_INC_USE_COUNT宏是一个关键,它的作用是起到一个计数的作用,有一个用户态程序打开一个设备,计数器就加一,例如,我们以模块方式加入一个驱动,若计数器不为零,就说明仍然有用户程序在使用此驱动,这时候,你就不能通过rmmod命令卸载驱动模块了。/*incrementourusagecountforthemodule*/MOD_INC_USE_COUNT;++skel-open_count;/*saveourobjectinthefile'sprivatestructure*/file-private_data=skel;当open完设备后,read、write函数就可以收、发数据了。skel的write、和read函数他们是完成驱动对读写等操作的响应。在skel_write中,一个FILL_BULK_URB函数,就完成了urb系统callbak和我们自己的skel_write_bulk_callback之间的联系。注意skel_write_bulk_callback是中断方式,所以要注意时间不能太久,本程序中它就只是报告一些urb的状态等。read函数与write函数稍有不同在于:程序并没有用urb将数据从设备传送到驱动程序,而是我们用usb_bulk_msg函数代替,这个函数能够不需要创建urbs和操作urb函数的情况下,来发送数据给设备,或者从设备来接收数据??。我们调用usb_bulk_msg函数并传提一个存储空间,用来缓冲和放置驱动收到的数据,若没有收到数据,就失败并返回一个错误信息。usb_bulk_msg函数当对usb设备进行一次读或者写时,usb_bulk_msg函数是非常有用的;然而,当你需要连续地对设备进行读/写时,建议你建立一个自己的urbs,同时将urbs提交给usb子系统。skel_disconnect函数当我们释放设备文件句柄时,这个函数会被调用。MOD_DEC_USE_COUNT宏会被用到(和MOD_INC_USE_COUNT刚好对应,它减少一个计数器),首先确认当前是否有其它的程序正在访问这个设备,如果是最后一个用户在使用,我们可以关闭任何正在发生的写,操作如下:/*decrementourusagecountforthedevice*/--skel-open_count;if(skel-open_count=0){/*shutdownanybulkwritesthatmightbegoingon*/usb_unlink_urb(skel-write_urb);skel-open_count=0;}/*decrementourusagecountforthemodule*/MOD_DEC_USE_COUNT;最困难的是,usb设备可以在任何时间点从系统中取走,即使程序目前正在访问它。usb驱动程序必须要能够很好地处理解决此问题,它需要能够切断任何当前的读写,同时通知用户空间程序:usb设备已经被取走。如果程序有一个打开的设备句柄,在当前结构里,我们只要把它赋值为空,就像它已经消失了。对于每一次设备读写等其它函数操作,我们都要检查usb_device结构是否存在。如果不存在,就表明设备已经消失,并返回一个-ENODEV错误给用户程序。当最终我们调用release函数时,在没有文件打开这个设备时,无论usb_device结构是否存在、它都会清空skel_disconnect函数所作工作。
本文标题:USB设备驱动架构
链接地址:https://www.777doc.com/doc-2865345 .html