765 lines
21 KiB
C
765 lines
21 KiB
C
/*++
|
|
|
|
Copyright (c) 1995,1996 Microsoft Corporation
|
|
:ts=4
|
|
|
|
Module Name:
|
|
|
|
isoch.c
|
|
|
|
Abstract:
|
|
|
|
This module manages bulk, interrupt & control type
|
|
transactions on the USB.
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
2-15-95 : created
|
|
|
|
--*/
|
|
|
|
#include "wdm.h"
|
|
#include "stdarg.h"
|
|
#include "stdio.h"
|
|
|
|
|
|
#include "usbdi.h"
|
|
#include "hcdi.h"
|
|
#include "uhcd.h"
|
|
|
|
typedef struct _UHCD_INSERTION_CONTEXT {
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
ULONG FrameNumber;
|
|
PHW_TRANSFER_DESCRIPTOR TransferDescriptor;
|
|
} UHCD_INSERTION_CONTEXT, *PUHCD_INSERTION_CONTEXT;
|
|
|
|
|
|
BOOLEAN
|
|
UHCD_SyncInsertIsochDescriptor(
|
|
IN PUHCD_INSERTION_CONTEXT InsertionContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
PDEVICE_EXTENSION deviceExtension =
|
|
InsertionContext->DeviceExtension;
|
|
ULONG frameNumber = InsertionContext->FrameNumber;
|
|
PHW_TRANSFER_DESCRIPTOR transferDescriptor =
|
|
InsertionContext->TransferDescriptor;
|
|
|
|
i = frameNumber % FRAME_LIST_SIZE;
|
|
|
|
if (frameNumber <= deviceExtension->LastFrameProcessed) {
|
|
//
|
|
// we missed it just don't insert
|
|
//
|
|
goto UHCD_SyncInsertIsochDescriptor_Done;
|
|
}
|
|
|
|
// link to what is currently in the
|
|
// frame
|
|
transferDescriptor->HW_Link =
|
|
*( ((PULONG) (deviceExtension->FrameListVirtualAddress) + i) );
|
|
|
|
// now we are in the frame
|
|
*( ((PULONG) (deviceExtension->FrameListVirtualAddress) + i) ) =
|
|
transferDescriptor->PhysicalAddress;
|
|
|
|
#if DBG
|
|
{
|
|
ULONG length;
|
|
|
|
length = *( deviceExtension->IsoList + i);
|
|
|
|
length +=
|
|
UHCD_USB_TO_SYSTEM_BUFFER_LENGTH(transferDescriptor->MaxLength);
|
|
|
|
*( deviceExtension->IsoList + i ) = length;
|
|
|
|
// BUGBUG for iso debugging with camera only!!
|
|
//#ifdef MAX_DEBUG
|
|
// UHCD_ASSERT(length <= 385);
|
|
//#endif
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// free our context info
|
|
//
|
|
UHCD_SyncInsertIsochDescriptor_Done:
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
UHCD_InsertIsochDescriptor(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PHW_TRANSFER_DESCRIPTOR TransferDescriptor,
|
|
IN ULONG FrameNumber
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
UHCD_INSERTION_CONTEXT insertionContext;
|
|
PDEVICE_EXTENSION deviceExtension =
|
|
DeviceObject->DeviceExtension;
|
|
|
|
LOGENTRY(LOG_ISO,'iFrm', FrameNumber, &insertionContext,
|
|
deviceExtension->LastFrameProcessed);
|
|
|
|
|
|
insertionContext.DeviceExtension = DeviceObject->DeviceExtension;
|
|
insertionContext.FrameNumber = FrameNumber;
|
|
insertionContext.TransferDescriptor = TransferDescriptor;
|
|
|
|
// we had better have an interrupt object
|
|
UHCD_ASSERT(deviceExtension->InterruptObject != NULL);
|
|
KeSynchronizeExecution(deviceExtension->InterruptObject,
|
|
UHCD_SyncInsertIsochDescriptor,
|
|
&insertionContext);
|
|
|
|
}
|
|
|
|
|
|
USBD_STATUS
|
|
UHCD_InitializeIsochTransfer(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PUHCD_ENDPOINT Endpoint,
|
|
IN PHCD_URB Urb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the TDs needed by the hardware
|
|
to process this request, called from the AdapterControl
|
|
function of from within TranferCompleteDPC.
|
|
|
|
The transfer list for this URB should be ready for
|
|
processing before returning from this routine.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to a device object.
|
|
|
|
Endpoint - Endpoint associated with this Urb.
|
|
|
|
Urb - pointer to URB Request Packet for this transfer.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PHCD_EXTENSION urbWork;
|
|
#if DBG
|
|
ULONG i;
|
|
#endif
|
|
|
|
// UHCD_KdPrint((2, "'enter UHCD_InitializeIsochTransfer\n"));
|
|
|
|
ASSERT_ENDPOINT(Endpoint);
|
|
|
|
LOGENTRY(LOG_ISO,'tISO', Endpoint, Urb, Urb->UrbIsochronousTransfer.StartFrame);
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
urbWork = HCD_AREA(Urb).HcdExtension;
|
|
LOGENTRY(LOG_ISO,'tISw', urbWork->Flags, Urb, urbWork->Slot);
|
|
|
|
//
|
|
// See if we have already initialized this urb
|
|
//
|
|
if (urbWork->Flags & UHCD_TRANSFER_INITIALIZED) {
|
|
goto UHCD_InitializeIsochTransfer_Done;
|
|
}
|
|
|
|
//
|
|
// make sure the transfer is mapped
|
|
//
|
|
if (!(urbWork->Flags & UHCD_TRANSFER_MAPPED)) {
|
|
LOGENTRY(LOG_ISO,'nMpd', urbWork->Flags, Urb, 0);
|
|
goto UHCD_InitializeIsochTransfer_Done;
|
|
}
|
|
|
|
if (Urb->UrbIsochronousTransfer.StartFrame >
|
|
deviceExtension->LastFrameProcessed+1+FRAME_LIST_SIZE-1) {
|
|
|
|
//
|
|
// if the request is too far in the future to schedule
|
|
// TDs then delay initialization, request an interrupt.
|
|
// near a time when we can schedule this transfer.
|
|
//
|
|
|
|
UHCD_RequestInterrupt(DeviceObject, Urb->UrbIsochronousTransfer.StartFrame - 32);
|
|
|
|
LOGENTRY(LOG_ISO,'erly', Urb->UrbIsochronousTransfer.StartFrame,
|
|
deviceExtension->LastFrameProcessed, 0);
|
|
|
|
|
|
goto UHCD_InitializeIsochTransfer_Done;
|
|
}
|
|
|
|
urbWork->Flags |= UHCD_TRANSFER_INITIALIZED;
|
|
Endpoint->TdsScheduled[urbWork->Slot] = 0;
|
|
|
|
//
|
|
// initialize working space variables for this
|
|
// transfer.
|
|
//
|
|
|
|
urbWork->CurrentPacketIdx =
|
|
urbWork->BytesTransferred = 0;
|
|
|
|
urbWork->PacketsProcessed = 0;
|
|
|
|
Urb->UrbIsochronousTransfer.ErrorCount = 0;
|
|
|
|
#if DBG
|
|
i = UHCD_GetCurrentFrame(DeviceObject);
|
|
|
|
LOGENTRY(LOG_ISO,'bISO', i, Urb->UrbIsochronousTransfer.StartFrame, DeviceObject);
|
|
UHCD_KdPrint((2, "'IsochTransfer: start frame = 0x%x current frame = 0x%x\n",
|
|
Urb->UrbIsochronousTransfer.StartFrame, i));
|
|
|
|
#endif
|
|
|
|
UHCD_ScheduleIsochTransfer(DeviceObject,
|
|
Endpoint,
|
|
Urb);
|
|
|
|
UHCD_InitializeIsochTransfer_Done:
|
|
|
|
// UHCD_KdPrint((2, "'exit UHCD_InitializeIsochTransfer\n"));
|
|
|
|
return USBD_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
UHCD_ScheduleIsochTransfer(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PUHCD_ENDPOINT Endpoint,
|
|
IN PHCD_URB Urb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to a device object.
|
|
|
|
Endpoint - Endpoint associated with this Urb.
|
|
|
|
Urb - pointer to URB Request Packet for this transfer.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PHCD_EXTENSION urbWork;
|
|
PHW_TRANSFER_DESCRIPTOR transferDescriptor;
|
|
ULONG i, offset, length;
|
|
ULONG nextPacket;
|
|
PUHCD_TD_LIST urbTDList;
|
|
|
|
//UHCD_KdPrint((2, "'enter UHCD_ScheduleIsochTransfer\n"));
|
|
|
|
ASSERT_ENDPOINT(Endpoint);
|
|
|
|
UHCD_ASSERT(Endpoint->Type == USB_ENDPOINT_TYPE_ISOCHRONOUS);
|
|
UHCD_ASSERT(Endpoint->EndpointFlags & EPFLAG_NO_HALT);
|
|
|
|
LOGENTRY(LOG_ISO,'sISO', Endpoint, Urb, DeviceObject);
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
urbWork = HCD_AREA(Urb).HcdExtension;
|
|
urbTDList = Endpoint->SlotTDList[urbWork->Slot];
|
|
|
|
UHCD_ASSERT(urbWork->Flags & UHCD_TRANSFER_MAPPED);
|
|
|
|
LOGENTRY(LOG_ISO,'sIS2', Endpoint, urbTDList, urbWork->Slot);
|
|
|
|
//
|
|
// If we are done with this transfer just exit
|
|
//
|
|
|
|
if (urbWork->CurrentPacketIdx ==
|
|
Urb->UrbIsochronousTransfer.NumberOfPackets) {
|
|
goto UHCD_ScheduleIsochTransfer_Done;
|
|
}
|
|
|
|
//
|
|
// See if we can put any TDs into the schedule
|
|
//
|
|
|
|
for (i=0; i< Endpoint->TDCount; i++) {
|
|
|
|
//
|
|
// BUGBUG possibly attach TD list to URB
|
|
// for now we share the TDs among mutiple active
|
|
// requests.
|
|
//
|
|
transferDescriptor = &urbTDList->TDs[i];
|
|
|
|
if (transferDescriptor->Frame == 0) {
|
|
|
|
//
|
|
// TD is not in use, go ahead and schedule it
|
|
//
|
|
|
|
LOGENTRY(LOG_ISO,'ISOc', Urb->UrbIsochronousTransfer.StartFrame,
|
|
urbWork->CurrentPacketIdx, deviceExtension->LastFrameProcessed);
|
|
|
|
// See if it is too early to set up this TD
|
|
|
|
if (Urb->UrbIsochronousTransfer.StartFrame + urbWork->CurrentPacketIdx >
|
|
deviceExtension->LastFrameProcessed+1+FRAME_LIST_SIZE-1) {
|
|
LOGENTRY(LOG_ISO,'ISOd', 0, 0, 0);
|
|
|
|
break; // No, stop setting up TDs
|
|
}
|
|
|
|
// prepare the TD for this packet
|
|
transferDescriptor->Active = 1;
|
|
transferDescriptor->Endpoint = Endpoint->EndpointAddress;
|
|
transferDescriptor->Address = Endpoint->DeviceAddress;
|
|
|
|
//
|
|
// Set Pid based on direction
|
|
//
|
|
transferDescriptor->PID = DATA_DIRECTION_IN(Urb) ? USB_IN_PID : USB_OUT_PID;
|
|
|
|
transferDescriptor->Isochronous = 1;
|
|
transferDescriptor->ActualLength =
|
|
UHCD_SYSTEM_TO_USB_BUFFER_LENGTH(0);
|
|
transferDescriptor->StatusField = 0;
|
|
|
|
transferDescriptor->LowSpeedControl = 0;
|
|
transferDescriptor->ReservedMBZ = 0;
|
|
transferDescriptor->ErrorCounter = 0;
|
|
transferDescriptor->RetryToggle = 0;
|
|
|
|
//
|
|
// BUGBUG for now, one every frame
|
|
//
|
|
Endpoint->TdsScheduled[urbWork->Slot]++;
|
|
|
|
transferDescriptor->InterruptOnComplete = 0;
|
|
if (Endpoint->TdsScheduled[urbWork->Slot] >
|
|
(Endpoint->TDCount/2)) {
|
|
transferDescriptor->InterruptOnComplete = 1;
|
|
Endpoint->TdsScheduled[urbWork->Slot] = 0;
|
|
}
|
|
|
|
// request some interrupts near the end
|
|
if (Urb->UrbIsochronousTransfer.NumberOfPackets -
|
|
urbWork->CurrentPacketIdx < 5) {
|
|
transferDescriptor->InterruptOnComplete = 1;
|
|
}
|
|
|
|
transferDescriptor->Frame = Urb->UrbIsochronousTransfer.StartFrame +
|
|
urbWork->CurrentPacketIdx;
|
|
transferDescriptor->Urb = Urb;
|
|
|
|
//
|
|
// Prepare the buffer part of the TD.
|
|
//
|
|
offset =
|
|
Urb->UrbIsochronousTransfer.IsoPacket[urbWork->CurrentPacketIdx].Offset;
|
|
UHCD_ASSERT(urbWork->CurrentPacketIdx <
|
|
Urb->UrbIsochronousTransfer.NumberOfPackets);
|
|
|
|
nextPacket = urbWork->CurrentPacketIdx+1;
|
|
|
|
if (nextPacket >=
|
|
Urb->UrbIsochronousTransfer.NumberOfPackets) {
|
|
// this is the last packet
|
|
length = Urb->UrbIsochronousTransfer.TransferBufferLength -
|
|
offset;
|
|
} else {
|
|
// compute length based on offset of next packet
|
|
UHCD_ASSERT(Urb->UrbIsochronousTransfer.IsoPacket[nextPacket].Offset >
|
|
offset);
|
|
|
|
length = Urb->UrbIsochronousTransfer.IsoPacket[nextPacket].Offset -
|
|
offset;
|
|
}
|
|
|
|
transferDescriptor->PacketBuffer =
|
|
UHCD_GetPacketBuffer(DeviceObject,
|
|
Endpoint,
|
|
Urb,
|
|
urbWork,
|
|
offset,
|
|
length);
|
|
|
|
transferDescriptor->MaxLength =
|
|
UHCD_SYSTEM_TO_USB_BUFFER_LENGTH(length);
|
|
|
|
|
|
//
|
|
// Put the TD in to the schedule at the requested frame.
|
|
//
|
|
|
|
LOG_TD('isTD', transferDescriptor);
|
|
//UHCD_Debug_DumpTD(transferDescriptor);
|
|
|
|
if (transferDescriptor->PacketBuffer) {
|
|
UHCD_ASSERT(urbWork->CurrentPacketIdx <=
|
|
Urb->UrbIsochronousTransfer.NumberOfPackets);
|
|
|
|
UHCD_InsertIsochDescriptor(DeviceObject,
|
|
transferDescriptor,
|
|
Urb->UrbIsochronousTransfer.StartFrame +
|
|
urbWork->CurrentPacketIdx);
|
|
} else {
|
|
TEST_TRAP();
|
|
// failed to get the packet buffer,
|
|
// we set the fields in the TD as
|
|
// if the HC got it, the urb will
|
|
// get updated when the rest of the TDs
|
|
// are processed.
|
|
|
|
// make inactive
|
|
transferDescriptor->Active = 0;
|
|
// mark TD so we know we have a software
|
|
// error
|
|
transferDescriptor->StatusField = 0x3f;
|
|
}
|
|
|
|
urbWork->CurrentPacketIdx++;
|
|
|
|
if (urbWork->CurrentPacketIdx ==
|
|
Urb->UrbIsochronousTransfer.NumberOfPackets) {
|
|
break;
|
|
}
|
|
} /* end td->FRame == 0*/
|
|
} /* end for */
|
|
|
|
UHCD_ScheduleIsochTransfer_Done:
|
|
//UHCD_KdPrint((2, "'exit UHCD_ScheduleIsochTransfer\n"));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
USBD_STATUS
|
|
UHCD_ProcessIsochTransfer(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PUHCD_ENDPOINT Endpoint,
|
|
IN PHCD_URB Urb,
|
|
IN OUT PBOOLEAN Completed
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks to see if an isoch transfer is complete.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to a device object.
|
|
|
|
Endpoint - endpoint to check for completed transfers.
|
|
|
|
Urb - ptr to URB to process.
|
|
|
|
Completed - TRUE if this transfer is complete.
|
|
|
|
Return Value:
|
|
|
|
TRUE if this transfer is complete, Status set to proper
|
|
error code.
|
|
|
|
--*/
|
|
{
|
|
PHCD_EXTENSION urbWork;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PHW_TRANSFER_DESCRIPTOR transferDescriptor;
|
|
ULONG i, packetIdx;
|
|
USBD_STATUS err;
|
|
// PHCD_URB urb;
|
|
USBD_STATUS usbStatus = USBD_STATUS_SUCCESS;
|
|
PUHCD_TD_LIST urbTDList;
|
|
|
|
STARTPROC("Piso");
|
|
|
|
*Completed = FALSE;
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
urbWork = HCD_AREA(Urb).HcdExtension;
|
|
urbTDList = Endpoint->SlotTDList[urbWork->Slot];
|
|
|
|
ASSERT_ENDPOINT(Endpoint);
|
|
|
|
// make sure the urb has been properly initialized
|
|
UHCD_InitializeIsochTransfer(DeviceObject,
|
|
Endpoint,
|
|
Urb);
|
|
|
|
if ((urbWork->Flags & UHCD_TRANSFER_INITIALIZED) == 0) {
|
|
//
|
|
// urb has not been initialized yet, probably too early
|
|
// attempt to initialize now.
|
|
//
|
|
LOGENTRY(LOG_ISO,'npIS', Endpoint, Urb, urbTDList);
|
|
goto UHCD_ProcessIsochTransfer_Done;
|
|
}
|
|
|
|
//
|
|
// walk thru our TD list for this URB retire any TDs
|
|
// that are done.
|
|
//
|
|
LOGENTRY(LOG_ISO,'doIS', Endpoint, urbWork->Slot, urbTDList);
|
|
|
|
for (i=0; i< Endpoint->TDCount; i++) {
|
|
|
|
UHCD_ASSERT(urbTDList->TDs[i].Urb == Urb ||
|
|
urbTDList->TDs[i].Urb == NULL);
|
|
|
|
if (urbTDList->TDs[i].Frame <= deviceExtension->LastFrameProcessed &&
|
|
// only deal with TDs that have been removed
|
|
// from the schedule.
|
|
urbTDList->TDs[i].Frame != 0 &&
|
|
// don't check retired TDs
|
|
urbTDList->TDs[i].Urb == Urb) {
|
|
// only look at TDs for this urb
|
|
|
|
transferDescriptor = &urbTDList->TDs[i];
|
|
|
|
LOGENTRY(LOG_ISO,'piTD', transferDescriptor, transferDescriptor->Frame,
|
|
urbWork->PacketsProcessed);
|
|
|
|
//
|
|
// index for this packet
|
|
//
|
|
packetIdx = transferDescriptor->Frame -
|
|
Urb->UrbIsochronousTransfer.StartFrame;
|
|
|
|
//
|
|
// Update transfer buffer based on data received for
|
|
// this frame.
|
|
//
|
|
|
|
// assume we got no error
|
|
err = Urb->UrbIsochronousTransfer.IsoPacket[packetIdx].Status =
|
|
USBD_STATUS_SUCCESS;
|
|
//
|
|
// see if we got an error.
|
|
//
|
|
|
|
if (transferDescriptor->Active) {
|
|
//
|
|
// if the active bit is still set then we put this transfer
|
|
// in the schedule too late.
|
|
//
|
|
|
|
err = USBD_STATUS_NOT_ACCESSED;
|
|
|
|
deviceExtension->IsoStats.IsoPacketNotAccesed++;
|
|
LOGENTRY(LOG_MISC, 'nPRO', transferDescriptor, transferDescriptor->Frame,
|
|
err);
|
|
// TEST_TRAP();
|
|
} else if (transferDescriptor->StatusField) {
|
|
// BUGBUG map the hardware error
|
|
err = UHCD_MapTDError(deviceExtension, transferDescriptor->StatusField,
|
|
UHCD_USB_TO_SYSTEM_BUFFER_LENGTH(transferDescriptor->ActualLength));
|
|
LOGENTRY(LOG_MISC, 'hERR', transferDescriptor, transferDescriptor->Frame,
|
|
err);
|
|
deviceExtension->IsoStats.IsoPacketHWError++;
|
|
// TEST_TRAP();
|
|
}
|
|
|
|
if (USBD_ERROR(err)) {
|
|
|
|
//
|
|
// Note this error in the error list
|
|
//
|
|
// ErrorList is a list of packet indexes which have an error
|
|
|
|
UHCD_ASSERT(packetIdx <= 255);
|
|
|
|
|
|
Urb->UrbIsochronousTransfer.ErrorCount++;
|
|
|
|
Urb->UrbIsochronousTransfer.IsoPacket[packetIdx].Status = err;
|
|
}
|
|
|
|
// BUGBUG
|
|
// note, we report length even for
|
|
// errors.
|
|
|
|
//
|
|
// keep count the number of bytes succesfully transferred.
|
|
//
|
|
urbWork->BytesTransferred +=
|
|
UHCD_USB_TO_SYSTEM_BUFFER_LENGTH(transferDescriptor->ActualLength);
|
|
//
|
|
// return the length of the packet
|
|
//
|
|
if (USBD_TRANSFER_DIRECTION(
|
|
Urb->UrbIsochronousTransfer.TransferFlags) ==
|
|
USBD_TRANSFER_DIRECTION_IN) {
|
|
|
|
//
|
|
// return the length of the packet
|
|
//
|
|
|
|
Urb->UrbIsochronousTransfer.IsoPacket[packetIdx].Length =
|
|
UHCD_USB_TO_SYSTEM_BUFFER_LENGTH(transferDescriptor->ActualLength);
|
|
|
|
// if the device transmitted < max packet size
|
|
// set the buffer underrun status.
|
|
if (Urb->UrbIsochronousTransfer.IsoPacket[packetIdx].Length <
|
|
Endpoint->MaxPacketSize) {
|
|
Urb->UrbIsochronousTransfer.IsoPacket[packetIdx].Status =
|
|
USBD_STATUS_DATA_UNDERRUN & ~USBD_STATUS_HALTED;
|
|
}
|
|
} else {
|
|
Urb->UrbIsochronousTransfer.IsoPacket[packetIdx].Length = 0;
|
|
}
|
|
|
|
//
|
|
// retire this isoch TD
|
|
//
|
|
transferDescriptor->Frame = 0;
|
|
urbWork->PacketsProcessed++;
|
|
UHCD_ASSERT(urbWork->PacketsProcessed <=
|
|
Urb->UrbIsochronousTransfer.NumberOfPackets);
|
|
}
|
|
|
|
} /* for */
|
|
|
|
//
|
|
// see if we are done with this transfer
|
|
//
|
|
|
|
if (urbWork->PacketsProcessed ==
|
|
Urb->UrbIsochronousTransfer.NumberOfPackets) {
|
|
|
|
//
|
|
// All TDs for this transfer have been processed.
|
|
|
|
LOGENTRY(LOG_MISC, 'iCmp', Urb, 0,
|
|
urbWork->PacketsProcessed);
|
|
|
|
*Completed = TRUE;
|
|
|
|
//
|
|
// Clear the Urb field for all TDs associated with
|
|
// the completing urb
|
|
//
|
|
|
|
for (i=0; i< Endpoint->TDCount; i++) {
|
|
urbTDList->TDs[i].Urb = NULL;
|
|
}
|
|
|
|
//
|
|
// we should return an error if all packets completed with an error.
|
|
//
|
|
|
|
if (Urb->UrbIsochronousTransfer.ErrorCount ==
|
|
Urb->UrbIsochronousTransfer.NumberOfPackets) {
|
|
//
|
|
// Isoch transfer will be failed but isoch
|
|
// errors never stall the endpoint on the host so
|
|
// clear the stall bit now.
|
|
//
|
|
usbStatus = USBD_STATUS_ISOCH_REQUEST_FAILED;
|
|
// clear stall bit
|
|
usbStatus &= ~USBD_STATUS_HALTED;
|
|
|
|
} else {
|
|
usbStatus = USBD_STATUS_SUCCESS;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// not complete yet, put some more TDs in the schedule.
|
|
//
|
|
|
|
//
|
|
// Set up any TDs we still need to complete the
|
|
// current URB
|
|
//
|
|
|
|
UHCD_ScheduleIsochTransfer(DeviceObject,
|
|
Endpoint,
|
|
Urb);
|
|
#if 0
|
|
//
|
|
// some preprocessing code, try to start up the next transfer here
|
|
//
|
|
// NOTE: this will kick in close to the end of the current transfer
|
|
//
|
|
|
|
UHCD_ASSERT(Endpoint->MaxRequests == 2);
|
|
|
|
// this trick only works if maxrequests is 2
|
|
i = !urbWork->Slot;
|
|
urb = Endpoint->ActiveTransfers[i];
|
|
|
|
//
|
|
// When we near the end of this transfer we want to start the next one
|
|
//
|
|
|
|
//BUGBUG
|
|
// should be when numpackets - packetsprocessed < numTds
|
|
// ie there are some extra
|
|
// Urb->UrbIsochronousTransfer.NumberOfPackets -
|
|
// urbWork->PacketsProcessed < NUM_TDS_PER_ENDPOINT
|
|
if (urbWork->PacketsProcessed > Urb->UrbIsochronousTransfer.NumberOfPackets-
|
|
8
|
|
&& urb != NULL) {
|
|
|
|
UHCD_KdPrint((2, "'process next iso urb from ProcessIsochTransfer\n"));
|
|
|
|
LOGENTRY(LOG_ISO,'iPRE', urb, &Endpoint->PendingTransferList, Endpoint);
|
|
|
|
UHCD_InitializeIsochTransfer(DeviceObject,
|
|
Endpoint,
|
|
urb);
|
|
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
UHCD_ProcessIsochTransfer_Done:
|
|
|
|
ENDPROC("pIso");
|
|
|
|
return usbStatus;
|
|
}
|