linux下USB大容量存储设备驱动分析与实现

更新时间:2023-07-18 19:43:49 阅读: 评论:0

linuxUSB大容量存储设备驱动分析与实现
【摘要】本文介绍了linux USB子系统架构及USB协议,重点分析了linuxUSB大容量存储设备驱动程序,并结合U盘特点对设备驱动程序做了可靠的裁剪,以交叉编译和控制台调试的方式,在TQ2440 ARM开发板上成功实现了设备驱动模块的加载与卸载,最终达到了U盘热插拔和读写的目的。
【关键词】USB;大容量存储设备;设备驱动
USBuniversal rial bus)通用串行总线是一种高速、支持即插即用和热插拔的总线标准,由intelmicrosoft等公司制定,适用于多种USB外围设备(U盘、USB键盘鼠标、USB摄像头等)与主机之间的高速数据传输,USB2.0协议规定的最大传输速率可达480Mb/s,突破了传统串行总线的带宽限制。
Linux作为一种性能稳定,可定制,兼容性强的开源操作系统,在嵌入式设备中得到了广泛应用,且开发者可以方便地获得linux社区提供的强大技术支持,从而能够大大降低开发成本。
本文以天嵌公司的TQ2440 ARM开发板为硬件平台,以linux2.6.30为操作系统内核,通过串
口工具cure CRT,使用金士顿U盘作为USB存储设备,的分析并实现了linuxUSB大容量存储设备驱动。
1.USB子系统
类似于linux scsi子系统,USB子系统也采用树形拓扑结构,层级关系因系统功能的不同而不同,拓扑模型如图1所示。系统作为主机时拓扑层级为:USB设备驱动、USB核心、USB主控制器驱动;作为从设备时层级为:Gadget驱动、Gadget APIUSB设备控制器驱动。本文以linux为主机系统,U盘为从设备,因此只讨论主机侧拓扑结构。
USB设备驱动负责:向USB核心注册设备驱动、管理USB设备的探测与断开、实现与USB核心通信;USB核心提供一系列数据结构,宏定义和函数来抽象底层硬件设备,为设备驱动和主控器驱动提供特定的接口,读取并解析USB设备和配置描述符,为USB设备分配地址,转发设备驱动数据包,配置设备,维护设备链表和设备驱动链表,维护设备信息;USB主控制器驱动负责:与核心层通信、管理主控制器与设备的实际通信。
通常厂商提供主控制器驱动,而linux实现了USB核心(usb core)部分,因此本文将研究USB设备驱动。
2.USB协议
2.1 设备,配置,接口,端点
USB协议用设备(device)、配置(confi-guration)、接口(interface)、端点(endpoint)来描述设备的全部信息。每个设备有一个或多个配置(configuration),同一时刻只能有一个配置处于活跃状态;每个配置有一个或多个接口(interface);每个接口都有特定的设备驱动,例如USB音响有音量调节旋钮和扬声器,则对应于旋钮驱动和扬声器驱动;每个接口有零个或多个端点(栗子endpoint),端点是通信的末端,数据传输以管道(pipe)的形式在端点上实现,管道具有单向传输性,因此通常要为设备分配多个管道,读设备时使用上行管道,写设备时使用下行管道。
2.2 传输方式
数据传输有四种方式:
控制(control)传输用于非周期性的可靠传输,如USB鼠标键盘等;中断(interrupt)传输用于速率稳定的数据传输;批量(bulk)传输用于大量数据传输,对数据传输时间要求
不高,如U盘、硬盘、软盘等;等时(isochronous)传输用于实时数据传输,且对数据传输误码率要求不高,如摄像头、扬声器等。
根据传输方式的不同,端点分为控制端点、中断端点、批量端点、等时端点四种,端点0缺省为控制端点,其它端点需分配设置。管道分为控制管道、中断管道、批量管道、等时管道。
2.3 传输协议
根据存储介质的不同,USB大容量存储(Mass storage)设备通常分为两类:scsi设备和floppy设备。传输协议关系如图2所示,主机与scsi设备之间采用Bulk Only方式传输数据,设备内部采用scsi命令传输;主机与floppy设备之间采用CBIcontrol/bulk/interrupt)方式传输数据,设备内部采用UFIuniversal floppy interface)协议传输。
3.接口
USB设备每个接口都有特定的设备驱动,设备驱动用接口描述符(interface descriptor)来描述设备接口属性及通信特征,代码清单如下:
struct usb_interface_descriptor {
接口描述符包含三个重要域bInterfa-ceClassbInterfaceSubClassbInter-faceProtocol,分别对应于接口类型(cla-ss),接口子类型(subclass),接口协议(protocol)。
U盘属于Mass Storage类设备,所以bInterfaceClass=Mass Storage即接口类型为Mass StorageU盘在linux下表现为一种scsi块设备,对它的操作必须遵守scsi协议规范,因此bInterfaceSubClass=SCSI Transparent即子类型为SCSI Transparent;最初的存储设备采用CBIcontrol/bulk/interrupt)传输方式,control端点传输控制块,bulk端点传输数据,interrupt端点传输状态信息,因此造成了端点资源的极大浪费,随着USB技术的发展,Bulk-Only传输方式得到了普及,相比于CBI,这种传输方式统一使用bulk端点来传输控制块、数据及状态信息,节省了端点资源,提高了总线利用率,对于U盘,bInterfaceProtocol=Bulk Only Transport即接口传输协议为Bulk Only Transport4.urb
urbusb request block)是设备驱动用来描述与设备通信的数据结构载体,是主机与USB设备通信的电波
urb处理流程如图3所示,当scsi host获得一个scsi命令后将其添加到命令链表中,设备驱动循环检测scsi命令链表并取出命令,将其赋给USB设备的srbscsi request block),至此USB设备驱动已获取了一个scsi命令块,而在USB子系统中,命令的传输载体为urb,因此需构建包含scsi命令的urb并将其传递给USB核心层,步骤如下:
1)动态分配并初始化urb
usb_alloc_urb()→usb_init_urb()
2人教版八年级上册数学>青山原不老)运行控制线程
For(;;){
kthread_runusb_stor_control_threadus”usb-storage”
……}
实际上usb_stor_control_thread是一个死循环线程,它负责完成:检测urb是否存在检测urb请求是否超时检测urb传输方向检测目标(scsi target)和逻辑单元号(scsi lun
→proto_handler()检测urb传递状态。proto_handler是一个指向urb传输类型函数的指针,实现方式如下:
当设备接口子类(subclass)为US_SC_SCSI即设备表现为scsi块设备时,proto_handler指向的是usb_stor_transparent_scsi_command(),在这个函数中又使用了函数指针transporttransport指向的具体函数在获取传输方式时就已经指定,实现方式如下:
当传输方式为US_PR_BULKBulk_Only传输时,transport指向usb_stor_Bulk_transport(),这个函数负责填充urb并将其传递给USB核心。USB核心获得urb控制权后,将其传递给指定的主控制器驱动,至此实现了urb从设备驱动到主控制器驱动的传输。当urb传输完成后,主控制器驱动将通知设备驱动urb的传输状态。
5.设备驱动程序分析
设备驱动模块的入口和出口分别为module_init()和module_exit(),它们分别调用模块初始化函数usb_stor_initusb_stor_init)和卸载函数usb_stor_exit眼睛流泪是什么原因引起的(usb_stor_exit)实现向USB核心注册驱动和卸载驱动。注册驱动时调用usb_register&usb_storage_driver),
卸载时调用usb_deregister&usb_storage_driver)。usb_storage_driver是设备驱动的心脏,它为设备驱动与USB核心提供了通信接口,其中定义了各种驱动操作函数,代码清单如下:
name为模块名。
probe对应驱动函数storage_probe(),storage_probe房事秘诀( )完成:流管员
获取接口数据保存接口数据分配设备DMA映射缓存获取不常见设备,可裁剪掉获取传输类型获取传输协议设置管道设置控制发送管道设置控制接收管道设置bulk发送管道设置bulk安全学习记录接收管道设置中断接收管道分配,初始化并传递urb给核心层scsi总线层添加scsi host→创建scsi总线扫描线程开始scsi线程扫描。U盘插入后,USB核心调用设备驱动程序的probe函数在总线维护的设备链表中寻找适合该驱动的设备,如果找到则将驱动绑定到总线。
disconnect对应的驱动函数为usb_storage_disconnect(),它负责完成:停止scsi扫描移除scsi host→停止接收新的scsi命令释放所有的总线和设备资源。U盘拔出后,鲜肉汤圆USB核心调用usb_storage_disconnect()解除驱动与总线的绑定。
suspendresume实现系统待机状态下设备挂起操作,它们对应的驱动函数usb_stor_suspend()和usb_stor_resume()依赖于内核电源管理配置项(Power Management support)。为了达到低耗的效果,Linux对设备电源有严格的管理,当系统待机时设备应处于低功率状态下,因此要对耗电设备执行挂起操作。
pre_retpost_ret负责端口重启后获取接口数据。id_table是驱动支持的设备列表,USB设备品种繁多,而一个驱动模块只能支持特定的一个或多个设备(最多16个设备),因此需要在驱动中建立USB设备表,代码实现如下:
struct usb_device_id usb_storage_usb_ids[]={
{USB_DEVICEUSB_MASS_VENDOR_IDUSB_MASS_PRODUCT_ID}

本文发布于:2023-07-18 19:43:49,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/1103658.html

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

标签:设备   驱动   传输   端点
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图