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

View file

@ -11,6 +11,9 @@
#define INITGUID #define INITGUID
#include "usbehci.h" #include "usbehci.h"
VOID StatusChangeEndpointCallBack(
PVOID Context);
class CHubController : public IHubController, class CHubController : public IHubController,
public IDispatchIrp public IDispatchIrp
{ {
@ -63,6 +66,7 @@ public:
NTSTATUS HandleClassOther(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleClassOther(IN OUT PIRP Irp, PURB Urb);
NTSTATUS HandleBulkOrInterruptTransfer(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleBulkOrInterruptTransfer(IN OUT PIRP Irp, PURB Urb);
friend VOID StatusChangeEndpointCallBack(PVOID Context);
// constructor / destructor // constructor / destructor
CHubController(IUnknown *OuterUnknown){} CHubController(IUnknown *OuterUnknown){}
@ -91,6 +95,9 @@ protected:
PULONG m_DeviceAddressBitmapBuffer; PULONG m_DeviceAddressBitmapBuffer;
LIST_ENTRY m_UsbDeviceList; LIST_ENTRY m_UsbDeviceList;
PIRP m_PendingSCEIrp; PIRP m_PendingSCEIrp;
//Internal Functions
BOOLEAN QueryStatusChageEndpoint(PIRP Irp);
}; };
typedef struct typedef struct
@ -253,6 +260,10 @@ CHubController::Initialize(
m_DeviceDescriptor.bcdUSB = 0x200; //FIXME 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 // clear init flag
// //
@ -262,6 +273,62 @@ CHubController::Initialize(
return STATUS_SUCCESS; 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 NTSTATUS
CHubController::GetHubControllerDeviceObject(PDEVICE_OBJECT * HubDeviceObject) CHubController::GetHubControllerDeviceObject(PDEVICE_OBJECT * HubDeviceObject)
@ -693,9 +760,6 @@ CHubController::HandleBulkOrInterruptTransfer(
IN OUT PIRP Irp, IN OUT PIRP Irp,
PURB Urb) PURB Urb)
{ {
ULONG PortCount, PortId;
USHORT PortStatus, PortChange;
// //
// First check if the request is for the Status Change Endpoint // First check if the request is for the Status Change Endpoint
// //
@ -703,42 +767,13 @@ CHubController::HandleBulkOrInterruptTransfer(
// //
// Is the Request for the root hub // Is the Request for the root hub
// //
if (Urb->UrbHeader.UsbdDeviceHandle==0) if (Urb->UrbHeader.UsbdDeviceHandle == 0)
{ {
// ASSERT(m_PendingSCEIrp == NULL);
// There should only be one SCE request pending at a time if (QueryStatusChageEndpoint(Irp))
//
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++)
{ {
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; return STATUS_SUCCESS;
}
// //
// Else pend the IRP, to be completed when a device connects or disconnects. // Else pend the IRP, to be completed when a device connects or disconnects.
@ -747,6 +782,7 @@ CHubController::HandleBulkOrInterruptTransfer(
IoMarkIrpPending(Irp); IoMarkIrpPending(Irp);
return STATUS_PENDING; return STATUS_PENDING;
} }
UNIMPLEMENTED UNIMPLEMENTED
return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED;
} }
@ -2843,3 +2879,22 @@ CreateHubController(
// //
return STATUS_SUCCESS; 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; 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 // AcquireDeviceLock

View file

@ -48,8 +48,8 @@ protected:
LONG m_Ref; LONG m_Ref;
KSPIN_LOCK m_Lock; KSPIN_LOCK m_Lock;
PDMA_ADAPTER m_Adapter; PDMA_ADAPTER m_Adapter;
PQUEUE_HEAD AsyncQueueHead; PQUEUE_HEAD AsyncListQueueHead;
PQUEUE_HEAD PendingQueueHead; PQUEUE_HEAD PendingListQueueHead;
VOID LinkQueueHead(PQUEUE_HEAD HeadQueueHead, PQUEUE_HEAD NewQueueHead); VOID LinkQueueHead(PQUEUE_HEAD HeadQueueHead, PQUEUE_HEAD NewQueueHead);
VOID UnlinkQueueHead(PQUEUE_HEAD QueueHead); VOID UnlinkQueueHead(PQUEUE_HEAD QueueHead);
@ -93,6 +93,26 @@ CUSBQueue::Initialize(
// //
KeInitializeSpinLock(&m_Lock); 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; return Status;
} }
@ -112,8 +132,17 @@ NTSTATUS
CUSBQueue::AddUSBRequest( CUSBQueue::AddUSBRequest(
IUSBRequest * Request) IUSBRequest * Request)
{ {
UNIMPLEMENTED PQUEUE_HEAD QueueHead;
return STATUS_NOT_IMPLEMENTED; ASSERT(Request != NULL);
Request->GetQueueHead(&QueueHead);
//
// Add it to the pending list
//
LinkQueueHead(PendingListQueueHead, QueueHead);
return STATUS_SUCCESS;
} }
NTSTATUS NTSTATUS
@ -135,8 +164,18 @@ NTSTATUS
CUSBQueue::CreateUSBRequest( CUSBQueue::CreateUSBRequest(
IUSBRequest **OutRequest) IUSBRequest **OutRequest)
{ {
UNIMPLEMENTED PUSBREQUEST UsbRequest;
return STATUS_NOT_IMPLEMENTED; NTSTATUS Status;
*OutRequest = NULL;
Status = InternalCreateUSBRequest(&UsbRequest);
if (NT_SUCCESS(Status))
{
*OutRequest = UsbRequest;
}
return Status;
} }
// //

View file

@ -935,3 +935,37 @@ CUSBRequest::ShouldReleaseRequestAfterCompletion()
return FALSE; 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); NTSTATUS CreateUSBQueue(PUSBQUEUE *OutUsbQueue);
//
// usb_request.cpp
//
NTSTATUS InternalCreateUSBRequest(PUSBREQUEST *OutRequest);
#endif #endif