?? pehci.c
字號:
/*
* Set the ISO_BUF_FILL bit to 1 to indicate that there is a PTD for ISO that needs to
* be processed.
*/
iso_dbg(ISO_DBG_DATA, "[phcd_iso_handler]: Buffer Status: 0x%08x\n", (unsigned int) (buff_stat | ISO_BUFFER));
isp1761_reg_write32(hcd->dev, hcd->regs.buffer_status, (buff_stat | ISO_BUFFER));
} /* list_for_each(position, itd_sched) */
iso_dbg(ISO_DBG_INFO, "[phcd_iso_handler]: ISO-Frame scheduling done\n");
} /* if( schedule == TRUE ) */
if( remove == TRUE)
{
iso_dbg(ISO_DBG_INFO, "[phcd_iso_handler]: Something is for removal\n");
list_for_each_safe(position, lst_temp, itd_remove)
{
last_td = FALSE;
/* Get an ITD in the list for processing */
itd = list_entry(position, struct ehci_itd, itd_list);
/* Get the PTD that was allocated for this particular ITD. */
td_ptd_map = &ptd_map_buff->map_list[itd->itd_index];
iso_dbg(ISO_DBG_DATA, "[phcd_iso_handler]: ITD Index: %d\n", itd->itd_index);
urb = itd->urb;
/*
* Get the base address of the memory allocated in the
* PAYLOAD region for this ITD
*/
mem_addr = &itd->mem_addr;
memset(iso_ptd, 0, sizeof(struct _isp1761_isoptd));
/*
* Read this ptd from the ram address,address is in the
* td_ptd_map->ptd_header_addr
*/
isp1761_mem_read( hcd->dev,
td_ptd_map->ptd_header_addr,
0,
(__u32 *) iso_ptd,
PHCI_QHA_LENGTH,
0
);
iso_dbg(ISO_DBG_DATA, "[phcd_iso_handler]: DWORD0 = 0x%08x\n", iso_ptd->td_info1);
iso_dbg(ISO_DBG_DATA, "[phcd_iso_handler]: DWORD1 = 0x%08x\n", iso_ptd->td_info2);
iso_dbg(ISO_DBG_DATA, "[phcd_iso_handler]: DWORD2 = 0x%08x\n", iso_ptd->td_info3);
iso_dbg(ISO_DBG_DATA, "[phcd_iso_handler]: DWORD3 = 0x%08x\n", iso_ptd->td_info4);
iso_dbg(ISO_DBG_DATA, "[phcd_iso_handler]: DWORD4 = 0x%08x\n", iso_ptd->td_info5);
iso_dbg(ISO_DBG_DATA, "[phcd_iso_handler]: DWORD5 = 0x%08x\n", iso_ptd->td_info6);
iso_dbg(ISO_DBG_DATA, "[phcd_iso_handler]: DWORD6 = 0x%08x\n", iso_ptd->td_info7);
iso_dbg(ISO_DBG_DATA, "[phcd_iso_handler]: DWORD7 = 0x%08x\n", iso_ptd->td_info8);
/* Go over the status of each of the 8 Micro Frames */
for( uframe_cnt = 0; uframe_cnt < 8; uframe_cnt++)
{
/*
* We go over the status one at a time. The status bits and their
* equivalent status are:
* Bit 0 - Transaction Error (IN and OUT)
* Bit 1 - Babble (IN token only)
* Bit 2 - Underrun (OUT token only)
*/
usof_stat = iso_ptd->td_info5 >> (8 + (uframe_cnt * 3));
switch(usof_stat & 0x7)
{
case INT_UNDERRUN:
iso_dbg(ISO_DBG_ERR, "[phcd_iso_handler Error]: Buffer underrun\n");
urb->error_count++;
break;
case INT_EXACT:
iso_dbg(ISO_DBG_ERR, "[phcd_iso_handler Error]: Transaction error\n");
urb->error_count++;
break;
case INT_BABBLE:
iso_dbg(ISO_DBG_ERR, "[phcd_iso_handler Error]: Babble error\n");
urb->iso_frame_desc[itd->itd_index].status = -EOVERFLOW;
urb->error_count++;
break;
} /* switch(usof_stat & 0x7) */
} /* end of for( ulMicroFrmCnt = 0; ulMicroFrmCnt < 8; ulMicroFrmCnt++) */
/*
* Get the number of bytes transferred. This indicates the number of
* bytes sent or received for this transaction.
*/
if(urb->dev->speed != USB_SPEED_HIGH)
/* Length is 1K for full/low speed device */
length = PTD_XFERRED_NONHSLENGTH(iso_ptd->td_info4);
else
/* Length is 32K for high speed device */
length = PTD_XFERRED_LENGTH(iso_ptd->td_info4);
/* Halted, need to finish all the transfer on this endpoint*/
if(iso_ptd->td_info4 & PTD_STATUS_HALTED)
{
iso_dbg(ISO_DBG_ERR, "[phcd_iso_handler Error] PTD Halted\n");
/*
* When there is an error, do not process the other PTDs.
* Stop at the PTD with the error and remove all other PTDs.
*/
td_ptd_map->lasttd = 1;
/*
* In case of halt, next transfer will start with toggle zero,
* USB specs, 5.8.5
*/
td_ptd_map->datatoggle = 0;
} /* if(iso_ptd->td_info4 & PTD_STATUS_HALTED) */
/* Update the actual length of the transfer from the data we got earlier */
urb->iso_frame_desc[itd->index].actual_length = length;
/* If the PTD have been executed properly the V bit should be cleared */
if(iso_ptd->td_info1 & QHA_VALID)
{
iso_dbg(ISO_DBG_ERR,"[phcd_iso_handler Error]: Valid bit not cleared\n");
urb->iso_frame_desc[itd->index].status = -ENOSPC;
}
else
{
urb->iso_frame_desc[itd->index].status = 0;
}
/* Check if this is the last ITD either due to some error or normal completion*/
if((td_ptd_map->lasttd) ||(itd->hw_next == EHCI_LIST_END))
{
last_td = TRUE;
}
/* Copy data to/from */
if(length && (length <= MAX_PTD_BUFFER_SIZE))
{
switch(PTD_PID(iso_ptd->td_info2))
{
case IN_PID:
/*
* Get the data from the PAYLOAD area and place it into
* the buffer provided by the requestor.
*/
isp1761_mem_read( hcd->dev,
(unsigned long) mem_addr->phy_addr,
0,
(__u32 *)(le32_to_cpu(itd->hw_bufp[0])),
length,
0
);
case OUT_PID:
/*
* urb->actual length was initialized to zero, so for the first
* uFrame having it incremented immediately is not a problem.
*/
urb->actual_length += length;
break;
}/* switch(PTD_PID(iso_ptd->td_info2)) */
}/* if(length && (length <= MAX_PTD_BUFFER_SIZE)) */
if( last_td == TRUE )
{
/* Start removing the ITDs in the list */
while(1)
{
/*
* This indicates that we are processing the tail PTD.
* Perform cleanup procedure on this last PTD
*/
if(itd->hw_next == EHCI_LIST_END)
{
td_ptd_map = &ptd_map_buff->map_list[itd->itd_index];
/*
* Free up our allocation in the PAYLOAD area so that others can use
* it.
*/
phci_hcd_mem_free(&itd->mem_addr);
/* Remove this ITD entry in the ITD list */
list_del(&itd->itd_list);
/* Free up the memory allocated for the ITD structure */
qha_free(qha_cache, itd);
/* Indicate that the PTD we have used is now free */
td_ptd_map->state = TD_PTD_NEW;
/* Decrease the number of active PTDs scheduled*/
hcd->periodic_sched --;
/* Skip this PTD during the next PTD processing. */
skip_map |= td_ptd_map->ptd_bitmap;
isp1761_reg_write32(hcd->dev, hcd->regs.isotdskipmap, skip_map);
/* All ITDs in this list have been successfully removed. */
break;
} /* if(itd->hw_next == EHCI_LIST_END) */
/*
* This indicates that we stopped due to an error on a PTD that is
* not the last in the list. We need to free up this PTD as well as
* the PTDs after it.
*/
else
{
/*
* Put the current ITD error onto this variable.
* We will be unlinking this from the list and free up its
* resources later.
*/
current_itd = itd;
td_ptd_map = &ptd_map_buff->map_list[itd->itd_index];
/*
* Get the next ITD, and place it to the itd variable.
* In a way we are moving forward in the ITD list.
*/
itd = (struct ehci_itd *)le32_to_cpu(current_itd->hw_next);
/* Free up the current ITD's resources */
phci_hcd_mem_free(¤t_itd->mem_addr);
/* Remove this ITD entry in the ITD list */
list_del(¤t_itd->itd_list);
/* Free up the memory allocated for the ITD structure */
qha_free(qha_cache,current_itd);
/* Inidicate that the PTD we have used is now free */
td_ptd_map->state = TD_PTD_NEW;
/* Decrease the number of active PTDs scheduled*/
hcd->periodic_sched --;
/* Sine it is done, skip this PTD during the next PTD processing. */
skip_map |= td_ptd_map->ptd_bitmap;
isp1761_reg_write32(hcd->dev, hcd->regs.isotdskipmap, skip_map);
/*
* Start all over again until it gets to the tail of the
* list of PTDs/ITDs
*/
continue;
} /* else of if(itd->hw_next == EHCI_LIST_END) */
/* It should never get here, but I put this as a precaution */
break;
} /* end of while(1) */
/* Check if there were ITDs that were not processed due to the error */
if(urb->status == -EINPROGRESS)
{
if( (urb->actual_length != urb->transfer_buffer_length) &&
(urb->transfer_flags & URB_SHORT_NOT_OK))
{
iso_dbg(ISO_DBG_ERR,"[phcd_iso_handler Error]: Short Packet\n");
urb->status = -EREMOTEIO;
}
else
{
urb->status = 0;
}
}
urb->hcpriv = 0;
/* We need to unlock this here, since this was locked when we are called
* from the interrupt handler */
spin_unlock(&hcd->lock);
/* Perform URB cleanup */
#ifdef LINUX_269
usb_hcd_giveback_urb (&hcd->usb_hcd, urb, regs);
#else
usb_hcd_giveback_urb (&hcd->usb_hcd, urb);
#endif
spin_lock(&hcd->lock);
continue;
}/* if( last_td == TRUE ) */
/*
* If the last_td is not set then we do not need to check for errors and directly
* proceed with the cleaning sequence.
*/
/* Decrement the count of active PTDs */
hcd->periodic_sched --;
/* Free up the memory we allocated in the PAYLOAD area */
phci_hcd_mem_free(&itd->mem_addr);
/* Remove this ITD from the list of active ITDs */
list_del(&itd->itd_list);
/* Free up the memory we allocated for the ITD structure */
qha_free(qha_cache, itd);
/*
* Clear the bit associated with this PTD from the grouptdmap and
* make this PTD available for other transfers
*/
td_ptd_map->state = TD_PTD_NEW;
/* Skip this PTD during the next PTD processing. */
skip_map |= td_ptd_map->ptd_bitmap;
isp1761_reg_write32(hcd->dev, hcd->regs.isotdskipmap, skip_map);
} /* list_for_each_safe(position, lst_temp, itd_remove) */
iso_dbg(ISO_DBG_INFO, "[phcd_iso_handler]: ISO-Frame removal done\n");
} /* if( remove == TRUE) */
/*
* When there is no more PTDs queued for scheduling or removal
* clear the buffer status to indicate there are no more PTDs for
* processing and set the skip map to 1 to indicate that the first
* PTD is also the last PTD.
*/
if(hcd->periodic_sched <= 0)
{
iso_dbg(ISO_DBG_INFO, "[phcd_iso_handler]: No more PTDs queued\n");
buff_stat &= ~ISO_BUFFER;
isp1761_reg_write32(hcd->dev, hcd->regs.buffer_status, buff_stat);
isp1761_reg_write32(hcd->dev,hcd->regs.isotdlastmap, 0x1);
hcd->periodic_sched = 0;
}
} /* end of phcd_iso_handler */
#endif /* CONFIG_ISO_SUPPORT */
/*interrupt transfer handler*/
/********************************************************
1. read done map
2. read the ptd to see any errors
3. copy the payload to and from
4. update ehci td
5. make new ptd if transfer there and earlier done
6. schedule
*********************************************************/
static void
pehci_hcd_intl_worker(phci_hcd *hcd,struct pt_regs *regs)
{
int i = 0;
u32 donemap = 0, donetoclear;
u32 mask = 0x1,index = 0;
u32 pendingmap = 0;
u32 location = 0;
u32 length = 0;
u32 skipmap = 0;
u32 ormask = 0;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -