16.4.1 UDC(USB设备控制器)和Gadget(小配件)驱动的关键数据结构与API
USB设备控制器(UDC)驱动指的是作为其他USB主机控制器外设的USB硬件设备上底层硬件控制器的驱动,该硬件和驱动负责将一个USB设备依附于一个USB主机控制器上。例如,当某运行Linux系统的手机作为PC的U盘时,手机中的底层USB控制器行使USB设备控制器的功能,这时运行在底层的是UDC驱动,手机要成为U盘,在UDC驱动之上需要另外一个驱动,对于USB大容量存储器而言,这个驱动为File Storage驱动,称为Function驱动。
图16.1 Linux USB驱动总体结构
从图16.1左边看,USB设备驱动调用USB核心的API,具体驱动与SoC无关;从图16.1右边看,Function驱动调用通用的Gadget FunctionAPI,具体Function驱动也与SoC无关。
UDC驱动和Function驱动都位于内核的drivers/usb/gadget目录,如drivers/usb/gadget/udc下面的
at91_udc.c、omap_udc.c、s3c2410_udc.c等是对应SoC平台上的UDC驱动,而drivers/usb/gadget/function目录下的f_serial.c、f_mass_storage.c、f_rndis.c等文件实现了一些Gadget功能,重要的Function驱动如下所
示。
Ethernet over USB:该驱动模拟以太网网口,支持多种运行方式——CDC Ethernet(实现标准的
Communications Device Class "Ethernet Model"协议)、CDC Subset以及RNDIS(微软公司对CDC Ethernet的变种实现)。
File-Backed Storage Gadget:最常见的U盘功能实现。
Serial Gadget:包括Generic Serial实现(只需要Bulk-in/Bulk-out端点+ep0)和CDC ACM规范实现。
Gadget MIDI(音乐设备数字接口):暴露ALSA MIDI接口。
USB Video Class Gadget驱动:让Linux系统成为另外一个系统的USB视频采集源。
另外,drivers/usb/gadget源代码还实现一个Gadget文件系统(GadgetFS),将Gadget API接口暴露给应用层,以便在应用层实现用户空间的驱动。
USB设备控制器驱动,需要关心四个核心的数据结构,这些数据结构包括描述一个USB设备控制器的usb_gadget、UDC操作usb_gadget_ops、描述一个端点的usb_ep以及描述端点操作的usb_ep_ops结构体。UDC驱动围绕这些数据结构及其成员函数展开,代码清单16.30列出了这些关键的数据结构,代码路径:
include/linux/usb/gadget.h
代码清单16.30 UDC驱动的关键数据结构
/**
* struct usb_gadget - represents a usb slave device
* @work: (internal use) Workqueue to be used for sysfs_notify()
* @ops: Function pointers used to access hardware-specific operations.
* @ep0: Endpoint zero, used when reading or writing responses to
* driver setup() requests
* @ep_list: List of other endpoints supported by the device.
* @speed: Speed of current connection to USB host.
* @max_speed: Maximal speed the UDC can handle. UDC must support this
* and all slower speeds.
* @state: the state we are now (attached, suspended, configured, etc)
* @name: Identifies the controller hardware type. Used in diagnostics
* and sometimes configuration.
* @dev: Driver model state for this abstract device.
* @out_epnum: last used out ep number
* @in_epnum: last used in ep number
* @sg_supported: true if we can handle scatter-gather
* @is_otg: True if the USB device port uses a Mini-AB jack, so that the
* gadget driver must provide a USB OTG descriptor.
* @is_a_peripheral: False unless is_otg, the "A" end of a USB cable
* is in the Mini-AB jack, and HNP has been used to switch roles
* so that the "A" device currently acts as A-Peripheral, not A-Host.
* @a_hnp_support: OTG device feature flag, indicating that the A-Host
* supports HNP at this port.
* @a_alt_hnp_support: OTG device feature flag, indicating that the A-Host
* only supports HNP on a different root port.
* @b_hnp_enable: OTG device feature flag, indicating that the A-Host
* enabled HNP support.
* @quirk_ep_out_aligned_size: epout requires buffer size to be aligned to
* MaxPacketSize.
* @xfer_isr_count: UI (transfer complete) interrupts count
* @usb_core_id: Identifies the usb core controlled by this usb_gadget.
* Used in case of more then one core operates concurrently.
* @bam2bam_func_enabled; Indicates function using bam2bam is enabled or not.
* @extra_buf_alloc: Extra allocation size for AXI prefetch so that out of
* boundary access is protected.
* @interrupt_num: Interrupt number for the underlying platform device.
*
* Gadgets have a mostly-portable "gadget driver" implementing device
* functions, handling all usb configurations and interfaces. Gadget
* drivers talk to hardware-specific code indirectly, through ops vectors.
* That insulates the gadget driver from hardware details, and packages
* the hardware endpoints through generic i/o queues. The "usb_gadget"
* and "usb_ep" interfaces provide that insulation from the hardware.
*
* Except for the driver data, all fields in this structure are
* read-only to the gadget driver. That driver data is part of the
* "driver model" infrastructure in 2.6 (and later) kernels, and for
* earlier systems is grouped in a similar structure that's not known
* to the rest of the kernel.
*
* Values of the three OTG device feature flags are updated before the
* setup() call corresponding to USB_REQ_SET_CONFIGURATION, and before
* driver suspend() calls. They are valid only when is_otg, and when the
* device is acting as a B-Peripheral (so is_a_peripheral is false).
*/
struct usb_gadget {
struct work_struct work;
/* readonly to gadget driver */
const struct usb_gadget_ops *ops;
struct usb_ep *ep0;
struct list_head ep_list; /* of usb_ep */
enum usb_device_speed speed;
enum usb_device_speed max_speed;
enum usb_device_state state;
const char *name;
struct device dev;
unsigned out_epnum;
unsigned in_epnum;
unsig