由此接口进入OHCI模块![]()
将请求传输块urb交给端口ep,由其负责将urb所要传输的数据发送/接收
----------------------------------------------------
static int ohci_urb_enqueue ( struct
usb_hcd *hcd,
struct
usb_host_endpoint *ep,
struct
urb *urb,
int mem_flags)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
struct ed *ed;
urb_priv_t *urb_priv;
unsigned int pipe = urb->pipe;
int i, size = 0;
unsigned long flags;
int retval = 0;
#ifdef OHCI_VERBOSE_DEBUG
urb_print (urb, "SUB", usb_pipein (pipe));
#endif
if (! (ed =
ed_get (ohci, ep, urb->dev, pipe, urb->interval)))
return -ENOMEM;
根据端点的类型确定size(size决定该端点上挂载的td的数目,除实时端点上的td外,其它端点上的td能够装载4K的数据)
|-----------------------------------------------------------------|
| switch (ed->type) { |
| case PIPE_CONTROL: |
| if (urb->transfer_buffer_length > 4096) |
| return -EMSGSIZE; |
| size = 2; |
| default: |
| size += urb->transfer_buffer_length / 4096; |
| if ((urb->transfer_buffer_length % 4096) != 0) |
| size++; |
| if (size == 0) |
| size++; |
| else if ((urb->transfer_flags & URB_ZERO_PACKET) != 0 |
| && (urb->transfer_buffer_length |
| % usb_maxpacket (urb->dev, pipe, |
| usb_pipeout (pipe))) == 0) |
| size++; |
| break; |
| case PIPE_ISOCHRONOUS: |
| size = urb->number_of_packets; |
| break; |
| } |
|-----------------------------------------------------------------|
给urb_priv_t分配空间,并为其上所挂载的td指针数组分配空间
|--------------------------------------------------------------------------------------|
| urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (struct td *), mem_flags); |
|--------------------------------------------------------------------------------------|
if (!urb_priv)
return -ENOMEM;
初始化urb_priv以及其上的td指针数组(urb_priv_t->td[i])
|----------------------------------------------------------------------------|
| memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *)); |
| INIT_LIST_HEAD (&urb_priv->pending); |
| urb_priv->length = size; |
| urb_priv->ed = ed; |
| for (i = 0; i < size; i++) { |
| urb_priv->td [i] = td_alloc (ohci, mem_flags); |
| if (!urb_priv->td [i]) { |
| urb_priv->length = i; |
| urb_free_priv (ohci, urb_priv); |
| return -ENOMEM; |
| } |
| } |
|----------------------------------------------------------------------------|
spin_lock_irqsave (&ohci->lock, flags);
if (!HC_IS_RUNNING(hcd->state)) {
retval = -ENODEV;
goto fail;
}
spin_lock (&urb->lock);
初始化urb->hcpriv(将加工好的的hcpriv挂载到urb上); urb->start_frame(如果是实时传输,则需要指定开始处理该urb的
帧号);
|-------------------------------------------------------|
| if (urb->status != -EINPROGRESS) { |
| spin_unlock (&urb->lock); |
| urb->hcpriv = urb_priv; |
| finish_urb (ohci, urb, NULL); |
| retval = 0; |
| goto fail; |
| } |
| if (ed->state == ED_IDLE) { |
| retval = ed_schedule(ohci, ed); -| 根据ed的类型将ed插入相应队列中
| if (retval < 0) |
| goto fail0; |
| if (ed->type == PIPE_ISOCHRONOUS) { |
| u16 frame = ohci_frame_no(ohci); |
| frame += max_t (u16, 8, ed->interval); |
| frame &= ~(ed->interval - 1); |
| frame |= ed->branch; |
| urb->start_frame = frame; |
| } |
| } else if (ed->type == PIPE_ISOCHRONOUS) |
| urb->start_frame = ed->last_iso + ed->interval; |
| urb->hcpriv = urb_priv; |
|-------------------------------------------------------|
将urb需要发送的数据安排到相应的ed下的td队列中
(urb->hcpriv->td[]是本次传输请求所需要的td,
urb->transfer_dma是本次传输请求所要传输的数据,
td_submit_urb()将这些数据安排到td[i]中,并将该td[i]插入urb->hcpriv->ed.td_list中)
|--------------------------------------|
| td_submit_urb (ohci, urb); |
|--------------------------------------|
fail0:
spin_unlock (&urb->lock);
fail:
if (retval)
urb_free_priv (ohci, urb_priv);
spin_unlock_irqrestore (&ohci->lock, flags);
return retval;
}