?? ehci.c
字號(hào):
pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
//test if the purb is canceled
if (purb->flags & URB_FLAG_FORCE_CANCEL)
{
purb->status = STATUS_CANCELLED;
}
else if (raw_status == 0)
purb->status = STATUS_SUCCESS;
else if (pipe_content->trans_type == USB_ENDPOINT_XFER_INT ||
pipe_content->trans_type == USB_ENDPOINT_XFER_BULK ||
pipe_content->trans_type == USB_ENDPOINT_XFER_CONTROL)
{
if (raw_status & QTD_STS_BABBLE)
purb->status = USB_STATUS_DATA_OVERRUN;
else if (raw_status & QTD_STS_HALT)
purb->status = USB_STATUS_ENDPOINT_HALTED;
else if (raw_status & QTD_STS_DBE)
purb->status = USB_STATUS_BUFFER_OVERRUN;
else if (raw_status & QTD_STS_XACT)
purb->status = USB_STATUS_CRC; // crc is included in xact err.
else if (raw_status & QTD_STS_MMF)
purb->status = USB_STATUS_BTSTUFF;
else
purb->status = STATUS_UNSUCCESSFUL;
}
else if (pipe_content->trans_type == USB_ENDPOINT_XFER_ISOC)
{
if (pipe_content->speed_high)
{
if (raw_status & ITD_STS_BUFERR)
purb->status = USB_STATUS_BUFFER_OVERRUN;
else if (raw_status & ITD_STS_BABBLE)
purb->status = USB_STATUS_BABBLE_DETECTED;
else if (raw_status & ITD_STS_XACTERR) // Xact Err
purb->status = USB_STATUS_CRC;
else
purb->status = STATUS_UNSUCCESSFUL;
}
else
{
if (raw_status & SITD_STS_ERR) // ERR is received from hub's tt
purb->status = USB_STATUS_ERROR;
else if (raw_status & SITD_STS_DBE)
purb->status = USB_STATUS_BUFFER_OVERRUN;
else if (raw_status & SITD_STS_BABBLE)
purb->status = USB_STATUS_BABBLE_DETECTED;
else if (raw_status & SITD_STS_XACTERR) // Xact Error
purb->status = USB_STATUS_CRC;
else if (raw_status & SITD_STS_MISSFRM) // missing microframe
purb->status = USB_STATUS_DATA_TOGGLE_MISMATCH;
else
purb->status = STATUS_UNSUCCESSFUL;
}
}
if (purb->status != STATUS_SUCCESS)
{
hcd_dbg_print(DBGLVL_MEDIUM, ("ehci_set_error_code(): error status 0x%x\n", raw_status));
}
return purb->status;
}
static BOOLEAN NTAPI
ehci_sync_remove_urb_finished(PVOID context)
{
PEHCI_DEV ehci;
PLIST_ENTRY pthis, pnext, ptemp;
PURB purb;
PSYNC_PARAM pparam;
pparam = (PSYNC_PARAM) context;
ehci = pparam->ehci;
ptemp = (PLIST_ENTRY) pparam->context;
if (ehci == NULL)
{
return (UCHAR) (pparam->ret = FALSE);
}
ListFirst(&ehci->urb_list, pthis);
while (pthis)
{
//remove urbs not in the schedule
ListNext(&ehci->urb_list, pthis, pnext);
purb = (PURB) pthis;
if ((purb->flags & URB_FLAG_IN_SCHEDULE) == 0)
{
//finished or canceled( not applied for split bulk ).
RemoveEntryList(pthis);
InsertTailList(ptemp, pthis);
}
pthis = pnext;
}
pparam->ret = TRUE;
return (UCHAR) TRUE;
}
VOID NTAPI
ehci_dpc_callback(PKDPC dpc, PVOID context, PVOID sysarg1, PVOID sysarg2)
{
PEHCI_DEV ehci;
LIST_HEAD temp_list;
PLIST_ENTRY pthis, pnext;
PURB purb;
PEHCI_QH pqh;
PEHCI_QTD ptd;
PUHCI_PENDING_ENDP pending_endp;
PUSB_DEV pdev;
PUSB_ENDPOINT pendp;
BOOLEAN finished;
LONG i;
ULONG ehci_status, urb_status;
SYNC_PARAM sync_param;
UCHAR ep_type;
USE_BASIC_NON_PENDING_IRQL;
ehci = (PEHCI_DEV) context;
if (ehci == NULL)
return;
ehci_status = (ULONG) sysarg1;
InitializeListHead(&temp_list);
sync_param.ehci = ehci;
sync_param.context = (PVOID) & temp_list;
ehci_dbg_print(DBGLVL_MAXIMUM, ("ehci_dpc_callback(): entering..., ehci=0x%x\n", ehci));
//remove finished purb from ehci's purb-list
KeSynchronizeExecution(ehci->pdev_ext->ehci_int, ehci_sync_remove_urb_finished, &sync_param);
//release resources( itds, sitds, fstns, tds, and qhs ) allocated for the purb
while (IsListEmpty(&temp_list) == FALSE)
{
//not in any public queue, if do not access into dev, no race
//condition will occur
purb = (PURB) RemoveHeadList(&temp_list);
urb_status = purb->status;
ep_type = endp_type(purb->pendp);
if (ep_type == USB_ENDPOINT_XFER_ISOC)
{
// collect error for iso transfer
urb_status = ehci_scan_iso_error(ehci, purb);
}
//the only place we do not use this lock on non-pending-endp-list data
KeAcquireSpinLockAtDpcLevel(&ehci->pending_endp_list_lock);
while (IsListEmpty(&purb->trasac_list) == FALSE)
{
UCHAR em_type;
pthis = RemoveHeadList(&purb->trasac_list);
em_type = (UCHAR) elem_type(pthis, TRUE);
if (em_type == INIT_LIST_FLAG_QH)
{
pqh = qh_from_list_entry(pthis);
elem_safe_free(pthis, TRUE);
}
else
{
//must be an itd, sitd chain
InsertHeadList(&purb->trasac_list, pthis);
for(i = 0, purb->bytes_transfered = 0; i < purb->td_count; i++)
{
PEHCI_QTD_CONTENT ptdc = NULL;
PEHCI_ITD_CONTENT pitdc;
PEHCI_SITD_CONTENT psitdc;
em_type = (UCHAR) elem_type(pthis, TRUE);
// accumulate data transfered in tds
if (em_type == INIT_LIST_FLAG_QTD)
{
ptd = qtd_from_list_entry(pthis);
ptdc = (PEHCI_QTD_CONTENT) ptd;
if ((ptdc->status & QTD_STS_ACTIVE) == 0 && ((ptdc->status & QTD_ANY_ERROR) == 0))
purb->bytes_transfered += ptd->bytes_to_transfer;
}
else if (em_type == INIT_LIST_FLAG_ITD)
{
int j;
pitdc = (PEHCI_ITD_CONTENT) itd_from_list_entry(pthis);
for(j = 0; j < 8; j++)
{
if ((pitdc->status_slot[j].status & ITD_STS_ACTIVE) == 0
&& (pitdc->status_slot[j].status & ITD_ANY_ERROR) == 0)
purb->bytes_transfered += ptdc->bytes_to_transfer;
}
}
else if (em_type == INIT_LIST_FLAG_SITD)
{
psitdc = (PEHCI_SITD_CONTENT) sitd_from_list_entry(pthis);
if ((psitdc->status & SITD_STS_ACTIVE) == 0 && (psitdc->status & SITD_ANY_ERROR) == 0)
purb->bytes_transfered += ptdc->bytes_to_transfer;
}
ListNext(&purb->trasac_list, pthis, pnext);
pthis = pnext;
}
// check to see if an fstn is there
ListFirstPrev(&purb->trasac_list, pthis);
if (elem_type(pthis, TRUE) == INIT_LIST_FLAG_FSTN)
{
RemoveEntryList(pthis);
elem_safe_free(pthis, TRUE);
}
ListFirst(&purb->trasac_list, pthis);
RemoveEntryList(&purb->trasac_list);
// free the tds
elem_safe_free(pthis, FALSE);
//termination condition
InitializeListHead(&purb->trasac_list);
purb->last_finished_td = NULL;
}
}
if (ep_type == USB_ENDPOINT_XFER_ISOC || ep_type == USB_ENDPOINT_XFER_INT)
ehci_claim_bandwidth(ehci, purb, FALSE); //release band-width
KeReleaseSpinLockFromDpcLevel(&ehci->pending_endp_list_lock);
ehci_set_error_code(purb, urb_status);
pdev = dev_from_endp(purb->pendp);
pendp = purb->pendp;
// perform clear tt buffer if error on full/low bulk/control pipe
if (ep_type == USB_ENDPOINT_XFER_BULK || ep_type == USB_ENDPOINT_XFER_CONTROL)
{
PURB_HS_PIPE_CONTENT pipe_content;
PUSB_DEV phub;
UCHAR port_idx;
get_parent_hs_hub(pdev, phub, port_idx);
pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
if (pipe_content->speed_high == 0 && purb->status != STATUS_SUCCESS)
{
// lets schedule an event to clear the tt buffer
hub_post_clear_tt_event(phub, port_idx, purb->pipe);
}
else if (pipe_content->speed_high == 0)
{
if (phub == NULL)
TRAP();
else
{
// release tt if no error
hub_unlock_tt(phub, (UCHAR) port_idx, (UCHAR) pipe_content->trans_type);
}
}
}
finished = TRUE;
//since the ref_count for the purb is not released, we can safely have one
//pointer to dev
if (purb->status == USB_STATUS_BABBLE_DETECTED)
{
usb_dbg_print(DBGLVL_MEDIUM,
("ehci_dpc_callback(): alert!!!, babble detected, severe error, reset the whole bus\n"));
// ehci_start( ehci );
}
if (ehci_status & STS_HALT) //&& !ehci->is_suspended
{
ehci_start(&ehci->hcd_interf);
}
//this will let the new request in ehci_generic_urb_completion to this endp
//be processed rather than queued in the pending_endp_list
lock_dev(pdev, TRUE);
usb_endp_busy_count_dec(pendp);
unlock_dev(pdev, TRUE);
if (usb_success(purb->status) == FALSE)
{
// set error code and complete the purb and purb is invalid from this point
ehci_generic_urb_completion(purb, purb->context);
}
else
{
if (ep_type == USB_ENDPOINT_XFER_BULK)
{
purb->rest_bytes -= purb->bytes_transfered;
if (purb->rest_bytes)
{
finished = FALSE;
}
else
{
ehci_generic_urb_completion(purb, purb->context);
}
}
else
{
ehci_generic_urb_completion(purb, purb->context);
// DbgBreakPoint();
//purb is now invalid
}
}
KeAcquireSpinLockAtDpcLevel(&ehci->pending_endp_list_lock);
lock_dev(pdev, TRUE);
if (finished)
pdev->ref_count--;
if (urb_status && ((ep_type == USB_ENDPOINT_XFER_BULK) || (ep_type == USB_ENDPOINT_XFER_INT)))
{
// error on int or bulk pipe, cleared in usb_reset_pipe_completion
pendp->flags &= ~USB_ENDP_FLAG_STAT_MASK;
pendp->flags |= USB_ENDP_FLAG_STALL;
}
if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
{
unlock_dev(pdev, TRUE);
KeReleaseSpinLockFromDpcLevel(&ehci->pending_endp_list_lock);
if (finished == FALSE)
{
purb->status = STATUS_DEVICE_DOES_NOT_EXIST;
ehci_generic_urb_completion(purb, purb->context);
lock_dev(pdev, TRUE);
pdev->ref_count--;
unlock_dev(pdev, TRUE);
}
continue;
}
if (finished && IsListEmpty(&pendp->urb_list) == TRUE)
{
unlock_dev(pdev, TRUE);
KeReleaseSpinLockFromDpcLevel(&ehci->pending_endp_list_lock);
continue;
}
else if (finished == TRUE)
{
//has purb in the endp's purb-list
if (usb_endp_busy_count(pendp) > 0)
{
//the urbs still have chance to be sheduled but not this time
unlock_dev(pdev, TRUE);
KeReleaseSpinLockFromDpcLevel(&ehci->pending_endp_list_lock);
continue;
}
}
if (finished == FALSE)
{
//a split bulk transfer, ( not the high speed split transfer )
purb->bytes_transfered = 0;
purb->bytes_to_transfer =
EHCI_MAX_SIZE_TRANSFER > purb->rest_bytes ? purb->rest_bytes : EHCI_MAX_SIZE_TRANSFER;
//the purb is not finished
purb->flags &= ~URB_FLAG_STATE_MASK;
purb->flags |= URB_FLAG_STATE_PENDING;
InsertHeadList(&pendp->urb_list, (PLIST_ENTRY) purb);
}
pending_endp = alloc_pending_endp(&ehci->pending_endp_pool, 1);
pending_endp->pendp = pendp;
InsertTailList(&ehci->pending_endp_list, &pending_endp->endp_link);
unlock_dev(pdev, TRUE);
KeReleaseSpinLockFromDpcLevel(&ehci->pending_endp_list_lock);
}
//ah...exhausted, let's find some in the pending_endp_list to rock
ehci_process_pending_endp(ehci);
return;
}
static BOOLEAN NTAPI
ehci_sync_cancel_urbs_dev(PVOID context)
{
//cancel all the urbs on one dev
PEHCI_DEV ehci;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -