[USBEHCI_NEW]

- Fix warning because comparing signed vs unsigned
- Implement function for retrieving the device descriptor
- Implement function for retrieving a configuration descriptor (including contained interface descriptor and endpoint descriptor)
- Cleanup interface for IUSBRequest:
- When caller initializes IUSBRequest with an IRP, then the operation mode is asynchronously. Therefore when the request is completed, IUSBRequest::ShouldReleaseRequestAfterCompletion will return true, which makes IUSBQueue call Release on IUSBRequest
- When the caller initializes IUSBRequest with an setup packet, the operation mode is synchronously. After submitting the IUSBRequest to queue, the caller should call IUSBRequest::GetResultStatus. This function will then block untill the operation has been completed. However, the caller needs to call Release() as those requests are not cleaned up by the IUSBQueue


svn path=/branches/usb-bringup/; revision=51406
This commit is contained in:
Johannes Anderwald 2011-04-19 18:35:40 +00:00
parent 9b8bc8512c
commit d4f7a44a18
4 changed files with 647 additions and 155 deletions

View file

@ -288,7 +288,7 @@ CHubController::GetHubControllerSymbolicLink(
return STATUS_UNSUCCESSFUL;
}
if (BufferLength < m_HubDeviceInterfaceString.Length - 8)
if (BufferLength < (ULONG)m_HubDeviceInterfaceString.Length - 8)
{
//
// buffer too small
@ -774,7 +774,7 @@ CHubController::HandleClassOther(
//
// sanity check
//
PC_ASSERT(Urb->UrbControlVendorClassRequest.Index - 1 < NumPort);
PC_ASSERT(Urb->UrbControlVendorClassRequest.Index - 1 < (USHORT)NumPort);
//
// port range reported start from 1 -n
@ -1882,7 +1882,8 @@ USBHI_GetUsbDescriptors(
//
// submit urb
//
Status = UsbDevice->SubmitUrb(Urb);
//Status = UsbDevice->SubmitUrb(Urb);
UNIMPLEMENTED
if (NT_SUCCESS(Status))
{

View file

@ -172,6 +172,15 @@ DECLARE_INTERFACE_(IUSBHardwareDevice, IUnknown)
virtual NTSTATUS GetUSBQueue(OUT struct IUSBQueue **OutUsbQueue) = 0;
//-----------------------------------------------------------------------------------------
//
// GetDMA
//
// Description: returns the DMA object which can be used to allocate memory from the common buffer
virtual NTSTATUS GetDMA(OUT struct IDMAMemoryManager **OutDMAMemoryManager) = 0;
//-----------------------------------------------------------------------------------------
//
// ResetController()
@ -363,40 +372,33 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown)
// The irp contains an URB block which contains all necessary information
virtual NTSTATUS InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager,
IN OUT PIRP Irp);
//-----------------------------------------------------------------------------------------
//
// SetCompletionEvent
//
// Description: sets up completion event which is signaled when the
// request is completed or cancelled
virtual NTSTATUS SetCompletionEvent(IN PKEVENT Event) = 0;
IN OUT PIRP Irp) = 0;
//-----------------------------------------------------------------------------------------
//
// CompletionCallback
//
// Description: called when request has been completed. It is called when
// IUSBQueue completes the request
// IUSBQueue completes a queue head
virtual VOID CompletionCallback(IN NTSTATUS NtStatusCode,
IN ULONG UrbStatusCode) = 0;
IN ULONG UrbStatusCode,
IN struct _QUEUE_HEAD *QueueHead) = 0;
//-----------------------------------------------------------------------------------------
//
// CancelCallback
//
// Description: called when request is cancelled. Called by IUSBQueue
// Description: called when the queue head is cancelled
virtual VOID CancelCallback(IN NTSTATUS NtStatusCode) = 0;
virtual VOID CancelCallback(IN NTSTATUS NtStatusCode,
IN struct _QUEUE_HEAD *QueueHead) = 0;
//-----------------------------------------------------------------------------------------
//
// GetQueueHead
//
// Description: returns an initialized queue head with contains the all transfer descriptors
// Description: returns an initialized queue head which contains all transfer descriptors
virtual NTSTATUS GetQueueHead(struct _QUEUE_HEAD ** OutHead) = 0;
@ -406,6 +408,9 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown)
//
// Description: returns true when the request has been completed
// Should be called after the CompletionCallback has been invoked
// This function is called by IUSBQueue after queue head has been completed
// If the function returns true, IUSBQueue will then call ShouldReleaseRequestAfterCompletion
// If that function returns also true, it calls Release() to delete the IUSBRequest
virtual BOOLEAN IsRequestComplete() = 0;
@ -417,6 +422,34 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown)
virtual ULONG GetTransferType() = 0;
//-----------------------------------------------------------------------------------------
//
// GetResultStatus
//
// Description: returns the status code of the result
// Note: this function will block the caller untill the request has been completed
virtual VOID GetResultStatus(OUT OPTIONAL NTSTATUS * NtStatusCode,
OUT OPTIONAL PULONG UrbStatusCode) = 0;
//-----------------------------------------------------------------------------------------
//
// IsRequestInitialized
//
// Description: returns true when the request has been successfully initialized using InitializeXXX methods
virtual BOOLEAN IsRequestInitialized() = 0;
//-----------------------------------------------------------------------------------------
//
// ShouldReleaseRequestAfterCompletion
//
// Description: this function gets called when the request returns
// IUSBQueue will then call Release() on the object to release all associated memory
// This function will typically return true when the request has been initialized with an irp
// If the request was initialized with an setup packet, it will return false
virtual BOOLEAN ShouldReleaseRequestAfterCompletion() = 0;
};
typedef IUSBRequest *PUSBREQUEST;
@ -446,7 +479,7 @@ DECLARE_INTERFACE_(IUSBQueue, IUnknown)
//
// GetPendingRequestCount
//
// Description: returns the number of pending requests
// Description: returns the number of pending requests true from IsRequestComplete
virtual ULONG GetPendingRequestCount() = 0;
@ -608,7 +641,7 @@ DECLARE_INTERFACE_(IUSBDevice, IUnknown)
//
// Description: gets the device address of the this device
virtual ULONG GetDeviceAddress() = 0;
virtual UCHAR GetDeviceAddress() = 0;
//-----------------------------------------------------------------------------------------
@ -657,7 +690,7 @@ DECLARE_INTERFACE_(IUSBDevice, IUnknown)
//
// Description: sets device handle data
virtual NTSTATUS SetDeviceAddress(ULONG DeviceAddress) = 0;
virtual NTSTATUS SetDeviceAddress(UCHAR DeviceAddress) = 0;
//-----------------------------------------------------------------------------------------
//
@ -677,11 +710,11 @@ DECLARE_INTERFACE_(IUSBDevice, IUnknown)
//-----------------------------------------------------------------------------------------
//
// SubmitUrb
// SubmitIrp
//
// Description: submits an urb
// Description: submits an irp containing an urb
virtual NTSTATUS SubmitUrb(PURB Urb) = 0;
virtual NTSTATUS SubmitIrp(PIRP Urb) = 0;
};

View file

@ -11,6 +11,24 @@
#define INITGUID
#include "usbehci.h"
typedef struct _USB_ENDPOINT
{
USB_ENDPOINT_DESCRIPTOR EndPointDescriptor;
} USB_ENDPOINT, *PUSB_ENDPOINT;
typedef struct _USB_INTERFACE
{
USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
USB_ENDPOINT *EndPoints;
} USB_INTERFACE, *PUSB_INTERFACE;
typedef struct _USB_CONFIGURATION
{
USB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
USB_INTERFACE *Interfaces;
} USB_CONFIGURATION, *PUSB_CONFIGURATION;
class CUSBDevice : public IUSBDevice
{
public:
@ -37,20 +55,22 @@ public:
virtual NTSTATUS Initialize(IN PHUBCONTROLLER HubController, IN PUSBHARDWAREDEVICE Device, IN PVOID Parent, IN ULONG Port, IN ULONG PortStatus);
virtual BOOLEAN IsHub();
virtual NTSTATUS GetParent(PVOID * Parent);
virtual ULONG GetDeviceAddress();
virtual UCHAR GetDeviceAddress();
virtual ULONG GetPort();
virtual USB_DEVICE_SPEED GetSpeed();
virtual USB_DEVICE_TYPE GetType();
virtual ULONG GetState();
virtual void SetDeviceHandleData(PVOID Data);
virtual NTSTATUS SetDeviceAddress(ULONG DeviceAddress);
virtual NTSTATUS SetDeviceAddress(UCHAR DeviceAddress);
virtual void GetDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor);
virtual UCHAR GetConfigurationValue();
virtual NTSTATUS SubmitUrb(PURB Urb);
virtual NTSTATUS SubmitIrp(PIRP Irp);
// local function
virtual NTSTATUS CommitUrb(PURB Urb);
virtual NTSTATUS CommitSetupPacket(PUSB_DEFAULT_PIPE_SETUP_PACKET Packet, IN ULONG BufferLength, IN OUT PVOID Buffer, IN OPTIONAL PIRP Irp, IN OPTIONAL PKEVENT pEvent);
virtual NTSTATUS CommitIrp(PIRP Irp);
virtual NTSTATUS CommitSetupPacket(PUSB_DEFAULT_PIPE_SETUP_PACKET Packet, IN ULONG BufferLength, IN OUT PMDL Mdl);
virtual NTSTATUS CreateConfigurationDescriptor(ULONG ConfigurationIndex);
virtual NTSTATUS CreateDeviceDescriptor();
// constructor / destructor
CUSBDevice(IUnknown *OuterUnknown){}
@ -62,13 +82,15 @@ protected:
PUSBHARDWAREDEVICE m_Device;
PVOID m_Parent;
ULONG m_Port;
ULONG m_DeviceAddress;
UCHAR m_DeviceAddress;
PVOID m_Data;
KSPIN_LOCK m_Lock;
USB_DEVICE_DESCRIPTOR m_DeviceDescriptor;
ULONG m_PortStatus;
PUSBQUEUE m_Queue;
PDMAMEMORYMANAGER m_DmaManager;
PUSB_CONFIGURATION m_ConfigurationDescriptors;
};
//----------------------------------------------------------------------------------------
@ -126,45 +148,34 @@ CUSBDevice::Initialize(
}
//
// FIXME: get dma manager
// get dma manager
//
//Status = m_Device->GetDMA(&m_DmaManager);
Status = m_Device->GetDMA(&m_DmaManager);
if (!NT_SUCCESS(Status))
{
//
// failed to get usb queue
// failed to get dma manager
//
DPRINT1("CUSBDevice::Initialize GetUsbQueue failed with %x\n", Status);
DPRINT1("CUSBDevice::Initialize GetDMA failed with %x\n", Status);
return Status;
}
//
// sanity check
//
PC_ASSERT(m_DmaManager);
//
// zero descriptor
//
RtlZeroMemory(&m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
//
// setup request
//
CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
CtrlSetup.wValue.HiByte = USB_DEVICE_DESCRIPTOR_TYPE;
CtrlSetup.wLength = sizeof(USB_DEVICE_DESCRIPTOR);
CtrlSetup.bmRequestType.B = 0x80;
//
// commit setup packet
//
Status = CommitSetupPacket(&CtrlSetup, sizeof(USB_DEVICE_DESCRIPTOR), &m_DeviceDescriptor, 0, 0);
//
// check for success
// get device descriptor
//
Status = CreateDeviceDescriptor();
if (!NT_SUCCESS(Status))
{
DPRINT1("CUSBDevice::Initialize CommitSetupPacket failed with %x\n", Status);
//
// failed to get device descriptor
//
DPRINT1("CUSBDevice::Initialize Failed to get device descriptor with %x\n", Status);
return Status;
}
//
@ -201,7 +212,7 @@ CUSBDevice::GetParent(
}
//----------------------------------------------------------------------------------------
ULONG
UCHAR
CUSBDevice::GetDeviceAddress()
{
//
@ -295,10 +306,12 @@ CUSBDevice::SetDeviceHandleData(
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBDevice::SetDeviceAddress(
ULONG DeviceAddress)
UCHAR DeviceAddress)
{
USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
NTSTATUS Status;
UCHAR OldAddress;
ULONG Index;
//
// zero request
@ -314,7 +327,7 @@ CUSBDevice::SetDeviceAddress(
//
// set device address
//
Status = CommitSetupPacket(&CtrlSetup, 0, 0, 0, 0);
Status = CommitSetupPacket(&CtrlSetup, 0, 0);
//
// check for success
@ -329,14 +342,69 @@ CUSBDevice::SetDeviceAddress(
}
//
// store device address
// back up old address
//
OldAddress = m_DeviceAddress;
//
// store new device address
//
m_DeviceAddress = DeviceAddress;
//
// check that setting device address succeeded by retrieving the device descriptor
//
Status = CreateDeviceDescriptor();
if (!NT_SUCCESS(Status))
{
//
// failed to retrieve device descriptor
//
DPRINT1("CUSBbDevice::SetDeviceAddress> failed to set new device address %d, falling back to %d Error %x\n", DeviceAddress, OldAddress, Status);
m_DeviceAddress = OldAddress;
//
// return error status
//
return Status;
}
//
// sanity checks
//
PC_ASSERT(m_DeviceDescriptor.bNumConfigurations);
//
// allocate configuration descriptor
//
m_ConfigurationDescriptors = (PUSB_CONFIGURATION) ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_CONFIGURATION) * m_DeviceDescriptor.bNumConfigurations, TAG_USBEHCI);
//
// zero configuration descriptor
//
RtlZeroMemory(m_ConfigurationDescriptors, sizeof(USB_CONFIGURATION) * m_DeviceDescriptor.bNumConfigurations);
//
// retrieve the configuration descriptors
//
for(Index = 0; Index < m_DeviceDescriptor.bNumConfigurations; Index++)
{
//
// retrieve configuration descriptors from device
//
Status = CreateConfigurationDescriptor(Index);
if (!NT_SUCCESS(Status))
{
DPRINT1("CUSBDevice::SetDeviceAddress> failed to retrieve configuration %lu\n", Index);
break;
}
}
//
// done
//
return STATUS_SUCCESS;
return Status;
}
//----------------------------------------------------------------------------------------
@ -357,17 +425,63 @@ CUSBDevice::GetConfigurationValue()
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBDevice::CommitUrb(
PURB Urb)
CUSBDevice::CommitIrp(
PIRP Irp)
{
UNIMPLEMENTED
return STATUS_NOT_IMPLEMENTED;
NTSTATUS Status;
PUSBREQUEST Request;
if (!m_Queue || m_DmaManager)
{
//
// no queue, wtf?
//
DPRINT1("CUSBDevice::CommitUrb> no queue / dma !!!\n");
return STATUS_UNSUCCESSFUL;
}
//
// build usb request
//
Status = m_Queue->CreateUSBRequest(&Request);
if (!NT_SUCCESS(Status))
{
//
// failed to build request
//
DPRINT1("CUSBDevice::CommitSetupPacket> CreateUSBRequest failed with %x\n", Status);
return Status;
}
//
// initialize request
//
Status = Request->InitializeWithIrp(m_DmaManager, Irp);
//
// now add the request
//
Status = m_Queue->AddUSBRequest(Request);
if (!NT_SUCCESS(Status))
{
//
// failed to add request
//
DPRINT1("CUSBDevice::CommitSetupPacket> failed add request to queue with %x\n", Status);
Request->Release();
return Status;
}
//
// done
//
return Status;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBDevice::SubmitUrb(
PURB Urb)
CUSBDevice::SubmitIrp(
PIRP Irp)
{
KIRQL OldLevel;
NTSTATUS Status;
@ -380,7 +494,7 @@ CUSBDevice::SubmitUrb(
//
// commit urb
//
Status = CommitUrb(Urb);
Status = CommitIrp(Irp);
//
// release lock
@ -394,16 +508,10 @@ NTSTATUS
CUSBDevice::CommitSetupPacket(
PUSB_DEFAULT_PIPE_SETUP_PACKET Packet,
IN ULONG BufferLength,
IN OUT PVOID Buffer,
IN PIRP Irp,
IN PKEVENT pEvent)
IN OUT PMDL Mdl)
{
NTSTATUS Status;
PUSBREQUEST Request;
KEVENT Event;
BOOLEAN Wait = FALSE;
PMDL Mdl = 0;
if (!m_Queue)
{
@ -427,8 +535,6 @@ CUSBDevice::CommitSetupPacket(
return Status;
}
/* FIXME build MDL */
//
// initialize request
//
@ -443,33 +549,7 @@ CUSBDevice::CommitSetupPacket(
return Status;
}
//
// is a irp or event provided ?
//
if (Irp == NULL && pEvent == NULL)
{
//
// no completion details provided, requestor wants synchronized
//
KeInitializeEvent(&Event, NotificationEvent, FALSE);
pEvent = &Event;
Wait = TRUE;
}
//
// set completion details
//
Status = Request->SetCompletionEvent(pEvent);
if (!NT_SUCCESS(Status))
{
//
// failed to set completion details
//
DPRINT1("CUSBDevice::CommitSetupPacket> failed to set completion details with %x\n", Status);
Request->Release();
return Status;
}
//
// now add the request
//
@ -484,22 +564,10 @@ CUSBDevice::CommitSetupPacket(
return Status;
}
if (Wait)
{
//
// wait for the operation to complete
//
KeWaitForSingleObject(pEvent, Executive, KernelMode, FALSE, NULL);
}
//TODO:
// Get result code from operation
//
// get the result code when the operation has been finished
//
// returns the result code when the operation has been finished
//
//Status = Request->GetResultCode();
Request->GetResultStatus(&Status, NULL);
//
// release request
@ -511,6 +579,263 @@ CUSBDevice::CommitSetupPacket(
//
return Status;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBDevice::CreateDeviceDescriptor()
{
USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
PMDL Mdl;
NTSTATUS Status;
//
// zero descriptor
//
RtlZeroMemory(&m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
//
// setup request
//
CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
CtrlSetup.wValue.HiByte = USB_DEVICE_DESCRIPTOR_TYPE;
CtrlSetup.wLength = sizeof(USB_DEVICE_DESCRIPTOR);
CtrlSetup.bmRequestType.B = 0x80;
//
// allocate mdl describing the device descriptor
//
Mdl = IoAllocateMdl(&m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR), FALSE, FALSE, 0);
if (!Mdl)
{
//
// failed to allocate mdl
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// build mdl for non paged pool
//
MmBuildMdlForNonPagedPool(Mdl);
//
// commit setup packet
//
Status = CommitSetupPacket(&CtrlSetup, sizeof(USB_DEVICE_DESCRIPTOR), Mdl);
//
// now free the mdl
//
IoFreeMdl(Mdl);
//
// done
//
return Status;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBDevice::CreateConfigurationDescriptor(
ULONG Index)
{
PVOID Buffer;
USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
NTSTATUS Status;
PMDL Mdl;
ULONG InterfaceIndex, EndPointIndex;
PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
PUSB_ENDPOINT_DESCRIPTOR EndPointDescriptor;
//
// sanity checks
//
PC_ASSERT(m_ConfigurationDescriptors);
//
// first allocate a buffer which should be enough to store all different interfaces and endpoints
//
Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_USBEHCI);
if (!Buffer)
{
//
// failed to allocate buffer
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// build setup packet
//
CtrlSetup.bmRequestType._BM.Recipient = BMREQUEST_TO_DEVICE;
CtrlSetup.bmRequestType._BM.Type = BMREQUEST_STANDARD;
CtrlSetup.bmRequestType._BM.Reserved = 0;
CtrlSetup.bmRequestType._BM.Dir = BMREQUEST_DEVICE_TO_HOST;
CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
CtrlSetup.wValue.LowByte = 0;
CtrlSetup.wValue.HiByte = USB_CONFIGURATION_DESCRIPTOR_TYPE;
CtrlSetup.wIndex.W = 0;
CtrlSetup.wLength = PAGE_SIZE;
//
// FIXME: where put configuration index?
//
//
// now build MDL describing the buffer
//
Mdl = IoAllocateMdl(Buffer, PAGE_SIZE, FALSE, FALSE, 0);
if (!Mdl)
{
//
// failed to allocate mdl
//
ExFreePoolWithTag(Buffer, TAG_USBEHCI);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// build mdl for non paged pool
//
MmBuildMdlForNonPagedPool(Mdl);
//
// commit packet
//
Status = CommitSetupPacket(&CtrlSetup, PAGE_SIZE, Mdl);
if (!NT_SUCCESS(Status))
{
//
// failed to issue request, cleanup
//
IoFreeMdl(Mdl);
ExFreePool(Buffer);
return Status;
}
//
// now free the mdl
//
IoFreeMdl(Mdl);
//
// get configuration descriptor
//
ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)Buffer;
//
// sanity check
//
PC_ASSERT(ConfigurationDescriptor->bLength == sizeof(USB_CONFIGURATION_DESCRIPTOR));
PC_ASSERT(ConfigurationDescriptor->wTotalLength <= PAGE_SIZE);
PC_ASSERT(ConfigurationDescriptor->bNumInterfaces);
//
// request is complete, initialize configuration descriptor
//
RtlCopyMemory(&m_ConfigurationDescriptors[Index].ConfigurationDescriptor, ConfigurationDescriptor, ConfigurationDescriptor->bLength);
//
// now allocate interface descriptors
//
m_ConfigurationDescriptors[Index].Interfaces = (PUSB_INTERFACE)ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_INTERFACE) * ConfigurationDescriptor->bNumInterfaces, TAG_USBEHCI);
if (!m_ConfigurationDescriptors[Index].Interfaces)
{
//
// failed to allocate interface descriptors
//
ExFreePool(Buffer);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// zero interface descriptor
//
RtlZeroMemory(m_ConfigurationDescriptors[Index].Interfaces, sizeof(USB_INTERFACE) * ConfigurationDescriptor->bNumInterfaces);
//
// get first interface descriptor
//
InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)(ConfigurationDescriptor + 1);
//
// setup interface descriptors
//
for(InterfaceIndex = 0; InterfaceIndex < ConfigurationDescriptor->bNumInterfaces; InterfaceIndex++)
{
//
// sanity check
//
PC_ASSERT(InterfaceDescriptor->bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
PC_ASSERT(InterfaceDescriptor->bNumEndpoints);
//
// copy current interface descriptor
//
RtlCopyMemory(&m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].InterfaceDescriptor, InterfaceDescriptor, InterfaceDescriptor->bLength);
//
// allocate end point descriptors
//
m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].EndPoints = (PUSB_ENDPOINT)ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_ENDPOINT) * InterfaceDescriptor->bNumEndpoints, TAG_USBEHCI);
if (!m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].EndPoints)
{
//
// failed to allocate endpoint
//
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
//
// zero memory
//
RtlZeroMemory(m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].EndPoints, sizeof(USB_ENDPOINT) * InterfaceDescriptor->bNumEndpoints);
//
// initialize end point descriptors
//
EndPointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)(InterfaceDescriptor + 1);
for(EndPointIndex = 0; EndPointIndex < InterfaceDescriptor->bNumEndpoints; EndPointIndex++)
{
//
// sanity check
//
PC_ASSERT(EndPointDescriptor->bLength == sizeof(USB_ENDPOINT_DESCRIPTOR));
//
// copy endpoint descriptor
//
RtlCopyMemory(&m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].EndPoints[EndPointIndex].EndPointDescriptor, EndPointDescriptor, EndPointDescriptor->bLength);
//
// move to next offset
//
EndPointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)EndPointDescriptor + EndPointDescriptor->bLength);
}
//
// update interface descriptor offset
//
InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)EndPointDescriptor;
}
//
// free buffer
//
ExFreePoolWithTag(Buffer, TAG_USBEHCI);
//
// done
//
return Status;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CreateUSBDevice(

View file

@ -38,12 +38,14 @@ public:
// IUSBRequest interface functions
virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, IN OUT ULONG TransferBufferLength, IN OUT PMDL TransferBuffer);
virtual NTSTATUS InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager, IN OUT PIRP Irp);
virtual NTSTATUS SetCompletionEvent(IN PKEVENT Event);
virtual VOID CompletionCallback(IN NTSTATUS NtStatusCode, IN ULONG UrbStatusCode);
virtual VOID CancelCallback(IN NTSTATUS NtStatusCode);
virtual VOID CompletionCallback(IN NTSTATUS NtStatusCode, IN ULONG UrbStatusCode, IN struct _QUEUE_HEAD *QueueHead);
virtual VOID CancelCallback(IN NTSTATUS NtStatusCode, IN struct _QUEUE_HEAD *QueueHead);
virtual NTSTATUS GetQueueHead(struct _QUEUE_HEAD ** OutHead);
virtual BOOLEAN IsRequestComplete();
virtual ULONG GetTransferType();
virtual VOID GetResultStatus(OUT OPTIONAL NTSTATUS *NtStatusCode, OUT OPTIONAL PULONG UrbStatusCode);
virtual BOOLEAN IsRequestInitialized();
virtual BOOLEAN ShouldReleaseRequestAfterCompletion();
// local functions
ULONG InternalGetTransferType();
@ -60,17 +62,60 @@ public:
protected:
LONG m_Ref;
//
// memory manager for allocating setup packet / queue head / transfer descriptors
//
PDMAMEMORYMANAGER m_DmaManager;
PUSB_DEFAULT_PIPE_SETUP_PACKET m_SetupPacket;
ULONG m_TransferBufferLength;
PMDL m_TransferBufferMDL;
//
// caller provided irp packet containing URB request
//
PIRP m_Irp;
//
// transfer buffer length
//
ULONG m_TransferBufferLength;
//
// transfer buffer MDL
//
PMDL m_TransferBufferMDL;
//
// caller provided setup packet
//
PUSB_DEFAULT_PIPE_SETUP_PACKET m_SetupPacket;
//
// completion event for callers who initialized request with setup packet
//
PKEVENT m_CompletionEvent;
//
// DMA queue head
//
PQUEUE_HEAD m_QueueHead;
//
// DMA transfer descriptors linked to the queue head
//
PQUEUE_TRANSFER_DESCRIPTOR m_TransferDescriptors[3];
//
// allocated setup packet from the DMA pool
//
PUSB_DEFAULT_PIPE_SETUP_PACKET m_DescriptorPacket;
PHYSICAL_ADDRESS m_DescriptorSetupPacket;
//
// stores the result of the operation
//
NTSTATUS m_NtStatusCode;
ULONG m_UrbStatusCode;
};
//----------------------------------------------------------------------------------------
@ -105,6 +150,23 @@ CUSBRequest::InitializeWithSetupPacket(
m_TransferBufferLength = TransferBufferLength;
m_TransferBufferMDL = TransferBuffer;
//
// allocate completion event
//
m_CompletionEvent = (PKEVENT)ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_USBEHCI);
if (!m_CompletionEvent)
{
//
// failed to allocate completion event
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// initialize completion event
//
KeInitializeEvent(m_CompletionEvent, NotificationEvent, FALSE);
//
// done
//
@ -166,7 +228,7 @@ CUSBRequest::InitializeWithIrp(
if (Urb->UrbBulkOrInterruptTransfer.TransferBufferLength)
{
//
// it must have an MDL
// FIXME: it must have an MDL
//
PC_ASSERT(Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL);
@ -189,38 +251,27 @@ CUSBRequest::InitializeWithIrp(
return STATUS_SUCCESS;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBRequest::SetCompletionEvent(
IN PKEVENT Event)
{
if (m_QueueHead)
{
//
// WTF? operation is already in progress
//
return STATUS_UNSUCCESSFUL;
}
//
// store completion event
//
m_CompletionEvent = Event;
//
// done
//
return STATUS_SUCCESS;
}
//----------------------------------------------------------------------------------------
VOID
CUSBRequest::CompletionCallback(
IN NTSTATUS NtStatusCode,
IN ULONG UrbStatusCode)
IN ULONG UrbStatusCode,
IN struct _QUEUE_HEAD *QueueHead)
{
PIO_STACK_LOCATION IoStack;
PURB Urb;
//
// FIXME: support linked queue heads
//
//
// store completion code
//
m_NtStatusCode = NtStatusCode;
m_UrbStatusCode = UrbStatusCode;
if (m_Irp)
{
//
@ -260,23 +311,33 @@ CUSBRequest::CompletionCallback(
//
IoCompleteRequest(m_Irp, IO_NO_INCREMENT);
}
if (m_CompletionEvent)
else
{
//
// FIXME: make sure the request was not split
// signal completion event
//
PC_ASSERT(m_CompletionEvent);
KeSetEvent(m_CompletionEvent, 0, FALSE);
}
}
//----------------------------------------------------------------------------------------
VOID
CUSBRequest::CancelCallback(
IN NTSTATUS NtStatusCode)
IN NTSTATUS NtStatusCode,
IN struct _QUEUE_HEAD *QueueHead)
{
PIO_STACK_LOCATION IoStack;
PURB Urb;
//
// FIXME: support linked queue heads
//
//
// store cancelleation code
//
m_NtStatusCode = NtStatusCode;
if (m_Irp)
{
//
@ -306,12 +367,12 @@ CUSBRequest::CancelCallback(
//
IoCompleteRequest(m_Irp, IO_NO_INCREMENT);
}
if (m_CompletionEvent)
else
{
//
// FIXME: make sure the request was not split
// signal completion event
//
PC_ASSERT(m_CompletionEvent);
KeSetEvent(m_CompletionEvent, 0, FALSE);
}
}
@ -370,6 +431,7 @@ CUSBRequest::IsRequestComplete()
//
// FIXME: check if request was split
//
UNIMPLEMENTED
return TRUE;
}
//----------------------------------------------------------------------------------------
@ -452,7 +514,6 @@ CUSBRequest::BuildControlTransferQueueHead(
ULONG NumTransferDescriptors, Index;
PQUEUE_HEAD QueueHead;
//
// first allocate the queue head
//
@ -802,3 +863,75 @@ CUSBRequest::BuildSetupPacket()
return Status;
}
//----------------------------------------------------------------------------------------
VOID
CUSBRequest::GetResultStatus(
OUT OPTIONAL NTSTATUS * NtStatusCode,
OUT OPTIONAL PULONG UrbStatusCode)
{
//
// sanity check
//
PC_ASSERT(m_CompletionEvent);
//
// wait for the operation to complete
//
KeWaitForSingleObject(m_CompletionEvent, Executive, KernelMode, FALSE, NULL);
//
// copy status
//
if (NtStatusCode)
{
*NtStatusCode = m_NtStatusCode;
}
//
// copy urb status
//
if (UrbStatusCode)
{
*UrbStatusCode = m_UrbStatusCode;
}
}
//-----------------------------------------------------------------------------------------
BOOLEAN
CUSBRequest::IsRequestInitialized()
{
if (m_Irp || m_SetupPacket)
{
//
// request is initialized
//
return TRUE;
}
//
// request is not initialized
//
return FALSE;
}
//-----------------------------------------------------------------------------------------
BOOLEAN
CUSBRequest::ShouldReleaseRequestAfterCompletion()
{
if (m_Irp)
{
//
// the request is completed, release it
//
return TRUE;
}
else
{
//
// created with an setup packet, don't release
//
return FALSE;
}
}