提交urb的实现
*******************************************************************************************
rh_queue_status
// 将urb插入endpoint的链表中
retval = usb_hcd_link_urb_to_ep(hcd, urb);
.
/* Host side RX (IN) using Mentor DMA works as follows:
submit_urb ->
- if queue was empty, ProgramEndpoint
- first IN token is sent out (by setting ReqPkt)
LinuxIsr -> RxReady()
/\ => first packet is received
| - Set in mode 0 (DmaEnab, ~ReqPkt)
| -> DMA Isr (transfer complete) -> RxReady()
| - Ack receive (~RxPktRdy), turn off DMA (~DmaEnab)
| - if urb not complete, send next IN token (ReqPkt)
| | else complete urb.
| |
---------------------------
musb_host_rx // 在drivers/usb/usb20/musb_host.c中
. 发生EXDEV的原因
musb_host_rx
if (rx_count > d->length) {
// (1)增加urb的error_count成员的计数
if (d_status == 0) {
d_status = -EOVERFLOW;
urb->error_count++;
}
DBG(2, "** OVERFLOW %d into %d\n",\
rx_count, d->length);
// (2)将urb的state成员设置为EXDEV
musb_advance_schedule(musb, urb, hw_ep, USB_DIR_IN);
case USB_ENDPOINT_XFER_ISOC:
if (status == 0 && urb->error_count)
status = -EXDEV;
break;
}
. 在musb_host_rx函数中积累urb的number_of_packets成员数量的packet之后调用musb_advance_schedule将这个urb交给urb的complete函数处理:
musb_host_rx
if (usb_pipeisoc(pipe)) {
struct usb_iso_packet_descriptor *d;
d = urb->iso_frame_desc + qh->iso_idx;
d->actual_length = xfer_len;
/* even if there was an error, we did the dma
* for iso_frame_desc->length
*/
if (d->status != -EILSEQ && d->status != -EOVERFLOW)
d->status = 0;
if (++qh->iso_idx >= urb->number_of_packets)
done = true;
else
done = false;
finish:
urb->actual_length += xfer_len;
qh->offset += xfer_len;
if (done) { // 如果条件为真,让urb的complete函数处理这个urb。
if (use_sg)
use_sg = false;
if (urb->status == -EINPROGRESS)
urb->status = status;
musb_advance_schedule(musb, urb, hw_ep, USB_DIR_IN);
. 在musb_host_rx函数中,调用musb_host_packet_rx,在这个函数中,调用musb_read_fifo(hw_ep, length, buf)从fifo中读取一个urb中一个数据包的数据。
读取的目标地址是urb中数据包指向的地址。读取的大小是一个数据包的大小。只有当urb中的所有数据包都读到数据之后,这个函数才返回done(1)。
. DBG(4, "RX%d count %d, buffer 0x%x len %d/%d\n",
epnum, rx_count,
(unsigned int)urb->transfer_dma
+ urb->actual_length,
qh->offset,
urb->transfer_buffer_length);
<5>[ 115.854718]<2>-(0)[0:swapper/0][zhongcai]RX2 count 12, buffer 0x777a000c len 12/98304
<5>[ 115.855217]<2>-(0)[0:swapper/0][zhongcai]RX2 count 12, buffer 0x777a0018 len 24/98304
<5>[ 115.855338]<2>-(0)[0:swapper/0][zhongcai]RX2 count 12, buffer 0x777a0024 len 36/98304
<5>[ 115.855463]<2>-(0)[0:swapper/0][zhongcai]RX2 count 12, buffer 0x777a0030 len 48/98304
rx_count: 本次接收到的字节数,比如上面的例子中,4次都是每次接收12字节;
urb->transfer_dma + urb->actual_length:urb当前存放数据的dma地址(因为之前已经存储了数据,urb->actual_length是urb目前接收到的数据的长度);
qh->offset:urb当前数据的offset(因为之前已经接收了数据);
urb->transfer_buffer_length:urb缓冲区的大小。
. urb中actual size成员的更新(在musb_host_rx函数中)
(1)在musb_host_rx函数中,如果urb的成员status是EINPROGRESS,则本次urb的actual_length成员的大小不会更新。这种情况dma指针不是null。
musb_host_rx
} else if (urb->status == -EINPROGRESS) {
if (dma) {
DBG(4, "RX%d count %d, buffer 0x%x len %d/%d\n",
(2)但是如果在musb_host_rx函数中,执行的是如下的分支,这个urb的actual size成员本次会更新,会增加dma结构中actual_len成员值的大小:
musb_host_rx
if (dma && (rx_csr & MUSB_RXCSR_DMAENAB)) {
xfer_len = dma->actual_len;
. hw_ep->regs的设定
(1)musb->mregs的设定
musb_probe
musb_init_controller(dev, irq, base, pbase)
allocate_instance
musb->mregs = mbase;
(2)基于musb->mregs设定hw_ep->regs
musb_core_init
void __iomem *mbase = musb->mregs;
for (i = 0; i < musb->nr_endpoints; i++) {
struct musb_hw_ep *hw_ep = musb->endpoints + i;
hw_ep->fifo = MUSB_FIFO_OFFSET(i) + mbase;
hw_ep->regs = MUSB_EP_OFFSET(i, 0) + mbase;
.
void musb_start(struct musb *musb)
musb_platform_enable(musb);
musb_gadget_enable
. musb中的musb_platform_ops类型成员ops指向如下的结构:
static const struct musb_platform_ops mt_usb_ops = {
.init = mt_usb_init,
.exit = mt_usb_exit,
/*.set_mode = mt_usb_set_mode,*/
.try_idle = mt_usb_try_idle,
.enable = mt_usb_enable,
.disable = mt_usb_disable,
.set_vbus = mt_usb_set_vbus,
.vbus_status = mt_usb_get_vbus_status
. add higg bandwidth rx iso support
http://markmail.org/message/4euuqryd23heygh5#query:+page:1+mid:4gk52yqkcphyiock+state:results