




免费预览已结束,剩余3页可下载查看
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
25.2 USB驱动程序框架Linux内核提供了完整的USB驱动程序框架。USB总线采用树形结构,在一条总线上只能有唯一的主机设备。Linux内核从主机和设备两个角度观察USB总线结构。本节介绍Linux内核USB驱动程序框架。25.2.1 Linux内核USB驱动框架图25-2是Linux内核从主机和设备两个角度观察USB总线结构的示意图。从图25-2中可以看出,Linux内核USB驱动是按照主机驱动和设备驱动两套体系实现的,下面介绍两套体系的结构和特点。1基本结构图25-2的左侧是主机驱动结构。主机驱动的最底层是USB主机控制器,提供了OHCI/EHCI/UHCI这3种类型的总线控制功能。在USB控制器的上一层是主机控制器的驱动,分别对应OHCI/EHCI/UHCI这3种类型的总线接口。USB核心部分连接了USB控制器驱动和设备驱动,是两者之间的转换接口。USB设备驱动层提供了各种设备的驱动程序。USB主机部分的设计结构完全是从USB总线特点出发的。在USB总线上可以连接各种不同类型的设备,包括字符设备、块设备和网络设备。所有类型的USB设备都是用相同的电气接口,使用的传输协议也基本相同。向用户提供某种特定类型的USB设备时,需要处理USB总线协议。内核完成所有的USB总线协议处理,并且向用户提供编程接口。图25-2 Linux内核USB总线结构图25-2右侧是设备驱动结构。与USB主机类似,USB设备提供了相同的层次结构与之对应。但是在USB设备一侧使用名为Gadget API的结构作为核心。Gadget API是Linux内核实现的对应USB设备的核心结构。Gadget API屏蔽了USB设备控制器的细节,控制具体的USB设备实现。2设备每个USB设备提供了不同级别的配置信息。一个USB设备可以包含一个或多个配置,不同的配置使设备表现出不同的特点。其中,设备的配置是通过接口组成的。Linux内核定义了USB设备描述结构如下:struct usb_device_descriptor _u8 bLength; / 设备描述符长度 _u8 bDescriptorType; / 设备类型 _le16 bcdUSB; / USB版本号(使用BCD编码) _u8 bDeviceClass; / USB设备类型 _u8 bDeviceSubClass; / USB设备子类型 _u8 bDeviceProtocol; / USB设备协议号 _u8 bMaxPacketSize0; / 传输数据的最大包长 _le16 idVendor; / 厂商编号 _le16 idProduct; / 产品编号 _le16 bcdDevice; / 设备出厂号 _u8 iManufacturer; / 厂商字符串索引 _u8 iProduct; / 产品字符串索引 _u8 iSerialNumber; / 产品序列号索引 _u8 bNumConfigurations; / 最大的配置数量 _attribute_ (packed);从usb_device_descriptor结构定义看出,一个设备描述符定义了与USB设备有关的所有信息。3接口在USB体系中,接口是由多个端点组成的。一个接口代表一个基本的功能,是USB设备驱动程序控制的对象。一个USB设备最少有一个接口,功能复杂的USB设备可以有多个接口。接口描述定义如下:struct usb_interface_descriptor _u8 bLength; / 描述符长度 _u8 bDescriptorType; / 描述符类型 _u8 bInterfaceNumber; / 接口编号 _u8 bAlternateSetting; / 备用接口编号 _u8 bNumEndpoints; / 端点数量 _u8 bInterfaceClass; / 接口类型 _u8 bInterfaceSubClass; / 接口子类型 _u8 bInterfaceProtocol; / 接口使用的协议 _u8 iInterface; / 接口索引字符串数值 _attribute_ (packed);4端点端点是USB总线通信的基本形式,每个USB设备接口可以认为是端点的集合。主机只能通过端点与设备通信。USB体系结构规定每个端点都有一个唯一的地址,由设备地址和端点号决定端点地址。端点还包括了与主机通信用到的属性,如传输方式、总线访问频率、带宽和端点号等。端点的通信是单向的,通过端点传输的数据只能是从主机到设备或者从设备到主机。端点定义描述如下:struct usb_endpoint_descriptor _u8 bLength; / 描述符长度 _u8 bDescriptorType; / 描述符类型 _u8 bEndpointAddress; / 端点地址 _u8 bmAttributes; / 端点属性 _le16 wMaxPacketSize; / 端点接收的最大数据包长度 _u8 bInterval; / 轮询端点的时间间隔 /* NOTE: these two are _only_ in audio endpoints. */ /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */ _u8 bRefresh; _u8 bSynchAddress; _attribute_ (packed);5配置配置是一个接口的集合。Linux内核配置的定义如下:struct usb_config_descriptor _u8 bLength; / 描述符长度 _u8 bDescriptorType; / 描述符类型 _le16 wTotalLength; / 配置返回数据长度 _u8 bNumInterfaces; / 最大接口数 _u8 bConfigurationValue; / 配置参数值 _u8 iConfiguration; / 配置描述字符串索引 _u8 bmAttributes; / 供电模式 _u8 bMaxPower; / 接口的最大电流 _attribute_ (packed);配置描述符结构定义了配置的基本属性和接口数量等信息。25.2.2 主机驱动结构USB主机控制器有3种类型: OHCI:英文全称是Open Host Controller Interface,是用于SiS和Ali芯片组的USB控制器。 UHCI:英文全称是Universal Host Controller Interface,用于Intel和AMD芯片组的USB控制器。UHCI类型的控制器比OHCI控制器硬件结构要简单,但是需要额外的驱动支持,因此从理论上说速度要慢。 EHCI:是USB 2.0规范提出的一种控制器标准,可以兼容UHCI和OHCI。1USB主机控制器驱动Linux内核使用usb_hcd结构描述USB主机控制器驱动。usb_hcd结构描述了USB主机控制器的硬件信息、状态和操作函数,定义如下:struct usb_hcd /* usb_bus.hcpriv points to this */ /* * housekeeping / 控制器基本信息 */ struct usb_bus self; /* hcd is-a bus */ const char *product_desc; /* product/vendor string */ / 厂商名称字符串 char irq_descr24; /* driver + bus # */ / 驱动和总线类型 struct timer_list rh_timer; /* drives root-hub polling */ / 根hub轮询时间间隔 struct urb *status_urb; /* the current status urb */ / 当前urb状态 /* * hardware info/state / 硬件信息和状态 */ const struct hc_driver *driver; /* hw-specific hooks */ / 控制器驱动使用的回调函数 /* Flags that need to be manipulated atomically */ unsigned long flags;#define HCD_FLAG_HW_ACCESSIBLE 0x00000001#define HCD_FLAG_SAW_IRQ 0x00000002 unsigned rh_registered:1;/* is root hub registered? */ / 是否注册根hub /* The next flag is a stopgap, to be removed when all the HCDs * support the new root-hub polling mechanism. */ unsigned uses_new_polling:1; / 是否允许轮询根hub状态 unsigned poll_rh:1; /* poll for rh status? */ unsigned poll_pending:1; /* status has changed? */ / 状态是否改变 int irq; /* irq allocated */ / 控制器的中断请求号 void _iomem *regs; /* device memory/io */ / 控制器使用的内存和I/O u64 rsrc_start; /* memory/io resource start */ / 控制器使用的内存和I/O起始地址 u64 rsrc_len; /* memory/io resource length */ / 控制器使用的内存和I/O资源长度 unsigned power_budget; /* in mA, 0 = no limit */#define HCD_BUFFER_POOLS 4 struct dma_pool *pool HCD_BUFFER_POOLS; int state;# define _ACTIVE 0x01# define _SUSPEND 0x04# define _TRANSIENT 0x80# define HC_STATE_HALT 0# define HC_STATE_RUNNING (_ACTIVE)# define HC_STATE_QUIESCING (_SUSPEND|_TRANSIENT|_ACTIVE)# define HC_STATE_RESUMING (_SUSPEND|_TRANSIENT)# define HC_STATE_SUSPENDED (_SUSPEND)#define HC_IS_RUNNING(state) (state) & _ACTIVE)#define HC_IS_SUSPENDED(state) (state) & _SUSPEND) /* more shared queuing code would be good; it should support * smarter scheduling, handle transaction translators, etc; * input size of periodic table to an interrupt scheduler. * (ohci 32, uhci 1024, ehci 256/512/1024). */ /* The HC drivers private data is stored at the end of * this structure. */ unsigned long hcd_priv0 _attribute_ (aligned (sizeof(unsigned long);2OHCI控制器驱动usb_hcd结构可以理解为一个通用的USB控制器描述结构。OHCI主机控制器是usb_hcd结构的具体实现,内核使用ohci_hcd结构描述OHCI主机控制器,定义如下:struct ohci_hcd spinlock_t lock; /* * I/O memory used to communicate with the HC (dma-consistent) / 用于HC通信的I/O内存地址 */ struct ohci_regs _iomem *regs; /* * main memory used to communicate with the HC (dma-consistent). / 用于HC通行的主内存地址 * hcd adds to schedule for a live hc any time, but removals finish * only at the start of the next frame. */ struct ohci_hcca *hcca; dma_addr_t hcca_dma; struct ed *ed_rm_list; /* to be removed */ / 将被移除列表 struct ed *ed_bulktail; /* last in bulk list */ / 列表最后一项 struct ed *ed_controltail; /* last in ctrl list */ / 控制列表最后一项 struct ed *periodic NUM_INTS; /* shadow int_table */ /* * OTG controllers and transceivers need software interaction; * other external transceivers should be software-transparent */ struct otg_transceiver *transceiver; /* * memory management for queue data structures / 内存管理队列使用的数据结构 */ struct dma_pool *td_cache; struct dma_pool *ed_cache; struct td *td_hash TD_HASH_SIZE; struct list_head pending; /* * driver state */ int num_ports; int load NUM_INTS; u32 hc_control; /* copy of hc control reg */ HC控制寄存器复制 unsigned long next_statechange; /* suspend/resume */ / 挂起/恢复 u32 fminterval; /* saved register */ / 保存的寄存器 struct notifier_block reboot_notifier; unsigned long flags; /* for HC bugs */* 以下是各厂家芯片ID定义 */#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */#define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */#define OHCI_QUIRK_INITRESET 0x04 /* SiS, OPTi, . */#define OHCI_BIG_ENDIAN 0x08 /* big endian HC */#define OHCI_QUIRK_ZFMICRO 0x10 /* Compaq ZFMicro chipset*/ / 芯片的初始化逻辑里也同样会有怪异的Bug;OHCI主机控制器是嵌入式系统最常用的一种USB主机控制器。25.2.3 设备驱动结构USB协议规定了许多种USB设备类型。Linux内核实现了音频设备、通信设备、人机接口、存储设备、电源设备、打印设备等几种USB设备类。1基本概念Linux内核实现的USB设备类驱动都是针对通用的设备类型设计的。如存储设备类,只要USB存储设备是按照标准的USB存储设备规范实现的,就可以直接被内核USB存储设备驱动程序驱动。如果一个USB设备是非标准的,则需要编写对应设备的驱动程序。Linux内核为不同的USB设备分配了设备号。在内核中还提供了一个usbfs文件系统,通过usbfs文件系统,用户可以方便地使用USB设备。为了使用usbfs,使用root权限在控制台输入“mount t usbfs none /proc/bus/usb”,可以加载USB文件系统到内核。在插入一个USB设备的时候,内核会试图加载对应的驱动程序。2设备驱动结构内核使用usb_driver结构体描述USB设备驱动,定义如下:struct usb_driver const char *name; int (*probe) (struct usb_interface *intf, const struct usb_device_id *id); / 探测函数 void (*disconnect) (struct usb_interface *intf); / 断开连接函数 int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf); / I/O控制函数 int (*suspend) (struct usb_interface *intf, pm_message_t message); / 挂起函数 int (*resume) (struct usb_interface *intf); / 恢复函数 void (*pre_reset) (struct usb_interface *intf); void (*post_reset) (struct usb_interface *intf); const struct usb_device_id *id_table; struct usb_dynids dynids; struct device_driver driver; unsigned int no_dynamic_id:1;实现一个USB设备的驱动主要是实现probe()和disconnect()函数接口。probe()函数在插入USB设备的时候被调用,disconnect()函数在拔出USB设备的时候被调用。在25.2.4节中详细讲解USB设备驱动程序框架。3USB请求块USB请求块(USB request block,urb)的功能类似于网络设备中的sk_buff,用于描述USB设备与主机通信的基本数据结构。urb结构在内核中定义如下:struct urb /* private: usb core and host controller only fields in the urb */ / 私有数据,仅供USB核心和主机控制器使用 struct kref kref; /* reference count of the URB */ / urb引用计数 spinlock_t lock; /* lock for the URB */ / urb锁 void *hcpriv; /* private data for host controller */ / 主机控制器私有数据 int bandwidth; /* bandwidth for INT/ISO request */ / 请求带宽 atomic_t use_count; /* concurrent submissions counter */ / 并发传输计数 u8 reject; /* submissions will fail */ / 传输即将失败标志 /* public: documented fields in the urb that can be used by drivers */ / 公有数据,可以被驱动使用 struct list_head urb_list; /* list head for use by the urbs / 链表头 * current owner */ struct usb_device *dev; /* (in) pointer to associated device */ / 关联的USB设备 unsigned int pipe; /* (in) pipe information */ / 管道信息 int status; /* (return) non-ISO status */ / 当前状态 unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | .*/ void *transfer_buffer; /* (in) associated data buffer */ / 数据缓冲区 dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */ / DMA使用的缓冲区 int transfer_buffer_length; /* (in) data buffer length */ / 缓冲区大小 int actual_length; /* (return) actual transfer length */ / 实际接收或发送数据的长度 unsigned char *setup_packet; /* (in) setup packet (control only) */ dma_addr_t setup_dma; /* (in) dma addr for setup_packet */ / 设置数据包缓冲区 int start_frame; /* (modify) start frame (ISO) */ / 等时传输中返回初始帧 int number_of_packets; /* (in) number of ISO packets */ / 等时传输中缓冲区数据 int interval; /* (modify) transfer interval / 轮询的时间间隔 * (INT/ISO) */ int error_count; /* (return) number of ISO errors */ / 出错次数 void *context; /* (in) context for completion */ usb_complete_t complete; /* (in) completion routine */ struct usb_iso_packet_descriptor iso_frame_desc0; /* (in) ISO ONLY */;内核提供了一组函数操作urb类型的结构变量。urb的使用流程如下:(1)创建urb。在使用之前,USB设备驱动需要调用usb_alloc_urb()函数创建一个urb,函数定义如下:struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags);iso_packets参数是urb包含的等时数据包数目,如果为0表示不创建等时数据包。mem_flags参数是分配内存标志。如果分配urb成功,函数返回一个urb结构类型的指针,否则返回0。内核还提供了释放urb的函数,定义如下:void usb_free_urb(struct urb *urb)在不使用urb的时候(退出驱动程序或者挂起驱动),需要使用usb_free_urb()函数释放urb。(2)初始化urb,设置USB设备的端点。使用内核提供的usb_int_urb()函数设置urb初始结构,定义如下:void usb_init_urb(struct urb *urb);(3)提交urb到USB核心。在分配并设置urb完毕后,使用usb_submit_urb()函数把新的urb提交到USB核心,函数定义如下:int usb_submit_urb(struct urb *urb, gfp_t mem_flags);参数urb指向被提交的urb结构,mem_flags是传递给USB核心的内存选项,用于告知USB核心如何分配内存缓冲区。如果函数执行成功,urb的控制权被USB核心接管,否则函数返回错误。25.2.4 USB驱动程序框架Linux内核代码driver/usb/usb-skeleton.c文件是一个标准的USB设备驱动程序。编写一个USB设备的驱动可以参考usb-skeleton.c文件,实际上,可以直接修改该文件驱动新的USB设备。下面以usb-skeleton.c文件为例分析usb-skel设备驱动框架。1基本数据结构usb-skel设备使用自定义结构usb_skel记录设备驱动用到的所有描述符,该结构定义如下:struct usb_skel struct usb_device * udev; /* the usb device for this device */ / USB设备描述符 struct usb_interface * interface; /* the interface for this device */ / USB接口描述符 struct semaphore limit_sem; /* limiting the number of writes in progress */ / 互斥信号量 unsigned char * bulk_in_buffer; /* the buffer to receive data */ / 数据接收缓冲区 size_t bulk_in_size; /* the size of the receive buffer */ / 数据接收缓冲区大小 _u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ / 入端点地址 _u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ / 出端点地址 struct kref kref;usb-skel设备驱动把usb_skel结构存放在了urb结构的context指针里。通过urb,设备的所有操作函数都可以访问到usb_skel结构。其中,limit_sem成员是一个信号量,当多个usb-skel类型的设备存在于系统中的时候,需要控制设备之间的数据同步。2驱动程序初始化和注销与其他所有的Linux设备驱动程序一样,usb-skel驱动使用module_init()宏设置初始化函数,使用module_exit()宏设置注销函数。usb-skel驱动的初始化函数是usb_skel_init()函数,定义如下:static int _init usb_skel_init(void) int result; /* register this driver with the USB subsystem */ result = usb_register(&skel_driver); / 注册USB设备驱动 if (result) err(usb_register failed. Error number %d, result); return result;usb_skel_init()函数调用内核提供的usb_register()函数注册了一个usb_driver类型的结构变量,该变量定义如下:static struct usb_driver skel_driver = .name = skeleton, / USB设备名称 .probe = skel_probe, / USB设备初始化函数 .disconnect = skel_disconnect, / USB设备注销函数 .id_table = skel_table, / USB设备ID映射表;skel_driver结构变量中,定义了usb-skel设备的名、设备初始化函数、设备注销函数和USB ID映射表。其中usb-skel设备的USB ID映射表定义如下:static struct usb_device_id skel_table = USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) , /* Terminating entry */;skel_table中只有一项,定义了一个默认的usb-skel设备的ID。其中,USB_SKEL_VENDOR_ID是USB设备的厂商ID,USB_SKEL_PRODUCT_ID是USB设备ID。注销函数的操作比较简单,调用usb_deregister()函数注销usb-skel设备驱动,函数定义如下:static void _exit usb_skel_exit(void) /* deregister this driver with th
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 理想的风筝读后感700字(7篇)
- 企业人才储备及发展路径规划工具
- 纪检业务实战培训课件
- 五子棋争霸赛250字12篇
- 2025年日语能力测试N1级词汇语法强化训练试卷
- 乡村集体经济合作管理合同
- 2025年社会工作师职业水平考试社会工作评估实务(中级)试卷
- 宁德三年级数学试卷
- 鄱阳二中数学试卷
- 邳州初中考数学试卷
- 中国移动-安全-L1,2,3(珍藏版)
- 2017年全国大学生数学建模A题
- 2023年专升本计算机题库含答案专升本计算机真题
- scratch3.0编程校本课程
- GB/T 25146-2010工业设备化学清洗质量验收规范
- GB/T 1685-2008硫化橡胶或热塑性橡胶在常温和高温下压缩应力松弛的测定
- GB/T 14825-1993农药可湿性粉剂悬浮率测定方法
- GB/T 12008.7-2010塑料聚醚多元醇第7部分:黏度的测定
- 最全最好的血液净化课件资料
- 固定资产清查工作报告
- 住宅项目景观工程施工策划(图文并茂)
评论
0/150
提交评论