700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 第16章 USB主机 设备与Gadget驱动之USB UDC与Gadget驱动(一)

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

时间:2020-07-14 18:52:01

相关推荐

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

16.4.1UDC(USB设备控制器)和Gadget(小配件)驱动的关键数据结构与API

USB设备控制器(UDC)驱动指的是作为其他USB主机控制器外设的USB硬件设备上底层硬件控制器的驱动,该硬件和驱动负责将一个USB设备依附于一个USB主机控制器上。例如,当某运行Linux系统的手机作为PC的U盘时,手机中的底层USB控制器行使USB设备控制器的功能,这时运行在底层的是UDC驱动,手机要成为U盘,在UDC驱动之上需要另外一个驱动,对于USB大容量存储器而言,这个驱动为File Storage驱动,称为Function驱动。

图16.1Linux 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.30UDC驱动的关键数据结构

/**

* 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_speedspeed;

enum usb_device_speedmax_speed;

enum usb_device_statestate;

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;

u8usb_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_typeep_type;

u8 ep_num;

u8 ep_intr_num;

boolendless;

};

/* 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;

intret = -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.31usb_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.32usb_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;

intstatus;

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 *);

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

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。