第16章 USB主机、设备与Gadget驱动之USB UDC与Gadget驱动(一)

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;

        unsigned                        sg_supported:1;
        unsigned                        is_otg:1;
        unsigned                        is_a_peripheral:1;
        unsigned                        b_hnp_enable:1;
        unsigned                        a_hnp_support:1;
        unsigned                        a_alt_hnp_support:1;
        unsigned                        quirk_ep_out_aligned_size:1;
        bool                            remote_wakeup;
        u32                             xfer_isr_count;
        u8                              usb_core_id;
        bool                            l1_supported;
        bool                            bam2bam_func_enabled;
        u32                             extra_buf_alloc;
        int                             interrupt_num;
};

/**
 * struct usb_ep - device side representation of USB endpoint
 * @name:identifier for the endpoint, such as "ep-a" or "ep9in-bulk"
 * @ops: Function pointers used to access hardware-specific operations.
 * @ep_list:the gadget's ep_list holds all of its endpoints
 * @maxpacket:The maximum packet size used on this endpoint.  The initial
 *      value can sometimes be reduced (hardware allowing), according to
 *      the endpoint descriptor used to configure the endpoint.
 * @maxpacket_limit:The maximum packet size value which can be handled by this
 *      endpoint. It's set once by UDC driver when endpoint is initialized, and
 *      should not be changed. Should not be confused with maxpacket.
 * @max_streams: The maximum number of streams supported
 *      by this EP (0 - 16, actual number is 2^n)
 * @mult: multiplier, 'mult' value for SS Isoc EPs
 * @maxburst: the maximum number of bursts supported by this EP (for usb3)
 * @driver_data:for use by the gadget driver.
 * @address: used to identify the endpoint when finding descriptor that
 *      matches connection speed
 * @desc: endpoint descriptor.  This pointer is set before the endpoint is
 *      enabled and remains valid until the endpoint is disabled.
 * @comp_desc: In case of SuperSpeed support, this is the endpoint companion
 *      descriptor that is used to configure the endpoint
 * @ep_type: Used to specify type of EP eg. normal vs h/w accelerated.
 * @ep_intr_num: Interrupter number for EP.
 * @endless: In case where endless transfer is being initiated, this is set
 *      to disable usb event interrupt for few events.
 *
 * the bus controller driver lists all the general purpose endpoints in
 * gadget->ep_list.  the control endpoint (gadget->ep0) is not in that list,
 * and is accessed only in response to a driver setup() callback.

 */

struct usb_ep {
        void                    *driver_data;
        const char              *name;
        const struct usb_ep_ops *ops;
        struct list_head        ep_list;
        unsigned                maxpacket:16;
        unsigned                maxpacket_limit:16;
        unsigned                max_streams:16;
        unsigned                mult:2;
        unsigned                maxburst:5;
        u8                      address;
        const struct usb_endpoint_descriptor    *desc;
        const struct usb_ss_ep_comp_descriptor  *comp_desc;
        enum ep_type            ep_type;
        u8                      ep_num;
        u8                      ep_intr_num;
        bool                    endless;
};

/* the rest of the api to the controller hardware: device operations,
 * which don't involve endpoints (or i/o).
 */
struct usb_gadget_ops {
        int     (*get_frame)(struct usb_gadget *);
        int     (*wakeup)(struct usb_gadget *);
        int     (*func_wakeup)(struct usb_gadget *, int interface_id);
        int     (*set_selfpowered) (struct usb_gadget *, int is_selfpowered);
        int     (*vbus_session) (struct usb_gadget *, int is_active);
        int     (*vbus_draw) (struct usb_gadget *, unsigned mA);
        int     (*pullup) (struct usb_gadget *, int is_on);
        int     (*restart)(struct usb_gadget *);
        int     (*ioctl)(struct usb_gadget *,
                                unsigned code, unsigned long param);
        void    (*get_config_params)(struct usb_dcd_config_params *);
        int     (*udc_start)(struct usb_gadget *,
                        struct usb_gadget_driver *);
        int     (*udc_stop)(struct usb_gadget *,
                        struct usb_gadget_driver *);
};

/* endpoint-specific parts of the api to the usb controller hardware.
 * unlike the urb model, (de)multiplexing layers are not required.
 * (so this api could slash overhead if used on the host side...)
 *
 * note that device side usb controllers commonly differ in how many
 * endpoints they support, as well as their capabilities.
 */
struct usb_ep_ops {
        int (*enable) (struct usb_ep *ep,
                const struct usb_endpoint_descriptor *desc);
        int (*disable) (struct usb_ep *ep);

        struct usb_request *(*alloc_request) (struct usb_ep *ep,
                gfp_t gfp_flags);
        void (*free_request) (struct usb_ep *ep, struct usb_request *req);

        int (*queue) (struct usb_ep *ep, struct usb_request *req,
                gfp_t gfp_flags);
        int (*dequeue) (struct usb_ep *ep, struct usb_request *req);

        int (*set_halt) (struct usb_ep *ep, int value);
        int (*set_wedge) (struct usb_ep *ep);

        int (*fifo_status) (struct usb_ep *ep);
        void (*fifo_flush) (struct usb_ep *ep);
        int (*gsi_ep_op)(struct usb_ep *ep, void *op_data,
                enum gsi_ep_op op);
};

备注:

    在具体的UDC驱动中,需要封装usb_gadget和每个端点usb_ep,实现usb_gadget的usb_gadget_ops并实现端点的usb_ep_ops,完成usb_request。这些事情搞定后,注册一个UDC,通过usb_add_gadget_udc()API来进行的,其原型为:

include/linux/usb/gadget.h

int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);

drivers/usb/gadget/udc/udc-core.c

/**
 * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
 * @parent: the parent device to this udc. Usually the controller driver's
 * device.
 * @gadget: the gadget to be added to the list.
 * @release: a gadget release function.
 *
 * Returns zero on success, negative errno otherwise.
 */
int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
                void (*release)(struct device *dev))
{
        struct usb_udc          *udc;
        int                     ret = -ENOMEM;

        udc = kzalloc(sizeof(*udc), GFP_KERNEL);
        if (!udc)
                goto err1;

        dev_set_name(&gadget->dev, "gadget");
        INIT_WORK(&gadget->work, usb_gadget_state_work);
        gadget->dev.parent = parent;

#ifdef  CONFIG_HAS_DMA
        dma_set_coherent_mask(&gadget->dev, parent->coherent_dma_mask);
        gadget->dev.dma_parms = parent->dma_parms;
        gadget->dev.dma_mask = parent->dma_mask;
#endif

        if (release)
                gadget->dev.release = release;
        else
                gadget->dev.release = usb_udc_nop_release;

        ret = device_register(&gadget->dev);
        if (ret)

                goto err2;

        device_initialize(&udc->dev);
        udc->dev.release = usb_udc_release;
        udc->dev.class = udc_class;
        udc->dev.groups = usb_udc_attr_groups;
        udc->dev.parent = parent;
        ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
        if (ret)
                goto err3;

        udc->gadget = gadget;
        mutex_lock(&udc_lock);
        list_add_tail(&udc->list, &udc_list);
        ret = device_add(&udc->dev);
        if (ret)
                goto err4;

        usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
        mutex_unlock(&udc_lock);

        return 0;

err4:
        list_del(&udc->list);
        mutex_unlock(&udc_lock);
err3:
        put_device(&udc->dev);
err2:
        put_device(&gadget->dev);
        kfree(udc);
err1:
        return ret;
}
EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release);

/**
 * usb_add_gadget_udc - adds a new gadget to the udc class driver list
 * @parent: the parent device to this udc. Usually the controller
 * driver's device.
 * @gadget: the gadget to be added to the list
 *
 * Returns zero on success, negative errno otherwise.
 */
int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
{
        return usb_add_gadget_udc_release(parent, gadget, NULL);
}
EXPORT_SYMBOL_GPL(usb_add_gadget_udc);

结论:

    注册UDC(USB设备控制器)之前,需要先把usb_gadget这个结构体的ep_list(端点链表)填充好,并填充好usb_gadget的usb_gadget_ops以及每个端点的usb_gadget_ops。

    而Gadget的Function,需要自己填充usb_interface_descriptor、usb_endpoint_descriptor,合成一些
usb_descriptor_header,并实现usb_function结构体的成员函数。usb_function结构体定义于

include/linux/usb/composite.h中,其形式如代码清单16.31所示。

代码清单16.31 usb_function结构体

/**
 * struct usb_function - describes one function of a configuration
 * @name: For diagnostics, identifies the function.
 * @strings: tables of strings, keyed by identifiers assigned during bind()
 *      and by language IDs provided in control requests
 * @fs_descriptors: Table of full (or low) speed descriptors, using interface and
 *      string identifiers assigned during @bind().  If this pointer is null,
 *      the function will not be available at full speed (or at low speed).
 * @hs_descriptors: Table of high speed descriptors, using interface and
 *      string identifiers assigned during @bind().  If this pointer is null,
 *      the function will not be available at high speed.
 * @ss_descriptors: Table of super speed descriptors, using interface and
 *      string identifiers assigned during @bind(). If this
 *      pointer is null after initiation, the function will not
 *      be available at super speed.
 * @config: assigned when @usb_add_function() is called; this is the
 *      configuration with which this function is associated.
 * @os_desc_table: Table of (interface id, os descriptors) pairs. The function
 *      can expose more than one interface. If an interface is a member of
 *      an IAD, only the first interface of IAD has its entry in the table.
 * @os_desc_n: Number of entries in os_desc_table
 * @bind: Before the gadget can register, all of its functions bind() to the
 *      available resources including string and interface identifiers used
 *      in interface or class descriptors; endpoints; I/O buffers; and so on.
 * @unbind: Reverses @bind; called as a side effect of unregistering the
 *      driver which added this function.
 * @free_func: free the struct usb_function.
 * @mod: (internal) points to the module that created this structure.
 * @set_alt: (REQUIRED) Reconfigures altsettings; function drivers may
 *      initialize usb_ep.driver data at this time (when it is used).
 *      Note that setting an interface to its current altsetting resets
 *      interface state, and that all interfaces have a disabled state.
 * @get_alt: Returns the active altsetting.  If this is not provided,
 *      then only altsetting zero is supported.
 * @disable: (REQUIRED) Indicates the function should be disabled.  Reasons
 *      include host resetting or reconfiguring the gadget, and disconnection.
 * @setup: Used for interface-specific control requests.
 * @suspend: Notifies functions when the host stops sending USB traffic.
 * @resume: Notifies functions when the host restarts USB traffic.
 * @get_status: Returns function status as a reply to
 *      GetStatus() request when the recipient is Interface.
 * @func_suspend: callback to be called when
 *      SetFeature(FUNCTION_SUSPEND) is received
 * @func_is_suspended: Tells whether the function is currently in
 *      Function Suspend state (used in Super Speed mode only).
 * @func_wakeup_allowed: Tells whether Function Remote Wakeup has been allowed
 *      by the USB host (used in Super Speed mode only).
 * @func_wakeup_pending: Marks that the function has issued a Function Wakeup
 *      while the USB bus was suspended and therefore a Function Wakeup
 *      notification needs to be sent once the USB bus is resumed.
 *
 * A single USB function uses one or more interfaces, and should in most
 * cases support operation at both full and high speeds.  Each function is
 * associated by @usb_add_function() with a one configuration; that function
 * causes @bind() to be called so resources can be allocated as part of
 * setting up a gadget driver.  Those resources include endpoints, which
 * should be allocated using @usb_ep_autoconfig().
 *
 * To support dual speed operation, a function driver provides descriptors
 * for both high and full speed operation.  Except in rare cases that don't
 * involve bulk endpoints, each speed needs different endpoint descriptors.
 *
 * Function drivers choose their own strategies for managing instance data.
 * The simplest strategy just declares it "static', which means the function
 * can only be activated once.  If the function needs to be exposed in more
 * than one configuration at a given speed, it needs to support multiple
 * usb_function structures (one for each configuration).
 *
 * A more complex strategy might encapsulate a @usb_function structure inside
 * a driver-specific instance structure to allows multiple activations.  An
 * example of multiple activations might be a CDC ACM function that supports
 * two or more distinct instances within the same configuration, providing
 * several independent logical data links to a USB host.
 */

struct usb_function {
        const char                      *name;
        int                             intf_id;
        struct usb_gadget_strings       **strings;
        struct usb_descriptor_header    **fs_descriptors;
        struct usb_descriptor_header    **hs_descriptors;
        struct usb_descriptor_header    **ss_descriptors;
        struct usb_configuration        *config;
        struct usb_os_desc_table        *os_desc_table;
        unsigned                        os_desc_n;

        /* REVISIT:  bind() functions can be marked __init, which
         * makes trouble for section mismatch analysis.  See if
         * we can't restructure things to avoid mismatching.
         * Related:  unbind() may kfree() but bind() won't...
         */

        /* configuration management:  bind/unbind */
        int                     (*bind)(struct usb_configuration *,  struct usb_function *);
        void                    (*unbind)(struct usb_configuration *,  struct usb_function *);
        void                    (*free_func)(struct usb_function *f);
        struct module           *mod;

        /* runtime state management */
        int                     (*set_alt)(struct usb_function *, unsigned interface, unsigned alt);
        int                     (*get_alt)(struct usb_function *, unsigned interface);
        void                    (*disable)(struct usb_function *);
        int                     (*setup)(struct usb_function *,
                                        const struct usb_ctrlrequest *);
        void                    (*suspend)(struct usb_function *);
        void                    (*resume)(struct usb_function *);

        /* USB 3.0 additions */
        int                     (*get_status)(struct usb_function *);
        int                     (*func_suspend)(struct usb_function *, u8 suspend_opt);
        unsigned                func_is_suspended:1;
        unsigned                func_wakeup_allowed:1;
        unsigned                func_wakeup_pending:1;
        /* private: */
        /* internals */
        struct list_head                list;
        DECLARE_BITMAP(endpoints, 32);
        const struct usb_function_instance *fi;
};

备注:

    fs_descriptors是全速和低速的描述符表;hs_descriptors是高速描述符表;ss_descriptors是超高速描述符表。bind()完成在Gadget注册时获取I/O缓冲、端点等资源。

    在usb_function的成员函数以及各种描述符准备好后,内核通过usb_function_register()API来完成Gadget Function的注册,该API的原型为:

include/linux/usb/composite.h

int usb_function_register(struct usb_function_driver *newf);

其函数定义如下:

drivers/usb/gadget/functions.c

int usb_function_register(struct usb_function_driver *newf)
{
        struct usb_function_driver *fd;
        int ret;

        ret = -EEXIST;
        mutex_lock(&func_lock);
        list_for_each_entry(fd, &func_list, list) {
                if (!strcmp(fd->name, newf->name))
                        goto out;
        }
        ret = 0;
        list_add_tail(&newf->list, &func_list);
out:
        mutex_unlock(&func_lock);
        return ret;
}
EXPORT_SYMBOL_GPL(usb_function_register);

void usb_function_unregister(struct usb_function_driver *fd)
{
        mutex_lock(&func_lock);
        list_del(&fd->list);
        mutex_unlock(&func_lock);
}
EXPORT_SYMBOL_GPL(usb_function_unregister);

    在Gadget驱动中,用usb_request结构体来描述一次传输请求,这个结构体的地位类似于USB主机侧的URB。usb_request结构体的定义如代码清单16.32所示。

    代码清单16.32 usb_request结构体

include/linux/usb/gadget.h

/**
 * struct usb_request - describes one i/o request
 * @buf: Buffer used for data.  Always provide this; some controllers
 *      only use PIO, or don't use DMA for some endpoints.
 * @dma: DMA address corresponding to 'buf'.  If you don't set this
 *      field, and the usb controller needs one, it is responsible
 *      for mapping and unmapping the buffer.
 * @sg: a scatterlist for SG-capable controllers.
 * @num_sgs: number of SG entries
 * @num_mapped_sgs: number of SG entries mapped to DMA (internal)
 * @length: Length of that data
 * @stream_id: The stream id, when USB3.0 bulk streams are being used
 * @no_interrupt: If true, hints that no completion irq is needed.
 *      Helpful sometimes with deep request queues that are handled
 *      directly by DMA controllers.
 * @zero: If true, when writing data, makes the last packet be "short"
 *     by adding a zero length packet as needed;
 * @short_not_ok: When reading data, makes short packets be
 *     treated as errors (queue stops advancing till cleanup).
 * @dma_pre_mapped: Tells the USB core driver whether this request should be
 *      DMA-mapped before it is queued to the USB HW. When set to true, it means
 *      that the request has already been mapped in advance and therefore the
 *      USB core driver does NOT need to do DMA-mapping when the request is
 *      queued to the USB HW.
 * @complete: Function called when request completes, so this request and
 *      its buffer may be re-used.  The function will always be called with
 *      interrupts disabled, and it must not sleep.
 *      Reads terminate with a short packet, or when the buffer fills,
 *      whichever comes first.  When writes terminate, some data bytes
 *      will usually still be in flight (often in a hardware fifo).
 *      Errors (for reads or writes) stop the queue from advancing
 *      until the completion function returns, so that any transfers
 *      invalidated by the error may first be dequeued.
 * @context: For use by the completion callback
 * @list: For use by the gadget driver.
 * @status: Reports completion code, zero or a negative errno.
 *      Normally, faults block the transfer queue from advancing until
 *      the completion callback returns.
 *      Code "-ESHUTDOWN" indicates completion caused by device disconnect,
 *      or when the driver disabled the endpoint.
 * @actual: Reports bytes transferred to/from the buffer.  For reads (OUT
 *      transfers) this may be less than the requested length.  If the
 *      short_not_ok flag is set, short reads are treated as errors
 *      even when status otherwise indicates successful completion.
 *      Note that for writes (IN transfers) some data bytes may still
 *      reside in a device-side FIFO when the request is reported as
 *      complete.
 * @udc_priv: Vendor private data in usage by the UDC.
 *
 * These are allocated/freed through the endpoint they're used with.  The
 * hardware's driver can add extra per-request data to the memory it returns,
 * which often avoids separate memory allocations (potential failures),
 * later when the request is queued.
 *
 * Request flags affect request handling, such as whether a zero length
 * packet is written (the "zero" flag), whether a short read should be
 * treated as an error (blocking request queue advance, the "short_not_ok"
 * flag), or hinting that an interrupt is not required (the "no_interrupt"
 * flag, for use with deep request queues).
 *
 * Bulk endpoints can use any size buffers, and can also be used for interrupt
 * transfers. interrupt-only endpoints can be much less functional.
 *
 * NOTE:  this is analogous to 'struct urb' on the host side, except that
 * it's thinner and promotes more pre-allocation.
 */

struct usb_request {
        void                    *buf;
        unsigned                length;
        dma_addr_t              dma;
        struct scatterlist      *sg;
        unsigned                num_sgs;
        unsigned                num_mapped_sgs;
        unsigned                stream_id:16;
        unsigned                no_interrupt:1;
        unsigned                zero:1;
        unsigned                short_not_ok:1;
        unsigned                dma_pre_mapped:1;
        void                    (*complete)(struct usb_ep *ep, struct usb_request *req);
        void                    *context;
        struct list_head        list;
        int                     status;
        unsigned                actual;
        unsigned                udc_priv;
};

        在include/linux/usb/gadget.h文件中,还封装了一些常用的API,以供Gadget Function驱动调用,从而便于它们操作端点,如下所示。

(1)使能和禁止端点

static inline int usb_ep_enable(struct usb_ep *ep);

static inline int usb_ep_enable(struct usb_ep *ep)
{
return ep->ops->enable(ep, ep->desc);
}

static inline int usb_ep_disable(struct usb_ep *ep);

static inline int usb_ep_disable(struct usb_ep *ep)
{
return ep->ops->disable(ep);
}

(2)分配和释放usb_request

用于分配和释放一个依附于某端点的usb_request

static inline struct usb_request *usb_ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
{
return ep->ops->alloc_request(ep, gfp_flags);

}

static inline void usb_ep_free_request(struct usb_ep *ep, struct usb_request *req)
{
ep->ops->free_request(ep, req);
}

(3)提交和取消usb_request

static inline int usb_ep_queue(struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags)
{
return ep->ops->queue(ep, req, gfp_flags);
}

static inline int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
{
return ep->ops->dequeue(ep, req);

}

备注:

      usb_ep_queue函数告诉UDC完成usb_request(读写缓冲),当请求被完成后,与该请求对应的completion()函数会被调用。

(4)端点FIFO管理

static inline int usb_ep_fifo_status(struct usb_ep *ep)
{
if (ep->ops->fifo_status)
return ep->ops->fifo_status(ep);  // 返回目前FIFO中的字节数
else
return -EOPNOTSUPP;
}

static inline void usb_ep_fifo_flush(struct usb_ep *ep)
{
if (ep->ops->fifo_flush)
ep->ops->fifo_flush(ep); // 冲刷掉FIFO中的数据
}

(5)端点自动配置

struct usb_ep *usb_ep_autoconfig(struct usb_gadget *, struct usb_endpoint_descriptor *);

根据端点描述符及控制器端点情况,分配一个合适的端点。


猜你喜欢

转载自blog.csdn.net/xiezhi123456/article/details/80596294
今日推荐