mirror of
https://github.com/reactos/reactos.git
synced 2025-01-04 05:20:54 +00:00
[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:
parent
9b8bc8512c
commit
d4f7a44a18
4 changed files with 647 additions and 155 deletions
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue