现在的位置: 首页 > 综合 > 正文

td_fill函数

2014年06月05日 ⁄ 综合 ⁄ 共 2509字 ⁄ 字号 评论关闭

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;



抱歉!评论已关闭.