1.td_fill是用来填充传输描述符td
static void td_fill (ohci_t *ohci, unsigned int info, void *data, int len, struct usb_device *dev, int index, urb_priv_t *urb_priv) { volatile td_t *td, *td_pt; if (index > urb_priv->length) { err("index > length"); return; } /* use this td as the next dummy */ td_pt = urb_priv->td [index]; //缓存下一个TD块的地址 td_pt->hwNextTD = 0; /* fill the old dummy TD */ //获取当前TD块的地址 td = urb_priv->td [index] = (td_t *)(m32_swap (urb_priv->ed->hwTailP) & ~0xf); td->ed = urb_priv->ed; //填充ED块的地址 td->next_dl_td = NULL; td->index = index; td->data = (U32)data; //填充数据缓冲区的地址 if (!len) data = 0; //填充hwINFO字段 //[20,19]事务类型00b SETUP 01b OUT (只有在ED未设置方向,此设置才有效) //10b IN 11b Reserved(SETUP事务是每个控制传输的开头,);[23,21] td->hwINFO = m32_swap (info); //填充hwCMP 这个指针就指出了要接收或发送的数据缓冲区(比如设置包,要取得的描述符) td->hwCBP = m32_swap (data); //填充hwBE //数据缓冲区尾地址 if (data) td->hwBE = m32_swap (((int)data + len - 1)); else td->hwBE = 0; // 填充TD块字中下一个TD的地址 td->hwNextTD = m32_swap (td_pt); /* append to queue */ td->ed->hwTailP = td->hwNextTD; }
控制传输阶段中,一个TD用语设置包(gsetup),一个TD用于ACK,然后每4096个字节需要一个TD
即需要的TD个数为:size = (transfer_len == 0)? 2: (transfer_len - 1) / 4096 + 3;
获取设备描述符属于控制传输阶段,USB返回8个字节,所以需要3个TD
在usb_ohci.h中有定义:__align(32) td_t gtd[NUM_TD+1]; 即总共定义了65个TD数据结构,地址为0x30150B20,0x30150B50,0x30150B80........
在td_submit_job()函数中有如下程序:
case PIPE_CONTROL: info = TD_CC | TD_DP_SETUP | TD_T_DATA0; td_fill (ohci, info, setup, 8, dev, cnt++, urb); if (data_len > 0) { info = usb_pipeout (pipe)? TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1; /* NOTE: mishandles transfers >8K, some >4K */ td_fill (ohci, info, data, data_len, dev, cnt++, urb); } info = usb_pipeout (pipe)? TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1; td_fill (ohci, info, data, 0, dev, cnt++, urb); if (!ohci->sleeping) {; writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */ temp=rHcCommonStatus; } break;
td_fill函数在这里使用了3次,即填充了3个TD块,3个TD块的填充结果如下:
//td[0]起始地址为0x30150B20 即设置包的TD地址 td[0].ed = 0x30151A00; //填充ED块的地址 td[0].hwINFO = 0xF2000000; td[0].hwCBP = 0x301430E0; td[0].hwBE = 0x301430E7; td[0].hwNextTD = 0x30150B50; td[0].ed.TailP=0x30150B50; //td[1]起始地址为0x30150B50 即数据缓冲区的TD地址 td[1].ed = 0x30151A00; //填充ED块的地址 td[1].hwINFO = 0xF3140000; td[1].hwCBP = 0x301438AC; td[1].hwBE = 0x301438B3; td[1].hwNextTD = 0x30150B80; td[1].ed.TailP=0x30150B80; //td[2]起始地址为0x30150B80 即ACK 的TD地址 td[2].ed = 0x30151A00; //填充ED块的地址 td[2].hwINFO = 0xF3080000; td[2].hwCBP = 0x0; td[2].hwBE = 0x0; td[2].hwNextTD = 0x30150BB0; td[2].ed.TailP=0x30150BB0;
然后启动发送过程:
rHcControlHeadED = (U32)& gCtrlED; rHcControl |=(1<<4); rHcCommandStatus=0x02;
查看对应的缓冲区数据如下:
0x301430e0 80 06 00 01 00 00 08 00 //设置包--->获取设备描述符 0x301438ac 12 01 00 02 00 00 00 40 //U盘回复报文---->U盘设备描述符
事务结束后,TD结构变化如下:
td[2].hwNextTD = 0x30150B50; td[1].hwNextTD = 0x30150B20; td[0].hwNextTD = 0x00;