USB请求队列
2025-09-26
本文链接为:http://www.usbzh.com/article/detail-1591.html ,欢迎转载,转载请附上本文链接。
和端点的使能与禁用一样,端点的请求也与UDC端点的ops相关。
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);
}
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);
}
ep_alloc_request
队列的申请.Linux充分体现了与Windows的不同,可以光明正大的将结构体暴露给上一层,但Windows就可能是一个PVOID类型的指针。
USB请求创建与端点相关。通过队列提交ep_queue请求后,通过回调函数通知操作完成。
static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
{
struct ci_hw_req *hwreq = NULL;
if (ep == NULL)
return NULL;
hwreq = kzalloc(sizeof(struct ci_hw_req), gfp_flags);
if (hwreq != NULL) {
INIT_LIST_HEAD(&hwreq->queue);
INIT_LIST_HEAD(&hwreq->tds);
}
return (hwreq == NULL) ? NULL : &hwreq->req;
}
ep_free_request
static void ep_free_request(struct usb_ep *ep, struct usb_request *req)
{
struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
struct ci_hw_req *hwreq = container_of(req, struct ci_hw_req, req);
struct td_node *node, *tmpnode;
unsigned long flags;
if (ep == NULL || req == NULL) {
return;
} else if (!list_empty(&hwreq->queue)) {
//还在队列中
dev_err(hwep->ci->dev, "freeing queued request\n");
return;
}
spin_lock_irqsave(hwep->lock, flags);
//释放DMA td
list_for_each_entry_safe(node, tmpnode, &hwreq->tds, td) {
dma_pool_free(hwep->td_pool, node->ptr, node->dma);
list_del_init(&node->td);
node->ptr = NULL;
kfree(node);
}
kfree(hwreq);
spin_unlock_irqrestore(hwep->lock, flags);
}
ep_queue
static int ep_queue(struct usb_ep *ep, struct usb_request *req,
gfp_t __maybe_unused gfp_flags)
{
struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
int retval = 0;
unsigned long flags;
if (ep == NULL || req == NULL || hwep->ep.desc == NULL)
return -EINVAL;
spin_lock_irqsave(hwep->lock, flags);
if (hwep->ci->gadget.speed == USB_SPEED_UNKNOWN) {
spin_unlock_irqrestore(hwep->lock, flags);
return 0;
}
retval = _ep_queue(ep, req, gfp_flags);
spin_unlock_irqrestore(hwep->lock, flags);
return retval;
}
·_ep_queue
主要执行:
list_empty(&hwreq->queue))
判断是否已经在队列中,防止重复挂入_hardware_enqueue
硬件拆包list_add_tail(&hwreq->queue, &hwep->qh.queue)
static int _ep_queue(struct usb_ep *ep, struct usb_request *req,
gfp_t __maybe_unused gfp_flags)
{
struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
struct ci_hw_req *hwreq = container_of(req, struct ci_hw_req, req);
struct ci_hdrc *ci = hwep->ci;
int retval = 0;
if (ep == NULL || req == NULL || hwep->ep.desc == NULL)
return -EINVAL;
if (hwep->type == USB_ENDPOINT_XFER_CONTROL) {
if (req->length)
hwep = (ci->ep0_dir == RX) ? ci->ep0out : ci->ep0in;
if (!list_empty(&hwep->qh.queue)) {
_ep_nuke(hwep);
dev_warn(hwep->ci->dev, "endpoint ctrl %X nuked\n",
_usb_addr(hwep));
}
}
//同步传输的请求数据长度,不能超过一次传输的最大数据量
if (usb_endpoint_xfer_isoc(hwep->ep.desc) && hwreq->req.length > (1 + hwep->ep.mult) * hwep->ep.maxpacket)
{
dev_err(hwep->ci->dev, "request length too big for isochronous\n");
return -EMSGSIZE;
}
//该请求不能已经在其它队列中排队,必须为空闲的
if (!list_empty(&hwreq->queue)) {
dev_err(hwep->ci->dev, "request already in queue\n");
return -EBUSY;
}
/* push request */
hwreq->req.status = -EINPROGRESS; //默认状态设置
hwreq->req.actual = 0; //无论是收还是发,实际传输都应先是0
//该列列请求在硬件设备层的配置,DMA相关
retval = _hardware_enqueue(hwep, hwreq);
if (retval == -EALREADY)
retval = 0;
if (!retval)
{
//该端点的请求都在hwep->qh.queue队列中
list_add_tail(&hwreq->queue, &hwep->qh.queue);
}
return retval;
}
ep_dequeue
ep_dequeue会将一个已经调用ep_queue的请求从硬件队列中移除,并会调用该请求的完成函数。
其余功能详见注释。
static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
{
struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
struct ci_hw_req *hwreq = container_of(req, struct ci_hw_req, req);
unsigned long flags;
struct td_node *node, *tmpnode;
if (ep == NULL || req == NULL || hwreq->req.status != -EALREADY ||
hwep->ep.desc == NULL || list_empty(&hwreq->queue) ||
list_empty(&hwep->qh.queue))
return -EINVAL;
spin_lock_irqsave(hwep->lock, flags);
if (hwep->ci->gadget.speed != USB_SPEED_UNKNOWN)
hw_ep_flush(hwep->ci, hwep->num, hwep->dir);
list_for_each_entry_safe(node, tmpnode, &hwreq->tds, td) {
dma_pool_free(hwep->td_pool, node->ptr, node->dma);
list_del(&node->td);
kfree(node);
}
/* pop request */
//从端点队列中移除
list_del_init(&hwreq->queue);
//移除dma映射
usb_gadget_unmap_request(&hwep->ci->gadget, req, hwep->dir);
//设备请求标识
req->status = -ECONNRESET;
//调用完成函数
if (hwreq->req.complete != NULL) {
spin_unlock(hwep->lock);
usb_gadget_giveback_request(&hwep->ep, &hwreq->req);
spin_lock(hwep->lock);
}
spin_unlock_irqrestore(hwep->lock, flags);
return 0;
}
void usb_gadget_giveback_request(struct usb_ep *ep, struct usb_request *req)
{
if (likely(req->status == 0))
usb_led_activity(USB_LED_EVENT_GADGET);
req->complete(ep, req);
}
数据中断流向
“drivers\usb\chipidea\udc.c”
UDC驱动中,驱动配置数下:
int ci_hdrc_gadget_init(struct ci_hdrc *ci)
{
struct ci_role_driver *rdrv;
if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC))
return -ENXIO;
rdrv = devm_kzalloc(ci->dev, sizeof(struct ci_role_driver), GFP_KERNEL);
if (!rdrv)
return -ENOMEM;
rdrv->start = udc_id_switch_for_device;
rdrv->stop = udc_id_switch_for_host;
rdrv->irq = udc_irq;
rdrv->suspend = udc_suspend;
rdrv->resume = udc_resume;
rdrv->name = "gadget";
ci->roles[CI_ROLE_GADGET] = rdrv;
return udc_start(ci);
}
中断函数为udc_irq。
static irqreturn_t udc_irq(struct ci_hdrc *ci)
{
...
intr = hw_test_and_clear_intr_active(ci);
if (intr) {
....
//中断执行
if (USBi_UI & intr)
isr_tr_complete_handler(ci);
}
...
}
isr_tr_complete_handler是事务完成中断处理函数。
static void isr_tr_complete_handler(struct ci_hdrc *ci)
__releases(ci->lock)
__acquires(ci->lock)
{
unsigned i;
int err;
for (i = 0; i < ci->hw_ep_max; i++) {
struct ci_hw_ep *hwep = &ci->ci_hw_ep[i];
if (hwep->ep.desc == NULL)
continue; /* not configured */
if (hw_test_and_clear_complete(ci, i)) {
//端点数据收发请求
err = isr_tr_complete_low(hwep);
if (hwep->type == USB_ENDPOINT_XFER_CONTROL) {
if (err > 0) /* needs status phase */
err = isr_setup_status_phase(ci);
if (err < 0) {
spin_unlock(&ci->lock);
if (_ep_set_halt(&hwep->ep, 1, false))
dev_err(ci->dev, "error: _ep_set_halt\n");
spin_lock(&ci->lock);
}
}
}
//setup请求,包括ClearFeature等标准请求
if (i == 0 &&
hw_test_and_clear(ci, OP_ENDPTSETUPSTAT, BIT(0)))
isr_setup_packet_handler(ci);
}
}
数据收发请求是从队列中
static int isr_tr_complete_low(struct ci_hw_ep *hwep)
__releases(hwep->lock)
__acquires(hwep->lock)
{
struct ci_hw_req *hwreq, *hwreqtemp;
struct ci_hw_ep *hweptemp = hwep;
int retval = 0;
list_for_each_entry_safe(hwreq, hwreqtemp, &hwep->qh.queue, queue){
//数据拷贝
retval = _hardware_dequeue(hwep, hwreq);
if (retval < 0)
break;
//取出队列,并完成
list_del_init(&hwreq->queue);
if (hwreq->req.complete != NULL) {
spin_unlock(hwep->lock);
if ((hwep->type == USB_ENDPOINT_XFER_CONTROL) && hwreq->req.length)
hweptemp = hwep->ci->ep0in;
//调用完成例程
usb_gadget_giveback_request(&hweptemp->ep, &hwreq->req);
spin_lock(hwep->lock);
}
}
if (retval == -EBUSY)
retval = 0;
return retval;
}
而关于数据到队列中的拷贝,则是_hardware_dequeue
函数来实现的。