You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
689 lines
20 KiB
689 lines
20 KiB
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
iso.c
|
|
|
|
Abstract:
|
|
|
|
miniport transfer code for iso
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
|
|
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
|
|
PURPOSE.
|
|
|
|
Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
|
|
|
|
|
|
Revision History:
|
|
|
|
3-1-00 : created, jdunn
|
|
|
|
--*/
|
|
|
|
#include "common.h"
|
|
|
|
//implements the following miniport functions:
|
|
|
|
USB_MINIPORT_STATUS
|
|
OHCI_OpenIsoEndpoint(
|
|
PDEVICE_DATA DeviceData,
|
|
PENDPOINT_PARAMETERS EndpointParameters,
|
|
PENDPOINT_DATA EndpointData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PUCHAR buffer;
|
|
HW_32BIT_PHYSICAL_ADDRESS phys, edPhys;
|
|
PHCD_ENDPOINT_DESCRIPTOR ed;
|
|
ULONG i, available, tdCount;
|
|
|
|
LOGENTRY(DeviceData, G, '_opS', 0, 0, 0);
|
|
|
|
buffer = EndpointParameters->CommonBufferVa;
|
|
phys = EndpointParameters->CommonBufferPhys;
|
|
available = EndpointParameters->CommonBufferBytes;
|
|
|
|
|
|
#if DBG
|
|
{
|
|
ULONG offset;
|
|
|
|
offset = BYTE_OFFSET(buffer);
|
|
|
|
// OHCI requires 16 byte alignemnt
|
|
OHCI_ASSERT(DeviceData, (offset % 16) == 0);
|
|
}
|
|
#endif
|
|
|
|
// use control list
|
|
EndpointData->StaticEd =
|
|
&DeviceData->StaticEDList[ED_ISOCHRONOUS];
|
|
|
|
// make the Ed
|
|
ed = (PHCD_ENDPOINT_DESCRIPTOR) buffer;
|
|
|
|
edPhys = phys;
|
|
phys += sizeof(HCD_ENDPOINT_DESCRIPTOR);
|
|
buffer += sizeof(HCD_ENDPOINT_DESCRIPTOR);
|
|
available -= sizeof(HCD_ENDPOINT_DESCRIPTOR);
|
|
|
|
EndpointData->TdList = (PHCD_TD_LIST) buffer;
|
|
|
|
tdCount = available/sizeof(HCD_TRANSFER_DESCRIPTOR);
|
|
LOGENTRY(DeviceData, G, '_tdC', tdCount, TDS_PER_ISO_ENDPOINT, 0);
|
|
OHCI_ASSERT(DeviceData, tdCount >= TDS_PER_ISO_ENDPOINT);
|
|
|
|
EndpointData->TdCount = tdCount;
|
|
for (i=0; i<tdCount; i++) {
|
|
OHCI_InitializeTD(DeviceData,
|
|
EndpointData,
|
|
&EndpointData->TdList->Td[i],
|
|
phys);
|
|
|
|
phys += sizeof(HCD_TRANSFER_DESCRIPTOR);
|
|
}
|
|
|
|
EndpointData->HcdEd =
|
|
OHCI_InitializeED(DeviceData,
|
|
EndpointData,
|
|
ed,
|
|
&EndpointData->TdList->Td[0],
|
|
edPhys);
|
|
|
|
// iso endpoints do not halt
|
|
ed->EdFlags = EDFLAG_NOHALT;
|
|
|
|
OHCI_InsertEndpointInSchedule(DeviceData,
|
|
EndpointData);
|
|
|
|
return USBMP_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
ULONG
|
|
OHCI_IsoTransferLookAhead(
|
|
PDEVICE_DATA DeviceData,
|
|
PENDPOINT_DATA EndpointData,
|
|
PTRANSFER_PARAMETERS TransferParameters,
|
|
PTRANSFER_CONTEXT TransferContext,
|
|
PMINIPORT_ISO_TRANSFER IsoTransfer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calculates how many TDs we will need for this transfer
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PHCD_TRANSFER_DESCRIPTOR td, lastTd;
|
|
ULONG currentPacket;
|
|
PMINIPORT_ISO_TRANSFER tmpIsoTransfer;
|
|
ULONG need = 1, n;
|
|
|
|
LOGENTRY(DeviceData, G, '_lk1', EndpointData, TransferParameters,
|
|
EndpointData->HcdEd);
|
|
|
|
OHCI_ASSERT(DeviceData, IsoTransfer->PacketCount > 0);
|
|
// sometimes you just need memory
|
|
n = sizeof(MINIPORT_ISO_TRANSFER) + sizeof(MINIPORT_ISO_PACKET) *
|
|
(IsoTransfer->PacketCount-1);
|
|
tmpIsoTransfer = ExAllocatePool(NonPagedPool, n);
|
|
if (tmpIsoTransfer == NULL) {
|
|
// this will cause us to return busy
|
|
return 99999;
|
|
}
|
|
RtlCopyMemory(tmpIsoTransfer, IsoTransfer, n);
|
|
|
|
td = OHCI_ALLOC_TD(DeviceData, EndpointData);
|
|
currentPacket = 0;
|
|
// we need at least one TD to do the caculations
|
|
if (td == USB_BAD_PTR) {
|
|
// this will cause us to return busy
|
|
return 99999;
|
|
}
|
|
|
|
do {
|
|
|
|
INITIALIZE_TD_FOR_TRANSFER(td, TransferContext);
|
|
//TransferContext->PendingTds++;
|
|
//EndpointData->PendingTds++;
|
|
|
|
currentPacket =
|
|
OHCI_MapIsoTransferToTd(DeviceData,
|
|
tmpIsoTransfer,
|
|
currentPacket,
|
|
td);
|
|
|
|
// alloc another iso TD
|
|
lastTd = td;
|
|
// reuse the same td since this is not a real transfer
|
|
//td = OHCI_ALLOC_TD(DeviceData, EndpointData);
|
|
need++;
|
|
|
|
SET_NEXT_TD(lastTd, td);
|
|
|
|
} while (currentPacket < tmpIsoTransfer->PacketCount);
|
|
|
|
// free the TD we borrowed
|
|
OHCI_FREE_TD(DeviceData, EndpointData, td);
|
|
ExFreePool(tmpIsoTransfer);
|
|
|
|
return need;
|
|
}
|
|
|
|
|
|
USB_MINIPORT_STATUS
|
|
OHCI_IsoTransfer(
|
|
PDEVICE_DATA DeviceData,
|
|
PENDPOINT_DATA EndpointData,
|
|
PTRANSFER_PARAMETERS TransferParameters,
|
|
PTRANSFER_CONTEXT TransferContext,
|
|
PMINIPORT_ISO_TRANSFER IsoTransfer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PHCD_TRANSFER_DESCRIPTOR td, lastTd;
|
|
ULONG currentPacket;
|
|
ULONG tdsNeeded;
|
|
|
|
EndpointData->PendingTransfers++;
|
|
|
|
// we have enough tds, program the transfer
|
|
|
|
LOGENTRY(DeviceData, G, '_nby', EndpointData, TransferParameters,
|
|
EndpointData->HcdEd);
|
|
|
|
TransferContext->IsoTransfer = IsoTransfer;
|
|
|
|
// lookahead calculation
|
|
// see if we can handle this transfer
|
|
//
|
|
tdsNeeded = OHCI_IsoTransferLookAhead(DeviceData,
|
|
EndpointData,
|
|
TransferParameters,
|
|
TransferContext,
|
|
IsoTransfer);
|
|
|
|
if ((EndpointData->TdCount - EndpointData->PendingTds) <
|
|
tdsNeeded) {
|
|
|
|
return USBMP_STATUS_BUSY;
|
|
}
|
|
|
|
//
|
|
// grab the dummy TD from the tail of the queue
|
|
//
|
|
td = EndpointData->HcdTailP;
|
|
OHCI_ASSERT(DeviceData, td->Flags & TD_FLAG_BUSY);
|
|
|
|
currentPacket = 0;
|
|
|
|
LOGENTRY(DeviceData, G, '_iso', EndpointData, TransferContext,
|
|
td);
|
|
|
|
do {
|
|
|
|
INITIALIZE_TD_FOR_TRANSFER(td, TransferContext);
|
|
TransferContext->PendingTds++;
|
|
EndpointData->PendingTds++;
|
|
|
|
currentPacket =
|
|
OHCI_MapIsoTransferToTd(DeviceData,
|
|
IsoTransfer,
|
|
currentPacket,
|
|
td);
|
|
|
|
// alloc another iso TD
|
|
lastTd = td;
|
|
td = OHCI_ALLOC_TD(DeviceData, EndpointData);
|
|
OHCI_ASSERT(DeviceData, td != USB_BAD_PTR);
|
|
SET_NEXT_TD(lastTd, td);
|
|
|
|
} while (currentPacket < IsoTransfer->PacketCount);
|
|
|
|
// td should be the new dummy,
|
|
// now put a new dummy TD on the tail of the EP queue
|
|
//
|
|
|
|
SET_NEXT_TD_NULL(td);
|
|
|
|
//
|
|
// Set new TailP in ED
|
|
// note: This is the last TD in the list and the place holder.
|
|
//
|
|
|
|
TransferContext->NextXferTd =
|
|
EndpointData->HcdTailP = td;
|
|
//if (TransferParameters->TransferBufferLength > 128) {
|
|
// TEST_TRAP();
|
|
//}
|
|
|
|
// put the request on the hardware queue
|
|
LOGENTRY(DeviceData, G,
|
|
'_Til', TransferContext->PendingTds ,
|
|
td->PhysicalAddress, EndpointData->HcdEd->HwED.HeadP);
|
|
EndpointData->HcdEd->HwED.TailP = td->PhysicalAddress;
|
|
|
|
LOGENTRY(DeviceData, G, '_igo', EndpointData->HcdHeadP,
|
|
TransferContext->TcFlags, 0);
|
|
|
|
//if (TransferParameters->TransferBufferLength > 128) {
|
|
// TEST_TRAP();
|
|
//}
|
|
|
|
return USBMP_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
ULONG
|
|
OHCI_MapIsoTransferToTd(
|
|
PDEVICE_DATA DeviceData,
|
|
PMINIPORT_ISO_TRANSFER IsoTransfer,
|
|
ULONG CurrentPacket,
|
|
PHCD_TRANSFER_DESCRIPTOR Td
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
LengthMapped
|
|
|
|
--*/
|
|
{
|
|
HW_32BIT_PHYSICAL_ADDRESS logicalStart, logicalEnd;
|
|
HW_32BIT_PHYSICAL_ADDRESS startPage, endPage;
|
|
PMINIPORT_ISO_PACKET iPacket;
|
|
ULONG packetsThisTd;
|
|
ULONG lengthThisTd, offset;
|
|
USHORT startFrame;
|
|
|
|
packetsThisTd = 0;
|
|
lengthThisTd = 0;
|
|
logicalStart = 0;
|
|
|
|
LOGENTRY(DeviceData, G, '_mpI', CurrentPacket,
|
|
IsoTransfer->PacketCount, 0);
|
|
OHCI_ASSERT(DeviceData, CurrentPacket < IsoTransfer->PacketCount);
|
|
|
|
Td->FrameIndex = CurrentPacket;
|
|
|
|
while (CurrentPacket < IsoTransfer->PacketCount) {
|
|
|
|
LOGENTRY(DeviceData, G, '_mpC', CurrentPacket,
|
|
IsoTransfer->PacketCount, 0);
|
|
|
|
iPacket = &IsoTransfer->Packets[CurrentPacket];
|
|
|
|
OHCI_ASSERT(DeviceData, iPacket->BufferPointerCount < 3);
|
|
OHCI_ASSERT(DeviceData, iPacket->BufferPointerCount != 0);
|
|
|
|
// cases are:
|
|
// case 1 - packet has pagebreak
|
|
// case 1a we have already filled in part of the current TD
|
|
// <bail, next pass will be 1b>
|
|
//
|
|
// case 1b we have not used the current TD yet
|
|
// <add packet to TD and bail>
|
|
//
|
|
// case 2 - packet has no pagebreak and will fit
|
|
// case 2a current packet is on different page than previous
|
|
// packet
|
|
// <add packet and bail>
|
|
//
|
|
// case 2b current packet is on same page as previous packet
|
|
// <add packet and try to add another>
|
|
//
|
|
// case 2c TD has not been used yet
|
|
// <add packet and try to add another>
|
|
//
|
|
// case 3 - packet will not fit
|
|
// <bail>
|
|
|
|
// does the packet have a page break?
|
|
if (iPacket->BufferPointerCount > 1) {
|
|
// yes,
|
|
// case 1
|
|
|
|
if (packetsThisTd != 0) {
|
|
// case 1a
|
|
// we have packets in this TD bail,
|
|
// leave it for next time
|
|
LOGENTRY(DeviceData, G, '_c1a', 0, 0, lengthThisTd);
|
|
break;
|
|
}
|
|
|
|
// case 1b give the packet its own TD
|
|
|
|
// convert to a 16-bit frame number
|
|
startFrame = (USHORT) iPacket->FrameNumber;
|
|
|
|
LOGENTRY(DeviceData, G, '_c1b', iPacket, CurrentPacket, startFrame);
|
|
|
|
logicalStart = iPacket->BufferPointer0.Hw32 & ~OHCI_PAGE_SIZE_MASK;
|
|
offset = iPacket->BufferPointer0.Hw32 & OHCI_PAGE_SIZE_MASK;
|
|
|
|
logicalEnd = iPacket->BufferPointer1.Hw32 +
|
|
iPacket->BufferPointer1Length;
|
|
|
|
lengthThisTd = iPacket->Length;
|
|
packetsThisTd++;
|
|
|
|
CurrentPacket++;
|
|
|
|
Td->HwTD.Packet[0].Offset = (USHORT) offset;
|
|
Td->HwTD.Packet[0].Ones = 0xFFFF;
|
|
|
|
break;
|
|
}
|
|
|
|
// will this packet fit in the current Td?
|
|
|
|
if (packetsThisTd < 8 &&
|
|
(lengthThisTd+iPacket->Length < OHCI_PAGE_SIZE * 2)) {
|
|
|
|
LOGENTRY(DeviceData, G, '_fit', iPacket, CurrentPacket, 0);
|
|
|
|
OHCI_ASSERT(DeviceData, iPacket->BufferPointerCount == 1);
|
|
OHCI_ASSERT(DeviceData, iPacket->Length ==
|
|
iPacket->BufferPointer0Length);
|
|
|
|
// yes
|
|
// case 2
|
|
if (logicalStart == 0) {
|
|
// first packet, set logical start & end
|
|
// case 2c and frame number
|
|
LOGENTRY(DeviceData, G, '_c2c', iPacket, CurrentPacket, 0);
|
|
|
|
startFrame = (USHORT) iPacket->FrameNumber;
|
|
|
|
offset = iPacket->BufferPointer0.Hw32 & OHCI_PAGE_SIZE_MASK;
|
|
logicalStart = iPacket->BufferPointer0.Hw32 & ~OHCI_PAGE_SIZE_MASK;
|
|
|
|
logicalEnd = iPacket->BufferPointer0.Hw32 +
|
|
iPacket->BufferPointer0Length;
|
|
lengthThisTd += iPacket->Length;
|
|
Td->HwTD.Packet[0].Offset = (USHORT) offset;
|
|
Td->HwTD.Packet[0].Ones = 0xFFFF;
|
|
packetsThisTd++;
|
|
|
|
CurrentPacket++;
|
|
|
|
} else {
|
|
// not first packet
|
|
LOGENTRY(DeviceData, G, '_adp', iPacket, CurrentPacket,
|
|
packetsThisTd);
|
|
|
|
logicalEnd = iPacket->BufferPointer0.Hw32 +
|
|
iPacket->Length;
|
|
OHCI_ASSERT(DeviceData, lengthThisTd < OHCI_PAGE_SIZE * 2);
|
|
|
|
Td->HwTD.Packet[packetsThisTd].Offset
|
|
= (USHORT) (lengthThisTd + offset);
|
|
Td->HwTD.Packet[packetsThisTd].Ones = 0xFFFF;
|
|
|
|
lengthThisTd += iPacket->Length;
|
|
packetsThisTd++;
|
|
|
|
startPage = logicalStart & ~OHCI_PAGE_SIZE_MASK;
|
|
endPage = logicalEnd & ~OHCI_PAGE_SIZE_MASK;
|
|
|
|
CurrentPacket++;
|
|
|
|
// did we cross a page?
|
|
if (startPage != endPage) {
|
|
// yes, bail now
|
|
LOGENTRY(DeviceData, G, '_c2a', Td, CurrentPacket, 0);
|
|
break;
|
|
}
|
|
|
|
LOGENTRY(DeviceData, G, '_c2b', Td, CurrentPacket, 0);
|
|
|
|
// no, keep going
|
|
}
|
|
} else {
|
|
// won't fit
|
|
// bail and leave it for next time
|
|
LOGENTRY(DeviceData, G, '_ca3', Td, CurrentPacket, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
Td->HwTD.CBP = logicalStart;
|
|
Td->HwTD.BE = logicalEnd-1;
|
|
Td->TransferCount = lengthThisTd;
|
|
Td->HwTD.Iso.StartingFrame = startFrame;
|
|
Td->HwTD.Iso.FrameCount = packetsThisTd-1;
|
|
Td->HwTD.Iso.Isochronous = 1;
|
|
Td->HwTD.Iso.IntDelay = HcTDIntDelay_0ms;
|
|
LOGENTRY(DeviceData, G, '_iso', Td, 0, CurrentPacket);
|
|
|
|
return CurrentPacket;
|
|
}
|
|
|
|
|
|
VOID
|
|
OHCI_ProcessDoneIsoTd(
|
|
PDEVICE_DATA DeviceData,
|
|
PHCD_TRANSFER_DESCRIPTOR Td,
|
|
BOOLEAN CompleteTransfer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
process a completed Iso TD
|
|
|
|
Parameters
|
|
|
|
--*/
|
|
{
|
|
PTRANSFER_CONTEXT transferContext;
|
|
PENDPOINT_DATA endpointData;
|
|
USBD_STATUS usbdStatus;
|
|
PMINIPORT_ISO_TRANSFER isoTransfer;
|
|
ULONG frames, n, i;
|
|
|
|
transferContext = TRANSFER_CONTEXT_PTR(Td->TransferContext);
|
|
isoTransfer = transferContext->IsoTransfer;
|
|
|
|
transferContext->PendingTds--;
|
|
endpointData = transferContext->EndpointData;
|
|
endpointData->PendingTds--;
|
|
|
|
LOGENTRY(DeviceData, G, '_Did', transferContext,
|
|
0,
|
|
Td);
|
|
|
|
// walk the PSWs and fill in the IsoTransfer structure
|
|
|
|
frames = Td->HwTD.Iso.FrameCount+1;
|
|
n = Td->FrameIndex;
|
|
|
|
for (i = 0; i<frames; i++) {
|
|
|
|
PMINIPORT_ISO_PACKET mpPak;
|
|
PHC_OFFSET_PSW psw;
|
|
|
|
mpPak = &isoTransfer->Packets[n+i];
|
|
psw = &Td->HwTD.Packet[i];
|
|
|
|
mpPak->LengthTransferred = 0;
|
|
|
|
if (IN_TRANSFER(transferContext->TransferParameters)) {
|
|
// in transfer
|
|
|
|
// if we got an error the length may still be
|
|
// valid, so we return it
|
|
if (psw->ConditionCode != HcCC_NotAccessed) {
|
|
mpPak->LengthTransferred = psw->Size;
|
|
}
|
|
LOGENTRY(DeviceData, G, '_isI',
|
|
i,
|
|
mpPak->LengthTransferred,
|
|
psw->ConditionCode);
|
|
|
|
} else {
|
|
// out transfer
|
|
|
|
// assume all data was sent if no error is indicated
|
|
if (psw->ConditionCode == HcCC_NoError) {
|
|
mpPak->LengthTransferred = mpPak->Length;
|
|
}
|
|
LOGENTRY(DeviceData, G, '_isO',
|
|
i,
|
|
mpPak->LengthTransferred,
|
|
psw->ConditionCode);
|
|
}
|
|
|
|
if (psw->ConditionCode == HcCC_NoError) {
|
|
mpPak->UsbdStatus = USBD_STATUS_SUCCESS;
|
|
} else {
|
|
mpPak->UsbdStatus = psw->ConditionCode;
|
|
mpPak->UsbdStatus |= 0xC0000000;
|
|
}
|
|
|
|
}
|
|
|
|
// mark the TD free
|
|
OHCI_FREE_TD(DeviceData, endpointData, Td);
|
|
|
|
if (transferContext->PendingTds == 0 && CompleteTransfer) {
|
|
// all TDs for this transfer are done
|
|
// clear the HAVE_TRANSFER flag to indicate
|
|
// we can take another
|
|
endpointData->PendingTransfers--;
|
|
|
|
transferContext->TransferParameters->FrameCompleted =
|
|
OHCI_Get32BitFrameNumber(DeviceData);
|
|
|
|
|
|
LOGENTRY(DeviceData, G, '_cpi',
|
|
transferContext,
|
|
0,
|
|
0);
|
|
|
|
USBPORT_COMPLETE_ISO_TRANSFER(DeviceData,
|
|
endpointData,
|
|
transferContext->TransferParameters,
|
|
transferContext->IsoTransfer);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
OHCI_PollIsoEndpoint(
|
|
PDEVICE_DATA DeviceData,
|
|
PENDPOINT_DATA EndpointData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called when the endpoint 'needs attention'
|
|
|
|
The goal here is to determine which TDs, if any,
|
|
have completed and complete any associated transfers
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PHCD_TRANSFER_DESCRIPTOR td, currentTd;
|
|
PHCD_ENDPOINT_DESCRIPTOR ed;
|
|
ULONG i;
|
|
PTRANSFER_CONTEXT transfer;
|
|
HW_32BIT_PHYSICAL_ADDRESS headP;
|
|
|
|
ed = EndpointData->HcdEd;
|
|
|
|
LOGENTRY(DeviceData, G, '_pli', ed, 0, 0);
|
|
|
|
// note it is important the the compiler generate a
|
|
// dword move when reading the queuehead HeadP register
|
|
// since this location is also accessed by the host
|
|
// hardware
|
|
headP = ed->HwED.HeadP;
|
|
|
|
// get the 'currentTD'
|
|
currentTd = (PHCD_TRANSFER_DESCRIPTOR)
|
|
USBPORT_PHYSICAL_TO_VIRTUAL(headP & ~HcEDHeadP_FLAGS,
|
|
DeviceData,
|
|
EndpointData);
|
|
|
|
LOGENTRY(DeviceData, G, '_cTD', currentTd,
|
|
headP & ~HcEDHeadP_FLAGS,
|
|
TRANSFER_CONTEXT_PTR(currentTd->TransferContext));
|
|
|
|
// iso endpoints shpuld not halt
|
|
OHCI_ASSERT(DeviceData, (ed->HwED.HeadP & HcEDHeadP_HALT) == 0)
|
|
|
|
|
|
// Walk the swHeadP to the current TD (hw headp)
|
|
// mark all TDs we find as completed
|
|
//
|
|
// NOTE: this step may be skipped if the
|
|
// done queue is reliable
|
|
|
|
td = EndpointData->HcdHeadP;
|
|
|
|
while (td != currentTd) {
|
|
LOGENTRY(DeviceData, G, '_mDN', td, 0, 0);
|
|
SET_FLAG(td->Flags, TD_FLAG_DONE);
|
|
td = TRANSFER_DESCRIPTOR_PTR(td->NextHcdTD);
|
|
}
|
|
|
|
// set the sw headp to the new current head
|
|
EndpointData->HcdHeadP = currentTd;
|
|
|
|
// now flush all completed TDs
|
|
for (i=0; i<EndpointData->TdCount; i++) {
|
|
td = &EndpointData->TdList->Td[i];
|
|
|
|
if ((td->Flags & (TD_FLAG_XFER | TD_FLAG_DONE)) ==
|
|
(TD_FLAG_XFER | TD_FLAG_DONE)) {
|
|
OHCI_ProcessDoneIsoTd(DeviceData,
|
|
td,
|
|
TRUE);
|
|
}
|
|
}
|
|
}
|