linux设备驱动之USB驱动-USB主机、设备与Gadget驱动
一、 Linux USB驱动层次
1、 主机侧与设备侧USB驱动
USB采用树形拓扑结构,主机侧和设备侧的USB控制器分别称为主机控制器(Host Controller)和USB设备控制器(UDC),每条总线上只用一个主机控制器,负责协调主机和设备之间的通信,而设备不能主动向主机发送任何消息。在linux系统中,USB主机控制器硬件,在其上运行的是USB主机控制器驱动,在主机控制器上的为USB核心层,再上层为USB设备驱动层(插入主机上的U盘、鼠标、USB转串口等设备驱动)。因此,在主机侧的层次结构中,要实现的USB驱动包括两类:USB主机控制器驱动和USB设备驱动,前者控制其中的USB设备,后者控制USB设备如何与主机通信。linux 内核中的USB核心非常重要,其功能包括:通过定义一些数据结构、宏和功能函数。向上为设备驱动提供编程接口,向下为USB主机控制器驱动提供编程接口;维护整个系统的USB设备信息;完成设备热插拔控制、总线数据传输控制等。下图为linux USB驱动总体结构
右侧Linux内核中USB设备侧驱动程序分为3个层次:UDC驱动程序、Gadget Function API和Gadget Function驱动程序。UDC驱动程序直接访问硬件,控制USB设备和主机间的底层通信 ,向上提供与硬件相关操作的回调函数。当前Gadget Function API是UDC驱动程序回调函数的简单包装。Gadget Function驱动程序具体控制USB设备功能的实习,使设备表现出"网络连接"、”打印机“或者''USB Mass Storage''等特性,它使用Gadget Function API控制UDC实现上述功能。Gadget Function API把下层的UDC驱动程序和上层的Gadget Function驱动程序隔离开,使得Linux系统中编写USB设备侧驱动程序时能够把功能的实现和底层通信分离。
2、 设备、配置、接口、端点
在USB设备的逻辑组织中,包括设备、配置、接口和端点4个层次。
每个USB设备都提供不同级别的配置信息,可以包含一个或多个配置,不同的配置使设备表现出不同的功能组合(在探测/连接期间需从其中选定一个),配置由多个接口组成。
在USB协议中,接口由多个端点组成,代表一个基本的功能,是USB设备驱动程序控制的对象,一个功能复杂的USB设备可以具有多个接口。每个配置中可以有多个接口,而设备接口是端点的汇集(Collection)。例如,USB扬声器可以包含一个音频接口及其堆旋钮和按钮的接口。一个配置中的所有接口可以同时有效,并可被不同的驱动程序连接。每个接口可以有备用接口,以提供不同质量的服务参数。
端点是UBS通信的最基本形势,每个USB设备接口在主机看来就是一个端点。主机只能通过端点与设备进行通信,以使用设备的功能。在USB系统中每一个端点都有唯一的地址,这是由设备号和端点号给出的。每个端点都有一定的属性,其中包括传输方式、总线访问频率、宽带、端点号和数据包的最大容量等。一个USB端点只能在一个方向上承载数据,从主机到设备(称为输出端点)或者从设备到主机(称为输入端点),因此端点可看作一个单向的管道。端点0通常作为端点,用于设备初始化等。只要设备连接到USB上并且上电,端点0就可以被访问。端点1、2等一般用作数据端点,存放主机与设备间往来的数据。
总体而言,USB设备非常复杂,由许多不同的逻辑单元组成,这些单元之间的关系如下:
1)设备通常有一个或多个配置
2)配置通常有一个或多个接口
3)接口通常有一个或多个设置
4)接口有零个或多个端点
这种层次配置信息在设备中通过一组标准的描述符来描述,如下所示。
1)设备描述符:关于设备的通用的信息,如供应商ID、产品ID和修订ID,支持的设备类、子类和适用的协议以及默认端点的最大包大小等。在linux内核中,USB设备用usb_device_descriptor结构体,位于include/uapi/linux/usb/ch9.h文件中,代码如下:
285 /* USB_DT_DEVICE: Device descriptor */286 struct usb_device_descriptor {287 __u8 bLength;288 __u8 bDescriptorType;289 290 __le16 bcdUSB;291 __u8 bDeviceClass;292 __u8 bDeviceSubClass;293 __u8 bDeviceProtocol;294 __u8 bMaxPacketSize0;295 __le16 idVendor;296 __le16 idProduct;297 __le16 bcdDevice;298 __u8 iManufacturer;299 __u8 iProduct;300 __u8 iSerialNumber;301 __u8 bNumConfigurations;302 } __attribute__ ((packed));
2)配置描述符:此配置中的接口数、支持的挂起和恢复能力以及功率要求。USB配置在内核中使用usb_host_config结构体描述,而USB配置描述符定义为结构体usb_config_descriptor,代码如下:
346 struct usb_config_descriptor {347 __u8 bLength;348 __u8 bDescriptorType;349 350 __le16 wTotalLength;351 __u8 bNumInterfaces;352 __u8 bConfigurationValue;353 __u8 iConfiguration;354 __u8 bmAttributes;355 __u8 bMaxPower;356 } __attribute__ ((packed));
3)接口描述符:接口类、子类和适用的协议,接口备用配置的数目和端点数目。USB接口在内核中usb_interface结构体描述,而USB接口描述符定义为结构体usb_interface_descriptor,代码如下:
389 struct usb_interface_descriptor {390 __u8 bLength;391 __u8 bDescriptorType;392 393 __u8 bInterfaceNumber;394 __u8 bAlternateSetting;395 __u8 bNumEndpoints;396 __u8 bInterfaceClass;397 __u8 bInterfaceSubClass;398 __u8 bInterfaceProtocol;399 __u8 iInterface;400 } __attribute__ ((packed));
4)端点描述符:端点地址、方向和类型,支持的最大包大小,如果是中断类型的端点则还包括轮询频率。在linux内核中,USB端点使用usb_host_endpoint结构体来描述,而UBS端点描述符定义为usb_endpoint_desciptor结构体,代码如下:
406 /* USB_DT_ENDPOINT: Endpoint descriptor */407 struct usb_endpoint_descriptor {408 __u8 bLength;409 __u8 bDescriptorType;410 411 __u8 bEndpointAddress;412 __u8 bmAttributes;413 __le16 wMaxPacketSize;414 __u8 bInterval;415 416 /* NOTE: these two are _only_ in audio endpoints. */417 /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */418 __u8 bRefresh;419 __u8 bSynchAddress;420 } __attribute__ ((packed));
5)字符串描述符:在其他描述符中会为某些字段提供字符串索引,它们可被用来检索描述性字符串,可以以多种语言形势提供。字符串描述符是可选的,有的设备有,有的设备没有。字符串描述符对应usb_string_descriptor结构体,代码如下:
371 /* USB_DT_STRING: String descriptor */372 struct usb_string_descriptor {373 __u8 bLength;374 __u8 bDescriptorType;375 376 union {377 __le16 legacy_padding;378 __DECLARE_FLEX_ARRAY(__le16, wData); /* UTF-16LE encoded */379 };380 } __attribute__ ((packed));
二、 USB主机控制器驱动
1、 USB主机控制器驱动的整体结构
USB主机控制器有这些规格:OHCI、UHCI、EHCI、和xHCI。OHCI驱动程序用来非PC系统上以及带有SIS和ALi芯片组的PC主体上的USB芯片提供支持。UHCI驱动程序多用来为大多数其他PC主板(包括Intel和Via)上的USB芯片提供支持。UHCI驱动程序多用来为大多数其他PC主板(Inte和Via)上的USB芯片提供支持。EHCI由USB2.0规范所提出,它兼容于OHCI和UHCI。由于UHCI的硬件线路比OHCI简单,所以成本较低,但需要较复杂的驱动程序,CPU负荷稍重。xHCI,即可扩展的主机控制器接口是Intel公司开发的一个USB主机控制器接口,它目前主要是面向USB3.0的,同时它也支持USB2.0及以下的设备。
1.主机控制器驱动
在linux内核中,用usb_hcd结构体描述USB主机控制器驱动,它包含USB主机控制器的“家务”信息、硬件资源、状态描述和用于操作主机控制器的hc_driver等,其定义如下:
68 struct usb_hcd {69 70 /*71 * housekeeping72 */73 struct usb_bus self; /* hcd is-a bus */74 struct kref kref; /* reference counter */75 76 const char *product_desc; /* product/vendor string */77 int speed; /* Speed for this roothub.78 * May be different from79 * hcd->driver->flags & HCD_MASK80 */81 char irq_descr[24]; /* driver + bus # */82 83 struct timer_list rh_timer; /* drives root-hub polling */84 struct urb *status_urb; /* the current status urb */85 #ifdef CONFIG_PM86 struct work_struct wakeup_work; /* for remote wakeup */87 #endif88 struct work_struct died_work; /* for when the device dies */89 90 /*91 * hardware info/state92 */93 const struct hc_driver *driver; /* hw-specific hooks */94 95 /*96 * OTG and some Host controllers need software interaction with phys;97 * other external phys should be software-transparent98 */99 struct usb_phy *usb_phy;
100 struct usb_phy_roothub *phy_roothub;
101
102 /* Flags that need to be manipulated atomically because they can
103 * change while the host controller is running. Always use
104 * set_bit() or clear_bit() to change their values.
105 */
106 unsigned long flags;
..............
..............
206
207 /* memory pool for HCs having local memory, or %NULL */
208 struct gen_pool *localmem_pool;
209
210 /* more shared queuing code would be good; it should support
211 * smarter scheduling, handle transaction translators, etc;
212 * input size of periodic table to an interrupt scheduler.
213 * (ohci 32, uhci 1024, ehci 256/512/1024).
214 */
215
216 /* The HC driver's private data is stored at the end of
217 * this structure.
218 */
219 unsigned long hcd_priv[]
220 __attribute__ ((aligned(sizeof(s64))));
221 };
usb_hcd结构体中第93行的hc_driver成员非常重要,它包含具体的用于操作主机控制器的钩子函数,即“hw-specific hooks”,其定义如下代码:
237 struct hc_driver {
238 const char *description; /* "ehci-hcd" etc */
239 const char *product_desc; /* product/vendor string */
240 size_t hcd_priv_size; /* size of private data */
241
242 /* irq handler */
243 irqreturn_t (*irq) (struct usb_hcd *hcd);
244
245 int flags;
..............
..............
257 /* called to init HCD and root hub */
258 int (*reset) (struct usb_hcd *hcd);
259 int (*start) (struct usb_hcd *hcd);
..............
273 /* cleanly make HCD stop writing memory and doing I/O */
274 void (*stop) (struct usb_hcd *hcd);
275
276 /* shutdown HCD */
277 void (*shutdown) (struct usb_hcd *hcd);
278
279 /* return current frame number */
280 int (*get_frame_number) (struct usb_hcd *hcd);
281
282 /* manage i/o requests, device state */
283 int (*urb_enqueue)(struct usb_hcd *hcd,
284 struct urb *urb, gfp_t mem_flags);
285 int (*urb_dequeue)(struct usb_hcd *hcd,
286 struct urb *urb, int status);
.............
355 /* Allocate endpoint resources and add them to a new schedule */
356 int (*add_endpoint)(struct usb_hcd *, struct usb_device *,
357 struct usb_host_endpoint *);
358 /* Drop an endpoint from a new schedule */
359 int (*drop_endpoint)(struct usb_hcd *, struct usb_device *,
360 struct usb_host_endpoint *);
361 /* Check that a new hardware configuration, set using
362 * endpoint_enable and endpoint_disable, does not exceed bus
363 * bandwidth. This must be called before any set configuration
364 * or set interface requests are sent to the device.
365 */
366 int (*check_bandwidth)(struct usb_hcd *, struct usb_device *);
367 /* Reset the device schedule to the last known good schedule,
368 * which was set from a previous successful call to
369 * check_bandwidth(). This reverts any add_endpoint() and
370 * drop_endpoint() calls since that last successful call.
371 * Used for when a check_bandwidth() call fails due to resource
372 * or bandwidth constraints.
373 */
374 void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
375 /* Set the hardware-chosen device address */
376 int (*address_device)(struct usb_hcd *, struct usb_device *udev,
377 unsigned int timeout_ms);
............
390 int (*set_usb2_hw_lpm)(struct usb_hcd *, struct usb_device *, int);
391 /* USB 3.0 Link Power Management */
392 /* Returns the USB3 hub-encoded value for the U1/U2 timeout. */
393 int (*enable_usb3_lpm_timeout)(struct usb_hcd *,
394 struct usb_device *, enum usb3_link_state state);
395 /* The xHCI host controller can still fail the command to
396 * disable the LPM timeouts, so this can return an error code.
397 */
398 int (*disable_usb3_lpm_timeout)(struct usb_hcd *,
399 struct usb_device *, enum usb3_link_state state);
400 int (*find_raw_port_number)(struct usb_hcd *, int);
401 /* Call for power on/off the port if necessary */
402 int (*port_power)(struct usb_hcd *hcd, int portnum, bool enable);
403 /* Call for SINGLE_STEP_SET_FEATURE Test for USB2 EH certification */
404 #define EHSET_TEST_SINGLE_STEP_SET_FEATURE 0x06
405 int (*submit_single_step_set_feature)(struct usb_hcd *,
406 struct urb *, int);
407 };
在linux内核中,使用如下函数来创建HCD:
如下函数被用来增加和移除HCD:
第283行的urb_enqueue()函数非常关键,实际上,上层通过usb_submit_urb()提交1个USB请求后,该函数调用usb_hcd_submit_urb(),并最终调用至usb_hcd的driver成员(hc_driver类型)的urb_enqueue()函数。