📄 qtdptd.c
字号:
phci_hcd_submit_async(
phci_hcd *hcd,
struct usb_host_endpoint *ep,
struct list_head *qtd_list,
struct urb *urb,
int *status)
{
struct ehci_qtd *qtd;
struct hcd_dev *dev;
int epnum;
unsigned long flags;
struct ehci_qh *qh = 0;
urb_priv_t *urb_priv = urb->hcpriv;
qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
dev = (struct hcd_dev *) bus_to_hcd(urb->dev->bus);
epnum = usb_pipeendpoint (urb->pipe);
if (usb_pipein (urb->pipe) && !usb_pipecontrol (urb->pipe))
epnum |= 0x10;
pehci_entry("++ %s, enter\n", __FUNCTION__);
/* ehci_hcd->lock guards shared data against other CPUs:
* ehci_hcd: async, reclaim, periodic (and shadow), ...
* hcd_dev: ep[]
* ehci_qh: qh_next, qtd_list
* ehci_qtd: qtd_list
*
* Also, hold this lock when talking to HC registers or
* when updating hw_* fields in shared qh/qtd/... structures.
*/
spin_lock_irqsave (&hcd->lock, flags);
spin_lock(&hcd_data_lock);
qh = phci_hcd_qh_append_tds (hcd, ep, urb, qtd_list, &ep->hcpriv,status);
if(!qh || *status < 0)
goto cleanup;
/* Control/bulk operations through TTs don't need scheduling,
* the HC and TT handle it when the TT has a buffer ready.
*/
/* now the quehead can not be in the unlink state paranoid ??? */
if(qh->qh_state == QH_STATE_UNLINK){
pehci_info("%s: free the urb,qh->state %x\n",__FUNCTION__, qh->qh_state);
phci_hcd_qtd_list_free (hcd, urb, &qh->qtd_list);
spin_unlock(&hcd_data_lock);
spin_unlock_irqrestore (&hcd->lock, flags);
*status = -ENODEV;
return 0;
}
if (likely (qh != 0)) {
urb_priv->qh = qh;
if (likely (qh->qh_state == QH_STATE_IDLE))
phci_hcd_qh_link_async (hcd, qh,status);
}
cleanup:
spin_unlock(&hcd_data_lock);
/* free it from lock systme can sleep now */
spin_unlock_irqrestore (&hcd->lock, flags);
/* could not get the QH terminate and clean. */
if (unlikely (qh == 0) || *status < 0) {
phci_hcd_qtd_list_free (hcd, urb, qtd_list);
return qh;
}
return qh;
}
/*
* initilaize the s-mask c-mask for
* interrupt transfers.
*/
static int
phci_hcd_qhint_schedule(
phci_hcd *hcd,
struct ehci_qh *qh,
struct ehci_qtd *qtd,
struct _isp1761_qhint *qha,
struct urb *urb)
{
int i = 0;
u32 td_info3 = 0;
u32 td_info5 = 0;
u32 period = 0;
u32 usofmask = 1;
u32 usof = 0;
u32 ssplit=0,csplit = 0xFF;
int maxpacket;
u32 numberofusofs = 0;
/*and since whol msec frame is empty, i can schedule in any uframe*/
maxpacket = usb_maxpacket(urb->dev, urb->pipe,!usb_pipein(urb->pipe));
maxpacket &= 0x7ff;
/*length of the data per uframe*/
maxpacket = XFER_PER_UFRAME(qha->td_info1) * maxpacket;
/*caculate the number of uframes are required*/
numberofusofs = urb->transfer_buffer_length/maxpacket;
/*if something left*/
if(urb->transfer_buffer_length % maxpacket)
numberofusofs += 1;
for(i = 0;i<numberofusofs;i++){
usofmask <<= i;
usof |= usofmask;
}
/*
for full/low speed devices, as we
have seperate location for all the endpoints
let the start split goto the first uframe, means 0 uframe
*/
if(urb->dev->speed != USB_SPEED_HIGH &&
usb_pipeint(urb->pipe)){
/*set the complete splits*/
/*set all the bits and lets see whats happening*/
/*but this will be set based on the maximum packet size*/
ssplit = usof;
/* need to fix it*/
csplit = 0x1C;
qha->td_info6 = csplit;
period = qh->period;
if(period >= 32){
period = qh->period/2;
}
td_info3 = period;
goto done;
}else{
if(qh->period >= 8){
period = qh->period/8;
}else{
period = qh->period;
}
}
/*our limitaion is maximum of 32 ie 31, 5 bits*/
if(period >= 32){
period = 32;
/*devide by 2*/
period >>= 1;
}
if(qh->period >= 8){
/*millisecond period*/
td_info3 = (period << 3);
}else{
/*usof based tranmsfers*/
/*minimum 4 usofs*/
td_info3 = period;
usof = 0x11;
}
done:
td_info5 = usof;
qha->td_info3 |= td_info3;
qha->td_info5 |= usof;
return numberofusofs;
}
/*link interrupts qtds to endpoint*/
struct ehci_qh *
phci_hcd_submit_interrupt(
phci_hcd *hcd,
struct usb_host_endpoint *ep,
struct list_head *qtd_list,
struct urb *urb,
int *status)
{
struct ehci_qtd *qtd;
struct hcd_dev *dev;
int epnum;
unsigned long flags;
struct ehci_qh *qh = 0;
urb_priv_t *urb_priv = (urb_priv_t *)urb->hcpriv;
qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
dev = (struct hcd_dev *) bus_to_hcd(urb->dev->bus);
epnum = ep->desc.bEndpointAddress;
pehci_entry("++ %s, enter\n", __FUNCTION__);
/*check for more than one urb queued for this endpoint*/
qh = ep->hcpriv;
spin_lock_irqsave (&hcd->lock, flags);
if(unlikely(qh != 0)){
if(!list_empty(&qh->qtd_list)){
*status = -EBUSY;
goto done;
} else {
td_ptd_map_buff_t *ptd_map_buff;
td_ptd_map_t *td_ptd_map;
ptd_map_buff = &(td_ptd_map_buff[qh->type]);
td_ptd_map = &ptd_map_buff->map_list[qh->qtd_ptd_index];
ptd_map_buff->pending_ptd_bitmap |= td_ptd_map->ptd_bitmap;
/*NEW*/
td_ptd_map->qtd = qtd;
/* maybe reset hardware's data toggle in the qh */
if (unlikely (!usb_gettoggle (urb->dev, epnum & 0x0f,
!(epnum & 0x10)))) {
/*reset our data toggle*/
td_ptd_map->datatoggle = 0;
usb_settoggle (urb->dev, epnum & 0x0f,
!(epnum & 0x10), 1);
qh->datatoggle = 0;
}
/* trust the QH was set up as interrupt ... */
list_splice (qtd_list, &qh->qtd_list);
}
}
if(!qh){
qh = phci_hcd_make_qh(hcd, urb, qtd_list,status);
if(likely(qh == 0)){
*status = -ENOMEM;
goto done;
}
ep->hcpriv = qh;
}
if (likely (qh != 0)) {
urb_priv->qh = qh;
if (likely (qh->qh_state == QH_STATE_IDLE))
phci_hcd_qh_link_async (hcd, qh, status);
}
done:
/* free it from lock systme can sleep now */
spin_unlock_irqrestore (&hcd->lock, flags);
/* could not get the QH terminate and clean. */
if (unlikely (qh == 0) || *status < 0) {
phci_hcd_qtd_list_free (hcd, urb, qtd_list);
return qh;
}
return qh;
}
/*
* converts original EHCI QTD into PTD(philips transfer descriptor)
* we call PTD as qha also for atl transfers
* for ATL and INT transfers
*/
void *
phci_hcd_qha_from_qtd(
phci_hcd *hcd,
struct ehci_qtd *qtd,
struct urb *urb,
void *ptd,
u32 ptd_data_addr,
struct ehci_qh *qh )
{
u8 toggle = qh->datatoggle;
u32 token = 0;
u32 td_info1 = 0;
u32 td_info3 = 0;
u32 td_info4 = 0;
int maxpacket = 0;
u32 length = 0, temp = 0;
/*for non high speed devices*/
u32 portnum = 0;
u32 hubnum = 0;
u32 se = 0,rl = 0xf,nk = 0xf;
u8 datatoggle = 0;
struct isp1761_mem_addr *mem_addr = &qtd->mem_addr;
u32 data_addr = 0;
u32 multi = 0;
struct _isp1761_qha *qha = (isp1761_qha*)ptd;
pehci_entry("++ %s: Entered\n",__FUNCTION__);
maxpacket = usb_maxpacket(urb->dev,
urb->pipe,
usb_pipeout(urb->pipe));
multi = 1 + ((maxpacket >> 11) & 0x3);
maxpacket &= 0x7ff;
/************************first word*********************************/
length = qtd->length;
td_info1 = QHA_VALID;
td_info1 |= (length << 3);
td_info1 |= (maxpacket << 18);
td_info1 |= (usb_pipeendpoint(urb->pipe) << 31);
td_info1 |= MULTI(multi);
/*set the first dword*/
qha->td_info1 = td_info1;
pehci_print("%s: length %d, 1st word 0x%08x\n", __FUNCTION__,length,qha->td_info1);
/*******************second word***************************************/
temp = qtd->hw_token;
/*take the pid, thats of only interest to me from qtd,
*/
temp = temp & 0x0300;
temp = temp >> 8;
/*take the endpoint and its 3 bits*/
token = (usb_pipeendpoint(urb->pipe) & 0xE) >> 1;
token |= usb_pipedevice(urb->pipe) << 3;
if(urb->dev->speed != USB_SPEED_HIGH){
pehci_print("device is full/low speed, %d\n",urb->dev->speed);
token |= 1 << 14;
portnum = urb->dev->ttport;
/*IMMED*/
hubnum = urb->dev->tt->hub->devnum;
token |= portnum << 18;
token |= hubnum << 25;
/*for non-high speed transfer
reload and nak counts are zero
*/
rl = 0x0;
nk = 0x0;
}
/*se should be 0x2 for only low speed devices*/
if(urb->dev->speed == USB_SPEED_LOW)
se = 0x2;
if(usb_pipeint(urb->pipe)){
/* reload count and nakcount is
required for only async transfers
*/
rl = 0x0;
}
/*set the se field, should be zero for all
but low speed devices
*/
token |= se << 16;
/*take the pid*/
token |= temp << 10;
if(usb_pipebulk(urb->pipe))
token |= EPTYPE_BULK;
else if(usb_pipeint(urb->pipe))
token |= EPTYPE_INT;
else if (usb_pipeisoc(urb->pipe))
token |= EPTYPE_ISO;
qha->td_info2 = token;
pehci_print("%s: second word 0x%08x, qtd token 0x%08x\n",
__FUNCTION__, qha->td_info2,temp);
/***********************Third word*************************************/
/*calculate the data start address from mem_addr for qha*/
data_addr = ((u32)(mem_addr->phy_addr) & 0xffff) - 0x400;
data_addr >>= 3;
pehci_print("data start address %x\n", data_addr);
/*use this field only if there
* is something to transfer
* */
if(length)
td_info3 = data_addr << 8;
/*RL Count, 16*/
td_info3 |= (rl << 25);
qha->td_info3 = td_info3;
pehci_print("%s: third word 0x%08x, tdinfo 0x%08x\n",
__FUNCTION__, qha->td_info3,td_info3);
/**************************fourt word*************************************/
if(usb_pipecontrol(urb->pipe))
datatoggle = qtd->hw_token >> 31;
else
/*take the data toggle from the previous completed transfer
or zero in case of fresh*/
datatoggle = toggle;
td_info4 = QHA_ACTIVE;
/*dt*/
td_info4 |= datatoggle << 25;/*QHA_DATA_TOGGLE; */
/*3 retry count for setup else forever*/
if(PTD_PID(qha->td_info2) == SETUP_PID)
td_info4 |= (3 << 23);
else
td_info4 |= (0 << 23);
/*nak count*/
td_info4 |= (nk << 19);
td_info4 |= (qh->ping << 26);
qha->td_info4 = td_info4;
pehci_print("%s: fourt word 0x%08x\n",__FUNCTION__, qha->td_info4);
pehci_entry("-- %s: Exit, qha %p\n",__FUNCTION__, qha);
return qha;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -