嵌入式Linux系统下的USB驱动程序开发
摘要:随着科学技术的不断发展,奇瑞怒视Linux系统被广泛应用,其功能的不断增加,为后期的程序开发奠定了坚实的基础。我们经常见到计算机上有许多USB接口,对此类USB设备而言,嵌入式Linux系统下的USB驱动程序开发十分关键,并且Linux系统内核也能够支持USB设备的接入。文章对嵌入式Linux系统与USB设备驱动的基本架构进行介绍,探讨驱动程序开发期间所设计到的技术要点。
关键词:程序开发;嵌入式;USB驱动程序;Linux系统
前言:关于连接外部设备串行总线的标准则以通用串行总线为主,具有即插即用、热插拔等优势。当下嵌入式微处理器的技术发展极为迅速,其外设与CPU不仅价格低廉,结构小巧,便于携带,还具备强大的功能,能够为为嵌入式设备提供可靠的保障,加快了嵌入式系统的发展速度。此外,随着USB的不算发展,逐渐代替了传统的串并口,已成为了电脑和外部设备间数据传递的关键途径。
1.嵌入式Linux系统
最早的嵌入式系统出现在20世纪60年代末期,当时用来控制机电电话交换机,而目前已经在军事装备、通讯、航空、工业制造、汽车、仪器仪表等领域得到广泛应用。CPU相当于计算机系统的神经中枢,每年在全球范围内的产量约有20亿颗,其中就有高达82%应用在不同专业性极强的嵌入式系统中。通常情况下,只要是携带微处理器的专业软硬件系统均可称作嵌入式系统。在嵌入式操作系统中,嵌入式Linux是一个新成员,其最大的优势在于遵循GPL协议与源代码公开,近些年来热度不减。现阶段,正在投入开发的嵌入式系统当中,约50%的项目都选择Linux,以此作为嵌入式操作系统[1]。嵌入式Linux,通过优化与加工不断发展着的Linux操作系统,保证它能够在多种计算机系统中更加适配、兼容,构建良好的系统环境,其除了具备嵌入式操作系统的特性以外,还继承了互联网上海量的开放源代码资源。同时,该操作系统的版权费是免费的,并且性能优异,容易移植软件,开放的代码资源为更多的应用软件提供了有力的支持,在开发应用产品时无需过多的开发周期,可以提高新产品的上市速度。再者实时性能RT_Linux Hardhat Linux等嵌入式Linux的支持,可以更好地保障系统的安全性、实时性及稳定性[2]。我们在使用计算机上网的过程中,往往需要进入网络设置板块配置网络,在控制面板中到网络和internet设置,当你鼠标右键单击时,会出现相应的网络属性菜单栏,里面就包含有TCP/IP协议,它可以支持Lin
ux在网络正常运行,同时还可以为其提供成百上千兆的以太网络络,如光纤、令牌环网等等,所以Linux非常适合被用于各种程序的开发。此外,由于Linux系统自身就具备良好的模块性能,所以它的大小与嵌入式操作系统的要求相适合,让一切都成为了可能,从而出现了FirePlug、ETLinux、LOAF、LEM等嵌入式Linux系统。
2.USB基础及其驱动程序结构介绍
2.1USB基础
USB作为一类电缆总线,支持各类即插即用的外部设备在主机上实现数据传输。在主机与其他设备运行的过程中,USB总线允许使用、添加、设置外部设备。一个整体的USB系统涵盖了多类硬件设备的功能,其中包括USB HUB、USB HOST和USB DEVICE。其中USB HUB为集线器,利用一个小小的集线器,可以在上面接入多个USB数据线,可以同时实现多个设备的数据传输。在USB系统中,想要实现USB总线通信功能,还要以轮询机制为基础,在整个系统中主机是主导,支配着数据的分发与传输,任何的数据通信均由主机发起。此外,USB的传输方式种类繁多,包含有同步传输、中断传输、批量传输等,通信数据一般为双向,起到了很强的互动效用。由主机把数据输送到USB设备中,这便是数据下
行链路。经过USB设备把数据输送到主机上,这便为数据下行通道。也多种多样,分别具有四类传输方式,分别为中断传输、控制传输、同步传输和批量传输,可以双向传输通信数据。数据通过主机传至USB设备,在此情况下就叫作下行通信。当数据由USB设备向主机进行传输时,就叫作上行通信,主机掌握最大控制权。
2.2USB驱动基本框架
Linux系统中,由USB主机控制器驱动和USB设备驱动设备组成一个USB驱动整体。其中USB设备驱动指的是实际的设备,包含有USB键盘、USB摄像头与USB鼠标等。USB主机控制器是用于驱动芯片上的主机控制器硬件,主要负责和USB接口间的数据传输。USB最关键部分主要负责HUB驱动程序与设备驱动程序接口的USB总线管理。USB设备类型的驱动程序作为各个应用程序交互的衔接模块,能够对特定USB设备进行访问,实现应用程度的接口访问。由于USB设备应用到的函数和设备通信主要由USB核心所提供,因此其和平台并没有太大关系。
2.3USB总线传输协议
关于USB总线的数据传输,也需要按照既定的协议和规则执行,该协议的主要对象为USB设备、USB主机,两者需要制定相应的数据流协议。在数据传输过程中,USB总线传输协议通常划分为三层,即数据传输层、信号层、协议层。我们常说的数据包,就是在信号层传输的位信息,多个包信息组合在一起就形成了包信息流,主要在协议层进行传输,又称为事务处理。USB将总线上的时间分成若干个固定大小的帧,每个帧的大小根据SOF作为起始点,在每个帧内部能够以多个信息包的形式进行传输[3]
linux系统免费下载
3.嵌入式Linux系统下的USB驱动程序开发
USB驱动程序仍旧根据驱动-总线-设备的模型进行运转。同I2C总线设备的驱动编写一致,全部的USB驱动程序均应构建以struct usb_driver为主的结构体,其为USB核心代码描述了USB驱动程序。然而这仅仅是一个框架,用来挂接总线与设备,还需要字符设备、文件操作接口等相关工作的开展。
3.1为驱动程序提供支持的设备
Structusb_device_id结构体提供了各种驱动程序支持的USB设备,一个ID身份标识也仅仅可以控制一个USB设备驱动程序,对此,该结构体通常被这样定义:
“USB_SKEL_VENDOR_ID 0xfff0”、“USB_SKEL_PRODUCT_ID 0xfff0”
此外,还可以在代码中标出MODULE_DEVICE_TABLE(usb,skel_table),括号外的代码标识设备列表类型,括号中的是参数方面的设计,参数“usb”表示设备类型,“skel_table”参数表示设备表的名称[4]。假如你想要设计USB类型的设备驱动,第一个参数就写usb,如果你要设计摄像头类型的设备驱动,第一个参数就写CD。
3.2注册和注销USB驱动
无论是USB设备驱动的注册,还是其卸载,均会使用到usb_driver结构体。而且该结构体必须编写在驱动程序当中,其囊括了大量的回调函数,有助于相关核心代码实现此类驱动特有的功能,保证所创建的structusb_driver结构体的有效性[5]。特别是与hotplug相关的USB设备驱动,需要经过模块化的编译,再把它挂在Linux内核,确保系统的高效运转。usb设备驱动以Usb_driver参数为主,搭建外部框架,与此同时还应注重对其成员函数的分析。注册代码包括“struct usb_driver skel_drive”,并且在此参数中还包括“name”、“owner”、“probe”、“id_table”、“disconnect”等五个字段,着五个字段经常出现在初始化代码编写阶段,分别表示模块的名字、模块的所有者、探测函数、驱动程序所支
持的设备列表、断开函数。利用设备驱动结构体参数的usb_register_driver函数调用,将设备驱动注册至USB的核心中。
关于USB设备驱动的注销,代码框架包括“Static void_exit usb_skel_exit(void)”,其中“exit”代表退出,除此之外,还需要用到usb_deregister_driver函数,将struct_driver从Linux内核当中注销掉。因为上述注册提到“struct usb_driver skel_drive”,所以还需要进入skel_drive中进行操作,如Usb_deregister(&skel_driver)。
3.3回调函数的探测
借助USB接口对相关设备进行安装时,如果USB核心代码能够实现对这一驱动的处理,probe就会被调用,该探测函数将检查命令向其他设备进行传递,并对这一驱动程序进行准确判断,分析该驱动对此类设备的适应程度。加入这一驱动程序与此类设备不符合,也不适用,或者因为某些因素,设备被移除,这时断开函数就会被调用[6]。通常,在USB设备驱动程序的集线器内核线程使用探测与断开回调函数,要想节省USB探测的周期,尽量在打开USB设备时完成相关工作。对于探测函数,只有在USB驱动程序初始化阶段才能发挥最大作用,这时因为它会对USB设备的所有本地结构进行管理,更方便相关操作[7]。要想
真正达到设备通信的目的,还必须依靠USB驱动的相关技术特性,对设备的端点地址进行探测,这样一来就会通过USB驱动与外部设备连接关系的创建,从而实现USB驱动与外部设备的通信功能。探测代码应包括“for(i=0;idesc.bNum Endpoints;++i)”,对所有端点进行轮番询问,利用“endpoint=& iface_desc->endpoint [j].desc”对端点数据结构进行查看,然后采用if条件函数的方式,引出批量输入端点,接着再通过“buffer_size”函数,用来获取端点数据包大小,最后借用“bulk_in_endpointAddr=endpoint”函数来获取端口地址[8]。因一个USB接口具备多种设置类型,每个类型的设置中所配置的端点都大不相同。探测函数利用一个循环语句探测不同端点,明确端点的传输方向,同时实现储存功能,方便后期读写函数的调用。
3.4实现对urb的控制
urb在驱动程序中通常使用structurb进行描述,通过一类异步的方式且相同USB设备的特定端点发送与接收数据实现数据的接收和发送。不同类型的USB设备驱动可结合自身特点与具体情况,对多个向的urb端点进行布置。不同设备中的端点都应和urb队列相对应,做好相关的处理工作,在清空许多个urb队列之前,数据就已传输到相同端点。在创建urb的过
程中,可通过usb_alloc_urb函数,如果驱动已经完成对urb的使用,就要应用到usb_free_urb函数,实现对更多urb的释放。假如已完成对urb的建立,同时开始初始化,它就能传输至USB核心代码中。当USB核心已存在urb时,直至结束处理任务,在调用例程函数前,都无法访问urb中的函数成员。假设usb_submit_urb函数被成功调用,USB核心获得对urb的控制权,这时函数就会返回零值。倘若对usb_kill_urb函数进行调用,那么就会终止urb的生命周期,往往在设备从系统卸载或者清除时,调用断开回调函数[9]
3.5对USB设备驱动程序的编译
基于嵌入式Linux系统下的驱动程序,是将所编写的程序语言进行编译,以模块化的形式呈现出来,然后加载至内核中实现运行。针对程序员已编写好的驱动程序,需要建立一个与其相对应的makefile文件,在编译好make之后就能自动生成一个驱动模块。借助insmod***.ko便能把驱动程序放入内核中正常运行[8]。要想查看所在内核中加载的驱动模块,可使用lsmod命令。关于编译的makefile文件代码包括“Ifneq($(KERNELRELEASE),)”、“Obj-m:=usb-nRf2401_transmit,o”、“KERNELDIR?”、“PWD:=$(shell pwd)”等,在此过程中也使用到了i
f..else条件函数,其中的“KERNELRELEASE”为内核识别,Obj代表编译语言代码。为了使所编译的内核可以成功地安装在开发板中,“KERNELDIR?”的作用必不可少,因为其代表内核文件的安装路径,必须将路径地址填写正确。在创建开发板Linux系统设备节点时,该设备节点表示一个文件,以文件的形式将具体的设备表现出来,由设备文件来操作相应的应用程序,从而连接驱动程序[10]

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。