[USB\USBEHCI]

- Fix linking of QueueHeads. Implement LinkQueueHeadToCompletedList and CleanupAsyncList. These functions are used to software link the completed queueheads to a completed list. Only after the driver handshakes with the controller can this memory be freed.
Fix a few incorrect values for QueueHead.
- EhciDefferedRoutine: Implement handling of completed QueueHeads by removing them from the AnsycList and setting any errors for failure.
- Reserved a QueueHead that will always be in the AsyncList Address Register. By setting it as the Head of Reclamation the controller can know when it has reached the end of the QueueHead list.
- Remove all code from FdoDispatchInternalDeviceControl. This should never be called by upper level drivers.
Change 1 of 3.

svn path=/trunk/; revision=51325
This commit is contained in:
Michael Martin 2011-04-13 04:33:14 +00:00
parent 9c9874002e
commit b6256418e9
4 changed files with 341 additions and 429 deletions

View file

@ -21,10 +21,11 @@ EhciDefferedRoutine(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVO
ULONG tmp; ULONG tmp;
ULONG OpRegisters; ULONG OpRegisters;
PEHCI_HOST_CONTROLLER hcd; PEHCI_HOST_CONTROLLER hcd;
LONG i; int i;
FdoDeviceExtension = (PFDO_DEVICE_EXTENSION) DeferredContext; FdoDeviceExtension = (PFDO_DEVICE_EXTENSION) DeferredContext;
/* Nothing is valid if the Pdo is NULL */
if (!FdoDeviceExtension->Pdo) if (!FdoDeviceExtension->Pdo)
{ {
DPRINT1("PDO not set yet!\n"); DPRINT1("PDO not set yet!\n");
@ -36,127 +37,183 @@ EhciDefferedRoutine(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVO
OpRegisters = (ULONG)FdoDeviceExtension->hcd.OpRegisters; OpRegisters = (ULONG)FdoDeviceExtension->hcd.OpRegisters;
hcd = &FdoDeviceExtension->hcd; hcd = &FdoDeviceExtension->hcd;
CStatus = (ULONG) SystemArgument2; CStatus = (ULONG) SystemArgument2;
/* If Reclamation (The QueueHead list has been transveresed twice),
/* TD retired or Error */ look through the queuehead list and find queue heads that have been
if (CStatus & (EHCI_STS_INT | EHCI_ERROR_INT)) 1. Halted due to error
2. Transfer completion.
Move these QueueHeads to a temporary list that is used to pend memory release.
Either an Event is signalled or an Irp is completed depending on what was set during transfer request
setup. Next software issue a "DoorBell" that informs the controller the Asynchronous List is about to
be modified.
After the controller acks this with interrupt, the memory for queueheads are released. */
if (CStatus & (EHCI_STS_RECL| EHCI_STS_INT | EHCI_ERROR_INT))
{ {
DPRINT("Asyn Complete!\n"); PQUEUE_HEAD CurrentQH;
ULONG CurrentAddr, OffSet; PQUEUE_TRANSFER_DESCRIPTOR CurrentTD;
PQUEUE_HEAD CompletedQH, NextQH; BOOLEAN QueueHeadCompleted;
PQUEUE_TRANSFER_DESCRIPTOR CompletedTD, NextTD;
/* AsyncListAddr Register will have the next QueueHead to execute */
CurrentAddr = GetAsyncListQueueRegister(hcd);
/* Calculate the VA for the next QueueHead */ /* Go through the list and delink completed (not active) QueueHeads */
OffSet = CurrentAddr - (ULONG)FdoDeviceExtension->hcd.CommonBufferPA.LowPart; CurrentQH = hcd->AsyncListQueue;
NextQH = (PQUEUE_HEAD)((ULONG)FdoDeviceExtension->hcd.CommonBufferVA + OffSet); CurrentQH = CurrentQH->NextQueueHead;
/* Get the previous QueueHead which is the QueueHead just completed */ while ((CurrentQH) && (CurrentQH != hcd->AsyncListQueue))
CompletedQH = NextQH->PreviousQueueHead;
ASSERT(CompletedQH);
DPRINT("CompletedQH %x\n", CompletedQH);
//DumpQueueHead(CompletedQH);
/* Free memory for the Descriptors */
CompletedTD = CompletedQH->TransferDescriptor;
NextTD = CompletedTD;
while (NextTD)
{ {
CompletedTD = NextTD; DPRINT1("Checking QueueHead %x, Next %x\n", CurrentQH, CurrentQH->NextQueueHead);
NextTD = NextTD->NextDescriptor; DPRINT1("Active %d, Halted %d\n", CurrentQH->Token.Bits.Active, CurrentQH->Token.Bits.Halted);
FreeDescriptor(CompletedTD);
}
/* If the Event is set then release waiter */
if (CompletedQH->Event)
{
KeSetEvent(CompletedQH->Event, IO_NO_INCREMENT, FALSE);
}
/* Free the Mdl if there was one */ /* if the QueueHead has completed */
if(CompletedQH->MdlToFree) if (!CurrentQH->Token.Bits.Active)
IoFreeMdl(CompletedQH->MdlToFree);
/* Is there an IRP that needs to be completed */
if (CompletedQH->IrpToComplete)
{
PIRP Irp;
PIO_STACK_LOCATION Stack;
PURB Urb;
Irp = CompletedQH->IrpToComplete;
Stack = IoGetCurrentIrpStackLocation(Irp);
ASSERT(Stack);
Urb = (PURB) Stack->Parameters.Others.Argument1;
/* Check for error */
if (CStatus & EHCI_ERROR_INT)
{ {
/* Haled bit should be set */ /* Assume success */
if (CompletedQH->Token.Bits.Halted) USBD_STATUS UrbStatus = USBD_STATUS_SUCCESS;
QueueHeadCompleted = TRUE;
/* Check the Status of the QueueHead */
if (CurrentQH->Token.Bits.Halted)
{ {
if (CompletedQH->Token.Bits.DataBufferError) if (CurrentQH->Token.Bits.DataBufferError)
{ {
DPRINT1("Data buffer error\n"); DPRINT1("Data buffer error\n");
Urb->UrbHeader.Status = USBD_STATUS_DATA_BUFFER_ERROR; UrbStatus = USBD_STATUS_DATA_BUFFER_ERROR;
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
Irp->IoStatus.Information = 0;
} }
else if (CompletedQH->Token.Bits.BabbleDetected) else if (CurrentQH->Token.Bits.BabbleDetected)
{ {
DPRINT1("Babble Detected\n"); DPRINT1("Babble Detected\n");
Urb->UrbHeader.Status = USBD_STATUS_BABBLE_DETECTED; UrbStatus = USBD_STATUS_BABBLE_DETECTED;
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
Irp->IoStatus.Information = 0;
} }
else else
{ {
DPRINT1("Stall PID\n"); DPRINT1("Stall PID\n");
Urb->UrbHeader.Status = USBD_STATUS_STALL_PID; UrbStatus = USBD_STATUS_STALL_PID;
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
Irp->IoStatus.Information = 0;
} }
} }
}
else /* Check the Descriptors */
{ CurrentTD = CurrentQH->FirstTransferDescriptor;
Irp->IoStatus.Status = STATUS_SUCCESS; while (CurrentTD)
Irp->IoStatus.Information = 0; {
DPRINT1("Completing Irp\n"); /* FIXME: What needs to happen if the QueueHead was marked as complete but descriptors was not */
if ((CurrentTD->Token.Bits.Active) || (CurrentTD->Token.Bits.Halted))
{
/* The descriptor was not completed */
QueueHeadCompleted = FALSE;
DPRINT1("QueueHead was marked as completed but contains descriptors that were not completed\n");
ASSERT(FALSE);
break;
}
CurrentTD = CurrentTD->NextDescriptor;
}
if ((QueueHeadCompleted) || (CurrentQH->Token.Bits.Halted))
{
PQUEUE_HEAD FreeQH;
FreeQH = CurrentQH;
CurrentQH = CurrentQH->NextQueueHead;
DPRINT1("QueueHead %x has completed. Removing\n", FreeQH);
/* Move it into the completed list */
UnlinkQueueHead(hcd, FreeQH);
LinkQueueHeadToCompletedList(hcd, FreeQH);
DPRINT1("Remove done\n");
/* If the Event is set then the caller is waiting on completion */
if (FreeQH->Event)
{
KeSetEvent(FreeQH->Event, IO_NO_INCREMENT, FALSE);
}
/* If there is an IrpToComplete then the caller did not wait on completion
and the IRP was marked as PENDING. Complete it now. */
if (FreeQH->IrpToComplete)
{
PIRP Irp;
PIO_STACK_LOCATION Stack;
PURB Urb;
Irp = FreeQH->IrpToComplete;
Stack = IoGetCurrentIrpStackLocation(Irp);
ASSERT(Stack);
Urb = (PURB) Stack->Parameters.Others.Argument1;
ASSERT(Urb);
/* Check for error */
if (CStatus & EHCI_ERROR_INT)
{
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
Irp->IoStatus.Information = 0;
/* Set BufferLength to 0 as there was error */
if (Urb->UrbHeader.Function == URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE)
{
Urb->UrbControlDescriptorRequest.TransferBufferLength = 0;
}
DPRINT1("There was an Error, TransferBufferLength set to 0\n");
}
else
{
if (Urb->UrbHeader.Function == URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE)
{
if (Urb->UrbControlDescriptorRequest.TransferBufferLength >=
((PUSB_COMMON_DESCRIPTOR)(Urb->UrbControlDescriptorRequest.TransferBuffer))->bLength)
{
Urb->UrbControlDescriptorRequest.TransferBufferLength =
((PUSB_COMMON_DESCRIPTOR)(Urb->UrbControlDescriptorRequest.TransferBuffer))->bLength;
}
}
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
DPRINT1("Completing Irp\n");
}
Urb->UrbHeader.Status = UrbStatus;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
/* FIXME: Move to static function */
PEHCI_USBCMD_CONTENT UsbCmd;
/* Ring the DoorBell so that host controller knows a QueueHead was removed */
DPRINT1("Ringing Doorbell\n");
tmp = READ_REGISTER_ULONG((PULONG) (OpRegisters + EHCI_USBCMD));
UsbCmd = (PEHCI_USBCMD_CONTENT) &tmp;
UsbCmd->DoorBell = TRUE;
WRITE_REGISTER_ULONG((PULONG) (OpRegisters + EHCI_USBCMD), tmp);
continue;
}
} }
IoCompleteRequest(Irp, IO_NO_INCREMENT);
CurrentQH = CurrentQH->NextQueueHead;
} }
/* Unlink QueueHead */
UnlinkQueueHead(hcd, CompletedQH);
/* Wait for a complete AsnycList tranversal before deleting? */
DeleteQueueHead(CompletedQH);
} }
/* Port Change */
/* Port Change. */
/* FIXME: Use EnumControllerPorts instead */
if (CStatus & EHCI_STS_PCD) if (CStatus & EHCI_STS_PCD)
{ {
/* Loop through the ports */ /* Loop through the ports */
for (i = 0; i < FdoDeviceExtension->hcd.ECHICaps.HCSParams.PortCount; i++) for (i = 0; i < hcd->ECHICaps.HCSParams.PortCount; i++)
{ {
tmp = READ_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * i))); tmp = READ_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * i)));
/* Check for port change on this port */ /* Check for port change on this port */
if (tmp & 0x02) if (tmp & 0x02)
{ {
/* Clear status change */
tmp = READ_REGISTER_ULONG((PULONG)((OpRegisters + EHCI_PORTSC) + (4 * i)));
tmp |= 0x02;
WRITE_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * i)), tmp);
/* Connect or Disconnect? */ /* Connect or Disconnect? */
if (tmp & 0x01) if (tmp & 0x01)
{ {
DPRINT1("Device connected on port %d\n", i); DPRINT1("Device connected on port %d\n", i);
/* Check if a companion host controller exists */ /* Check if a companion host controller exists */
if (FdoDeviceExtension->hcd.ECHICaps.HCSParams.CHCCount) if (hcd->ECHICaps.HCSParams.CHCCount)
{ {
tmp = READ_REGISTER_ULONG((PULONG)((OpRegisters + EHCI_PORTSC) + (4 * i))); tmp = READ_REGISTER_ULONG((PULONG)((OpRegisters + EHCI_PORTSC) + (4 * i)));
@ -178,6 +235,7 @@ EhciDefferedRoutine(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVO
KeStallExecutionProcessor(30); KeStallExecutionProcessor(30);
/* FIXME: Hub driver does this also, is it needed here? */
/* As per USB 2.0 Specs, 9.1.2. Reset the port and clear the status change */ /* As per USB 2.0 Specs, 9.1.2. Reset the port and clear the status change */
//tmp |= 0x100 | 0x02; //tmp |= 0x100 | 0x02;
/* Sanity, Disable port */ /* Sanity, Disable port */
@ -190,21 +248,16 @@ EhciDefferedRoutine(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVO
tmp = READ_REGISTER_ULONG((PULONG)((OpRegisters + EHCI_PORTSC) + (4 * i))); tmp = READ_REGISTER_ULONG((PULONG)((OpRegisters + EHCI_PORTSC) + (4 * i)));
PdoDeviceExtension->ChildDeviceCount++; PdoDeviceExtension->ChildDeviceCount++;
PdoDeviceExtension->Ports[i].PortStatus &= ~0x8000; hcd->Ports[i].PortStatus &= ~0x8000;
PdoDeviceExtension->Ports[i].PortStatus |= USB_PORT_STATUS_HIGH_SPEED; hcd->Ports[i].PortStatus |= USB_PORT_STATUS_HIGH_SPEED;
PdoDeviceExtension->Ports[i].PortStatus |= USB_PORT_STATUS_CONNECT; hcd->Ports[i].PortStatus |= USB_PORT_STATUS_CONNECT;
PdoDeviceExtension->Ports[i].PortChange |= USB_PORT_STATUS_CONNECT; hcd->Ports[i].PortChange |= USB_PORT_STATUS_CONNECT;
DPRINT1("Completing URB\n"); DPRINT1("Completing URB\n");
CompletePendingURBRequest(PdoDeviceExtension); CompletePendingURBRequest(PdoDeviceExtension);
} }
else else
{ {
DPRINT1("Device disconnected on port %d\n", i); DPRINT1("Device disconnected on port %d\n", i);
/* Clear status change */
tmp = READ_REGISTER_ULONG((PULONG)((OpRegisters + EHCI_PORTSC) + (4 * i)));
tmp |= 0x02;
WRITE_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * i)), tmp);
} }
} }
} }
@ -214,6 +267,7 @@ EhciDefferedRoutine(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVO
if (CStatus & EHCI_STS_IAA) if (CStatus & EHCI_STS_IAA)
{ {
DPRINT1("Async Advance!\n"); DPRINT1("Async Advance!\n");
CleanupAsyncList(hcd);
} }
} }
@ -232,7 +286,7 @@ InterruptService(PKINTERRUPT Interrupt, PVOID ServiceContext)
/* Read device status */ /* Read device status */
CStatus = ReadControllerStatus(hcd); CStatus = ReadControllerStatus(hcd);
CStatus &= (EHCI_ERROR_INT | EHCI_STS_INT | EHCI_STS_IAA | EHCI_STS_PCD | EHCI_STS_FLR); CStatus &= (EHCI_ERROR_INT | EHCI_STS_INT | EHCI_STS_IAA | EHCI_STS_PCD | EHCI_STS_FLR | EHCI_STS_RECL);
if ((!CStatus) || (FdoDeviceExtension->DeviceState == 0)) if ((!CStatus) || (FdoDeviceExtension->DeviceState == 0))
{ {
@ -243,9 +297,22 @@ InterruptService(PKINTERRUPT Interrupt, PVOID ServiceContext)
/* Clear status */ /* Clear status */
ClearControllerStatus(hcd, CStatus); ClearControllerStatus(hcd, CStatus);
if (CStatus & EHCI_STS_RECL)
{
DPRINT("Reclamation\n");
}
if (CStatus & EHCI_ERROR_INT) if (CStatus & EHCI_ERROR_INT)
{ {
DPRINT1("EHCI Status=0x%x\n", CStatus); DPRINT1("EHCI Status=0x%x\n", CStatus);
/* This check added in case the NT USB Driver is still loading.
It will cause this error condition at every device connect. */
if(CStatus & EHCI_STS_PCD)
{
DPRINT1("EHCI Error: Another driver may be interfering with proper operation of this driver\n");
DPRINT1(" Hint: Ensure that the old NT Usb Driver has been removed!\n");
ASSERT(FALSE);
}
} }
if (CStatus & EHCI_STS_FATAL) if (CStatus & EHCI_STS_FATAL)
@ -270,6 +337,7 @@ StartDevice(PDEVICE_OBJECT DeviceObject, PCM_PARTIAL_RESOURCE_LIST raw, PCM_PART
PFDO_DEVICE_EXTENSION FdoDeviceExtension; PFDO_DEVICE_EXTENSION FdoDeviceExtension;
PCM_PARTIAL_RESOURCE_DESCRIPTOR resource; PCM_PARTIAL_RESOURCE_DESCRIPTOR resource;
DEVICE_DESCRIPTION DeviceDescription; DEVICE_DESCRIPTION DeviceDescription;
PEHCI_HOST_CONTROLLER hcd;
ULONG NumberResources; ULONG NumberResources;
ULONG iCount; ULONG iCount;
ULONG DeviceAddress; ULONG DeviceAddress;
@ -278,26 +346,21 @@ StartDevice(PDEVICE_OBJECT DeviceObject, PCM_PARTIAL_RESOURCE_LIST raw, PCM_PART
NTSTATUS Status; NTSTATUS Status;
FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
hcd = &FdoDeviceExtension->hcd;
/* Sanity Checks */
Status = IoGetDeviceProperty(FdoDeviceExtension->LowerDevice, Status = IoGetDeviceProperty(FdoDeviceExtension->LowerDevice,
DevicePropertyAddress, DevicePropertyAddress,
sizeof(ULONG), sizeof(ULONG),
&DeviceAddress, &DeviceAddress,
&PropertySize); &PropertySize);
if (NT_SUCCESS(Status))
{
DPRINT1("--->DeviceAddress: %x\n", DeviceAddress);
}
Status = IoGetDeviceProperty(FdoDeviceExtension->LowerDevice, Status = IoGetDeviceProperty(FdoDeviceExtension->LowerDevice,
DevicePropertyBusNumber, DevicePropertyBusNumber,
sizeof(ULONG), sizeof(ULONG),
&BusNumber, &BusNumber,
&PropertySize); &PropertySize);
if (NT_SUCCESS(Status))
{
DPRINT1("--->BusNumber: %x\n", BusNumber);
}
/* Get the resources the PNP Manager gave */ /* Get the resources the PNP Manager gave */
NumberResources = translated->Count; NumberResources = translated->Count;
@ -364,11 +427,21 @@ StartDevice(PDEVICE_OBJECT DeviceObject, PCM_PARTIAL_RESOURCE_LIST raw, PCM_PART
} }
} }
for (iCount = 0; iCount < hcd->ECHICaps.HCSParams.PortCount; iCount++)
{
hcd->Ports[iCount].PortStatus = 0x8000;
hcd->Ports[iCount].PortChange = 0;
if (hcd->ECHICaps.HCSParams.PortPowerControl)
hcd->Ports[iCount].PortStatus |= USB_PORT_STATUS_POWER;
}
KeInitializeDpc(&FdoDeviceExtension->DpcObject, KeInitializeDpc(&FdoDeviceExtension->DpcObject,
EhciDefferedRoutine, EhciDefferedRoutine,
FdoDeviceExtension); FdoDeviceExtension);
RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION)); RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION; DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
DeviceDescription.Master = TRUE; DeviceDescription.Master = TRUE;
DeviceDescription.ScatterGather = TRUE; DeviceDescription.ScatterGather = TRUE;
@ -377,20 +450,24 @@ StartDevice(PDEVICE_OBJECT DeviceObject, PCM_PARTIAL_RESOURCE_LIST raw, PCM_PART
DeviceDescription.InterfaceType = PCIBus; DeviceDescription.InterfaceType = PCIBus;
DeviceDescription.MaximumLength = EHCI_MAX_SIZE_TRANSFER; DeviceDescription.MaximumLength = EHCI_MAX_SIZE_TRANSFER;
FdoDeviceExtension->pDmaAdapter = IoGetDmaAdapter(FdoDeviceExtension->LowerDevice, hcd->pDmaAdapter = IoGetDmaAdapter(FdoDeviceExtension->LowerDevice,
&DeviceDescription, &DeviceDescription,
&FdoDeviceExtension->MapRegisters); &hcd->MapRegisters);
if (FdoDeviceExtension->pDmaAdapter == NULL) if (hcd->pDmaAdapter == NULL)
{ {
DPRINT1("Ehci: IoGetDmaAdapter failed!\n"); DPRINT1("Ehci: IoGetDmaAdapter failed!\n");
ASSERT(FALSE); ASSERT(FALSE);
} }
DPRINT1("MapRegisters %x\n", hcd->MapRegisters);
/* Allocate Common Buffer for Periodic Frame List */ /* Allocate Common Buffer for Periodic Frame List */
FdoDeviceExtension->PeriodicFrameList.VirtualAddr = FdoDeviceExtension->PeriodicFrameList.VirtualAddr =
FdoDeviceExtension->pDmaAdapter->DmaOperations->AllocateCommonBuffer(FdoDeviceExtension->pDmaAdapter, hcd->pDmaAdapter->DmaOperations->AllocateCommonBuffer(hcd->pDmaAdapter,
sizeof(ULONG) * 1024, &FdoDeviceExtension->PeriodicFrameList.PhysicalAddr, FALSE); sizeof(ULONG) * 1024,
&FdoDeviceExtension->PeriodicFrameList.PhysicalAddr,
FALSE);
if (FdoDeviceExtension->PeriodicFrameList.VirtualAddr == NULL) if (FdoDeviceExtension->PeriodicFrameList.VirtualAddr == NULL)
{ {
@ -403,36 +480,53 @@ StartDevice(PDEVICE_OBJECT DeviceObject, PCM_PARTIAL_RESOURCE_LIST raw, PCM_PART
ExInitializeFastMutex(&FdoDeviceExtension->FrameListMutex); ExInitializeFastMutex(&FdoDeviceExtension->FrameListMutex);
/* Allocate pages for queueheads and descriptors */ /* Allocate initial page for queueheads and descriptors */
FdoDeviceExtension->hcd.CommonBufferVA = FdoDeviceExtension->hcd.CommonBufferVA[0] =
FdoDeviceExtension->pDmaAdapter->DmaOperations->AllocateCommonBuffer(FdoDeviceExtension->pDmaAdapter, hcd->pDmaAdapter->DmaOperations->AllocateCommonBuffer(hcd->pDmaAdapter,
PAGE_SIZE * 16, PAGE_SIZE,
&FdoDeviceExtension->hcd.CommonBufferPA, &FdoDeviceExtension->hcd.CommonBufferPA[0],
FALSE); FALSE);
if (FdoDeviceExtension->hcd.CommonBufferVA == 0) if (FdoDeviceExtension->hcd.CommonBufferVA[0] == 0)
{ {
DPRINT1("Ehci: Failed to allocate common buffer!\n"); DPRINT1("Ehci: Failed to allocate common buffer!\n");
return STATUS_UNSUCCESSFUL; return STATUS_UNSUCCESSFUL;
} }
FdoDeviceExtension->hcd.CommonBufferSize = PAGE_SIZE * 16; hcd->CommonBufferSize = PAGE_SIZE * 16;
/* Zeroize it */ /* Zeroize it */
RtlZeroMemory(FdoDeviceExtension->hcd.CommonBufferVA, RtlZeroMemory(FdoDeviceExtension->hcd.CommonBufferVA[0],
PAGE_SIZE * 16); PAGE_SIZE);
/* Init SpinLock for host controller device lock */ /* Init SpinLock for host controller device lock */
KeInitializeSpinLock(&FdoDeviceExtension->hcd.Lock); KeInitializeSpinLock(&hcd->Lock);
/* Reserved a Queue Head that will always be in the AsyncList Address Register */ /* Reserved a Queue Head that will always be in the AsyncList Address Register. By setting it as the Head of Reclamation
FdoDeviceExtension->hcd.AsyncListQueue = CreateQueueHead(&FdoDeviceExtension->hcd); the controller can know when it has reached the end of the QueueHead list */
FdoDeviceExtension->hcd.AsyncListQueue->HorizontalLinkPointer = FdoDeviceExtension->hcd.AsyncListQueue->PhysicalAddr | QH_TYPE_QH; hcd->AsyncListQueue = CreateQueueHead(hcd);
FdoDeviceExtension->hcd.AsyncListQueue->EndPointCharacteristics.QEDTDataToggleControl = FALSE;
FdoDeviceExtension->hcd.AsyncListQueue->Token.Bits.InterruptOnComplete = FALSE;
hcd->AsyncListQueue->HorizontalLinkPointer = hcd->AsyncListQueue->PhysicalAddr | QH_TYPE_QH;
hcd->AsyncListQueue->EndPointCharacteristics.QEDTDataToggleControl = FALSE;
hcd->AsyncListQueue->Token.Bits.InterruptOnComplete = FALSE;
hcd->AsyncListQueue->EndPointCharacteristics.HeadOfReclamation = TRUE;
hcd->AsyncListQueue->Token.Bits.Halted = TRUE;
hcd->AsyncListQueue->NextQueueHead = hcd->AsyncListQueue;
hcd->AsyncListQueue->PreviousQueueHead = hcd->AsyncListQueue;
/* Reserve a Queue Head thats only purpose is for linking completed Queue Heads.
Completed QueueHeads are moved to this temporary. As the memory must still be valid
up until the controllers doorbell is rang to let it know info has been removed from QueueHead list */
hcd->CompletedListQueue = CreateQueueHead(hcd);
hcd->CompletedListQueue->NextQueueHead = hcd->CompletedListQueue;
hcd->CompletedListQueue->PreviousQueueHead = hcd->CompletedListQueue;
/* Ensure the controller is stopped */ /* Ensure the controller is stopped */
StopEhci(&FdoDeviceExtension->hcd); StopEhci(hcd);
SetAsyncListQueueRegister(hcd, hcd->AsyncListQueue->PhysicalAddr);
/* FIXME: Implement Periodic Frame List */
Status = IoConnectInterrupt(&FdoDeviceExtension->EhciInterrupt, Status = IoConnectInterrupt(&FdoDeviceExtension->EhciInterrupt,
InterruptService, InterruptService,
@ -446,10 +540,8 @@ StartDevice(PDEVICE_OBJECT DeviceObject, PCM_PARTIAL_RESOURCE_LIST raw, PCM_PART
FdoDeviceExtension->Affinity, FdoDeviceExtension->Affinity,
FALSE); FALSE);
StartEhci(&FdoDeviceExtension->hcd); StartEhci(hcd);
DPRINT1("AsycnAddr %x\n", GetAsyncListQueueRegister(&FdoDeviceExtension->hcd));
FdoDeviceExtension->DeviceState = DEVICESTARTED; FdoDeviceExtension->DeviceState = DEVICESTARTED;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -472,6 +564,10 @@ FdoQueryBusRelations(
DPRINT1("Ehci: QueryBusRelations\n"); DPRINT1("Ehci: QueryBusRelations\n");
/* FIXME: Currently only support for one ehci controller */
if (DeviceExtension->Pdo)
goto Done;
/* Create the PDO with the next available number */ /* Create the PDO with the next available number */
while (TRUE) while (TRUE)
{ {
@ -513,9 +609,10 @@ FdoQueryBusRelations(
PdoDeviceExtension->ControllerFdo = DeviceObject; PdoDeviceExtension->ControllerFdo = DeviceObject;
PdoDeviceExtension->DeviceObject = Pdo; PdoDeviceExtension->DeviceObject = Pdo;
PdoDeviceExtension->NumberOfPorts = DeviceExtension->hcd.ECHICaps.HCSParams.PortCount; //PdoDeviceExtension->NumberOfPorts = DeviceExtension->hcd.ECHICaps.HCSParams.PortCount;
InitializeListHead(&PdoDeviceExtension->IrpQueue); InitializeListHead(&PdoDeviceExtension->IrpQueue);
KeInitializeSpinLock(&PdoDeviceExtension->IrpQueueLock); KeInitializeSpinLock(&PdoDeviceExtension->IrpQueueLock);
KeInitializeEvent(&PdoDeviceExtension->QueueDrainedEvent, SynchronizationEvent, TRUE); KeInitializeEvent(&PdoDeviceExtension->QueueDrainedEvent, SynchronizationEvent, TRUE);
@ -525,7 +622,7 @@ FdoQueryBusRelations(
Pdo->Flags &= ~DO_DEVICE_INITIALIZING; Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
DeviceExtension->Pdo = Pdo; DeviceExtension->Pdo = Pdo;
Done:
DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS)); DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
if (!DeviceRelations) if (!DeviceRelations)
@ -534,8 +631,8 @@ FdoQueryBusRelations(
} }
DeviceRelations->Count = 1; DeviceRelations->Count = 1;
DeviceRelations->Objects[0] = Pdo; DeviceRelations->Objects[0] = DeviceExtension->Pdo;
ObReferenceObject(Pdo); ObReferenceObject(DeviceExtension->Pdo);
*pDeviceRelations = DeviceRelations; *pDeviceRelations = DeviceRelations;
return STATUS_SUCCESS; return STATUS_SUCCESS;
@ -705,6 +802,7 @@ AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT Pdo)
ASSERT(FdoDeviceExtension->LowerDevice == Pdo); ASSERT(FdoDeviceExtension->LowerDevice == Pdo);
/* Get the EHCI Device ID and Vendor ID */
Status = GetBusInterface(FdoDeviceExtension->LowerDevice, &FdoDeviceExtension->BusInterface); Status = GetBusInterface(FdoDeviceExtension->LowerDevice, &FdoDeviceExtension->BusInterface);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
@ -772,270 +870,8 @@ AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT Pdo)
NTSTATUS NTAPI NTSTATUS NTAPI
FdoDispatchInternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) FdoDispatchInternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{ {
PFDO_DEVICE_EXTENSION FdoDeviceExtension; /*FIXME: This should never be called by upper drivers as they should only be dealing with the pdo. */
PPDO_DEVICE_EXTENSION PdoDeviceExtension; DPRINT1("Upper Level Device Object shouldnt be calling this!!!!!!!!!!!!\n");
PIO_STACK_LOCATION Stack = NULL; ASSERT(FALSE);
NTSTATUS Status = STATUS_UNSUCCESSFUL; return STATUS_UNSUCCESSFUL;
ULONG_PTR Information = 0;
PUSB_DEVICE UsbDevice = NULL;
URB *Urb;
/*FIXME: This should never be called by upper drivers as they should only be dealing with the pdo */
FdoDeviceExtension = (PFDO_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
PdoDeviceExtension = (PPDO_DEVICE_EXTENSION) FdoDeviceExtension->Pdo->DeviceExtension;
ASSERT(FdoDeviceExtension->Common.IsFdo == TRUE);
Stack = IoGetCurrentIrpStackLocation(Irp);
ASSERT(Stack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_SUBMIT_URB);
Urb = (PURB) Stack->Parameters.Others.Argument1;
DPRINT("Header Length %d\n", Urb->UrbHeader.Length);
DPRINT("Header Function %d\n", Urb->UrbHeader.Function);
UsbDevice = DeviceHandleToUsbDevice(PdoDeviceExtension, Urb->UrbHeader.UsbdDeviceHandle);
if (!UsbDevice)
{
DPRINT1("Ehci: Invalid DeviceHandle or device not connected\n");
return STATUS_DEVICE_NOT_CONNECTED;
}
switch (Urb->UrbHeader.Function)
{
case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
{
DPRINT1("Ehci: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:\n");
break;
}
case URB_FUNCTION_GET_STATUS_FROM_DEVICE:
{
DPRINT1("Ehci: URB_FUNCTION_GET_STATUS_FROM_DEVICE\n");
break;
}
case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
{
DPRINT1("Ehci: URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n");
switch(Urb->UrbControlDescriptorRequest.DescriptorType)
{
case USB_DEVICE_DESCRIPTOR_TYPE:
{
DPRINT1("USB DEVICE DESC\n");
break;
}
case USB_CONFIGURATION_DESCRIPTOR_TYPE:
DPRINT1("USB CONFIG DESC\n");
//break;
case USB_STRING_DESCRIPTOR_TYPE:
{
DPRINT1("Usb String Descriptor\n");
break;
}
default:
{
DPRINT1("Ehci: Descriptor Type %x not supported!\n", Urb->UrbControlDescriptorRequest.DescriptorType);
}
}
break;
}
case URB_FUNCTION_SELECT_CONFIGURATION:
{
DPRINT1("Ehci: URB_FUNCTION_SELECT_CONFIGURATION\n");
DPRINT1("Urb->UrbSelectConfiguration.ConfigurationHandle %x\n",Urb->UrbSelectConfiguration.ConfigurationHandle);
break;
}
case URB_FUNCTION_CLASS_DEVICE:
{
DPRINT1("Ehci: URB_FUNCTION_CLASS_DEVICE %x\n",Urb->UrbControlVendorClassRequest.Request);
switch (Urb->UrbControlVendorClassRequest.Request)
{
case USB_REQUEST_GET_DESCRIPTOR:
{
DPRINT1("TransferFlags %x\n", Urb->UrbControlVendorClassRequest.TransferFlags);
DPRINT1("Urb->UrbControlVendorClassRequest.Value %x\n", Urb->UrbControlVendorClassRequest.Value);
switch (Urb->UrbControlVendorClassRequest.Value >> 8)
{
case USB_DEVICE_CLASS_AUDIO:
{
DPRINT1("USB_DEVICE_CLASS_AUDIO\n");
break;
}
case USB_DEVICE_CLASS_COMMUNICATIONS:
{
DPRINT1("USB_DEVICE_CLASS_COMMUNICATIONS\n");
break;
}
case USB_DEVICE_CLASS_HUMAN_INTERFACE:
{
DPRINT1("USB_DEVICE_CLASS_HUMAN_INTERFACE\n");
break;
}
case USB_DEVICE_CLASS_MONITOR:
{
DPRINT1("USB_DEVICE_CLASS_MONITOR\n");
break;
}
case USB_DEVICE_CLASS_PHYSICAL_INTERFACE:
{
DPRINT1("USB_DEVICE_CLASS_PHYSICAL_INTERFACE\n");
break;
}
case USB_DEVICE_CLASS_POWER:
{
DPRINT1("USB_DEVICE_CLASS_POWER\n");
break;
}
case USB_DEVICE_CLASS_PRINTER:
{
DPRINT1("USB_DEVICE_CLASS_PRINTER\n");
break;
}
case USB_DEVICE_CLASS_STORAGE:
{
DPRINT1("USB_DEVICE_CLASS_STORAGE\n");
break;
}
case USB_DEVICE_CLASS_RESERVED:
DPRINT1("Reserved!!!\n");
case USB_DEVICE_CLASS_HUB:
{
DPRINT1("USB_DEVICE_CLASS_HUB request\n");
break;
}
default:
{
DPRINT1("Unknown UrbControlVendorClassRequest Value\n");
}
}
break;
}
case USB_REQUEST_GET_STATUS:
{
DPRINT1("DEVICE: USB_REQUEST_GET_STATUS for port %d\n", Urb->UrbControlVendorClassRequest.Index);
break;
}
default:
{
DPRINT1("Unhandled URB request for class device\n");
//Urb->UrbHeader.Status = USBD_STATUS_INVALID_URB_FUNCTION;
}
}
break;
}
case URB_FUNCTION_CLASS_OTHER:
{
DPRINT1("Ehci: URB_FUNCTION_CLASS_OTHER\n");
switch (Urb->UrbControlVendorClassRequest.Request)
{
case USB_REQUEST_GET_STATUS:
{
DPRINT1("OTHER: USB_REQUEST_GET_STATUS for port %d\n", Urb->UrbControlVendorClassRequest.Index);
break;
}
case USB_REQUEST_CLEAR_FEATURE:
{
DPRINT1("USB_REQUEST_CLEAR_FEATURE Port %d, value %x\n", Urb->UrbControlVendorClassRequest.Index,
Urb->UrbControlVendorClassRequest.Value);
switch (Urb->UrbControlVendorClassRequest.Value)
{
case C_PORT_CONNECTION:
DPRINT1("Clearing Connect\n");
break;
case C_PORT_RESET:
DPRINT1("Clearing Reset\n");
break;
default:
DPRINT1("Unknown Value for Clear Feature %x \n", Urb->UrbControlVendorClassRequest.Value);
break;
}
break;
}
case USB_REQUEST_SET_FEATURE:
{
DPRINT1("USB_REQUEST_SET_FEATURE Port %d, value %x\n", Urb->UrbControlVendorClassRequest.Index,
Urb->UrbControlVendorClassRequest.Value);
switch(Urb->UrbControlVendorClassRequest.Value)
{
case PORT_RESET:
{
DPRINT1("Port reset\n");
break;
}
case PORT_ENABLE:
{
DPRINT1("Unhandled Set Feature\n");
break;
}
default:
{
DPRINT1("Unknown Set Feature!\n");
break;
}
}
break;
}
case USB_REQUEST_SET_ADDRESS:
{
DPRINT1("USB_REQUEST_SET_ADDRESS\n");
break;
}
case USB_REQUEST_GET_DESCRIPTOR:
{
DPRINT1("USB_REQUEST_GET_DESCRIPTOR\n");
break;
}
case USB_REQUEST_SET_DESCRIPTOR:
{
DPRINT1("USB_REQUEST_SET_DESCRIPTOR\n");
break;
}
case USB_REQUEST_GET_CONFIGURATION:
{
DPRINT1("USB_REQUEST_GET_CONFIGURATION\n");
break;
}
case USB_REQUEST_SET_CONFIGURATION:
{
DPRINT1("USB_REQUEST_SET_CONFIGURATION\n");
break;
}
case USB_REQUEST_GET_INTERFACE:
{
DPRINT1("USB_REQUEST_GET_INTERFACE\n");
break;
}
case USB_REQUEST_SET_INTERFACE:
{
DPRINT1("USB_REQUEST_SET_INTERFACE\n");
break;
}
case USB_REQUEST_SYNC_FRAME:
{
DPRINT1("USB_REQUEST_SYNC_FRAME\n");
break;
}
default:
{
DPRINT1("Unknown Function Class Unknown request\n");
break;
}
}
break;
}
default:
{
DPRINT1("Ehci: Unhandled URB %x\n", Urb->UrbHeader.Function);
//Urb->UrbHeader.Status = USBD_STATUS_INVALID_URB_FUNCTION;
}
}
Irp->IoStatus.Information = Information;
if (Status != STATUS_PENDING)
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
} }

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <ntddk.h> #include <ntddk.h>
#include <usb.h>
/* USB Command Register */ /* USB Command Register */
#define EHCI_USBCMD 0x00 #define EHCI_USBCMD 0x00
@ -98,8 +99,9 @@ typedef struct _QUEUE_TRANSFER_DESCRIPTOR
ULONG DWord; ULONG DWord;
} Token; } Token;
ULONG BufferPointer[5]; ULONG BufferPointer[5];
//Software //Software
ULONG BufferPointerVA[5];
ULONG PhysicalAddr; ULONG PhysicalAddr;
struct _QUEUE_TRANSFER_DESCRIPTOR *PreviousDescriptor; struct _QUEUE_TRANSFER_DESCRIPTOR *PreviousDescriptor;
struct _QUEUE_TRANSFER_DESCRIPTOR *NextDescriptor; struct _QUEUE_TRANSFER_DESCRIPTOR *NextDescriptor;
@ -167,10 +169,13 @@ typedef struct _QUEUE_HEAD
ULONG PhysicalAddr; ULONG PhysicalAddr;
struct _QUEUE_HEAD *PreviousQueueHead; struct _QUEUE_HEAD *PreviousQueueHead;
struct _QUEUE_HEAD *NextQueueHead; struct _QUEUE_HEAD *NextQueueHead;
PQUEUE_TRANSFER_DESCRIPTOR TransferDescriptor; ULONG NumberOfTransferDescriptors;
PQUEUE_TRANSFER_DESCRIPTOR FirstTransferDescriptor;
PQUEUE_TRANSFER_DESCRIPTOR DeadDescriptor;
PIRP IrpToComplete; PIRP IrpToComplete;
PMDL MdlToFree;
PKEVENT Event; PKEVENT Event;
PMDL Mdl;
BOOLEAN FreeMdl;
} QUEUE_HEAD, *PQUEUE_HEAD; } QUEUE_HEAD, *PQUEUE_HEAD;
/* USBCMD register 32 bits */ /* USBCMD register 32 bits */
@ -264,14 +269,27 @@ typedef struct _EHCI_CAPS {
UCHAR PortRoute [8]; UCHAR PortRoute [8];
} EHCI_CAPS, *PEHCI_CAPS; } EHCI_CAPS, *PEHCI_CAPS;
typedef struct _EHCIPORTS
{
ULONG PortNumber;
ULONG PortType;
USHORT PortStatus;
USHORT PortChange;
} EHCIPORTS, *PEHCIPORTS;
typedef struct _EHCI_HOST_CONTROLLER typedef struct _EHCI_HOST_CONTROLLER
{ {
PDMA_ADAPTER pDmaAdapter;
ULONG MapRegisters;
ULONG OpRegisters; ULONG OpRegisters;
EHCI_CAPS ECHICaps; EHCI_CAPS ECHICaps;
PVOID CommonBufferVA; ULONG NumberOfPorts;
PHYSICAL_ADDRESS CommonBufferPA; EHCIPORTS Ports[127];
PVOID CommonBufferVA[16];
PHYSICAL_ADDRESS CommonBufferPA[16];
ULONG CommonBufferSize; ULONG CommonBufferSize;
PQUEUE_HEAD AsyncListQueue; PQUEUE_HEAD AsyncListQueue;
PQUEUE_HEAD CompletedListQueue;
KSPIN_LOCK Lock; KSPIN_LOCK Lock;
} EHCI_HOST_CONTROLLER, *PEHCI_HOST_CONTROLLER; } EHCI_HOST_CONTROLLER, *PEHCI_HOST_CONTROLLER;
@ -305,3 +323,5 @@ SetPeriodicFrameListRegister(PEHCI_HOST_CONTROLLER hcd, ULONG PhysicalAddr);
ULONG ULONG
GetPeriodicFrameListRegister(PEHCI_HOST_CONTROLLER hcd); GetPeriodicFrameListRegister(PEHCI_HOST_CONTROLLER hcd);
BOOLEAN
EnumControllerPorts(PEHCI_HOST_CONTROLLER hcd);

View file

@ -32,7 +32,6 @@ CreateDescriptor(PEHCI_HOST_CONTROLLER hcd, UCHAR PIDCode, ULONG TotalBytesToTra
Descriptor->NextPointer = TERMINATE_POINTER; Descriptor->NextPointer = TERMINATE_POINTER;
Descriptor->AlternateNextPointer = TERMINATE_POINTER; Descriptor->AlternateNextPointer = TERMINATE_POINTER;
Descriptor->Token.Bits.DataToggle = TRUE; Descriptor->Token.Bits.DataToggle = TRUE;
Descriptor->Token.Bits.InterruptOnComplete = TRUE;
Descriptor->Token.Bits.ErrorCounter = 0x03; Descriptor->Token.Bits.ErrorCounter = 0x03;
Descriptor->Token.Bits.Active = TRUE; Descriptor->Token.Bits.Active = TRUE;
Descriptor->Token.Bits.PIDCode = PIDCode; Descriptor->Token.Bits.PIDCode = PIDCode;
@ -47,9 +46,9 @@ CreateDescriptor(PEHCI_HOST_CONTROLLER hcd, UCHAR PIDCode, ULONG TotalBytesToTra
} }
VOID VOID
FreeDescriptor(PQUEUE_TRANSFER_DESCRIPTOR Descriptor) FreeDescriptor(PEHCI_HOST_CONTROLLER hcd, PQUEUE_TRANSFER_DESCRIPTOR Descriptor)
{ {
ReleaseMemory((ULONG)Descriptor); ReleaseMemory(hcd, (ULONG)Descriptor);
} }
/* Queue Head */ /* Queue Head */
@ -87,14 +86,12 @@ CreateQueueHead(PEHCI_HOST_CONTROLLER hcd)
KIRQL OldIrql; KIRQL OldIrql;
KeAcquireSpinLock(&hcd->Lock, &OldIrql); KeAcquireSpinLock(&hcd->Lock, &OldIrql);
CurrentQH = (PQUEUE_HEAD)AllocateMemory(hcd, sizeof(QUEUE_HEAD), &PhysicalAddress); CurrentQH = (PQUEUE_HEAD)AllocateMemory(hcd, sizeof(QUEUE_HEAD), &PhysicalAddress);
RtlZeroMemory(CurrentQH, sizeof(QUEUE_HEAD)); RtlZeroMemory(CurrentQH, sizeof(QUEUE_HEAD));
ASSERT(CurrentQH); ASSERT(CurrentQH);
CurrentQH->PhysicalAddr = PhysicalAddress; CurrentQH->PhysicalAddr = PhysicalAddress;
CurrentQH->HorizontalLinkPointer = TERMINATE_POINTER; CurrentQH->HorizontalLinkPointer = TERMINATE_POINTER;
CurrentQH->CurrentLinkPointer = TERMINATE_POINTER;
CurrentQH->AlternateNextPointer = TERMINATE_POINTER; CurrentQH->AlternateNextPointer = TERMINATE_POINTER;
CurrentQH->NextPointer = TERMINATE_POINTER; CurrentQH->NextPointer = TERMINATE_POINTER;
@ -107,7 +104,7 @@ CreateQueueHead(PEHCI_HOST_CONTROLLER hcd)
CurrentQH->EndPointCharacteristics.NakCountReload = 0xF; CurrentQH->EndPointCharacteristics.NakCountReload = 0xF;
/* Get the Initial Data Toggle from the QEDT */ /* Get the Initial Data Toggle from the QEDT */
CurrentQH->EndPointCharacteristics.QEDTDataToggleControl = TRUE; CurrentQH->EndPointCharacteristics.QEDTDataToggleControl = FALSE;
/* High Speed Device */ /* High Speed Device */
CurrentQH->EndPointCharacteristics.EndPointSpeed = QH_ENDPOINT_HIGHSPEED; CurrentQH->EndPointCharacteristics.EndPointSpeed = QH_ENDPOINT_HIGHSPEED;
@ -120,7 +117,7 @@ CreateQueueHead(PEHCI_HOST_CONTROLLER hcd)
for (i=0; i<5; i++) for (i=0; i<5; i++)
CurrentQH->BufferPointer[i] = 0; CurrentQH->BufferPointer[i] = 0;
CurrentQH->Token.Bits.InterruptOnComplete = TRUE; CurrentQH->Token.Bits.InterruptOnComplete = FALSE;
KeReleaseSpinLock(&hcd->Lock, OldIrql); KeReleaseSpinLock(&hcd->Lock, OldIrql);
return CurrentQH; return CurrentQH;
@ -131,19 +128,17 @@ LinkQueueHead(PEHCI_HOST_CONTROLLER hcd, PQUEUE_HEAD QueueHead)
{ {
KIRQL OldIrql; KIRQL OldIrql;
PQUEUE_HEAD CurrentHead = (PQUEUE_HEAD)hcd->AsyncListQueue; PQUEUE_HEAD CurrentHead = (PQUEUE_HEAD)hcd->AsyncListQueue;
PQUEUE_HEAD PreviousHead = CurrentHead->PreviousQueueHead; PQUEUE_HEAD PreviousHead;
KeAcquireSpinLock(&hcd->Lock, &OldIrql); KeAcquireSpinLock(&hcd->Lock, &OldIrql);
PreviousHead = CurrentHead->PreviousQueueHead;
QueueHead->HorizontalLinkPointer = (CurrentHead->HorizontalLinkPointer | QH_TYPE_QH) & ~TERMINATE_POINTER;
QueueHead->NextQueueHead = CurrentHead; QueueHead->NextQueueHead = CurrentHead;
QueueHead->PreviousQueueHead = PreviousHead; QueueHead->PreviousQueueHead = PreviousHead;
PreviousHead->NextQueueHead = QueueHead;
CurrentHead->PreviousQueueHead = QueueHead; CurrentHead->PreviousQueueHead = QueueHead;
if (PreviousHead)
PreviousHead->NextQueueHead = QueueHead; QueueHead->HorizontalLinkPointer = (CurrentHead->HorizontalLinkPointer | QH_TYPE_QH) & ~TERMINATE_POINTER;
PreviousHead->HorizontalLinkPointer = QueueHead->PhysicalAddr| QH_TYPE_QH;
CurrentHead->HorizontalLinkPointer = QueueHead->PhysicalAddr | QH_TYPE_QH;
KeReleaseSpinLock(&hcd->Lock, OldIrql); KeReleaseSpinLock(&hcd->Lock, OldIrql);
} }
@ -152,24 +147,80 @@ VOID
UnlinkQueueHead(PEHCI_HOST_CONTROLLER hcd, PQUEUE_HEAD QueueHead) UnlinkQueueHead(PEHCI_HOST_CONTROLLER hcd, PQUEUE_HEAD QueueHead)
{ {
KIRQL OldIrql; KIRQL OldIrql;
PQUEUE_HEAD PreviousHead = QueueHead->PreviousQueueHead; PQUEUE_HEAD PreviousHead;
PQUEUE_HEAD NextHead = QueueHead->NextQueueHead; PQUEUE_HEAD NextHead;
KeAcquireSpinLock(&hcd->Lock, &OldIrql); KeAcquireSpinLock(&hcd->Lock, &OldIrql);
if (PreviousHead) PreviousHead = QueueHead->PreviousQueueHead;
{ NextHead = QueueHead->NextQueueHead;
PreviousHead->NextQueueHead = NextHead;
PreviousHead->HorizontalLinkPointer = QueueHead->HorizontalLinkPointer;
}
if (NextHead)
NextHead->PreviousQueueHead = PreviousHead;
PreviousHead->NextQueueHead = NextHead;
NextHead->PreviousQueueHead = PreviousHead;
PreviousHead->HorizontalLinkPointer = NextHead->HorizontalLinkPointer;
KeReleaseSpinLock(&hcd->Lock, OldIrql); KeReleaseSpinLock(&hcd->Lock, OldIrql);
} }
VOID VOID
DeleteQueueHead(PQUEUE_HEAD QueueHead) LinkQueueHeadToCompletedList(PEHCI_HOST_CONTROLLER hcd, PQUEUE_HEAD QueueHead)
{ {
ReleaseMemory((ULONG)QueueHead); KIRQL OldIrql;
PQUEUE_HEAD CurrentHead = (PQUEUE_HEAD)hcd->CompletedListQueue;
PQUEUE_HEAD PreviousHead;
KeAcquireSpinLock(&hcd->Lock, &OldIrql);
PreviousHead = CurrentHead->PreviousQueueHead;
QueueHead->NextQueueHead = CurrentHead;
QueueHead->PreviousQueueHead = PreviousHead;
PreviousHead->NextQueueHead = QueueHead;
CurrentHead->PreviousQueueHead = QueueHead;
KeReleaseSpinLock(&hcd->Lock, OldIrql);
}
VOID
DeleteQueueHead(PEHCI_HOST_CONTROLLER hcd, PQUEUE_HEAD QueueHead)
{
ReleaseMemory(hcd, (ULONG)QueueHead);
}
VOID
CleanupAsyncList(PEHCI_HOST_CONTROLLER hcd)
{
PQUEUE_TRANSFER_DESCRIPTOR Descriptor;
PQUEUE_HEAD QueueHead;
KIRQL OldIrql;
KeAcquireSpinLock(&hcd->Lock, &OldIrql);
QueueHead = hcd->CompletedListQueue;
QueueHead = QueueHead->NextQueueHead;
while (QueueHead != hcd->CompletedListQueue)
{
Descriptor = QueueHead->FirstTransferDescriptor;
while (Descriptor)
{
if (Descriptor->Token.Bits.PIDCode == PID_CODE_SETUP_TOKEN)
ReleaseMemory(hcd, Descriptor->BufferPointerVA[0]);
FreeDescriptor(hcd, Descriptor);
Descriptor = Descriptor->NextDescriptor;
}
if (QueueHead->FreeMdl)
{
DPRINT("Freeing Mdl %x, StartVA %x\n", QueueHead->Mdl, QueueHead->Mdl->StartVa);
IoFreeMdl(QueueHead->Mdl);
}
QueueHead = QueueHead->NextQueueHead;
}
hcd->CompletedListQueue->NextQueueHead = hcd->CompletedListQueue;
hcd->CompletedListQueue->PreviousQueueHead = hcd->CompletedListQueue;
KeReleaseSpinLock(&hcd->Lock, OldIrql);
} }

View file

@ -5,7 +5,7 @@ PQUEUE_TRANSFER_DESCRIPTOR
CreateDescriptor(PEHCI_HOST_CONTROLLER hcd, UCHAR PIDCode, ULONG TotalBytesToTransfer); CreateDescriptor(PEHCI_HOST_CONTROLLER hcd, UCHAR PIDCode, ULONG TotalBytesToTransfer);
VOID VOID
FreeDescriptor(PQUEUE_TRANSFER_DESCRIPTOR Descriptor); FreeDescriptor(PEHCI_HOST_CONTROLLER hcd, PQUEUE_TRANSFER_DESCRIPTOR Descriptor);
VOID VOID
DumpQueueHeadList(PEHCI_HOST_CONTROLLER hcd); DumpQueueHeadList(PEHCI_HOST_CONTROLLER hcd);
@ -20,5 +20,10 @@ VOID
UnlinkQueueHead(PEHCI_HOST_CONTROLLER hcd, PQUEUE_HEAD QueueHead); UnlinkQueueHead(PEHCI_HOST_CONTROLLER hcd, PQUEUE_HEAD QueueHead);
VOID VOID
DeleteQueueHead(PQUEUE_HEAD QueueHead); DeleteQueueHead(PEHCI_HOST_CONTROLLER hcd, PQUEUE_HEAD QueueHead);
VOID
LinkQueueHeadToCompletedList(PEHCI_HOST_CONTROLLER hcd, PQUEUE_HEAD QueueHead);
VOID
CleanupAsyncList(PEHCI_HOST_CONTROLLER hcd);