mirror of
https://github.com/reactos/reactos.git
synced 2024-07-07 13:15:07 +00:00
[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:
parent
d4f7a44a18
commit
4dff45da57
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -95,4 +95,9 @@ NTSTATUS CreateUSBDevice(PUSBDEVICE *OutDevice);
|
|||
//
|
||||
NTSTATUS CreateUSBQueue(PUSBQUEUE *OutUsbQueue);
|
||||
|
||||
//
|
||||
// usb_request.cpp
|
||||
//
|
||||
NTSTATUS InternalCreateUSBRequest(PUSBREQUEST *OutRequest);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue