[USBEHCI_NEW]

hub_controller: 
- Implement  StatusChangeEndpointCallBack called by HardwareDevice class when port status has changed on controller.
- Move Status Change Endpoint query code to IQueryStatusChageEndpoint as it is also needed by StatusChangeEndpointCallBack.
usb_request: 
- Implement InternalCreateUsbRequest.
usb_queue:
- Implement  CreateUsbRequest and AddUsbRequest
hardware:
- Implement GetAsyncListRegister and GetPeriodicListRegister.
- Implement SetStatusChangeEndpointCallBack for setting callback and context. Call the callback when a port status changes.
- Initialize the UsbQueue after creating the AsyncQueueHead, as the UsbQueue calls will call back with GetAsyncListRegister.



svn path=/branches/usb-bringup/; revision=51407
This commit is contained in:
Michael Martin 2011-04-20 04:30:22 +00:00
parent d4f7a44a18
commit 4dff45da57
6 changed files with 243 additions and 56 deletions

View file

@ -12,6 +12,8 @@
#include "usbehci.h"
#include "hardware.h"
typedef VOID __stdcall HD_INIT_CALLBACK(IN PVOID CallBackContext);
BOOLEAN
NTAPI
InterruptServiceRoutine(
@ -66,6 +68,10 @@ public:
VOID SetAsyncListRegister(ULONG PhysicalAddress);
VOID SetPeriodicListRegister(ULONG PhysicalAddress);
ULONG GetAsyncListRegister();
ULONG GetPeriodicListRegister();
VOID SetStatusChangeEndpointCallBack(PVOID CallBack, PVOID Context);
KIRQL AcquireDeviceLock(void);
VOID ReleaseDeviceLock(KIRQL OldLevel);
@ -100,7 +106,8 @@ protected:
PQUEUE_HEAD AsyncQueueHead;
PUSBQUEUE m_UsbQueue;
PDMAMEMORYMANAGER m_MemoryManager;
HD_INIT_CALLBACK* m_SCECallBack;
PVOID m_SCEContext;
VOID SetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd);
VOID GetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd);
ULONG EHCI_READ_REGISTER_ULONG(ULONG Offset);
@ -385,16 +392,6 @@ CUSBHardwareDevice::PnpStart(
return Status;
}
//
// Initialize the UsbQueue now that we have an AdapterObject.
//
Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to Initialize the UsbQueue\n");
return Status;
}
//
// Create a queuehead for the Async Register
//
@ -413,8 +410,20 @@ CUSBHardwareDevice::PnpStart(
AsyncQueueHead->EndPointCharacteristics.EndPointSpeed = QH_ENDPOINT_HIGHSPEED;
AsyncQueueHead->EndPointCapabilities.NumberOfTransactionPerFrame = 0x03;
InitializeListHead(&AsyncQueueHead->LinkedQueueHeads);
SetAsyncListRegister(AsyncQueueHead->PhysicalAddr);
//
// Initialize the UsbQueue now that we have an AdapterObject.
//
Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to Initialize the UsbQueue\n");
return Status;
}
//
// Start the controller
//
@ -838,6 +847,26 @@ CUSBHardwareDevice::SetPeriodicListRegister(
EHCI_WRITE_REGISTER_ULONG(EHCI_PERIODICLISTBASE, PhysicalAddress);
}
ULONG
CUSBHardwareDevice::GetAsyncListRegister()
{
return PhysicalAddress.LowPart;
}
ULONG CUSBHardwareDevice::GetPeriodicListRegister()
{
UNIMPLEMENTED
return NULL;
}
VOID CUSBHardwareDevice::SetStatusChangeEndpointCallBack(
PVOID CallBack,
PVOID Context)
{
m_SCECallBack = (HD_INIT_CALLBACK*)CallBack;
m_SCEContext = Context;
}
KIRQL
CUSBHardwareDevice::AcquireDeviceLock(void)
{
@ -937,7 +966,7 @@ EhciDefferedRoutine(
//
// Clear the port change status
//
This->EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * i), PortStatus | EHCI_PRT_CONNECTSTATUSCHANGE);
//This->EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * i), PortStatus | EHCI_PRT_CONNECTSTATUSCHANGE);
if (PortStatus & EHCI_PRT_CONNECTED)
{
@ -964,6 +993,7 @@ EhciDefferedRoutine(
// FIXME: Is a port reset needed, or does hub driver request this?
//
}
This->m_SCECallBack(This->m_SCEContext);
}
else
{

View file

@ -11,6 +11,9 @@
#define INITGUID
#include "usbehci.h"
VOID StatusChangeEndpointCallBack(
PVOID Context);
class CHubController : public IHubController,
public IDispatchIrp
{
@ -62,7 +65,8 @@ public:
NTSTATUS HandleSelectConfiguration(IN OUT PIRP Irp, PURB Urb);
NTSTATUS HandleClassOther(IN OUT PIRP Irp, PURB Urb);
NTSTATUS HandleBulkOrInterruptTransfer(IN OUT PIRP Irp, PURB Urb);
friend VOID StatusChangeEndpointCallBack(PVOID Context);
// constructor / destructor
CHubController(IUnknown *OuterUnknown){}
@ -91,6 +95,9 @@ protected:
PULONG m_DeviceAddressBitmapBuffer;
LIST_ENTRY m_UsbDeviceList;
PIRP m_PendingSCEIrp;
//Internal Functions
BOOLEAN QueryStatusChageEndpoint(PIRP Irp);
};
typedef struct
@ -253,6 +260,10 @@ CHubController::Initialize(
m_DeviceDescriptor.bcdUSB = 0x200; //FIXME
}
//
// Set the SCE Callback that the Hardware Device will call on port status change
//
Device->SetStatusChangeEndpointCallBack((PVOID)StatusChangeEndpointCallBack, this);
//
// clear init flag
//
@ -262,6 +273,62 @@ CHubController::Initialize(
return STATUS_SUCCESS;
}
//
// Queries the ports to see if there has been a device connected or removed.
//
BOOLEAN
CHubController::QueryStatusChageEndpoint(
PIRP Irp)
{
ULONG PortCount, PortId;
PIO_STACK_LOCATION IoStack;
USHORT PortStatus, PortChange;
PURB Urb;
//
// get current stack location
//
IoStack = IoGetCurrentIrpStackLocation(Irp);
ASSERT(IoStack);
//
// Get the Urb
//
Urb = (PURB)IoStack->Parameters.Others.Argument1;
ASSERT(Urb);
//
// Get the number of ports and check each one for device connected
//
m_Hardware->GetDeviceDetails(NULL, NULL, &PortCount, NULL);
DPRINT1("SCE Request\n");
((PULONG)Urb->UrbBulkOrInterruptTransfer.TransferBuffer)[0] = 0;
for (PortId = 0; PortId < PortCount; PortId++)
{
m_Hardware->GetPortStatus(PortId, &PortStatus, &PortChange);
DPRINT1("Port %d: Status %x, Change %x\n", PortId, PortStatus, PortChange);
//
// Loop the ports
//
if ((PortStatus & USB_PORT_STATUS_CONNECT) && (PortChange & USB_PORT_STATUS_CONNECT))
{
DPRINT1("Device is connected on port %d\n", PortId);
// Set the value for the port number
((PUCHAR)Urb->UrbBulkOrInterruptTransfer.TransferBuffer)[0] = 1 << ((PortId + 1) & 7);
}
}
//
// If there were changes then return TRUE
//
if (((PULONG)Urb->UrbBulkOrInterruptTransfer.TransferBuffer)[0] != 0)
return TRUE;
return FALSE;
}
//-----------------------------------------------------------------------------------------
NTSTATUS
CHubController::GetHubControllerDeviceObject(PDEVICE_OBJECT * HubDeviceObject)
@ -693,9 +760,6 @@ CHubController::HandleBulkOrInterruptTransfer(
IN OUT PIRP Irp,
PURB Urb)
{
ULONG PortCount, PortId;
USHORT PortStatus, PortChange;
//
// First check if the request is for the Status Change Endpoint
//
@ -703,42 +767,13 @@ CHubController::HandleBulkOrInterruptTransfer(
//
// Is the Request for the root hub
//
if (Urb->UrbHeader.UsbdDeviceHandle==0)
if (Urb->UrbHeader.UsbdDeviceHandle == 0)
{
//
// There should only be one SCE request pending at a time
//
ASSERT (m_PendingSCEIrp == NULL);
//
// Get the number of ports and check each one for device connected
//
m_Hardware->GetDeviceDetails(NULL, NULL, &PortCount, NULL);
DPRINT1("SCE Request\n");
DPRINT1("PortCount %d\n", PortCount);
((PULONG)Urb->UrbBulkOrInterruptTransfer.TransferBuffer)[0] = 0;
for (PortId = 0; PortId < PortCount; PortId++)
ASSERT(m_PendingSCEIrp == NULL);
if (QueryStatusChageEndpoint(Irp))
{
m_Hardware->GetPortStatus(PortId, &PortStatus, &PortChange);
DPRINT1("Port %d: Status %x, Change %x\n", PortId, PortStatus, PortChange);
//
// FIXME: Verify that this is correct.
//
if ((PortStatus & USB_PORT_STATUS_CONNECT) && (PortChange & USB_PORT_STATUS_CONNECT))
{
DPRINT1("Device is connected on port %d\n", PortId);
((PUCHAR)Urb->UrbBulkOrInterruptTransfer.TransferBuffer)[0] = 1 << ((PortId + 1) & 7);
break;
}
}
//
// If there were changes then return SUCCESS
//
if (((PULONG)Urb->UrbBulkOrInterruptTransfer.TransferBuffer)[0] != 0)
return STATUS_SUCCESS;
}
//
// Else pend the IRP, to be completed when a device connects or disconnects.
@ -747,6 +782,7 @@ CHubController::HandleBulkOrInterruptTransfer(
IoMarkIrpPending(Irp);
return STATUS_PENDING;
}
UNIMPLEMENTED
return STATUS_NOT_IMPLEMENTED;
}
@ -2843,3 +2879,22 @@ CreateHubController(
//
return STATUS_SUCCESS;
}
VOID StatusChangeEndpointCallBack(PVOID Context)
{
CHubController* This;
PIRP Irp;
This = (CHubController*)Context;
ASSERT(This);
DPRINT1("SCE Notification!\n");
Irp = This->m_PendingSCEIrp;
This->m_PendingSCEIrp = NULL;
This->QueryStatusChageEndpoint(Irp);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}

View file

@ -262,6 +262,30 @@ DECLARE_INTERFACE_(IUSBHardwareDevice, IUnknown)
//
virtual VOID SetPeriodicListRegister(ULONG PhysicalAddress) = 0;
//-----------------------------------------------------------------------------------------
//
// GetAsyncListRegister
//
// Description: Returns the memory address used in the Asynchronous Register
//
virtual ULONG GetAsyncListRegister() = 0;
//-----------------------------------------------------------------------------------------
//
// GetPeriodicListRegister
//
// Description: Returns the the memory address used in the Periodic Register
//
virtual ULONG GetPeriodicListRegister() = 0;
//-----------------------------------------------------------------------------------------
//
// SetStatusChangeEndpointCallBack
//
// Description: Used to callback to the hub controller when SCE detected
//
virtual VOID SetStatusChangeEndpointCallBack(PVOID CallBack,PVOID Context) = 0;
//-----------------------------------------------------------------------------------------
//
// AcquireDeviceLock

View file

@ -48,8 +48,8 @@ protected:
LONG m_Ref;
KSPIN_LOCK m_Lock;
PDMA_ADAPTER m_Adapter;
PQUEUE_HEAD AsyncQueueHead;
PQUEUE_HEAD PendingQueueHead;
PQUEUE_HEAD AsyncListQueueHead;
PQUEUE_HEAD PendingListQueueHead;
VOID LinkQueueHead(PQUEUE_HEAD HeadQueueHead, PQUEUE_HEAD NewQueueHead);
VOID UnlinkQueueHead(PQUEUE_HEAD QueueHead);
@ -93,6 +93,26 @@ CUSBQueue::Initialize(
//
KeInitializeSpinLock(&m_Lock);
//
// Get the AsyncQueueHead
//
AsyncListQueueHead = (PQUEUE_HEAD)Hardware->GetAsyncListRegister();
//
// Create the PendingListQueueHead from NONPAGEDPOOL. It will never be linked into the Asynclist Schedule
//
PendingListQueueHead = (PQUEUE_HEAD)ExAllocatePoolWithTag(NonPagedPool, sizeof(QUEUE_HEAD), TAG_USBEHCI);
if (!PendingListQueueHead)
{
DPRINT1("Pool Allocation failed!\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Initialize the List Head
//
InitializeListHead(&PendingListQueueHead->LinkedQueueHeads);
return Status;
}
@ -112,8 +132,17 @@ NTSTATUS
CUSBQueue::AddUSBRequest(
IUSBRequest * Request)
{
UNIMPLEMENTED
return STATUS_NOT_IMPLEMENTED;
PQUEUE_HEAD QueueHead;
ASSERT(Request != NULL);
Request->GetQueueHead(&QueueHead);
//
// Add it to the pending list
//
LinkQueueHead(PendingListQueueHead, QueueHead);
return STATUS_SUCCESS;
}
NTSTATUS
@ -135,8 +164,18 @@ NTSTATUS
CUSBQueue::CreateUSBRequest(
IUSBRequest **OutRequest)
{
UNIMPLEMENTED
return STATUS_NOT_IMPLEMENTED;
PUSBREQUEST UsbRequest;
NTSTATUS Status;
*OutRequest = NULL;
Status = InternalCreateUSBRequest(&UsbRequest);
if (NT_SUCCESS(Status))
{
*OutRequest = UsbRequest;
}
return Status;
}
//

View file

@ -934,4 +934,38 @@ CUSBRequest::ShouldReleaseRequestAfterCompletion()
//
return FALSE;
}
}
}
NTSTATUS
InternalCreateUSBRequest(
PUSBREQUEST *OutRequest)
{
PUSBREQUEST This;
//
// allocate requests
//
This = new(NonPagedPool, TAG_USBEHCI) CUSBRequest(0);
if (!This)
{
//
// failed to allocate
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// add reference count
//
This->AddRef();
//
// return result
//
*OutRequest = (PUSBREQUEST)This;
//
// done
//
return STATUS_SUCCESS;
}

View file

@ -95,4 +95,9 @@ NTSTATUS CreateUSBDevice(PUSBDEVICE *OutDevice);
//
NTSTATUS CreateUSBQueue(PUSBQUEUE *OutUsbQueue);
//
// usb_request.cpp
//
NTSTATUS InternalCreateUSBRequest(PUSBREQUEST *OutRequest);
#endif