Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2076 lines
57 KiB

/*++
Copyright (c) 1999, 2000 Microsoft Corporation
Module Name:
iso.c
Abstract:
miniport transfer code for interrupt endpoints
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, 2000 Microsoft Corporation. All Rights Reserved.
Revision History:
1-1-01 : created, jdunn
--*/
#include "common.h"
/*
We build a table of 32 TDs for iso endpoints and insert them in the
schedule, these TDs are static -- we only change the buffer pointers.
The TD 'table' represents a 32ms snapshot of time.
We end up with each iso endpoint siTD list as a column in the table
frame dummyQH iso1 iso2 iso3 staticQH
1 | | | |---> (periodic lists)
2 | | | |
3 | | | |
4 | | | |
... | | | |
| | | |
1024 | | | |
*/
#define ISO_SCHEDULE_SIZE 32
#define ISO_SCHEDULE_MASK 0x1f
#define HIGHSPEED(ed) ((ed)->Parameters.DeviceSpeed == HighSpeed ? TRUE : FALSE)
VOID
EHCI_RebalanceIsoEndpoint(
PDEVICE_DATA DeviceData,
PENDPOINT_PARAMETERS EndpointParameters,
PENDPOINT_DATA EndpointData
)
/*++
Routine Description:
compute how much common buffer we will need
for this endpoint
Arguments:
Return Value:
--*/
{
PHCD_SI_TRANSFER_DESCRIPTOR siTd;
ULONG i, f;
ULONG currentFrame;
currentFrame = EHCI_Get32BitFrameNumber(DeviceData);
// should only have to deal with s-mask and c-mask changes
EHCI_ASSERT(DeviceData, !HIGHSPEED(EndpointData));
//NOTE: irql should be raised for us
// update internal copy of parameters
EndpointData->Parameters = *EndpointParameters;
f = currentFrame & ISO_SCHEDULE_MASK;
for (i=0; i<EndpointData->TdCount; i++) {
siTd = &EndpointData->SiTdList->Td[f];
siTd->HwTD.Control.cMask =
EndpointParameters->SplitCompletionMask;
siTd->HwTD.Control.sMask =
EndpointParameters->InterruptScheduleMask;
f++;
f &= ISO_SCHEDULE_MASK;
}
}
VOID
EHCI_InitializeSiTD(
PDEVICE_DATA DeviceData,
PENDPOINT_DATA EndpointData,
PENDPOINT_PARAMETERS EndpointParameters,
PHCD_SI_TRANSFER_DESCRIPTOR SiTd,
PHCD_SI_TRANSFER_DESCRIPTOR PrevSiTd,
HW_32BIT_PHYSICAL_ADDRESS PhysicalAddress
)
/*++
Routine Description:
Initailze a static SiTD for an endpoint
Arguments:
Return Value:
none
--*/
{
SiTd->Sig = SIG_HCD_SITD;
SiTd->PhysicalAddress = PhysicalAddress;
ISO_PACKET_PTR(SiTd->Packet) = NULL;
SiTd->HwTD.Caps.ul = 0;
SiTd->HwTD.Caps.DeviceAddress =
EndpointParameters->DeviceAddress;
SiTd->HwTD.Caps.EndpointNumber =
EndpointParameters->EndpointAddress;
SiTd->HwTD.Caps.HubAddress =
EndpointParameters->TtDeviceAddress;
SiTd->HwTD.Caps.PortNumber =
EndpointParameters->TtPortNumber;
// 1 = IN 0 = OUT
SiTd->HwTD.Caps.Direction =
(EndpointParameters->TransferDirection == In) ? 1 : 0;
SiTd->HwTD.Control.ul = 0;
SiTd->HwTD.Control.cMask =
EndpointParameters->SplitCompletionMask;
SiTd->HwTD.Control.sMask =
EndpointParameters->InterruptScheduleMask;
SiTd->HwTD.BackPointer.HwAddress =
PrevSiTd->PhysicalAddress;
SiTd->HwTD.State.ul = 0;
}
VOID
EHCI_InsertIsoTdsInSchedule(
PDEVICE_DATA DeviceData,
PENDPOINT_DATA EndpointData,
PENDPOINT_DATA PrevEndpointData,
PENDPOINT_DATA NextEndpointData
)
/*++
Routine Description:
Insert an aync endpoint (queue head)
into the HW list
schedule should look like:
DUMMYQH->ISOQH-ISOQH->INTQH
Arguments:
--*/
{
//PHW_32BIT_PHYSICAL_ADDRESS frameBase;
ULONG i;
LOGENTRY(DeviceData, G, '_iAD', PrevEndpointData,
NextEndpointData, EndpointData);
//frameBase = DeviceData->FrameListBaseAddress;
for (i=0; i<USBEHCI_MAX_FRAME; i++) {
PHCD_SI_TRANSFER_DESCRIPTOR siTd, nextSiTd;
PHCD_QUEUEHEAD_DESCRIPTOR qh;
PHCD_QUEUEHEAD_DESCRIPTOR dQh;
ULONG phys;
siTd = &EndpointData->SiTdList->Td[i&0x1f];
// fixup next link
if (NextEndpointData == NULL &&
PrevEndpointData == NULL) {
// list empty add to head
if (i == 0) {
EHCI_ASSERT(DeviceData, DeviceData->IsoEndpointListHead == NULL);
DeviceData->IsoEndpointListHead = EndpointData;
EndpointData->PrevEndpoint = NULL;
EndpointData->NextEndpoint = NULL;
}
// list empty add to head
// no iso endpoints, link to the interrupt
// queue heads via the dummy qh
//
// point at the static perodic queue head pointed to
// by the appropriate dummy
// DUMMY->INTQH
// to
// ISOTD->INTQH
dQh = EHCI_GetDummyQueueHeadForFrame(DeviceData, i);
siTd->HwTD.NextLink.HwAddress = dQh->HwQH.HLink.HwAddress;
HW_PTR(siTd->NextLink) = HW_PTR(dQh->NextLink);
phys = siTd->PhysicalAddress;
SET_SITD(phys);
//
// appropriate dummy should point to these TDs
// DUMMY->INTQH, ISOTD->INTQH
// to
// DUMMY->ISOTD->INTQH
dQh = EHCI_GetDummyQueueHeadForFrame(DeviceData, i);
dQh->HwQH.HLink.HwAddress = phys;
HW_PTR(dQh->NextLink) = (PUCHAR) siTd;
} else {
if (NextEndpointData == NULL) {
// tail of list, list not empty
// add to tail
if (i == 0) {
EHCI_ASSERT(DeviceData, PrevEndpointData != NULL);
EHCI_ASSERT(DeviceData, DeviceData->IsoEndpointListHead != NULL);
PrevEndpointData->NextEndpoint = EndpointData;
EndpointData->PrevEndpoint = PrevEndpointData;
EndpointData->NextEndpoint = NULL;
}
LOGENTRY(DeviceData, G, '_iTL', PrevEndpointData,
NextEndpointData, EndpointData);
// tail of list, link to qh
// ISOTD->INTQH
// to
// ISOTD->newISOTD->INTQH
//
if (HIGHSPEED(PrevEndpointData)) {
PHCD_HSISO_TRANSFER_DESCRIPTOR previTd;
PUCHAR next;
previTd = &PrevEndpointData->HsIsoTdList->Td[i];
ASSERT_ITD(DeviceData, previTd);
siTd = &EndpointData->SiTdList->Td[i&0x1f];
ASSERT_SITD(DeviceData, siTd);
// fixup current next ptr
phys = previTd->HwTD.NextLink.HwAddress;
next = HW_PTR(previTd->NextLink);
siTd->HwTD.NextLink.HwAddress = phys;
HW_PTR(siTd->NextLink) = next;
// fixup prev next ptr
HW_PTR(previTd->NextLink) = (PUCHAR) siTd;
phys = siTd->PhysicalAddress;
SET_SITD(phys);
previTd->HwTD.NextLink.HwAddress = phys;
} else {
PHCD_SI_TRANSFER_DESCRIPTOR prevSiTd;
PUCHAR next;
prevSiTd = &PrevEndpointData->SiTdList->Td[i&0x1f];
ASSERT_SITD(DeviceData, prevSiTd);
siTd = &EndpointData->SiTdList->Td[i&0x1f];
ASSERT_SITD(DeviceData, siTd);
if (i<32) {
//newISOTD->INTQH
phys = prevSiTd->HwTD.NextLink.HwAddress;
next = HW_PTR(prevSiTd->NextLink);
siTd->HwTD.NextLink.HwAddress = phys;
HW_PTR(siTd->NextLink) = next;
LOGENTRY(DeviceData, G, '_in1', phys, next, siTd);
//ISOTD->newISOTD
phys = siTd->PhysicalAddress;
SET_SITD(phys);
next = (PUCHAR) siTd;
prevSiTd->HwTD.NextLink.HwAddress = phys;
HW_PTR(prevSiTd->NextLink) = next;
LOGENTRY(DeviceData, G, '_in2', phys, next, siTd);
}
}
// add to tail
} else {
// list not empty, not tail
// add to middle OR head
//
// link to the next iso endpoint
// ISOTD->INTQH
// to
// newISOTD->ISOTD->INTQH
if (i == 0) {
EHCI_ASSERT(DeviceData, NextEndpointData != NULL);
EndpointData->NextEndpoint = NextEndpointData;
NextEndpointData->PrevEndpoint = EndpointData;
}
// link to next
nextSiTd = &NextEndpointData->SiTdList->Td[i&0x1f];
phys = nextSiTd->PhysicalAddress;
SET_SITD(phys);
// link to the next iso endpoint
siTd->HwTD.NextLink.HwAddress = phys;
HW_PTR(siTd->NextLink) = (PUCHAR) nextSiTd;
// link to prev
if (PrevEndpointData != NULL) {
// middle
// ISOTD->ISOTD->INTQH, newISOTD->ISOTD->INTQH
// to
// ISOTD->newISOTD->ISOTD->INTQH
if (i == 0) {
PrevEndpointData->NextEndpoint = EndpointData;
EndpointData->PrevEndpoint = PrevEndpointData;
}
if (HIGHSPEED(PrevEndpointData)) {
PHCD_HSISO_TRANSFER_DESCRIPTOR previTd;
previTd = &PrevEndpointData->HsIsoTdList->Td[i];
ASSERT_ITD(DeviceData, previTd);
siTd = &EndpointData->SiTdList->Td[i&0x1f];
ASSERT_SITD(DeviceData, siTd);
phys = siTd->PhysicalAddress;
SET_SITD(phys);
previTd->HwTD.NextLink.HwAddress = phys;
HW_PTR(previTd->NextLink) = (PUCHAR) siTd;
} else {
PHCD_SI_TRANSFER_DESCRIPTOR prevSiTd;
prevSiTd = &PrevEndpointData->SiTdList->Td[i&0x1f];
ASSERT_SITD(DeviceData, prevSiTd);
siTd = &EndpointData->SiTdList->Td[i&0x1f];
ASSERT_SITD(DeviceData, siTd);
phys = siTd->PhysicalAddress;
SET_SITD(phys);
prevSiTd->HwTD.NextLink.HwAddress = phys;
HW_PTR(prevSiTd->NextLink) = (PUCHAR)siTd;
}
} else {
// head of list, list not empty
if (i == 0) {
EHCI_ASSERT(DeviceData, NextEndpointData != NULL);
EHCI_ASSERT(DeviceData, NextEndpointData ==
DeviceData->IsoEndpointListHead);
DeviceData->IsoEndpointListHead = EndpointData;
EndpointData->PrevEndpoint = NULL;
}
phys = siTd->PhysicalAddress;
SET_SITD(phys);
// head of list, link to Dummy QH
//
// appropriate dummy should point to these TDs
// DUMMY->ISOTD->INTQH, newISOTD->ISOTD->INTQH
// to
// DUMMY->newISOTD->ISOTD->INTQH
dQh = EHCI_GetDummyQueueHeadForFrame(DeviceData, i);
dQh->HwQH.HLink.HwAddress = phys;
HW_PTR(dQh->NextLink) = (PUCHAR) siTd;
}
}
} // not empty
}
}
VOID
EHCI_RemoveIsoTdsFromSchedule(
PDEVICE_DATA DeviceData,
PENDPOINT_DATA EndpointData
)
/*++
Routine Description:
unlink the iso TDs from the schedule
Arguments:
--*/
{
ULONG i;
PENDPOINT_DATA prevEndpoint, nextEndpoint;
PHCD_QUEUEHEAD_DESCRIPTOR dQh;
prevEndpoint = EndpointData->PrevEndpoint;
nextEndpoint = EndpointData->NextEndpoint;
LOGENTRY(DeviceData, G, '_iRM', prevEndpoint,
nextEndpoint, EndpointData);
if (DeviceData->IsoEndpointListHead == EndpointData) {
// this is the head
for (i=0; i<USBEHCI_MAX_FRAME; i++) {
PHCD_SI_TRANSFER_DESCRIPTOR siTd;
ULONG phys;
siTd = &EndpointData->SiTdList->Td[i&0x1f];
phys = siTd->HwTD.NextLink.HwAddress;
dQh = EHCI_GetDummyQueueHeadForFrame(DeviceData, i);
dQh->HwQH.HLink.HwAddress = phys;
HW_PTR(dQh->NextLink) = HW_PTR(siTd->NextLink);
}
DeviceData->IsoEndpointListHead =
EndpointData->NextEndpoint;
if (nextEndpoint != NULL) {
EHCI_ASSERT(DeviceData,
nextEndpoint->PrevEndpoint == EndpointData);
nextEndpoint->PrevEndpoint = NULL;
}
} else {
// middle or tail
EHCI_ASSERT(DeviceData, prevEndpoint != NULL);
if (HIGHSPEED(prevEndpoint)) {
for (i=0; i<USBEHCI_MAX_FRAME; i++) {
PHCD_HSISO_TRANSFER_DESCRIPTOR previTd;
PHCD_SI_TRANSFER_DESCRIPTOR siTd;
ULONG phys;
siTd = &EndpointData->SiTdList->Td[i&0x1f];
previTd = &prevEndpoint->HsIsoTdList->Td[i];
phys = siTd->HwTD.NextLink.HwAddress;
previTd->HwTD.NextLink.HwAddress = phys;
HW_PTR(previTd->NextLink) = HW_PTR(siTd->NextLink);
}
prevEndpoint->NextEndpoint =
EndpointData->NextEndpoint;
if (nextEndpoint) {
nextEndpoint->PrevEndpoint = prevEndpoint;
}
} else {
for (i=0; i<ISO_SCHEDULE_SIZE; i++) {
PHCD_SI_TRANSFER_DESCRIPTOR siTd, prevSiTd;
ULONG phys;
siTd = &EndpointData->SiTdList->Td[i];
prevSiTd = &prevEndpoint->SiTdList->Td[i];
phys = siTd->HwTD.NextLink.HwAddress;
prevSiTd->HwTD.NextLink.HwAddress = phys;
HW_PTR(prevSiTd->NextLink) = HW_PTR(siTd->NextLink);
}
prevEndpoint->NextEndpoint =
EndpointData->NextEndpoint;
if (nextEndpoint) {
nextEndpoint->PrevEndpoint = prevEndpoint;
}
}
}
}
USB_MINIPORT_STATUS
EHCI_OpenIsochronousEndpoint(
PDEVICE_DATA DeviceData,
PENDPOINT_PARAMETERS EndpointParameters,
PENDPOINT_DATA EndpointData
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PUCHAR buffer;
HW_32BIT_PHYSICAL_ADDRESS phys;
ULONG i;
ULONG bytes;
PHW_32BIT_PHYSICAL_ADDRESS frameBase;
PENDPOINT_DATA prevEndpoint, nextEndpoint;
LOGENTRY(DeviceData, G, '_opR', 0, 0, EndpointParameters);
buffer = EndpointParameters->CommonBufferVa;
phys = EndpointParameters->CommonBufferPhys;
// how much did we get
bytes = EndpointParameters->CommonBufferBytes;
EndpointData->SiTdList = (PHCD_SITD_LIST) buffer;
// bugbug use manifest
EndpointData->TdCount = ISO_SCHEDULE_SIZE;
EndpointData->LastFrame = 0;
for (i=0; i<EndpointData->TdCount; i++) {
EHCI_InitializeSiTD(DeviceData,
EndpointData,
EndpointParameters,
&EndpointData->SiTdList->Td[i],
i > 0 ?
&EndpointData->SiTdList->Td[i-1] :
&EndpointData->SiTdList->Td[EndpointData->TdCount-1],
phys);
phys += sizeof(HCD_SI_TRANSFER_DESCRIPTOR);
}
EndpointData->SiTdList->Td[0].HwTD.BackPointer.HwAddress =
EndpointData->SiTdList->Td[EndpointData->TdCount-1].PhysicalAddress;
// split iso eps are inserted after any high speed eps
if (DeviceData->IsoEndpointListHead == NULL) {
// empty list
prevEndpoint = NULL;
nextEndpoint = NULL;
} else {
prevEndpoint = NULL;
nextEndpoint = DeviceData->IsoEndpointListHead;
// walk the list to the first non HS ep or to
// a NULL
while (nextEndpoint != NULL &&
HIGHSPEED(nextEndpoint)) {
prevEndpoint = nextEndpoint;
nextEndpoint = prevEndpoint->NextEndpoint;
}
if (nextEndpoint != NULL) {
//
// nextEndpoint is first non high speed endpoint
// see what order it sould be added
if (EndpointData->Parameters.Ordinal == 1) {
// ordinal 1 add after this one
prevEndpoint = nextEndpoint;
nextEndpoint = prevEndpoint->NextEndpoint;
}
}
}
// insert this column of TDs thru the schedule
EHCI_InsertIsoTdsInSchedule(DeviceData,
EndpointData,
prevEndpoint,
nextEndpoint);
// init endpoint structures
InitializeListHead(&EndpointData->TransferList);
EHCI_EnablePeriodicList(DeviceData);
return USBMP_STATUS_SUCCESS;
}
VOID
EHCI_MapIsoPacketToTd(
PDEVICE_DATA DeviceData,
PENDPOINT_DATA EndpointData,
PMINIPORT_ISO_PACKET Packet,
PHCD_SI_TRANSFER_DESCRIPTOR SiTd
)
/*++
Routine Description:
Arguments:
Returns:
--*/
{
ULONG length;
LOGENTRY(DeviceData, G, '_mpI', SiTd, 0, Packet);
SiTd->HwTD.State.ul = 0;
SiTd->HwTD.BufferPointer0.ul = 0;
SiTd->HwTD.BufferPointer1.ul = 0;
SiTd->HwTD.BufferPointer0.ul =
Packet->BufferPointer0.Hw32;
length = Packet->BufferPointer0Length;
SiTd->StartOffset = SiTd->HwTD.BufferPointer0.CurrentOffset;
SiTd->HwTD.BufferPointer1.ul = 0;
if (Packet->BufferPointerCount > 1) {
EHCI_ASSERT(DeviceData,
(Packet->BufferPointer1.Hw32 & 0xFFF) == 0);
SiTd->HwTD.BufferPointer1.ul =
Packet->BufferPointer1.Hw32;
length += Packet->BufferPointer1Length;
}
// not sure if this is corrext for IN
SiTd->HwTD.BufferPointer1.Tposition = TPOS_ALL;
if (EndpointData->Parameters.TransferDirection == Out) {
if (length == 0) {
SiTd->HwTD.BufferPointer1.Tcount = 1;
} else {
SiTd->HwTD.BufferPointer1.Tcount = ((length -1) / 188) +1;
}
if (SiTd->HwTD.BufferPointer1.Tcount == 1) {
SiTd->HwTD.BufferPointer1.Tposition = TPOS_ALL;
} else {
SiTd->HwTD.BufferPointer1.Tposition = TPOS_BEGIN;
}
EHCI_ASSERT(DeviceData, SiTd->HwTD.BufferPointer1.Tcount <= 6);
} else {
SiTd->HwTD.BufferPointer1.Tcount = 0;
}
SiTd->HwTD.State.BytesToTransfer = length;
SiTd->HwTD.State.Active = 1;
SiTd->HwTD.State.InterruptOnComplete = 1;
EHCI_ASSERT(DeviceData, SiTd->HwTD.BackPointer.HwAddress != 0);
}
VOID
EHCI_CompleteIsoPacket(
PDEVICE_DATA DeviceData,
PMINIPORT_ISO_PACKET Packet,
PHCD_SI_TRANSFER_DESCRIPTOR SiTd
)
/*++
Routine Description:
Arguments:
Returns:
--*/
{
ULONG length;
ULONG cf = EHCI_Get32BitFrameNumber(DeviceData);
LOGENTRY(DeviceData, G, '_cpI', Packet, SiTd, cf);
if (SiTd->HwTD.State.Active == 1) {
// missed
Packet->LengthTransferred = 0;
LOGENTRY(DeviceData, G, '_cms',
Packet,
0,
Packet->FrameNumber);
} else {
//length = SiTd->HwTD.BufferPointer0.CurrentOffset -
// SiTd->StartOffset;
//LOGENTRY(DeviceData, G, '_cp2',
// Packet->FrameNumber,
// SiTd->HwTD.BufferPointer0.CurrentOffset,
// SiTd->StartOffset);
length = Packet->Length - SiTd->HwTD.State.BytesToTransfer;
LOGENTRY(DeviceData, G, '_cp3',
Packet->FrameNumber,
Packet->Length ,
SiTd->HwTD.State.BytesToTransfer);
Packet->LengthTransferred = length;
LOGENTRY(DeviceData, G, '_cpL', Packet, SiTd, length);
}
//Packet->LengthTransferred = 928;
// map status
LOGENTRY(DeviceData, G, '_cpS', Packet, SiTd->HwTD.State.ul,
Packet->UsbdStatus);
Packet->UsbdStatus = USBD_STATUS_SUCCESS;
}
PMINIPORT_ISO_PACKET
EHCI_GetPacketForFrame(
PDEVICE_DATA DeviceData,
PENDPOINT_DATA EndpointData,
PTRANSFER_CONTEXT *Transfer,
ULONG Frame
)
/*++
Routine Description:
fetch the iso packet associated with the given frame
if we have one in our current transfer list
Arguments:
Returns:
--*/
{
ULONG i;
PLIST_ENTRY listEntry;
listEntry = EndpointData->TransferList.Flink;
while (listEntry != &EndpointData->TransferList) {
PTRANSFER_CONTEXT transfer;
transfer = (PTRANSFER_CONTEXT) CONTAINING_RECORD(
listEntry,
struct _TRANSFER_CONTEXT,
TransferLink);
ASSERT_TRANSFER(DeviceData, transfer);
if (Frame <= transfer->FrameComplete) {
for(i=0; i<transfer->IsoTransfer->PacketCount; i++) {
if (transfer->IsoTransfer->Packets[i].FrameNumber == Frame) {
*Transfer = transfer;
return &transfer->IsoTransfer->Packets[i];
}
}
}
listEntry = transfer->TransferLink.Flink;
}
return NULL;
}
ULONG xCount = 0;
ULONG pCount = 0;
VOID
EHCI_InternalPollIsoEndpoint(
PDEVICE_DATA DeviceData,
PENDPOINT_DATA EndpointData,
BOOLEAN Complete
)
/*++
Routine Description:
Called when the endpoint 'needs attention'
static iso TD table
--------------------
0 < -- (lastFrame & 0x1f)
1 {completed}
2 {completed}
3 {limbo}
4 < -- (currentframe & 0x1f)
...
31
---------------------
Arguments:
Return Value:
--*/
{
ULONG x, i;
ULONG currentFrame, lastFrame;
PHCD_SI_TRANSFER_DESCRIPTOR siTd;
PMINIPORT_ISO_PACKET packet;
PLIST_ENTRY listEntry;
PTRANSFER_CONTEXT transfer;
ULONG transfersPending, fc;
currentFrame = EHCI_Get32BitFrameNumber(DeviceData);
lastFrame = EndpointData->LastFrame;
LOGENTRY(DeviceData, G, '_pis', lastFrame, currentFrame,
EndpointData);
// if (pCount > 60) {
// TEST_TRAP();
// }
if (currentFrame - lastFrame > ISO_SCHEDULE_SIZE) {
// overrun
lastFrame = currentFrame-1;
LOGENTRY(DeviceData, G, '_ove', lastFrame, currentFrame, 0);
// dump the current contents
for (i = 0; i <ISO_SCHEDULE_SIZE; i++) {
siTd = &EndpointData->SiTdList->Td[i];
transfer = ISO_TRANSFER_PTR(siTd->Transfer);
if (transfer != NULL) {
ISO_PACKET_PTR(siTd->Packet) = NULL;
ISO_TRANSFER_PTR(siTd->Transfer) = NULL;
transfer->PendingPackets--;
}
}
}
if (lastFrame == currentFrame) {
// too early to do anything
LOGENTRY(DeviceData, G, '_ear', lastFrame, currentFrame, 0);
return;
}
// TDs between lastframe and currentframe are complete,
// complete the packets associated with them
// f0
// f1
// f2 < ------- last frame }
// f3 } these are complete
// f4 <- backpointer may still be pointing here
// f5 < ------- current frame
// f6
// f7
// f8
x = (lastFrame & (ISO_SCHEDULE_MASK));
LOGENTRY(DeviceData, G, '_frm', lastFrame, x, currentFrame);
while (x != ((currentFrame-1) & ISO_SCHEDULE_MASK)) {
siTd = &EndpointData->SiTdList->Td[x];
ASSERT_SITD(DeviceData, siTd);
// complete this packet
packet = ISO_PACKET_PTR(siTd->Packet);
transfer = ISO_TRANSFER_PTR(siTd->Transfer);
LOGENTRY(DeviceData, G, '_gpk', transfer, packet, x);
if (packet != NULL) {
transfer = ISO_TRANSFER_PTR(siTd->Transfer);
ASSERT_TRANSFER(DeviceData, transfer);
EHCI_CompleteIsoPacket(DeviceData, packet, siTd);
ISO_PACKET_PTR(siTd->Packet) = NULL;
ISO_TRANSFER_PTR(siTd->Transfer) = NULL;
transfer->PendingPackets--;
}
lastFrame++;
x++;
x &= ISO_SCHEDULE_MASK;
}
// attempt to program what we can, if siTD is NULL
// then we can program this frame
// NOTE: No scheduling if paused!
if (EndpointData->State != ENDPOINT_PAUSE) {
LOGENTRY(DeviceData, G, '_psh', 0, 0, 0);
for (i=0; i <ISO_SCHEDULE_SIZE; i++) {
x = ((currentFrame+i) & ISO_SCHEDULE_MASK);
siTd = &EndpointData->SiTdList->Td[x];
ASSERT_SITD(DeviceData, siTd);
LOGENTRY(DeviceData, G, '_gpf', siTd, x, currentFrame+i);
// open slot?
if (ISO_PACKET_PTR(siTd->Packet) != NULL) {
// no, bail
continue;
}
// yes, see if we have a packet
packet = EHCI_GetPacketForFrame(DeviceData,
EndpointData,
&transfer,
currentFrame+i);
if (packet != NULL) {
EHCI_ASSERT(DeviceData, ISO_PACKET_PTR(siTd->Packet) == NULL);
EHCI_MapIsoPacketToTd(DeviceData, EndpointData,
packet, siTd);
ISO_PACKET_PTR(siTd->Packet) = packet;
ASSERT_TRANSFER(DeviceData, transfer);
ISO_TRANSFER_PTR(siTd->Transfer) = transfer;
transfer->PendingPackets++;
}
}
}
EHCI_ASSERT(DeviceData, lastFrame < currentFrame);
EndpointData->LastFrame = lastFrame;
// walk our list of active iso transfers and see
// if any are complete
listEntry = EndpointData->TransferList.Flink;
transfersPending = 0;
while (listEntry != &EndpointData->TransferList && Complete) {
PTRANSFER_CONTEXT transfer;
transfer = (PTRANSFER_CONTEXT) CONTAINING_RECORD(
listEntry,
struct _TRANSFER_CONTEXT,
TransferLink);
LOGENTRY(DeviceData, G, '_ckt', transfer, transfer->FrameComplete+2
, currentFrame);
EHCI_ASSERT(DeviceData, transfer->Sig == SIG_EHCI_TRANSFER);
if (currentFrame >= transfer->FrameComplete + 2 &&
transfer->PendingPackets == 0) {
listEntry = transfer->TransferLink.Flink;
RemoveEntryList(&transfer->TransferLink);
LOGENTRY(DeviceData, G, '_cpi', transfer, 0, 0);
// if (xCount==2) {
// TEST_TRAP();
//}
USBPORT_COMPLETE_ISO_TRANSFER(DeviceData,
EndpointData,
transfer->TransferParameters,
transfer->IsoTransfer);
} else {
transfersPending++;
fc = transfer->FrameComplete;
listEntry = transfer->TransferLink.Flink;
}
}
currentFrame = EHCI_Get32BitFrameNumber(DeviceData);
if (transfersPending == 1 &&
fc >= currentFrame &&
(fc - currentFrame) < 2 ) {
LOGENTRY(DeviceData, G, '_rei', fc, currentFrame, 0);
EHCI_InterruptNextSOF(DeviceData);
}
}
VOID
EHCI_PollIsoEndpoint(
PDEVICE_DATA DeviceData,
PENDPOINT_DATA EndpointData
)
{
LOGENTRY(DeviceData, G, '_ipl', 0, 0, 0);
if (!IsListEmpty(&EndpointData->TransferList)) {
LOGENTRY(DeviceData, G, '_III', 0, 0, 0);
if (HIGHSPEED(EndpointData)) {
EHCI_InternalPollHsIsoEndpoint(DeviceData, EndpointData, TRUE);
} else {
EHCI_InternalPollIsoEndpoint(DeviceData, EndpointData, TRUE);
}
}
}
USB_MINIPORT_STATUS
EHCI_AbortIsoTransfer(
PDEVICE_DATA DeviceData,
PENDPOINT_DATA EndpointData,
PTRANSFER_CONTEXT TransferContext
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
ULONG i;
// iso TD table should be idle at this point all we
// need to do is make sure we have no TDs still pointing
// at this transfer and remove it frome any internal
// queues
if (HIGHSPEED(EndpointData)) {
for (i = 0; i <USBEHCI_MAX_FRAME; i++) {
PHCD_HSISO_TRANSFER_DESCRIPTOR hsIsoTd;
ULONG period = EndpointData->Parameters.Period;
LOGENTRY(DeviceData, G, '_ibh', TransferContext,
EndpointData, period);
hsIsoTd = &EndpointData->HsIsoTdList->Td[i];
if (ISO_TRANSFER_PTR(hsIsoTd->Transfer) == TransferContext) {
ISO_TRANSFER_PTR(hsIsoTd->Transfer) = NULL;
ISO_PACKET_PTR(hsIsoTd->FirstPacket) = NULL;
TransferContext->PendingPackets -= (8/period);
}
}
} else {
for (i = 0; i <ISO_SCHEDULE_SIZE; i++) {
PHCD_SI_TRANSFER_DESCRIPTOR siTd;
LOGENTRY(DeviceData, G, '_ibi', TransferContext,
EndpointData, 1);
siTd = &EndpointData->SiTdList->Td[i];
if (ISO_TRANSFER_PTR(siTd->Transfer) == TransferContext) {
ISO_TRANSFER_PTR(siTd->Transfer) = NULL;
ISO_PACKET_PTR(siTd->Packet) = NULL;
TransferContext->PendingPackets--;
}
}
}
EHCI_ASSERT(DeviceData, TransferContext->TransferLink.Flink != NULL);
EHCI_ASSERT(DeviceData, TransferContext->TransferLink.Blink != NULL);
// remove this transfer from our lists
RemoveEntryList(&TransferContext->TransferLink);
TransferContext->TransferLink.Flink = NULL;
TransferContext->TransferLink.Blink = NULL;
return USBMP_STATUS_SUCCESS;
}
USB_MINIPORT_STATUS
EHCI_SubmitIsoTransfer(
PDEVICE_DATA DeviceData,
PENDPOINT_DATA EndpointData,
PTRANSFER_PARAMETERS TransferParameters,
PTRANSFER_CONTEXT TransferContext,
PMINIPORT_ISO_TRANSFER IsoTransfer
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
// init the structures and queue the endpoint
LOGENTRY(DeviceData, G, '_ISO', TransferContext, 0, 0);
RtlZeroMemory(TransferContext, sizeof(TRANSFER_CONTEXT));
TransferContext->Sig = SIG_EHCI_TRANSFER;
TransferContext->IsoTransfer = IsoTransfer;
TransferContext->EndpointData = EndpointData;
TransferContext->TransferParameters = TransferParameters;
if (HIGHSPEED(EndpointData)) {
TransferContext->FrameComplete =
IsoTransfer->Packets[0].FrameNumber + IsoTransfer->PacketCount/8;
} else {
TransferContext->FrameComplete =
IsoTransfer->Packets[0].FrameNumber + IsoTransfer->PacketCount;
}
TransferContext->PendingPackets = 0;
// if queues are empty the go ahead and reset the table
// so we can fill now
if (IsListEmpty(&EndpointData->TransferList)) {
EndpointData->LastFrame = 0;
LOGENTRY(DeviceData, G, '_rsi', 0, 0, 0);
}
InsertTailList(&EndpointData->TransferList,
&TransferContext->TransferLink);
// scehdule the initial part of the transfer if
// possible
if (HIGHSPEED(EndpointData)) {
EHCI_InternalPollHsIsoEndpoint(DeviceData,
EndpointData,
FALSE);
} else {
EHCI_InternalPollIsoEndpoint(DeviceData,
EndpointData,
FALSE);
}
xCount++;
//if (xCount==2) {
// TEST_TRAP();
//}
return USBMP_STATUS_SUCCESS;
}
VOID
EHCI_SetIsoEndpointState(
PDEVICE_DATA DeviceData,
PENDPOINT_DATA EndpointData,
MP_ENDPOINT_STATE State
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
ENDPOINT_TRANSFER_TYPE epType;
ULONG i, j;
epType = EndpointData->Parameters.TransferType;
EHCI_ASSERT(DeviceData, epType == Isochronous);
switch(State) {
case ENDPOINT_ACTIVE:
EndpointData->LastFrame = EHCI_Get32BitFrameNumber(DeviceData);
break;
case ENDPOINT_PAUSE:
// clear the active bit on all TDs
if (HIGHSPEED(EndpointData)) {
for (i=0; i<EndpointData->TdCount; i++) {
for(j=0; j<8; j++) {
EndpointData->HsIsoTdList->Td[i].HwTD.Transaction[j].Active = 0;
}
}
} else {
for (i=0; i<EndpointData->TdCount; i++) {
EndpointData->SiTdList->Td[i].HwTD.State.Active = 0;
}
}
break;
case ENDPOINT_REMOVE:
if (HIGHSPEED(EndpointData)) {
EHCI_RemoveHsIsoTdsFromSchedule(DeviceData,
EndpointData);
} else {
EHCI_RemoveIsoTdsFromSchedule(DeviceData,
EndpointData);
}
break;
default:
TEST_TRAP();
}
EndpointData->State = State;
}
/*
High Speed Iso code
We use a variation of the split Iso code here. We allocate 1024
static TDs and insert them in the schedule. These TDs are then
updated with the current transfers instead of inserted or removed.
*/
VOID
EHCI_Initialize_iTD(
PDEVICE_DATA DeviceData,
PENDPOINT_DATA EndpointData,
PENDPOINT_PARAMETERS EndpointParameters,
PHCD_HSISO_TRANSFER_DESCRIPTOR IsoTd,
HW_32BIT_PHYSICAL_ADDRESS PhysicalAddress,
ULONG Frame
)
/*++
Routine Description:
Initailze a static SiTD for an endpoint
Arguments:
Return Value:
none
--*/
{
ULONG i;
IsoTd->Sig = SIG_HCD_ITD;
IsoTd->PhysicalAddress = PhysicalAddress;
ISO_PACKET_PTR(IsoTd->FirstPacket) = NULL;
IsoTd->HostFrame = Frame;
for (i=0; i< 8; i++) {
IsoTd->HwTD.Transaction[i].ul = 0;
}
IsoTd->HwTD.BufferPointer0.DeviceAddress =
EndpointParameters->DeviceAddress;
IsoTd->HwTD.BufferPointer0.EndpointNumber =
EndpointParameters->EndpointAddress;
IsoTd->HwTD.BufferPointer1.MaxPacketSize =
EndpointParameters->MuxPacketSize;
// 1 = IN 0 = OUT
IsoTd->HwTD.BufferPointer1.Direction =
(EndpointParameters->TransferDirection == In) ? 1 : 0;
IsoTd->HwTD.BufferPointer2.Multi =
EndpointParameters->TransactionsPerMicroframe;
}
#define EHCI_OFFSET_MASK 0x00000FFF
#define EHCI_PAGE_SHIFT 12
VOID
EHCI_MapHsIsoPacketsToTd(
PDEVICE_DATA DeviceData,
PENDPOINT_DATA EndpointData,
PMINIPORT_ISO_PACKET FirstPacket,
PHCD_HSISO_TRANSFER_DESCRIPTOR IsoTd,
BOOLEAN InterruptOnComplete
)
/*++
Routine Description:
Arguments:
Returns:
--*/
{
PHC_ITD_BUFFER_POINTER currentBp;
PMINIPORT_ISO_PACKET pkt = FirstPacket;
ULONG page, offset, bpCount, i;
ULONG frame = FirstPacket->FrameNumber;
LOGENTRY(DeviceData, G, '_HHS', IsoTd, 0, FirstPacket);
ASSERT_ITD(DeviceData, IsoTd);
bpCount = 0;
currentBp = (PHC_ITD_BUFFER_POINTER) &IsoTd->HwTD.BufferPointer0;
// map the first packet
page = (pkt->BufferPointer0.Hw32 >> EHCI_PAGE_SHIFT);
currentBp->BufferPointer = page;
// This Td will represent 8 packets
for (i=0; i<8; i++) {
EHCI_ASSERT(DeviceData, pkt->FrameNumber == frame);
page = (pkt->BufferPointer0.Hw32 >> EHCI_PAGE_SHIFT);
offset = pkt->BufferPointer0.Hw32 & EHCI_OFFSET_MASK;
if (page != currentBp->BufferPointer) {
currentBp++;
bpCount++;
currentBp->BufferPointer = page;
}
IsoTd->HwTD.Transaction[i].Offset = offset;
IsoTd->HwTD.Transaction[i].Length = pkt->Length;
IsoTd->HwTD.Transaction[i].PageSelect = bpCount;
if (InterruptOnComplete && i==7) {
IsoTd->HwTD.Transaction[i].InterruptOnComplete = 1;
} else {
IsoTd->HwTD.Transaction[i].InterruptOnComplete = 0;
}
IsoTd->HwTD.Transaction[i].Active = 1;
if (pkt->BufferPointerCount > 1) {
page = (pkt->BufferPointer1.Hw32 >> EHCI_PAGE_SHIFT);
currentBp++;
bpCount++;
currentBp->BufferPointer = page;
EHCI_ASSERT(DeviceData, bpCount <= 6)
}
pkt++;
}
LOGENTRY(DeviceData, G, '_mhs', IsoTd, 0, bpCount);
}
VOID
EHCI_CompleteHsIsoPackets(
PDEVICE_DATA DeviceData,
PMINIPORT_ISO_PACKET FirstPacket,
PHCD_HSISO_TRANSFER_DESCRIPTOR IsoTd
)
/*++
Routine Description:
Complete the eight high speed packets associated with this
TD
Arguments:
Returns:
--*/
{
ULONG length, i;
ULONG cf = EHCI_Get32BitFrameNumber(DeviceData);
PMINIPORT_ISO_PACKET pkt = FirstPacket;
LOGENTRY(DeviceData, G, '_cpI', pkt, IsoTd, cf);
for (i=0; i<8; i++) {
if (IsoTd->HwTD.Transaction[i].Active == 1) {
// missed
pkt->LengthTransferred = 0;
LOGENTRY(DeviceData, G, '_cms',
pkt,
i,
pkt->FrameNumber);
pkt->UsbdStatus = USBD_STATUS_ISO_NOT_ACCESSED_BY_HW;
} else {
// if this is an out assume all data transferred
if (IsoTd->HwTD.BufferPointer1.Direction == 0) {
// out
length = pkt->Length;
LOGENTRY(DeviceData, G, '_cp3',
pkt->FrameNumber,
pkt->Length ,
pkt);
} else {
// in
length = IsoTd->HwTD.Transaction[i].Length;
LOGENTRY(DeviceData, G, '_cp4',
pkt->FrameNumber,
pkt->Length ,
pkt);
}
pkt->LengthTransferred = length;
// check the errubit
if (IsoTd->HwTD.Transaction[i].XactError) {
pkt->UsbdStatus = USBD_STATUS_XACT_ERROR;
//TEST_TRAP();
} else if (IsoTd->HwTD.Transaction[i].BabbleDetect) {
pkt->UsbdStatus = USBD_STATUS_BABBLE_DETECTED;
} else if (IsoTd->HwTD.Transaction[i].DataBufferError) {
pkt->UsbdStatus = USBD_STATUS_DATA_BUFFER_ERROR;
} else {
pkt->UsbdStatus = USBD_STATUS_SUCCESS;
}
LOGENTRY(DeviceData, G, '_cpL', pkt, IsoTd, length);
pkt++;
}
}
}
USB_MINIPORT_STATUS
EHCI_OpenHsIsochronousEndpoint(
PDEVICE_DATA DeviceData,
PENDPOINT_PARAMETERS EndpointParameters,
PENDPOINT_DATA EndpointData
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PUCHAR buffer;
HW_32BIT_PHYSICAL_ADDRESS phys;
ULONG i;
ULONG bytes;
PHW_32BIT_PHYSICAL_ADDRESS frameBase;
PENDPOINT_DATA prevEndpoint, nextEndpoint;
LOGENTRY(DeviceData, G, '_opS', 0, 0, EndpointParameters);
buffer = EndpointParameters->CommonBufferVa;
phys = EndpointParameters->CommonBufferPhys;
// how much did we get
bytes = EndpointParameters->CommonBufferBytes;
EndpointData->HsIsoTdList = (PHCD_HSISOTD_LIST) buffer;
// bugbug use manifest
EndpointData->TdCount = USBEHCI_MAX_FRAME;
EndpointData->LastFrame = 0;
for (i=0; i<EndpointData->TdCount; i++) {
EHCI_Initialize_iTD(DeviceData,
EndpointData,
EndpointParameters,
&EndpointData->HsIsoTdList->Td[i],
phys,
i);
phys += sizeof(HCD_HSISO_TRANSFER_DESCRIPTOR);
}
//
if (DeviceData->IsoEndpointListHead == NULL) {
// empty list, no iso endpoints
prevEndpoint = NULL;
nextEndpoint = NULL;
} else {
// currently we insert HS endpoints in front of split
// iso endpoints, so for high speed we just stick them
// on the head of the list
prevEndpoint = NULL;
nextEndpoint = DeviceData->IsoEndpointListHead;
}
// insert this column of TDs thru the schedule
EHCI_InsertHsIsoTdsInSchedule(DeviceData,
EndpointData,
prevEndpoint,
nextEndpoint);
// init endpoint structures
InitializeListHead(&EndpointData->TransferList);
EHCI_EnablePeriodicList(DeviceData);
return USBMP_STATUS_SUCCESS;
}
VOID
EHCI_RemoveHsIsoTdsFromSchedule(
PDEVICE_DATA DeviceData,
PENDPOINT_DATA EndpointData
)
/*++
Routine Description:
unlink the iso TDs from the schedule
Arguments:
--*/
{
//PHW_32BIT_PHYSICAL_ADDRESS frameBase;
ULONG i;
PENDPOINT_DATA prevEndpoint, nextEndpoint;
PHCD_QUEUEHEAD_DESCRIPTOR dQh;
prevEndpoint = EndpointData->PrevEndpoint;
nextEndpoint = EndpointData->NextEndpoint;
LOGENTRY(DeviceData, G, '_iRM', prevEndpoint,
nextEndpoint, EndpointData);
if (DeviceData->IsoEndpointListHead == EndpointData) {
// this is the head
//frameBase = DeviceData->FrameListBaseAddress;
for (i=0; i<USBEHCI_MAX_FRAME; i++) {
PHCD_HSISO_TRANSFER_DESCRIPTOR iTd;
ULONG phys;
iTd = &EndpointData->HsIsoTdList->Td[i];
phys = iTd->HwTD.NextLink.HwAddress;
dQh = EHCI_GetDummyQueueHeadForFrame(DeviceData, i);
dQh->HwQH.HLink.HwAddress = phys;
dQh->NextLink = iTd->NextLink;
//*frameBase = phys;
//frameBase++;
}
DeviceData->IsoEndpointListHead =
EndpointData->NextEndpoint;
if (nextEndpoint != NULL) {
EHCI_ASSERT(DeviceData,
nextEndpoint->PrevEndpoint == EndpointData);
nextEndpoint->PrevEndpoint = NULL;
}
} else {
// middle
TEST_TRAP();
EHCI_ASSERT(DeviceData, HIGHSPEED(prevEndpoint));
// link prev to next, prev will always be a HS ep
prevEndpoint->NextEndpoint = nextEndpoint;
if (nextEndpoint != NULL) {
nextEndpoint->PrevEndpoint = prevEndpoint;
}
for (i=0; i<USBEHCI_MAX_FRAME; i++) {
PHCD_HSISO_TRANSFER_DESCRIPTOR iTd, previTd;
ULONG phys;
iTd = &EndpointData->HsIsoTdList->Td[i];
previTd = &prevEndpoint->HsIsoTdList->Td[i];
phys = iTd->HwTD.NextLink.HwAddress;
previTd->HwTD.NextLink.HwAddress = phys;
}
}
}
VOID
EHCI_InsertHsIsoTdsInSchedule(
PDEVICE_DATA DeviceData,
PENDPOINT_DATA EndpointData,
PENDPOINT_DATA PrevEndpointData,
PENDPOINT_DATA NextEndpointData
)
/*++
Routine Description:
Insert an aync endpoint (queue head)
into the HW list
Arguments:
--*/
{
//PHW_32BIT_PHYSICAL_ADDRESS frameBase;
ULONG i;
LOGENTRY(DeviceData, G, '_iAH', PrevEndpointData,
NextEndpointData, EndpointData);
// always insert to head
EHCI_ASSERT(DeviceData, PrevEndpointData == NULL);
DeviceData->IsoEndpointListHead = EndpointData;
EndpointData->PrevEndpoint = NULL;
EndpointData->NextEndpoint =
NextEndpointData;
if (NextEndpointData != NULL) {
NextEndpointData->PrevEndpoint = EndpointData;
}
//frameBase = DeviceData->FrameListBaseAddress;
for (i=0; i<USBEHCI_MAX_FRAME; i++) {
PHCD_HSISO_TRANSFER_DESCRIPTOR iTd, nextiTd, previTd;
HW_32BIT_PHYSICAL_ADDRESS qh;
PHCD_QUEUEHEAD_DESCRIPTOR dQh;
ULONG phys;
iTd = &EndpointData->HsIsoTdList->Td[i];
ASSERT_ITD(DeviceData, iTd);
dQh = EHCI_GetDummyQueueHeadForFrame(DeviceData, i);
// fixup next link
if (NextEndpointData == NULL) {
// no iso endpoints, link to the interrupt
// queue heads via the dummy queue head
// qh = *frameBase;
qh = dQh->HwQH.HLink.HwAddress;
iTd->HwTD.NextLink.HwAddress = qh;
iTd->NextLink = dQh->NextLink;
} else {
// link to the next iso endpoint
if (HIGHSPEED(NextEndpointData)) {
PHCD_HSISO_TRANSFER_DESCRIPTOR tmp;
tmp = &NextEndpointData->HsIsoTdList->Td[i];
iTd->HwTD.NextLink.HwAddress =
tmp->PhysicalAddress;
HW_PTR(iTd->NextLink) = (PUCHAR) tmp;
} else {
PHCD_SI_TRANSFER_DESCRIPTOR tmp;
ULONG phys;
tmp = &NextEndpointData->SiTdList->Td[i%ISO_SCHEDULE_SIZE];
phys = tmp->PhysicalAddress;
SET_SITD(phys);
iTd->HwTD.NextLink.HwAddress = phys;
HW_PTR(iTd->NextLink) = (PUCHAR) tmp;
}
}
// fixup prev link
// since we always insert Hs iso on the head of the list
// prev endpoint should always be NULL
EHCI_ASSERT(DeviceData, PrevEndpointData == NULL);
phys = iTd->PhysicalAddress;
// link dummy QH to this TD
dQh->HwQH.HLink.HwAddress = phys;
HW_PTR(dQh->NextLink) = (PUCHAR) iTd;
//*frameBase = phys;
//frameBase++;
}
}
#define HSISO_SCHEDULE_MASK 0x3ff
VOID
EHCI_InternalPollHsIsoEndpoint(
PDEVICE_DATA DeviceData,
PENDPOINT_DATA EndpointData,
BOOLEAN Complete
)
/*++
Routine Description:
Called when the endpoint 'needs attention'
static iso TD table
--------------------
0 < -- (lastFrame & 0x3ff)
1 {completed}
2 {completed}
3 {completed}
4 < -- (currentframe & 0x3ff)
...
1023
---------------------
Arguments:
Return Value:
--*/
{
ULONG x, i;
ULONG currentFrame, lastFrame;
PHCD_HSISO_TRANSFER_DESCRIPTOR iTd;
PHCD_HSISO_TRANSFER_DESCRIPTOR lastiTd;
PMINIPORT_ISO_PACKET packet;
PLIST_ENTRY listEntry;
PTRANSFER_CONTEXT transfer;
currentFrame = EHCI_Get32BitFrameNumber(DeviceData);
lastFrame = EndpointData->LastFrame;
LOGENTRY(DeviceData, G, '_pis', lastFrame, currentFrame,
EndpointData);
if (currentFrame - lastFrame > USBEHCI_MAX_FRAME) {
// overrun
lastFrame = currentFrame-1;
LOGENTRY(DeviceData, G, '_ov1', lastFrame, currentFrame, 0);
// dump the current contents
for (i=0; i <USBEHCI_MAX_FRAME; i++) {
iTd = &EndpointData->HsIsoTdList->Td[i];
transfer = ISO_TRANSFER_PTR(iTd->Transfer);
if (transfer != NULL) {
ISO_PACKET_PTR(iTd->FirstPacket) = NULL;
ISO_TRANSFER_PTR(iTd->Transfer) = NULL;
transfer->PendingPackets-=8;
}
}
}
if (lastFrame == currentFrame) {
// too early to do anything
LOGENTRY(DeviceData, G, '_ear', lastFrame, currentFrame, 0);
return;
}
// TDs between lastframe and currentframe are complete,
// complete the packets associated with them
// f0
// f1
// f2 < ------- last frame }
// f3 } these are complete
// f4 }
// f5 < ------- current frame
// f6
// f7
// f8
x = (lastFrame & (HSISO_SCHEDULE_MASK));
lastiTd = NULL;
LOGENTRY(DeviceData, G, '_frh', lastFrame, x, currentFrame);
while (x != ((currentFrame-1) & HSISO_SCHEDULE_MASK)) {
iTd = &EndpointData->HsIsoTdList->Td[x];
ASSERT_ITD(DeviceData, iTd);
// complete this packet
packet = ISO_PACKET_PTR(iTd->FirstPacket);
transfer = ISO_TRANSFER_PTR(iTd->Transfer);
LOGENTRY(DeviceData, G, '_gpk', transfer, packet, x);
if (packet != NULL) {
transfer = ISO_TRANSFER_PTR(iTd->Transfer);
ASSERT_TRANSFER(DeviceData, transfer);
EHCI_CompleteHsIsoPackets(DeviceData, packet, iTd);
ISO_PACKET_PTR(iTd->FirstPacket) = NULL;
ISO_TRANSFER_PTR(iTd->Transfer) = NULL;
transfer->PendingPackets-=8;
}
lastFrame++;
x++;
x &= HSISO_SCHEDULE_MASK;
}
// attempt to program what we can, if iTD is NULL
// then we can program this frame
// NOTE: No scheduling if paused!
if (EndpointData->State != ENDPOINT_PAUSE) {
LOGENTRY(DeviceData, G, '_psh', 0, 0, 0);
for (i=0; i <USBEHCI_MAX_FRAME; i++) {
x = ((currentFrame+i) & HSISO_SCHEDULE_MASK);
iTd = &EndpointData->HsIsoTdList->Td[x];
ASSERT_ITD(DeviceData, iTd);
LOGENTRY(DeviceData, G, '_gpf', iTd, x, currentFrame+i);
// open slot?
if (ISO_PACKET_PTR(iTd->FirstPacket) != NULL) {
// no, bail
continue;
}
// yes, see if we have a packet
// this will fetch the first packet to transmit this frame
packet = EHCI_GetPacketForFrame(DeviceData,
EndpointData,
&transfer,
currentFrame+i);
if (packet != NULL) {
BOOLEAN ioc = FALSE;
ULONG sf, ef;
EHCI_ASSERT(DeviceData, ISO_PACKET_PTR(iTd->FirstPacket) == NULL);
if ((currentFrame+i) == transfer->FrameComplete) {
ioc = TRUE;
}
sf = transfer->FrameComplete -
transfer->IsoTransfer->PacketCount +5;
ef = transfer->FrameComplete -5;
// generate some interrupts on the first few frames of the
// transfer to help flush out any previous transfers
if (currentFrame+i <= sf ||
currentFrame+i >= ef) {
ioc = TRUE;
}
//interrupt every frame
//ioc = TRUE;
//if ((currentFrame % 2) == 0) {
// ioc = TRUE;
//}
// map 8 microframes
EHCI_MapHsIsoPacketsToTd(DeviceData, EndpointData,
packet, iTd, ioc);
lastiTd = iTd;
ISO_PACKET_PTR(iTd->FirstPacket) = packet;
ASSERT_TRANSFER(DeviceData, transfer);
ISO_TRANSFER_PTR(iTd->Transfer) = transfer;
transfer->PendingPackets+=8;
} else {
ULONG j;
// re-init itd
for (j=0; j<8; j++) {
iTd->HwTD.Transaction[j].InterruptOnComplete = 0;
}
}
}
// take a interrupt on the last TD programmed
if (lastiTd != NULL) {
lastiTd->HwTD.Transaction[7].InterruptOnComplete = 1;
}
}
EHCI_ASSERT(DeviceData, lastFrame < currentFrame);
EndpointData->LastFrame = lastFrame;
// walk our list of active iso transfers and see
// if any are complete
//restart:
listEntry = EndpointData->TransferList.Flink;
while (listEntry != &EndpointData->TransferList && Complete) {
PTRANSFER_CONTEXT transfer;
transfer = (PTRANSFER_CONTEXT) CONTAINING_RECORD(
listEntry,
struct _TRANSFER_CONTEXT,
TransferLink);
LOGENTRY(DeviceData, G, '_ckt', transfer, transfer->FrameComplete+2
, currentFrame);
EHCI_ASSERT(DeviceData, transfer->Sig == SIG_EHCI_TRANSFER);
if (currentFrame >= transfer->FrameComplete &&
transfer->PendingPackets == 0) {
listEntry = transfer->TransferLink.Flink;
RemoveEntryList(&transfer->TransferLink);
LOGENTRY(DeviceData, G, '_cpi', transfer, 0, 0);
USBPORT_COMPLETE_ISO_TRANSFER(DeviceData,
EndpointData,
transfer->TransferParameters,
transfer->IsoTransfer);
} else {
listEntry = transfer->TransferLink.Flink;
}
}
}
USB_MINIPORT_STATUS
EHCI_PokeIsoEndpoint(
PDEVICE_DATA DeviceData,
PENDPOINT_PARAMETERS EndpointParameters,
PENDPOINT_DATA EndpointData
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
ULONG i;
if (HIGHSPEED(EndpointData)) {
TEST_TRAP();
} else {
PHCD_SI_TRANSFER_DESCRIPTOR siTd;
for (i=0; i<EndpointData->TdCount; i++) {
siTd = &EndpointData->SiTdList->Td[i];
ASSERT_SITD(DeviceData, siTd);
siTd->HwTD.Caps.DeviceAddress =
EndpointParameters->DeviceAddress;
siTd->HwTD.Caps.HubAddress =
EndpointParameters->TtDeviceAddress;
}
}
return USBMP_STATUS_SUCCESS;
}
PHCD_QUEUEHEAD_DESCRIPTOR
EHCI_GetDummyQueueHeadForFrame(
PDEVICE_DATA DeviceData,
ULONG Frame
)
/*++
Routine Description:
Arguments:
Return Value:
queue head
--*/
{
PUCHAR base;
base = DeviceData->DummyQueueHeads;
return (PHCD_QUEUEHEAD_DESCRIPTOR)
(base + sizeof(HCD_QUEUEHEAD_DESCRIPTOR) * Frame);
}
VOID
EHCI_AddDummyQueueHeads(
PDEVICE_DATA DeviceData
)
/*++
Routine Description:
NEC errata:
Insert a table of 1024 dummy queue heads in the schedule for
HW to access and point them at the interrupt queue heads.
These queue heads must be before any iso TDs
This is a workaround for a law ine the NEC B0' stepping version
of the controller. We must put 'dummy' QH at the front of the
peridoic list such that the first thing fetched is always a QH
even when ISO TDs are in the schedule.
Arguments:
Return Value:
--*/
{
PHCD_QUEUEHEAD_DESCRIPTOR dQh, stqh;
HW_32BIT_PHYSICAL_ADDRESS qhPhys;
PHW_32BIT_PHYSICAL_ADDRESS frameBase;
ULONG i;
HW_32BIT_PHYSICAL_ADDRESS phys;
frameBase = DeviceData->FrameListBaseAddress;
phys = DeviceData->DummyQueueHeadsPhys;
for (i=0; i<USBEHCI_MAX_FRAME; i++) {
// no iso endpoints should be in the schedule yet
qhPhys = *frameBase;
dQh = EHCI_GetDummyQueueHeadForFrame(DeviceData, i);
// init the dummy queue head
RtlZeroMemory(dQh, sizeof(*dQh));
dQh->PhysicalAddress = phys;
dQh->Sig = SIG_DUMMY_QH;
dQh->HwQH.EpChars.DeviceAddress = 128;
dQh->HwQH.EpChars.EndpointNumber = 0;
dQh->HwQH.EpChars.EndpointSpeed = HcEPCHAR_FullSpeed;
dQh->HwQH.EpChars.MaximumPacketLength = 64;
dQh->HwQH.EpCaps.InterruptScheduleMask = 0;
dQh->HwQH.EpCaps.SplitCompletionMask = 0;
dQh->HwQH.EpCaps.HubAddress = 0;
dQh->HwQH.EpCaps.PortNumber = 0;
dQh->HwQH.EpCaps.HighBWPipeMultiplier = 0;
dQh->HwQH.CurrentTD.HwAddress = 0;
dQh->HwQH.Overlay.qTD.AltNext_qTD.HwAddress = EHCI_TERMINATE_BIT;
dQh->HwQH.Overlay.qTD.Next_qTD.HwAddress = EHCI_TERMINATE_BIT;
dQh->HwQH.Overlay.qTD.Token.Active = 0;
phys += sizeof(HCD_QUEUEHEAD_DESCRIPTOR);
// link dummy to first interrupt queue head
dQh->HwQH.HLink.HwAddress = qhPhys;
stqh = EHCI_GetQueueHeadForFrame(DeviceData, i);
EHCI_ASSERT(DeviceData, (qhPhys & ~EHCI_DTYPE_Mask) ==
stqh->PhysicalAddress);
HW_PTR(dQh->NextLink) = (PUCHAR)stqh;
// add dummy queue head to frame list
qhPhys = dQh->PhysicalAddress;
SET_QH(qhPhys);
*frameBase = qhPhys;
frameBase++;
}
}