mirror of
https://github.com/reactos/reactos.git
synced 2025-07-24 21:23:50 +00:00
[USBOHCI]
- Start of OHCI support - Based on new usbehci driver and Haiku USB Stack - Driver initializes the controller and retrieve number of ports svn path=/branches/usb-bringup/; revision=51851
This commit is contained in:
parent
3dfadd12ae
commit
d4c4a2e080
15 changed files with 8721 additions and 0 deletions
35
drivers/usb/usbohci/CMakeLists.txt
Normal file
35
drivers/usb/usbohci/CMakeLists.txt
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
|
||||||
|
set_cpp()
|
||||||
|
|
||||||
|
remove_definitions(-D_WIN32_WINNT=0x502)
|
||||||
|
add_definitions(-D_WIN32_WINNT=0x600)
|
||||||
|
|
||||||
|
add_library(usbohci SHARED
|
||||||
|
usbohci.cpp
|
||||||
|
usb_device.cpp
|
||||||
|
usb_request.cpp
|
||||||
|
usb_queue.cpp
|
||||||
|
hcd_controller.cpp
|
||||||
|
hardware.cpp
|
||||||
|
misc.cpp
|
||||||
|
purecall.cpp
|
||||||
|
hub_controller.cpp
|
||||||
|
memory_manager.cpp
|
||||||
|
usbohci.rc)
|
||||||
|
|
||||||
|
target_link_libraries(usbohci
|
||||||
|
libcntpr
|
||||||
|
stlport
|
||||||
|
${PSEH_LIB})
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
set_target_properties(usbohci PROPERTIES COMPILE_FLAGS "/GR-")
|
||||||
|
else()
|
||||||
|
target_link_libraries(usbohci -lgcc)
|
||||||
|
set_target_properties(usbohci PROPERTIES COMPILE_FLAGS "-fno-exceptions -fno-rtti")
|
||||||
|
endif(MSVC)
|
||||||
|
|
||||||
|
set_module_type(usbohci kernelmodedriver)
|
||||||
|
add_importlibs(usbohci ntoskrnl ks drmk hal)
|
||||||
|
|
||||||
|
add_cab_target(usbohci 2)
|
996
drivers/usb/usbohci/hardware.cpp
Normal file
996
drivers/usb/usbohci/hardware.cpp
Normal file
|
@ -0,0 +1,996 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
|
||||||
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
|
* FILE: drivers/usb/usbohci/hcd_controller.cpp
|
||||||
|
* PURPOSE: USB OHCI device driver.
|
||||||
|
* PROGRAMMERS:
|
||||||
|
* Michael Martin (michael.martin@reactos.org)
|
||||||
|
* Johannes Anderwald (johannes.anderwald@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define INITGUID
|
||||||
|
#include "usbohci.h"
|
||||||
|
#include "hardware.h"
|
||||||
|
|
||||||
|
typedef VOID __stdcall HD_INIT_CALLBACK(IN PVOID CallBackContext);
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
NTAPI
|
||||||
|
InterruptServiceRoutine(
|
||||||
|
IN PKINTERRUPT Interrupt,
|
||||||
|
IN PVOID ServiceContext);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
EhciDefferedRoutine(
|
||||||
|
IN PKDPC Dpc,
|
||||||
|
IN PVOID DeferredContext,
|
||||||
|
IN PVOID SystemArgument1,
|
||||||
|
IN PVOID SystemArgument2);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
StatusChangeWorkItemRoutine(PVOID Context);
|
||||||
|
|
||||||
|
class CUSBHardwareDevice : public IUSBHardwareDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
|
||||||
|
|
||||||
|
STDMETHODIMP_(ULONG) AddRef()
|
||||||
|
{
|
||||||
|
InterlockedIncrement(&m_Ref);
|
||||||
|
return m_Ref;
|
||||||
|
}
|
||||||
|
STDMETHODIMP_(ULONG) Release()
|
||||||
|
{
|
||||||
|
InterlockedDecrement(&m_Ref);
|
||||||
|
|
||||||
|
if (!m_Ref)
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return m_Ref;
|
||||||
|
}
|
||||||
|
// com
|
||||||
|
NTSTATUS Initialize(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT FunctionalDeviceObject, PDEVICE_OBJECT PhysicalDeviceObject, PDEVICE_OBJECT LowerDeviceObject);
|
||||||
|
NTSTATUS PnpStart(PCM_RESOURCE_LIST RawResources, PCM_RESOURCE_LIST TranslatedResources);
|
||||||
|
NTSTATUS PnpStop(void);
|
||||||
|
NTSTATUS HandlePower(PIRP Irp);
|
||||||
|
NTSTATUS GetDeviceDetails(PUSHORT VendorId, PUSHORT DeviceId, PULONG NumberOfPorts, PULONG Speed);
|
||||||
|
NTSTATUS GetDMA(OUT struct IDMAMemoryManager **m_DmaManager);
|
||||||
|
NTSTATUS GetUSBQueue(OUT struct IUSBQueue **OutUsbQueue);
|
||||||
|
|
||||||
|
NTSTATUS StartController();
|
||||||
|
NTSTATUS StopController();
|
||||||
|
NTSTATUS ResetController();
|
||||||
|
NTSTATUS ResetPort(ULONG PortIndex);
|
||||||
|
|
||||||
|
NTSTATUS GetPortStatus(ULONG PortId, OUT USHORT *PortStatus, OUT USHORT *PortChange);
|
||||||
|
NTSTATUS ClearPortStatus(ULONG PortId, ULONG Status);
|
||||||
|
NTSTATUS SetPortFeature(ULONG PortId, ULONG Feature);
|
||||||
|
|
||||||
|
VOID SetStatusChangeEndpointCallBack(PVOID CallBack, PVOID Context);
|
||||||
|
|
||||||
|
KIRQL AcquireDeviceLock(void);
|
||||||
|
VOID ReleaseDeviceLock(KIRQL OldLevel);
|
||||||
|
// local
|
||||||
|
BOOLEAN InterruptService();
|
||||||
|
NTSTATUS InitializeController();
|
||||||
|
NTSTATUS AllocateEndpointDescriptor(OUT POHCI_ENDPOINT_DESCRIPTOR *OutDescriptor);
|
||||||
|
|
||||||
|
// friend function
|
||||||
|
friend BOOLEAN NTAPI InterruptServiceRoutine(IN PKINTERRUPT Interrupt, IN PVOID ServiceContext);
|
||||||
|
friend VOID NTAPI EhciDefferedRoutine(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2);
|
||||||
|
friend VOID NTAPI StatusChangeWorkItemRoutine(PVOID Context);
|
||||||
|
// constructor / destructor
|
||||||
|
CUSBHardwareDevice(IUnknown *OuterUnknown){}
|
||||||
|
virtual ~CUSBHardwareDevice(){}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
LONG m_Ref; // reference count
|
||||||
|
PDRIVER_OBJECT m_DriverObject; // driver object
|
||||||
|
PDEVICE_OBJECT m_PhysicalDeviceObject; // pdo
|
||||||
|
PDEVICE_OBJECT m_FunctionalDeviceObject; // fdo (hcd controller)
|
||||||
|
PDEVICE_OBJECT m_NextDeviceObject; // lower device object
|
||||||
|
KSPIN_LOCK m_Lock; // hardware lock
|
||||||
|
PKINTERRUPT m_Interrupt; // interrupt object
|
||||||
|
KDPC m_IntDpcObject; // dpc object for deferred isr processing
|
||||||
|
PVOID VirtualBase; // virtual base for memory manager
|
||||||
|
PHYSICAL_ADDRESS PhysicalAddress; // physical base for memory manager
|
||||||
|
PULONG m_Base; // OHCI operational port base registers
|
||||||
|
PDMA_ADAPTER m_Adapter; // dma adapter object
|
||||||
|
ULONG m_MapRegisters; // map registers count
|
||||||
|
USHORT m_VendorID; // vendor id
|
||||||
|
USHORT m_DeviceID; // device id
|
||||||
|
PUSBQUEUE m_UsbQueue; // usb request queue
|
||||||
|
POHCIHCCA m_HCCA; // hcca virtual base
|
||||||
|
PHYSICAL_ADDRESS m_HCCAPhysicalAddress; // hcca physical address
|
||||||
|
POHCI_ENDPOINT_DESCRIPTOR m_ControlEndpointDescriptor; // dummy control endpoint descriptor
|
||||||
|
POHCI_ENDPOINT_DESCRIPTOR m_BulkEndpointDescriptor; // dummy control endpoint descriptor
|
||||||
|
POHCI_ENDPOINT_DESCRIPTOR m_IsoEndpointDescriptor; // iso endpoint descriptor
|
||||||
|
POHCI_ENDPOINT_DESCRIPTOR m_InterruptEndpoints[OHCI_STATIC_ENDPOINT_COUNT]; // endpoints for interrupt / iso transfers
|
||||||
|
ULONG m_NumberOfPorts; // number of ports
|
||||||
|
PDMAMEMORYMANAGER m_MemoryManager; // memory manager
|
||||||
|
HD_INIT_CALLBACK* m_SCECallBack; // status change callback routine
|
||||||
|
PVOID m_SCEContext; // status change callback routine context
|
||||||
|
BOOLEAN m_DoorBellRingInProgress; // door bell ring in progress
|
||||||
|
WORK_QUEUE_ITEM m_StatusChangeWorkItem; // work item for status change callback
|
||||||
|
ULONG m_SyncFramePhysAddr; // periodic frame list physical address
|
||||||
|
};
|
||||||
|
|
||||||
|
//=================================================================================================
|
||||||
|
// COM
|
||||||
|
//
|
||||||
|
NTSTATUS
|
||||||
|
STDMETHODCALLTYPE
|
||||||
|
CUSBHardwareDevice::QueryInterface(
|
||||||
|
IN REFIID refiid,
|
||||||
|
OUT PVOID* Output)
|
||||||
|
{
|
||||||
|
if (IsEqualGUIDAligned(refiid, IID_IUnknown))
|
||||||
|
{
|
||||||
|
*Output = PVOID(PUNKNOWN(this));
|
||||||
|
PUNKNOWN(*Output)->AddRef();
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBHardwareDevice::Initialize(
|
||||||
|
PDRIVER_OBJECT DriverObject,
|
||||||
|
PDEVICE_OBJECT FunctionalDeviceObject,
|
||||||
|
PDEVICE_OBJECT PhysicalDeviceObject,
|
||||||
|
PDEVICE_OBJECT LowerDeviceObject)
|
||||||
|
{
|
||||||
|
BUS_INTERFACE_STANDARD BusInterface;
|
||||||
|
PCI_COMMON_CONFIG PciConfig;
|
||||||
|
NTSTATUS Status;
|
||||||
|
ULONG BytesRead;
|
||||||
|
|
||||||
|
DPRINT1("CUSBHardwareDevice::Initialize\n");
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create DMAMemoryManager for use with QueueHeads and Transfer Descriptors.
|
||||||
|
//
|
||||||
|
Status = CreateDMAMemoryManager(&m_MemoryManager);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("Failed to create DMAMemoryManager Object\n");
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create the UsbQueue class that will handle the Asynchronous and Periodic Schedules
|
||||||
|
//
|
||||||
|
Status = CreateUSBQueue(&m_UsbQueue);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("Failed to create UsbQueue!\n");
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// store device objects
|
||||||
|
//
|
||||||
|
m_DriverObject = DriverObject;
|
||||||
|
m_FunctionalDeviceObject = FunctionalDeviceObject;
|
||||||
|
m_PhysicalDeviceObject = PhysicalDeviceObject;
|
||||||
|
m_NextDeviceObject = LowerDeviceObject;
|
||||||
|
|
||||||
|
//
|
||||||
|
// initialize device lock
|
||||||
|
//
|
||||||
|
KeInitializeSpinLock(&m_Lock);
|
||||||
|
|
||||||
|
//
|
||||||
|
// intialize status change work item
|
||||||
|
//
|
||||||
|
ExInitializeWorkItem(&m_StatusChangeWorkItem, StatusChangeWorkItemRoutine, PVOID(this));
|
||||||
|
|
||||||
|
m_VendorID = 0;
|
||||||
|
m_DeviceID = 0;
|
||||||
|
|
||||||
|
Status = GetBusInterface(PhysicalDeviceObject, &BusInterface);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("Failed to get BusInteface!\n");
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
BytesRead = (*BusInterface.GetBusData)(BusInterface.Context,
|
||||||
|
PCI_WHICHSPACE_CONFIG,
|
||||||
|
&PciConfig,
|
||||||
|
0,
|
||||||
|
PCI_COMMON_HDR_LENGTH);
|
||||||
|
|
||||||
|
if (BytesRead != PCI_COMMON_HDR_LENGTH)
|
||||||
|
{
|
||||||
|
DPRINT1("Failed to get pci config information!\n");
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(PciConfig.Command & PCI_ENABLE_BUS_MASTER))
|
||||||
|
{
|
||||||
|
DPRINT1("PCI Configuration shows this as a non Bus Mastering device!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_VendorID = PciConfig.VendorID;
|
||||||
|
m_DeviceID = PciConfig.DeviceID;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBHardwareDevice::PnpStart(
|
||||||
|
PCM_RESOURCE_LIST RawResources,
|
||||||
|
PCM_RESOURCE_LIST TranslatedResources)
|
||||||
|
{
|
||||||
|
ULONG Index;
|
||||||
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
|
||||||
|
DEVICE_DESCRIPTION DeviceDescription;
|
||||||
|
PVOID ResourceBase;
|
||||||
|
NTSTATUS Status;
|
||||||
|
ULONG Version;
|
||||||
|
|
||||||
|
DPRINT1("CUSBHardwareDevice::PnpStart\n");
|
||||||
|
for(Index = 0; Index < TranslatedResources->List[0].PartialResourceList.Count; Index++)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// get resource descriptor
|
||||||
|
//
|
||||||
|
ResourceDescriptor = &TranslatedResources->List[0].PartialResourceList.PartialDescriptors[Index];
|
||||||
|
|
||||||
|
switch(ResourceDescriptor->Type)
|
||||||
|
{
|
||||||
|
case CmResourceTypeInterrupt:
|
||||||
|
{
|
||||||
|
KeInitializeDpc(&m_IntDpcObject,
|
||||||
|
EhciDefferedRoutine,
|
||||||
|
this);
|
||||||
|
|
||||||
|
Status = IoConnectInterrupt(&m_Interrupt,
|
||||||
|
InterruptServiceRoutine,
|
||||||
|
(PVOID)this,
|
||||||
|
NULL,
|
||||||
|
ResourceDescriptor->u.Interrupt.Vector,
|
||||||
|
(KIRQL)ResourceDescriptor->u.Interrupt.Level,
|
||||||
|
(KIRQL)ResourceDescriptor->u.Interrupt.Level,
|
||||||
|
(KINTERRUPT_MODE)(ResourceDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED),
|
||||||
|
(ResourceDescriptor->ShareDisposition != CmResourceShareDeviceExclusive),
|
||||||
|
ResourceDescriptor->u.Interrupt.Affinity,
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// failed to register interrupt
|
||||||
|
//
|
||||||
|
DPRINT1("IoConnect Interrupt failed with %x\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CmResourceTypeMemory:
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// get resource base
|
||||||
|
//
|
||||||
|
ResourceBase = MmMapIoSpace(ResourceDescriptor->u.Memory.Start, ResourceDescriptor->u.Memory.Length, MmNonCached);
|
||||||
|
if (!ResourceBase)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// failed to map registers
|
||||||
|
//
|
||||||
|
DPRINT1("MmMapIoSpace failed\n");
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Get controllers capabilities
|
||||||
|
//
|
||||||
|
Version = READ_REGISTER_ULONG((PULONG)((ULONG_PTR)ResourceBase + OHCI_REVISION_OFFSET));
|
||||||
|
|
||||||
|
DPRINT1("Version %x\n", Version);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Store Resource base
|
||||||
|
//
|
||||||
|
m_Base = (PULONG)ResourceBase;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// zero device description
|
||||||
|
//
|
||||||
|
RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
|
||||||
|
|
||||||
|
//
|
||||||
|
// initialize device description
|
||||||
|
//
|
||||||
|
DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
|
||||||
|
DeviceDescription.Master = TRUE;
|
||||||
|
DeviceDescription.ScatterGather = TRUE;
|
||||||
|
DeviceDescription.Dma32BitAddresses = TRUE;
|
||||||
|
DeviceDescription.DmaWidth = Width32Bits;
|
||||||
|
DeviceDescription.InterfaceType = PCIBus;
|
||||||
|
DeviceDescription.MaximumLength = MAXULONG;
|
||||||
|
|
||||||
|
//
|
||||||
|
// get dma adapter
|
||||||
|
//
|
||||||
|
m_Adapter = IoGetDmaAdapter(m_PhysicalDeviceObject, &DeviceDescription, &m_MapRegisters);
|
||||||
|
if (!m_Adapter)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// failed to get dma adapter
|
||||||
|
//
|
||||||
|
DPRINT1("Failed to acquire dma adapter\n");
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create Common Buffer
|
||||||
|
//
|
||||||
|
VirtualBase = m_Adapter->DmaOperations->AllocateCommonBuffer(m_Adapter,
|
||||||
|
PAGE_SIZE * 4,
|
||||||
|
&PhysicalAddress,
|
||||||
|
FALSE);
|
||||||
|
if (!VirtualBase)
|
||||||
|
{
|
||||||
|
DPRINT1("Failed to allocate a common buffer\n");
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the DMAMemoryManager
|
||||||
|
//
|
||||||
|
Status = m_MemoryManager->Initialize(this, &m_Lock, PAGE_SIZE * 4, VirtualBase, PhysicalAddress, 32);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("Failed to initialize the DMAMemoryManager\n");
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the UsbQueue now that we have an AdapterObject.
|
||||||
|
//
|
||||||
|
Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, m_MemoryManager, NULL);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("Failed to Initialize the UsbQueue\n");
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// initializes the controller
|
||||||
|
//
|
||||||
|
Status = InitializeController();
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("Failed to Initialize the controller \n");
|
||||||
|
ASSERT(FALSE);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Stop the controller before modifying schedules
|
||||||
|
//
|
||||||
|
Status = StopController();
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("Failed to stop the controller \n");
|
||||||
|
ASSERT(FALSE);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Start the controller
|
||||||
|
//
|
||||||
|
DPRINT1("Starting Controller\n");
|
||||||
|
Status = StartController();
|
||||||
|
|
||||||
|
//
|
||||||
|
// done
|
||||||
|
//
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBHardwareDevice::PnpStop(void)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED
|
||||||
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBHardwareDevice::HandlePower(
|
||||||
|
PIRP Irp)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED
|
||||||
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBHardwareDevice::GetDeviceDetails(
|
||||||
|
OUT OPTIONAL PUSHORT VendorId,
|
||||||
|
OUT OPTIONAL PUSHORT DeviceId,
|
||||||
|
OUT OPTIONAL PULONG NumberOfPorts,
|
||||||
|
OUT OPTIONAL PULONG Speed)
|
||||||
|
{
|
||||||
|
if (VendorId)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// get vendor
|
||||||
|
//
|
||||||
|
*VendorId = m_VendorID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DeviceId)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// get device id
|
||||||
|
//
|
||||||
|
*DeviceId = m_DeviceID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NumberOfPorts)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// get number of ports
|
||||||
|
//
|
||||||
|
*NumberOfPorts = m_NumberOfPorts;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Speed)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// speed is 0x100
|
||||||
|
//
|
||||||
|
*Speed = 0x100;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS CUSBHardwareDevice::GetDMA(
|
||||||
|
OUT struct IDMAMemoryManager **OutDMAMemoryManager)
|
||||||
|
{
|
||||||
|
if (!m_MemoryManager)
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
*OutDMAMemoryManager = m_MemoryManager;
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBHardwareDevice::GetUSBQueue(
|
||||||
|
OUT struct IUSBQueue **OutUsbQueue)
|
||||||
|
{
|
||||||
|
if (!m_UsbQueue)
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
*OutUsbQueue = m_UsbQueue;
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBHardwareDevice::StartController(void)
|
||||||
|
{
|
||||||
|
ULONG Control, NumberOfPorts, Index, Descriptor;
|
||||||
|
|
||||||
|
//
|
||||||
|
// first write address of HCCA
|
||||||
|
//
|
||||||
|
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_HCCA_OFFSET), m_HCCAPhysicalAddress.LowPart);
|
||||||
|
|
||||||
|
//
|
||||||
|
// lets write physical address of dummy control endpoint descriptor
|
||||||
|
//
|
||||||
|
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_HEAD_ED_OFFSET), m_ControlEndpointDescriptor->PhysicalAddress.LowPart);
|
||||||
|
|
||||||
|
//
|
||||||
|
// lets write physical address of dummy bulk endpoint descriptor
|
||||||
|
//
|
||||||
|
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_BULK_HEAD_ED_OFFSET), m_BulkEndpointDescriptor->PhysicalAddress.LowPart);
|
||||||
|
|
||||||
|
//
|
||||||
|
// read control register
|
||||||
|
//
|
||||||
|
Control = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET));
|
||||||
|
|
||||||
|
//
|
||||||
|
// remove flags
|
||||||
|
//
|
||||||
|
Control &= ~(OHCI_CONTROL_BULK_SERVICE_RATIO_MASK | OHCI_ENABLE_LIST | OHCI_HC_FUNCTIONAL_STATE_MASK | OHCI_INTERRUPT_ROUTING);
|
||||||
|
|
||||||
|
//
|
||||||
|
// set command status flags
|
||||||
|
//
|
||||||
|
Control |= OHCI_ENABLE_LIST | OHCI_CONTROL_BULK_RATIO_1_4 | OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL;
|
||||||
|
|
||||||
|
//
|
||||||
|
// now start the controller
|
||||||
|
//
|
||||||
|
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET), Control);
|
||||||
|
|
||||||
|
//
|
||||||
|
// retrieve number of ports
|
||||||
|
//
|
||||||
|
for(Index = 0; Index < 10; Index++)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// wait a bit
|
||||||
|
//
|
||||||
|
KeStallExecutionProcessor(10);
|
||||||
|
|
||||||
|
//
|
||||||
|
// read descriptor
|
||||||
|
//
|
||||||
|
Descriptor = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_DESCRIPTOR_A_OFFSET));
|
||||||
|
|
||||||
|
//
|
||||||
|
// get number of ports
|
||||||
|
//
|
||||||
|
NumberOfPorts = OHCI_RH_GET_PORT_COUNT(Descriptor);
|
||||||
|
|
||||||
|
//
|
||||||
|
// check if we have received the ports
|
||||||
|
//
|
||||||
|
if (NumberOfPorts)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// sanity check
|
||||||
|
//
|
||||||
|
ASSERT(NumberOfPorts < OHCI_MAX_PORT_COUNT);
|
||||||
|
|
||||||
|
//
|
||||||
|
// store number of ports
|
||||||
|
//
|
||||||
|
m_NumberOfPorts = NumberOfPorts;
|
||||||
|
|
||||||
|
//
|
||||||
|
// print out number ports
|
||||||
|
//
|
||||||
|
DPRINT1("NumberOfPorts %lu\n", m_NumberOfPorts);
|
||||||
|
|
||||||
|
//
|
||||||
|
// done
|
||||||
|
//
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBHardwareDevice::AllocateEndpointDescriptor(
|
||||||
|
OUT POHCI_ENDPOINT_DESCRIPTOR *OutDescriptor)
|
||||||
|
{
|
||||||
|
POHCI_ENDPOINT_DESCRIPTOR Descriptor;
|
||||||
|
PHYSICAL_ADDRESS DescriptorAddress;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
//
|
||||||
|
// allocate descriptor
|
||||||
|
//
|
||||||
|
Status = m_MemoryManager->Allocate(sizeof(OHCI_ENDPOINT_DESCRIPTOR), (PVOID*)&Descriptor, &DescriptorAddress);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// failed to allocate descriptor
|
||||||
|
//
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// intialize descriptor
|
||||||
|
//
|
||||||
|
Descriptor->Flags = OHCI_ENDPOINT_SKIP;
|
||||||
|
Descriptor->HeadPhysicalDescriptor = 0;
|
||||||
|
Descriptor->NextPhysicalEndpoint = 0;
|
||||||
|
Descriptor->TailPhysicalDescriptor = 0;
|
||||||
|
Descriptor->PhysicalAddress.QuadPart = DescriptorAddress.QuadPart;
|
||||||
|
|
||||||
|
//
|
||||||
|
// store result
|
||||||
|
//
|
||||||
|
*OutDescriptor = Descriptor;
|
||||||
|
|
||||||
|
//
|
||||||
|
// done
|
||||||
|
//
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBHardwareDevice::InitializeController()
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
ULONG Index, Interval, IntervalIndex, InsertIndex;
|
||||||
|
POHCI_ENDPOINT_DESCRIPTOR Descriptor;
|
||||||
|
|
||||||
|
//
|
||||||
|
// first allocate the hcca area
|
||||||
|
//
|
||||||
|
Status = m_MemoryManager->Allocate(sizeof(OHCIHCCA), (PVOID*)&m_HCCA, &m_HCCAPhysicalAddress);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// no memory
|
||||||
|
//
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// now allocate an endpoint for control transfers
|
||||||
|
// this endpoint will never be removed
|
||||||
|
//
|
||||||
|
Status = AllocateEndpointDescriptor(&m_ControlEndpointDescriptor);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// no memory
|
||||||
|
//
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// now allocate an endpoint for bulk transfers
|
||||||
|
// this endpoint will never be removed
|
||||||
|
//
|
||||||
|
Status = AllocateEndpointDescriptor(&m_BulkEndpointDescriptor);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// no memory
|
||||||
|
//
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// now allocate an endpoint for iso transfers
|
||||||
|
// this endpoint will never be removed
|
||||||
|
//
|
||||||
|
Status = AllocateEndpointDescriptor(&m_IsoEndpointDescriptor);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// no memory
|
||||||
|
//
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// now allocate endpoint descriptors for iso / interrupt transfers interval is 1,2,4,8,16,32
|
||||||
|
//
|
||||||
|
for(Index = 0; Index < OHCI_STATIC_ENDPOINT_COUNT; Index++)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// allocate endpoint descriptor
|
||||||
|
//
|
||||||
|
Status = AllocateEndpointDescriptor(&Descriptor);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// no memory
|
||||||
|
//
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// save in array
|
||||||
|
//
|
||||||
|
m_InterruptEndpoints[Index] = Descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// now link the descriptors, taken from Haiku
|
||||||
|
//
|
||||||
|
Interval = OHCI_BIGGEST_INTERVAL;
|
||||||
|
IntervalIndex = OHCI_STATIC_ENDPOINT_COUNT - 1;
|
||||||
|
while (Interval > 1)
|
||||||
|
{
|
||||||
|
InsertIndex = Interval / 2;
|
||||||
|
while (InsertIndex < OHCI_BIGGEST_INTERVAL)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// assign endpoint address
|
||||||
|
//
|
||||||
|
m_HCCA->InterruptTable[InsertIndex] = m_InterruptEndpoints[IntervalIndex]->PhysicalAddress.LowPart;
|
||||||
|
InsertIndex += Interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
IntervalIndex--;
|
||||||
|
Interval /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// link all endpoint descriptors to first descriptor in array
|
||||||
|
//
|
||||||
|
m_HCCA->InterruptTable[0] = m_InterruptEndpoints[0]->PhysicalAddress.LowPart;
|
||||||
|
for (Index = 1; Index < OHCI_STATIC_ENDPOINT_COUNT; Index++)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// link descriptor
|
||||||
|
//
|
||||||
|
m_InterruptEndpoints[Index]->NextPhysicalEndpoint = m_InterruptEndpoints[0]->PhysicalAddress.LowPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Now link the first endpoint to the isochronous endpoint
|
||||||
|
//
|
||||||
|
m_InterruptEndpoints[0]->NextPhysicalEndpoint = m_IsoEndpointDescriptor->PhysicalAddress.LowPart;
|
||||||
|
|
||||||
|
//
|
||||||
|
// done
|
||||||
|
//
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBHardwareDevice::StopController(void)
|
||||||
|
{
|
||||||
|
ULONG Control, Reset;
|
||||||
|
ULONG Index;
|
||||||
|
|
||||||
|
//
|
||||||
|
// first turn off all interrupts
|
||||||
|
//
|
||||||
|
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_INTERRUPT_DISABLE_OFFSET), OHCI_ALL_INTERRUPTS);
|
||||||
|
|
||||||
|
//
|
||||||
|
// check context
|
||||||
|
//
|
||||||
|
Control = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET));
|
||||||
|
|
||||||
|
//
|
||||||
|
// FIXME: support routing
|
||||||
|
//
|
||||||
|
ASSERT((Control & OHCI_INTERRUPT_ROUTING) == 0);
|
||||||
|
|
||||||
|
//
|
||||||
|
// have a break
|
||||||
|
//
|
||||||
|
KeStallExecutionProcessor(100);
|
||||||
|
|
||||||
|
//
|
||||||
|
// some controllers also depend on this
|
||||||
|
//
|
||||||
|
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET), OHCI_HC_FUNCTIONAL_STATE_RESET);
|
||||||
|
|
||||||
|
//
|
||||||
|
// wait a bit
|
||||||
|
//
|
||||||
|
KeStallExecutionProcessor(100);
|
||||||
|
|
||||||
|
//
|
||||||
|
// now reset controller
|
||||||
|
//
|
||||||
|
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET), OHCI_HOST_CONTROLLER_RESET);
|
||||||
|
|
||||||
|
//
|
||||||
|
// reset time is 10ms
|
||||||
|
//
|
||||||
|
for(Index = 0; Index < 10; Index++)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// wait a bit
|
||||||
|
//
|
||||||
|
KeStallExecutionProcessor(10);
|
||||||
|
|
||||||
|
//
|
||||||
|
// read command status
|
||||||
|
//
|
||||||
|
Reset = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET));
|
||||||
|
|
||||||
|
//
|
||||||
|
// was reset bit cleared
|
||||||
|
//
|
||||||
|
if ((Reset & OHCI_HOST_CONTROLLER_RESET) == 0)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// controller completed reset
|
||||||
|
//
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// failed to reset controller
|
||||||
|
//
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBHardwareDevice::ResetController(void)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED
|
||||||
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBHardwareDevice::ResetPort(
|
||||||
|
IN ULONG PortIndex)
|
||||||
|
{
|
||||||
|
ASSERT(FALSE);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBHardwareDevice::GetPortStatus(
|
||||||
|
ULONG PortId,
|
||||||
|
OUT USHORT *PortStatus,
|
||||||
|
OUT USHORT *PortChange)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED
|
||||||
|
*PortStatus = 0;
|
||||||
|
*PortChange = 0;
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBHardwareDevice::ClearPortStatus(
|
||||||
|
ULONG PortId,
|
||||||
|
ULONG Status)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBHardwareDevice::SetPortFeature(
|
||||||
|
ULONG PortId,
|
||||||
|
ULONG Feature)
|
||||||
|
{
|
||||||
|
if (Feature == PORT_ENABLE)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// enable port
|
||||||
|
//
|
||||||
|
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_PORT_STATUS(PortId)), OHCI_RH_PORTSTATUS_PES);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
else if (Feature == PORT_POWER)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// enable power
|
||||||
|
//
|
||||||
|
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_PORT_STATUS(PortId)), OHCI_RH_PORTSTATUS_PPS);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
else if (Feature == PORT_SUSPEND)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// enable port
|
||||||
|
//
|
||||||
|
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_PORT_STATUS(PortId)), OHCI_RH_PORTSTATUS_PSS);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
else if (Feature == PORT_RESET)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// reset port
|
||||||
|
//
|
||||||
|
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_PORT_STATUS(PortId)), OHCI_RH_PORTSTATUS_PRS);
|
||||||
|
|
||||||
|
//
|
||||||
|
// is there a status change callback
|
||||||
|
//
|
||||||
|
if (m_SCECallBack != NULL)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// issue callback
|
||||||
|
//
|
||||||
|
m_SCECallBack(m_SCEContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
CUSBHardwareDevice::SetStatusChangeEndpointCallBack(
|
||||||
|
PVOID CallBack,
|
||||||
|
PVOID Context)
|
||||||
|
{
|
||||||
|
m_SCECallBack = (HD_INIT_CALLBACK*)CallBack;
|
||||||
|
m_SCEContext = Context;
|
||||||
|
}
|
||||||
|
|
||||||
|
KIRQL
|
||||||
|
CUSBHardwareDevice::AcquireDeviceLock(void)
|
||||||
|
{
|
||||||
|
KIRQL OldLevel;
|
||||||
|
|
||||||
|
//
|
||||||
|
// acquire lock
|
||||||
|
//
|
||||||
|
KeAcquireSpinLock(&m_Lock, &OldLevel);
|
||||||
|
|
||||||
|
//
|
||||||
|
// return old irql
|
||||||
|
//
|
||||||
|
return OldLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
CUSBHardwareDevice::ReleaseDeviceLock(
|
||||||
|
KIRQL OldLevel)
|
||||||
|
{
|
||||||
|
KeReleaseSpinLock(&m_Lock, OldLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
NTAPI
|
||||||
|
InterruptServiceRoutine(
|
||||||
|
IN PKINTERRUPT Interrupt,
|
||||||
|
IN PVOID ServiceContext)
|
||||||
|
{
|
||||||
|
ASSERT(FALSE);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID NTAPI
|
||||||
|
EhciDefferedRoutine(
|
||||||
|
IN PKDPC Dpc,
|
||||||
|
IN PVOID DeferredContext,
|
||||||
|
IN PVOID SystemArgument1,
|
||||||
|
IN PVOID SystemArgument2)
|
||||||
|
{
|
||||||
|
ASSERT(FALSE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
StatusChangeWorkItemRoutine(
|
||||||
|
PVOID Context)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// cast to hardware object
|
||||||
|
//
|
||||||
|
CUSBHardwareDevice * This = (CUSBHardwareDevice*)Context;
|
||||||
|
|
||||||
|
//
|
||||||
|
// is there a callback
|
||||||
|
//
|
||||||
|
if (This->m_SCECallBack)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// issue callback
|
||||||
|
//
|
||||||
|
This->m_SCECallBack(This->m_SCEContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CreateUSBHardware(
|
||||||
|
PUSBHARDWAREDEVICE *OutHardware)
|
||||||
|
{
|
||||||
|
PUSBHARDWAREDEVICE This;
|
||||||
|
|
||||||
|
This = new(NonPagedPool, TAG_USBOHCI) CUSBHardwareDevice(0);
|
||||||
|
|
||||||
|
if (!This)
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
|
||||||
|
This->AddRef();
|
||||||
|
|
||||||
|
// return result
|
||||||
|
*OutHardware = (PUSBHARDWAREDEVICE)This;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
213
drivers/usb/usbohci/hardware.h
Normal file
213
drivers/usb/usbohci/hardware.h
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ntddk.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// OHCI Operational Registers
|
||||||
|
//
|
||||||
|
|
||||||
|
#define OHCI_REVISION_OFFSET (0x00)
|
||||||
|
#define OHCI_REVISION_LOW(rev) ((rev) & 0x0f)
|
||||||
|
#define OHCI_REVISION_HIGH(rev) (((rev) >> 4) & 0x03)
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// OHCI Control Register
|
||||||
|
//
|
||||||
|
#define OHCI_CONTROL_OFFSET (0x004)
|
||||||
|
#define OHCI_CONTROL_BULK_SERVICE_RATIO_MASK (0x003)
|
||||||
|
#define OHCI_CONTROL_BULK_RATIO_1_1 (0x000)
|
||||||
|
#define OHCI_CONTROL_BULK_RATIO_1_2 (0x001)
|
||||||
|
#define OHCI_CONTROL_BULK_RATIO_1_3 (0x002)
|
||||||
|
#define OHCI_CONTROL_BULK_RATIO_1_4 (0x003)
|
||||||
|
#define OHCI_PERIODIC_LIST_ENABLE (0x004)
|
||||||
|
#define OHCI_ISOCHRONOUS_ENABLE (0x008)
|
||||||
|
#define OHCI_CONTROL_LIST_ENABLE (0x010)
|
||||||
|
#define OHCI_BULK_LIST_ENABLE (0x020)
|
||||||
|
#define OHCI_HC_FUNCTIONAL_STATE_MASK (0x0C0)
|
||||||
|
#define OHCI_HC_FUNCTIONAL_STATE_RESET (0x000)
|
||||||
|
#define OHCI_HC_FUNCTIONAL_STATE_RESUME (0x040)
|
||||||
|
#define OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL (0x080)
|
||||||
|
#define OHCI_HC_FUNCTIONAL_STATE_SUSPEND (0x0c0)
|
||||||
|
#define OHCI_INTERRUPT_ROUTING (0x100)
|
||||||
|
#define OHCI_REMOTE_WAKEUP_CONNECTED (0x200)
|
||||||
|
#define OHCI_REMORE_WAKEUP_ENABLED (0x400)
|
||||||
|
|
||||||
|
//
|
||||||
|
// OHCI Command Status Register
|
||||||
|
//
|
||||||
|
#define OHCI_COMMAND_STATUS_OFFSET (0x08)
|
||||||
|
#define OHCI_HOST_CONTROLLER_RESET 0x00000001
|
||||||
|
#define OHCI_CONTROL_LIST_FILLED 0x00000002
|
||||||
|
#define OHCI_BULK_LIST_FILLED 0x00000004
|
||||||
|
#define OHCI_OWNERSHIP_CHANGE_REQUEST 0x00000008
|
||||||
|
#define OHCI_SCHEDULING_OVERRUN_COUNT_MASK 0x00030000
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// OHCI Interrupt Status Register
|
||||||
|
//
|
||||||
|
#define OHCI_INTERRUPT_STATUS_OFFSET 0x0c
|
||||||
|
#define OHCI_SCHEDULING_OVERRUN 0x00000001
|
||||||
|
#define OHCI_WRITEBACK_DONE_HEAD 0x00000002
|
||||||
|
#define OHCI_START_OF_FRAME 0x00000004
|
||||||
|
#define OHCI_RESUME_DETECTED 0x00000008
|
||||||
|
#define OHCI_UNRECOVERABLE_ERROR 0x00000010
|
||||||
|
#define OHCI_FRAME_NUMBER_OVERFLOW 0x00000020
|
||||||
|
#define OHCI_ROOT_HUB_STATUS_CHANGE 0x00000040
|
||||||
|
#define OHCI_OWNERSHIP_CHANGE 0x40000000
|
||||||
|
#define OHCI_MASTER_INTERRUPT_ENABLE 0x80000000
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// OHCI Interrupt Enable Register
|
||||||
|
//
|
||||||
|
#define OHCI_INTERRUPT_ENABLE_OFFSET 0x10
|
||||||
|
|
||||||
|
//
|
||||||
|
// OHCI Interrupt Enable Register
|
||||||
|
//
|
||||||
|
#define OHCI_INTERRUPT_DISABLE_OFFSET 0x14
|
||||||
|
|
||||||
|
//
|
||||||
|
// OHCI HCCA Register
|
||||||
|
//
|
||||||
|
#define OHCI_HCCA_OFFSET 0x18
|
||||||
|
#define OHCI_PERIOD_CURRENT_ED_OFFSET 0x1c
|
||||||
|
#define OHCI_CONTROL_HEAD_ED_OFFSET 0x20
|
||||||
|
#define OHCI_CONTROL_CURRENT_ED_OFFSET 0x24
|
||||||
|
#define OHCI_BULK_HEAD_ED_OFFSET 0x28
|
||||||
|
|
||||||
|
//
|
||||||
|
// OHCI Root Hub Descriptor A register
|
||||||
|
//
|
||||||
|
#define OHCI_RH_DESCRIPTOR_A_OFFSET 0x48
|
||||||
|
#define OHCI_RH_GET_PORT_COUNT(s) ((s) & 0xff)
|
||||||
|
#define OHCI_RH_POWER_SWITCHING_MODE 0x0100
|
||||||
|
#define OHCI_RH_NO_POWER_SWITCHING 0x0200
|
||||||
|
#define OHCI_RH_DEVICE_TYPE 0x0400
|
||||||
|
#define OHCI_RH_OVER_CURRENT_PROTECTION_MODE 0x0800
|
||||||
|
#define OHCI_RH_NO_OVER_CURRENT_PROTECTION 0x1000
|
||||||
|
#define OHCI_RH_GET_POWER_ON_TO_POWER_GOOD_TIME(s) ((s) >> 24)
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Root Hub Descriptor B register (section 7.4.2)
|
||||||
|
//
|
||||||
|
|
||||||
|
#define OHCI_RH_DESCRIPTOR_B 0x4c
|
||||||
|
|
||||||
|
//
|
||||||
|
// Root Hub status register (section 7.4.3)
|
||||||
|
//
|
||||||
|
#define OHCI_RH_STATUS 0x50
|
||||||
|
#define OHCI_RH_LOCAL_POWER_STATUS 0x00000001
|
||||||
|
#define OHCI_RH_OVER_CURRENT_INDICATOR 0x00000002
|
||||||
|
#define OHCI_RH_DEVICE_REMOTE_WAKEUP_ENABLE 0x00008000
|
||||||
|
#define OHCI_RH_LOCAL_POWER_STATUS_CHANGE 0x00010000
|
||||||
|
#define OHCI_RH_OVER_CURRENT_INDICATOR_CHANGE 0x00020000
|
||||||
|
#define OHCI_RH_CLEAR_REMOTE_WAKEUP_ENABLE 0x80000000
|
||||||
|
|
||||||
|
//
|
||||||
|
// Root Hub port status (n) register (section 7.4.4)
|
||||||
|
//
|
||||||
|
#define OHCI_RH_PORT_STATUS(n) (0x54 + (n) * 4)// 0 based indexing
|
||||||
|
#define OHCI_RH_PORTSTATUS_CCS 0x00000001
|
||||||
|
#define OHCI_RH_PORTSTATUS_PES 0x00000002
|
||||||
|
#define OHCI_RH_PORTSTATUS_PSS 0x00000004
|
||||||
|
#define OHCI_RH_PORTSTATUS_POCI 0x00000008
|
||||||
|
#define OHCI_RH_PORTSTATUS_PRS 0x00000010
|
||||||
|
#define OHCI_RH_PORTSTATUS_PPS 0x00000100
|
||||||
|
#define OHCI_RH_PORTSTATUS_LSDA 0x00000200
|
||||||
|
#define OHCI_RH_PORTSTATUS_CSC 0x00010000
|
||||||
|
#define OHCI_RH_PORTSTATUS_PESC 0x00020000
|
||||||
|
#define OHCI_RH_PORTSTATUS_PSSC 0x00040000
|
||||||
|
#define OHCI_RH_PORTSTATUS_OCIC 0x00080000
|
||||||
|
#define OHCI_RH_PORTSTATUS_PRSC 0x00100000
|
||||||
|
|
||||||
|
//
|
||||||
|
// Enable List
|
||||||
|
//
|
||||||
|
|
||||||
|
#define OHCI_ENABLE_LIST (OHCI_PERIODIC_LIST_ENABLE \
|
||||||
|
| OHCI_ISOCHRONOUS_ENABLE \
|
||||||
|
| OHCI_CONTROL_LIST_ENABLE \
|
||||||
|
| OHCI_BULK_LIST_ENABLE)
|
||||||
|
|
||||||
|
//
|
||||||
|
// All interupts
|
||||||
|
//
|
||||||
|
#define OHCI_ALL_INTERRUPTS (OHCI_SCHEDULING_OVERRUN \
|
||||||
|
| OHCI_WRITEBACK_DONE_HEAD \
|
||||||
|
| OHCI_START_OF_FRAME \
|
||||||
|
| OHCI_RESUME_DETECTED \
|
||||||
|
| OHCI_UNRECOVERABLE_ERROR \
|
||||||
|
| OHCI_FRAME_NUMBER_OVERFLOW \
|
||||||
|
| OHCI_ROOT_HUB_STATUS_CHANGE \
|
||||||
|
| OHCI_OWNERSHIP_CHANGE)
|
||||||
|
|
||||||
|
//
|
||||||
|
// All normal interupts
|
||||||
|
//
|
||||||
|
#define OHCI_NORMAL_INTERRUPTS (OHCI_SCHEDULING_OVERRUN \
|
||||||
|
| OHCI_WRITEBACK_DONE_HEAD \
|
||||||
|
| OHCI_RESUME_DETECTED \
|
||||||
|
| OHCI_UNRECOVERABLE_ERROR \
|
||||||
|
| OHCI_ROOT_HUB_STATUS_CHANGE)
|
||||||
|
|
||||||
|
//
|
||||||
|
// FSMPS
|
||||||
|
//
|
||||||
|
|
||||||
|
#define OHCI_FSMPS(i) (((i - 210) * 6 / 7) << 16)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Periodic
|
||||||
|
//
|
||||||
|
|
||||||
|
#define OHCI_PERIODIC(i) ((i) * 9 / 10)
|
||||||
|
|
||||||
|
// --------------------------------
|
||||||
|
// HCCA structure (section 4.4)
|
||||||
|
// 256 bytes aligned
|
||||||
|
// --------------------------------
|
||||||
|
|
||||||
|
#define OHCI_NUMBER_OF_INTERRUPTS 32
|
||||||
|
#define OHCI_STATIC_ENDPOINT_COUNT 6
|
||||||
|
#define OHCI_BIGGEST_INTERVAL 32
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ULONG InterruptTable[OHCI_NUMBER_OF_INTERRUPTS];
|
||||||
|
ULONG CurrentFrameNumber;
|
||||||
|
ULONG DoneHead;
|
||||||
|
UCHAR Reserved[120];
|
||||||
|
}OHCIHCCA, *POHCIHCCA;
|
||||||
|
|
||||||
|
#define OHCI_DONE_INTERRUPTS 1
|
||||||
|
#define OHCI_HCCA_SIZE 256
|
||||||
|
#define OHCI_HCCA_ALIGN 256
|
||||||
|
#define OHCI_PAGE_SIZE 0x1000
|
||||||
|
#define OHCI_PAGE(x) ((x) &~ 0xfff)
|
||||||
|
#define OHCI_PAGE_OFFSET(x) ((x) & 0xfff)
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
// Hardware part
|
||||||
|
ULONG Flags;
|
||||||
|
ULONG TailPhysicalDescriptor;
|
||||||
|
ULONG HeadPhysicalDescriptor;
|
||||||
|
ULONG NextPhysicalEndpoint;
|
||||||
|
|
||||||
|
// Software part
|
||||||
|
PHYSICAL_ADDRESS PhysicalAddress;
|
||||||
|
}OHCI_ENDPOINT_DESCRIPTOR, *POHCI_ENDPOINT_DESCRIPTOR;
|
||||||
|
|
||||||
|
|
||||||
|
#define OHCI_ENDPOINT_SKIP 0x00004000
|
||||||
|
|
||||||
|
//
|
||||||
|
// Maximum port count set by OHCI
|
||||||
|
//
|
||||||
|
#define OHCI_MAX_PORT_COUNT 15
|
751
drivers/usb/usbohci/hcd_controller.cpp
Normal file
751
drivers/usb/usbohci/hcd_controller.cpp
Normal file
|
@ -0,0 +1,751 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
|
||||||
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
|
* FILE: drivers/usb/usbohci/hcd_controller.cpp
|
||||||
|
* PURPOSE: USB OHCI device driver.
|
||||||
|
* PROGRAMMERS:
|
||||||
|
* Michael Martin (michael.martin@reactos.org)
|
||||||
|
* Johannes Anderwald (johannes.anderwald@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define INITGUID
|
||||||
|
#include "usbohci.h"
|
||||||
|
|
||||||
|
class CHCDController : public IHCDController,
|
||||||
|
public IDispatchIrp
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
|
||||||
|
|
||||||
|
STDMETHODIMP_(ULONG) AddRef()
|
||||||
|
{
|
||||||
|
InterlockedIncrement(&m_Ref);
|
||||||
|
return m_Ref;
|
||||||
|
}
|
||||||
|
STDMETHODIMP_(ULONG) Release()
|
||||||
|
{
|
||||||
|
InterlockedDecrement(&m_Ref);
|
||||||
|
|
||||||
|
if (!m_Ref)
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return m_Ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IHCDController interface functions
|
||||||
|
NTSTATUS Initialize(IN PROOTHDCCONTROLLER RootHCDController, IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject);
|
||||||
|
|
||||||
|
// IDispatchIrp interface functions
|
||||||
|
NTSTATUS HandlePnp(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
|
||||||
|
NTSTATUS HandlePower(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
|
||||||
|
NTSTATUS HandleDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
|
||||||
|
|
||||||
|
// local functions
|
||||||
|
NTSTATUS CreateFDO(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT * OutDeviceObject);
|
||||||
|
NTSTATUS SetSymbolicLink(BOOLEAN Enable);
|
||||||
|
|
||||||
|
// constructor / destructor
|
||||||
|
CHCDController(IUnknown *OuterUnknown){}
|
||||||
|
virtual ~CHCDController(){}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
LONG m_Ref;
|
||||||
|
PROOTHDCCONTROLLER m_RootController;
|
||||||
|
PDRIVER_OBJECT m_DriverObject;
|
||||||
|
PDEVICE_OBJECT m_PhysicalDeviceObject;
|
||||||
|
PDEVICE_OBJECT m_FunctionalDeviceObject;
|
||||||
|
PDEVICE_OBJECT m_NextDeviceObject;
|
||||||
|
PUSBHARDWAREDEVICE m_Hardware;
|
||||||
|
PHUBCONTROLLER m_HubController;
|
||||||
|
ULONG m_FDODeviceNumber;
|
||||||
|
};
|
||||||
|
|
||||||
|
//=================================================================================================
|
||||||
|
// COM
|
||||||
|
//
|
||||||
|
NTSTATUS
|
||||||
|
STDMETHODCALLTYPE
|
||||||
|
CHCDController::QueryInterface(
|
||||||
|
IN REFIID refiid,
|
||||||
|
OUT PVOID* Output)
|
||||||
|
{
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------
|
||||||
|
NTSTATUS
|
||||||
|
CHCDController::Initialize(
|
||||||
|
IN PROOTHDCCONTROLLER RootHCDController,
|
||||||
|
IN PDRIVER_OBJECT DriverObject,
|
||||||
|
IN PDEVICE_OBJECT PhysicalDeviceObject)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
PCOMMON_DEVICE_EXTENSION DeviceExtension;
|
||||||
|
|
||||||
|
//
|
||||||
|
// create usb hardware
|
||||||
|
//
|
||||||
|
Status = CreateUSBHardware(&m_Hardware);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// failed to create hardware object
|
||||||
|
//
|
||||||
|
DPRINT1("Failed to create hardware object\n");
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// initialize members
|
||||||
|
//
|
||||||
|
m_DriverObject = DriverObject;
|
||||||
|
m_PhysicalDeviceObject = PhysicalDeviceObject;
|
||||||
|
m_RootController = RootHCDController;
|
||||||
|
|
||||||
|
//
|
||||||
|
// create FDO
|
||||||
|
//
|
||||||
|
Status = CreateFDO(m_DriverObject, &m_FunctionalDeviceObject);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// failed to create PDO
|
||||||
|
//
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// now attach to device stack
|
||||||
|
//
|
||||||
|
m_NextDeviceObject = IoAttachDeviceToDeviceStack(m_FunctionalDeviceObject, m_PhysicalDeviceObject);
|
||||||
|
if (!m_NextDeviceObject)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// failed to attach to device stack
|
||||||
|
//
|
||||||
|
IoDeleteDevice(m_FunctionalDeviceObject);
|
||||||
|
m_FunctionalDeviceObject = 0;
|
||||||
|
|
||||||
|
return STATUS_NO_SUCH_DEVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// initialize hardware object
|
||||||
|
//
|
||||||
|
Status = m_Hardware->Initialize(m_DriverObject, m_FunctionalDeviceObject, m_PhysicalDeviceObject, m_NextDeviceObject);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("Failed to initialize hardware object %x\n", Status);
|
||||||
|
|
||||||
|
//
|
||||||
|
// failed to initialize hardware object, detach from device stack
|
||||||
|
//
|
||||||
|
IoDetachDevice(m_NextDeviceObject);
|
||||||
|
|
||||||
|
//
|
||||||
|
// now delete the device
|
||||||
|
//
|
||||||
|
IoDeleteDevice(m_FunctionalDeviceObject);
|
||||||
|
|
||||||
|
//
|
||||||
|
// nullify pointers :)
|
||||||
|
//
|
||||||
|
m_FunctionalDeviceObject = 0;
|
||||||
|
m_NextDeviceObject = 0;
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// set device flags
|
||||||
|
//
|
||||||
|
m_FunctionalDeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// get device extension
|
||||||
|
//
|
||||||
|
DeviceExtension = (PCOMMON_DEVICE_EXTENSION)m_FunctionalDeviceObject->DeviceExtension;
|
||||||
|
PC_ASSERT(DeviceExtension);
|
||||||
|
|
||||||
|
//
|
||||||
|
// initialize device extension
|
||||||
|
//
|
||||||
|
DeviceExtension->IsFDO = TRUE;
|
||||||
|
DeviceExtension->IsHub = FALSE;
|
||||||
|
DeviceExtension->Dispatcher = PDISPATCHIRP(this);
|
||||||
|
|
||||||
|
//
|
||||||
|
// device is initialized
|
||||||
|
//
|
||||||
|
m_FunctionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// is there a root controller
|
||||||
|
//
|
||||||
|
if (m_RootController)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// add reference
|
||||||
|
//
|
||||||
|
m_RootController->AddRef();
|
||||||
|
|
||||||
|
//
|
||||||
|
// register with controller
|
||||||
|
//
|
||||||
|
m_RootController->RegisterHCD(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// done
|
||||||
|
//
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------
|
||||||
|
NTSTATUS
|
||||||
|
CHCDController::HandleDeviceControl(
|
||||||
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
|
IN PIRP Irp)
|
||||||
|
{
|
||||||
|
PIO_STACK_LOCATION IoStack;
|
||||||
|
PCOMMON_DEVICE_EXTENSION DeviceExtension;
|
||||||
|
NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
|
||||||
|
PUSB_HCD_DRIVERKEY_NAME DriverKey;
|
||||||
|
ULONG ResultLength;
|
||||||
|
|
||||||
|
//
|
||||||
|
// get current stack location
|
||||||
|
//
|
||||||
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||||
|
|
||||||
|
//
|
||||||
|
// get device extension
|
||||||
|
//
|
||||||
|
DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||||
|
|
||||||
|
//
|
||||||
|
// sanity check
|
||||||
|
//
|
||||||
|
PC_ASSERT(DeviceExtension->IsFDO);
|
||||||
|
|
||||||
|
DPRINT1("HandleDeviceControl>Type: IoCtl %x InputBufferLength %lu OutputBufferLength %lu\n",
|
||||||
|
IoStack->Parameters.DeviceIoControl.IoControlCode,
|
||||||
|
IoStack->Parameters.DeviceIoControl.InputBufferLength,
|
||||||
|
IoStack->Parameters.DeviceIoControl.OutputBufferLength);
|
||||||
|
|
||||||
|
//
|
||||||
|
// perform ioctl for FDO
|
||||||
|
//
|
||||||
|
if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_GET_HCD_DRIVERKEY_NAME)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// check if sizee is at least >= USB_HCD_DRIVERKEY_NAME
|
||||||
|
//
|
||||||
|
if(IoStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(USB_HCD_DRIVERKEY_NAME))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// get device property size
|
||||||
|
//
|
||||||
|
Status = IoGetDeviceProperty(m_PhysicalDeviceObject, DevicePropertyDriverKeyName, 0, NULL, &ResultLength);
|
||||||
|
|
||||||
|
//
|
||||||
|
// get input buffer
|
||||||
|
//
|
||||||
|
DriverKey = (PUSB_HCD_DRIVERKEY_NAME)Irp->AssociatedIrp.SystemBuffer;
|
||||||
|
|
||||||
|
//
|
||||||
|
// check result
|
||||||
|
//
|
||||||
|
if (Status == STATUS_BUFFER_TOO_SMALL)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// does the caller provide enough buffer space
|
||||||
|
//
|
||||||
|
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength >= ResultLength)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// it does
|
||||||
|
//
|
||||||
|
Status = IoGetDeviceProperty(m_PhysicalDeviceObject, DevicePropertyDriverKeyName, IoStack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(ULONG), DriverKey->DriverKeyName, &ResultLength);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// informal debug print
|
||||||
|
//
|
||||||
|
DPRINT1("Result %S\n", DriverKey->DriverKeyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// store result
|
||||||
|
//
|
||||||
|
DriverKey->ActualLength = ResultLength + FIELD_OFFSET(USB_HCD_DRIVERKEY_NAME, DriverKeyName) + sizeof(WCHAR);
|
||||||
|
Irp->IoStatus.Information = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
|
||||||
|
Status = STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// buffer is certainly too small
|
||||||
|
//
|
||||||
|
Status = STATUS_BUFFER_OVERFLOW;
|
||||||
|
Irp->IoStatus.Information = sizeof(USB_HCD_DRIVERKEY_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_ROOT_HUB_NAME)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// check if sizee is at least >= USB_HCD_DRIVERKEY_NAME
|
||||||
|
//
|
||||||
|
if(IoStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(USB_HCD_DRIVERKEY_NAME))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// sanity check
|
||||||
|
//
|
||||||
|
PC_ASSERT(m_HubController);
|
||||||
|
|
||||||
|
//
|
||||||
|
// get input buffer
|
||||||
|
//
|
||||||
|
DriverKey = (PUSB_HCD_DRIVERKEY_NAME)Irp->AssociatedIrp.SystemBuffer;
|
||||||
|
|
||||||
|
//
|
||||||
|
// get symbolic link
|
||||||
|
//
|
||||||
|
Status = m_HubController->GetHubControllerSymbolicLink(IoStack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(ULONG), DriverKey->DriverKeyName, &ResultLength);
|
||||||
|
|
||||||
|
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// null terminate it
|
||||||
|
//
|
||||||
|
PC_ASSERT(IoStack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(ULONG) - sizeof(WCHAR) >= ResultLength);
|
||||||
|
|
||||||
|
DriverKey->DriverKeyName[ResultLength / sizeof(WCHAR)] = L'\0';
|
||||||
|
DPRINT1("Result %S\n", DriverKey->DriverKeyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// store result
|
||||||
|
//
|
||||||
|
DriverKey->ActualLength = ResultLength + FIELD_OFFSET(USB_HCD_DRIVERKEY_NAME, DriverKeyName) + sizeof(WCHAR);
|
||||||
|
Irp->IoStatus.Information = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
|
||||||
|
Status = STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// buffer is certainly too small
|
||||||
|
//
|
||||||
|
Status = STATUS_BUFFER_OVERFLOW;
|
||||||
|
Irp->IoStatus.Information = sizeof(USB_HCD_DRIVERKEY_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// complete the request
|
||||||
|
//
|
||||||
|
Irp->IoStatus.Status = Status;
|
||||||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||||
|
|
||||||
|
//
|
||||||
|
// done
|
||||||
|
//
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CHCDController::HandlePnp(
|
||||||
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
|
IN PIRP Irp)
|
||||||
|
{
|
||||||
|
PIO_STACK_LOCATION IoStack;
|
||||||
|
PCOMMON_DEVICE_EXTENSION DeviceExtension;
|
||||||
|
PCM_RESOURCE_LIST RawResourceList;
|
||||||
|
PCM_RESOURCE_LIST TranslatedResourceList;
|
||||||
|
PDEVICE_RELATIONS DeviceRelations;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
//
|
||||||
|
// get device extension
|
||||||
|
//
|
||||||
|
DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||||
|
|
||||||
|
//
|
||||||
|
// sanity check
|
||||||
|
//
|
||||||
|
PC_ASSERT(DeviceExtension->IsFDO);
|
||||||
|
|
||||||
|
//
|
||||||
|
// get current stack location
|
||||||
|
//
|
||||||
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||||
|
|
||||||
|
switch(IoStack->MinorFunction)
|
||||||
|
{
|
||||||
|
case IRP_MN_START_DEVICE:
|
||||||
|
{
|
||||||
|
DPRINT1("CHCDController::HandlePnp IRP_MN_START FDO\n");
|
||||||
|
|
||||||
|
//
|
||||||
|
// first start lower device object
|
||||||
|
//
|
||||||
|
Status = SyncForwardIrp(m_NextDeviceObject, Irp);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// operation succeeded, lets start the device
|
||||||
|
//
|
||||||
|
RawResourceList = IoStack->Parameters.StartDevice.AllocatedResources;
|
||||||
|
TranslatedResourceList = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated;
|
||||||
|
|
||||||
|
if (m_Hardware)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// start the hardware
|
||||||
|
//
|
||||||
|
Status = m_Hardware->PnpStart(RawResourceList, TranslatedResourceList);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// enable symbolic link
|
||||||
|
//
|
||||||
|
Status = SetSymbolicLink(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINT1("CHCDController::HandlePnp IRP_MN_START FDO: Status %x\n", Status);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
||||||
|
{
|
||||||
|
DPRINT1("CHCDController::HandlePnp IRP_MN_QUERY_DEVICE_RELATIONS Type %lx\n", IoStack->Parameters.QueryDeviceRelations.Type);
|
||||||
|
|
||||||
|
if (m_HubController == NULL)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// create hub controller
|
||||||
|
//
|
||||||
|
Status = CreateHubController(&m_HubController);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// failed to create hub controller
|
||||||
|
//
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// initialize hub controller
|
||||||
|
//
|
||||||
|
Status = m_HubController->Initialize(m_DriverObject, PHCDCONTROLLER(this), m_Hardware, TRUE, 0 /* FIXME*/);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// failed to initialize hub controller
|
||||||
|
//
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// add reference to prevent it from getting deleting while hub driver adds / removes references
|
||||||
|
//
|
||||||
|
m_HubController->AddRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IoStack->Parameters.QueryDeviceRelations.Type == BusRelations)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// allocate device relations
|
||||||
|
//
|
||||||
|
DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
|
||||||
|
|
||||||
|
if (!DeviceRelations)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// no memory
|
||||||
|
//
|
||||||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// init device relations
|
||||||
|
//
|
||||||
|
DeviceRelations->Count = 1;
|
||||||
|
Status = m_HubController->GetHubControllerDeviceObject(&DeviceRelations->Objects [0]);
|
||||||
|
|
||||||
|
//
|
||||||
|
// sanity check
|
||||||
|
//
|
||||||
|
PC_ASSERT(Status == STATUS_SUCCESS);
|
||||||
|
|
||||||
|
ObReferenceObject(DeviceRelations->Objects [0]);
|
||||||
|
|
||||||
|
//
|
||||||
|
// store result
|
||||||
|
//
|
||||||
|
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
|
||||||
|
Status = STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// not supported
|
||||||
|
//
|
||||||
|
PC_ASSERT(0);
|
||||||
|
Status = STATUS_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IRP_MN_STOP_DEVICE:
|
||||||
|
{
|
||||||
|
DPRINT1("CHCDController::HandlePnp IRP_MN_STOP_DEVICE\n");
|
||||||
|
|
||||||
|
if (m_Hardware)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// stop the hardware
|
||||||
|
//
|
||||||
|
Status = m_Hardware->PnpStop();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// fake success
|
||||||
|
//
|
||||||
|
Status = STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// stop lower device
|
||||||
|
//
|
||||||
|
Status = SyncForwardIrp(m_NextDeviceObject, Irp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IRP_MN_REMOVE_DEVICE:
|
||||||
|
{
|
||||||
|
DPRINT1("CHCDController::HandlePnp IRP_MN_REMOVE_DEVICE FDO\n");
|
||||||
|
|
||||||
|
//
|
||||||
|
// detach device from device stack
|
||||||
|
//
|
||||||
|
IoDetachDevice(m_NextDeviceObject);
|
||||||
|
|
||||||
|
//
|
||||||
|
// delete device
|
||||||
|
//
|
||||||
|
IoDeleteDevice(m_FunctionalDeviceObject);
|
||||||
|
|
||||||
|
Status = STATUS_SUCCESS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// forward irp to next device object
|
||||||
|
//
|
||||||
|
IoSkipCurrentIrpStackLocation(Irp);
|
||||||
|
return IoCallDriver(m_NextDeviceObject, Irp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// store result and complete request
|
||||||
|
//
|
||||||
|
Irp->IoStatus.Status = Status;
|
||||||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CHCDController::HandlePower(
|
||||||
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
|
IN PIRP Irp)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED
|
||||||
|
|
||||||
|
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
|
||||||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||||
|
|
||||||
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CHCDController::CreateFDO(
|
||||||
|
PDRIVER_OBJECT DriverObject,
|
||||||
|
PDEVICE_OBJECT * OutDeviceObject)
|
||||||
|
{
|
||||||
|
WCHAR CharDeviceName[64];
|
||||||
|
NTSTATUS Status;
|
||||||
|
ULONG UsbDeviceNumber = 0;
|
||||||
|
UNICODE_STRING DeviceName;
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// construct device name
|
||||||
|
//
|
||||||
|
swprintf(CharDeviceName, L"\\Device\\USBFDO-%d", UsbDeviceNumber);
|
||||||
|
|
||||||
|
//
|
||||||
|
// initialize device name
|
||||||
|
//
|
||||||
|
RtlInitUnicodeString(&DeviceName, CharDeviceName);
|
||||||
|
|
||||||
|
//
|
||||||
|
// create device
|
||||||
|
//
|
||||||
|
Status = IoCreateDevice(DriverObject,
|
||||||
|
sizeof(COMMON_DEVICE_EXTENSION),
|
||||||
|
&DeviceName,
|
||||||
|
FILE_DEVICE_CONTROLLER,
|
||||||
|
0,
|
||||||
|
FALSE,
|
||||||
|
OutDeviceObject);
|
||||||
|
|
||||||
|
//
|
||||||
|
// check for success
|
||||||
|
//
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
break;
|
||||||
|
|
||||||
|
//
|
||||||
|
// is there a device object with that same name
|
||||||
|
//
|
||||||
|
if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Try the next name
|
||||||
|
//
|
||||||
|
UsbDeviceNumber++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// bail out on other errors
|
||||||
|
//
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("CreateFDO: Failed to create %wZ, Status %x\n", &DeviceName, Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// store FDO number
|
||||||
|
//
|
||||||
|
m_FDODeviceNumber = UsbDeviceNumber;
|
||||||
|
|
||||||
|
DPRINT1("CreateFDO: DeviceName %wZ\n", &DeviceName);
|
||||||
|
|
||||||
|
/* done */
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CHCDController::SetSymbolicLink(
|
||||||
|
BOOLEAN Enable)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
WCHAR LinkName[32];
|
||||||
|
WCHAR FDOName[32];
|
||||||
|
UNICODE_STRING Link, FDO;
|
||||||
|
|
||||||
|
if (Enable)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// create legacy link
|
||||||
|
//
|
||||||
|
swprintf(LinkName, L"\\DosDevices\\HCD%d", m_FDODeviceNumber);
|
||||||
|
swprintf(FDOName, L"\\Device\\USBFDO-%d", m_FDODeviceNumber);
|
||||||
|
RtlInitUnicodeString(&Link, LinkName);
|
||||||
|
RtlInitUnicodeString(&FDO, FDOName);
|
||||||
|
|
||||||
|
//
|
||||||
|
// create symbolic link
|
||||||
|
//
|
||||||
|
Status = IoCreateSymbolicLink(&Link, &FDO);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// FIXME: handle me
|
||||||
|
//
|
||||||
|
ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// create legacy link
|
||||||
|
//
|
||||||
|
swprintf(LinkName, L"\\DosDevices\\HCD%d", m_FDODeviceNumber);
|
||||||
|
RtlInitUnicodeString(&Link, LinkName);
|
||||||
|
|
||||||
|
//
|
||||||
|
// now delete the symbolic link
|
||||||
|
//
|
||||||
|
Status = IoDeleteSymbolicLink(&Link);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// FIXME: handle me
|
||||||
|
//
|
||||||
|
ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// done
|
||||||
|
//
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CreateHCDController(
|
||||||
|
PHCDCONTROLLER *OutHcdController)
|
||||||
|
{
|
||||||
|
PHCDCONTROLLER This;
|
||||||
|
|
||||||
|
//
|
||||||
|
// allocate controller
|
||||||
|
//
|
||||||
|
This = new(NonPagedPool, TAG_USBOHCI) CHCDController(0);
|
||||||
|
if (!This)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// failed to allocate
|
||||||
|
//
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// add reference count
|
||||||
|
//
|
||||||
|
This->AddRef();
|
||||||
|
|
||||||
|
//
|
||||||
|
// return result
|
||||||
|
//
|
||||||
|
*OutHcdController = (PHCDCONTROLLER)This;
|
||||||
|
|
||||||
|
//
|
||||||
|
// done
|
||||||
|
//
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
3193
drivers/usb/usbohci/hub_controller.cpp
Normal file
3193
drivers/usb/usbohci/hub_controller.cpp
Normal file
File diff suppressed because it is too large
Load diff
723
drivers/usb/usbohci/interfaces.h
Normal file
723
drivers/usb/usbohci/interfaces.h
Normal file
|
@ -0,0 +1,723 @@
|
||||||
|
|
||||||
|
#ifndef INTERFACES_HPP
|
||||||
|
#define INTERFACES_HPP
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Object Hierachy
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// | IRootHCDController |
|
||||||
|
// | IHCDController Intel USB Universal Host Controller - 3A37 |
|
||||||
|
// | IHCDController - Intel USB Universal HostController - 3A38 |
|
||||||
|
// | IHCDController - Intel USB Universal HostController - 3A38 |
|
||||||
|
// |------------------------------------------------------------------|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// IHCDController Intel USB Universal Host Controller - 3A37
|
||||||
|
// IHubController
|
||||||
|
// IUSBHardwareDevice
|
||||||
|
// IDMAMemoryManager
|
||||||
|
// IUSBQueue <- interacts with -> IUSBRequest
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Each IHCDController creates an IUSBHardwareDevice class upon initialization. The
|
||||||
|
// IUSBHardwardeDevice class is used to abstract usb controller specifics. The IHubController
|
||||||
|
// manages all attached devices and handles hub control ioctl requests.
|
||||||
|
//
|
||||||
|
// Each IUSBHardwareDevice has one IDMAMemoryManager and one IUSBQueue. The IDMAMemoryManager
|
||||||
|
// is used to handle dma memory allocations. The IUSBQueue manages requests which are send to the
|
||||||
|
// usb hardware. See IUSBRequest class for details.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================================================
|
||||||
|
//
|
||||||
|
// class IRootHCDController
|
||||||
|
//
|
||||||
|
// Description: This class serves as the root host controller. The host controller mantains
|
||||||
|
// a list of registered controllers and provides support functions for the host controllers
|
||||||
|
|
||||||
|
struct IHCDController;
|
||||||
|
|
||||||
|
DECLARE_INTERFACE_(IRootHCDController, IUnknown)
|
||||||
|
{
|
||||||
|
DEFINE_ABSTRACT_UNKNOWN()
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Initialize
|
||||||
|
//
|
||||||
|
// Description: This function initializes the root host controller. It allocates the resources
|
||||||
|
// required to manage the registered controllers
|
||||||
|
|
||||||
|
virtual NTSTATUS Initialize() = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// RegisterHCD
|
||||||
|
//
|
||||||
|
// Description: this function registers a host controller with the root host controller
|
||||||
|
|
||||||
|
virtual NTSTATUS RegisterHCD(struct IHCDController * Controller) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// UnregisterHCD
|
||||||
|
//
|
||||||
|
// Description: this function unregistes a host controller
|
||||||
|
|
||||||
|
virtual NTSTATUS UnregisterHCD(struct IHCDController * Controller) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetControllerCount
|
||||||
|
//
|
||||||
|
// Description: returns the number of host controllers registered
|
||||||
|
|
||||||
|
virtual ULONG GetControllerCount() = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef IRootHCDController *PROOTHDCCONTROLLER;
|
||||||
|
|
||||||
|
//=========================================================================================
|
||||||
|
//
|
||||||
|
// class IHCDController
|
||||||
|
//
|
||||||
|
// Description: This class is used to manage a single USB host controller
|
||||||
|
//
|
||||||
|
|
||||||
|
DECLARE_INTERFACE_(IHCDController, IUnknown)
|
||||||
|
{
|
||||||
|
DEFINE_ABSTRACT_UNKNOWN()
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Initialize
|
||||||
|
//
|
||||||
|
// Description: This function initializes the IHCDController implementation.
|
||||||
|
// It creates an IUSBHardwareDevice object and initializes it. It also registeres itself with
|
||||||
|
// the IRootHCDController
|
||||||
|
//
|
||||||
|
virtual NTSTATUS Initialize(IN PROOTHDCCONTROLLER RootHCDController,
|
||||||
|
IN PDRIVER_OBJECT DriverObject,
|
||||||
|
IN PDEVICE_OBJECT PhysicalDeviceObject) = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef IHCDController *PHCDCONTROLLER;
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================================================
|
||||||
|
//
|
||||||
|
// class IUSBHardwareDevice
|
||||||
|
//
|
||||||
|
// Description: This class provides access to the usb hardware controller
|
||||||
|
//
|
||||||
|
|
||||||
|
struct IDMAMemoryManager;
|
||||||
|
struct IUSBQueue;
|
||||||
|
|
||||||
|
DECLARE_INTERFACE_(IUSBHardwareDevice, IUnknown)
|
||||||
|
{
|
||||||
|
DEFINE_ABSTRACT_UNKNOWN()
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Initialize
|
||||||
|
//
|
||||||
|
// Description: Initializes the usb device controller
|
||||||
|
|
||||||
|
virtual NTSTATUS Initialize(PDRIVER_OBJECT DriverObject,
|
||||||
|
PDEVICE_OBJECT FunctionalDeviceObject,
|
||||||
|
PDEVICE_OBJECT PhysicalDeviceObject,
|
||||||
|
PDEVICE_OBJECT LowerDeviceObject) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// PnpStart
|
||||||
|
//
|
||||||
|
// Description: handles pnp start request from device. It registeres the interrupt,
|
||||||
|
// sets up the ports and prepares the device. It then starts the controller
|
||||||
|
|
||||||
|
virtual NTSTATUS PnpStart(PCM_RESOURCE_LIST RawResources,
|
||||||
|
PCM_RESOURCE_LIST TranslatedResources) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// PnpStop
|
||||||
|
//
|
||||||
|
// Description: handles pnp stop request from device. It unregisteres the interrupt, releases ports and dma object.
|
||||||
|
|
||||||
|
virtual NTSTATUS PnpStop(void) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetDeviceDetails
|
||||||
|
//
|
||||||
|
// Description: returns the device details such as vendor id, device id, number of ports and speed
|
||||||
|
|
||||||
|
virtual NTSTATUS GetDeviceDetails(OUT OPTIONAL PUSHORT VendorId,
|
||||||
|
OUT OPTIONAL PUSHORT DeviceId,
|
||||||
|
OUT OPTIONAL PULONG NumberOfPorts,
|
||||||
|
OUT OPTIONAL PULONG Speed) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetUSBQueue
|
||||||
|
//
|
||||||
|
// Description: returns interface to internal IUSBQueue
|
||||||
|
// Interface is reference counted, you need to call release method when you are done with it
|
||||||
|
// Do not call Initialize on IUSBQueue, the object is already initialized
|
||||||
|
|
||||||
|
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()
|
||||||
|
//
|
||||||
|
// Description: this function resets the controller
|
||||||
|
// Returns STATUS_SUCCESS when the controller was successfully reset
|
||||||
|
|
||||||
|
virtual NTSTATUS ResetController() = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// StartController
|
||||||
|
//
|
||||||
|
// Description: this functions starts controller allowing interrupts for device connects/removal, and execution of
|
||||||
|
// Periodic and Asynchronous Schedules.
|
||||||
|
//
|
||||||
|
|
||||||
|
virtual NTSTATUS StartController() = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// StopController
|
||||||
|
//
|
||||||
|
// Description: this functions stops controller disabling interrupts for device connects/removal, and execution of
|
||||||
|
// Periodic and Asynchronous Schedules.
|
||||||
|
//
|
||||||
|
|
||||||
|
virtual NTSTATUS StopController() = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// ResetPort
|
||||||
|
//
|
||||||
|
// Description: this functions resets the port on the controller
|
||||||
|
//
|
||||||
|
|
||||||
|
virtual NTSTATUS ResetPort(ULONG PortNumber) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetPortStatus
|
||||||
|
//
|
||||||
|
// Description: this functions return status and change state of port
|
||||||
|
//
|
||||||
|
virtual NTSTATUS GetPortStatus(ULONG PortId, OUT USHORT *PortStatus, OUT USHORT *PortChange) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// ClearPortStatus
|
||||||
|
//
|
||||||
|
// Description: Clears Status of Port, for example Connection, Enable and Reset
|
||||||
|
//
|
||||||
|
virtual NTSTATUS ClearPortStatus(ULONG PortId, ULONG Status) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// SetPortFeature
|
||||||
|
//
|
||||||
|
// Description: this functions Sets Feature on Port, for example Enable, Power and Reset
|
||||||
|
//
|
||||||
|
virtual NTSTATUS SetPortFeature(ULONG PortId, ULONG Feature) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// SetStatusChangeEndpointCallBack
|
||||||
|
//
|
||||||
|
// Description: Used to callback to the hub controller when SCE detected
|
||||||
|
//
|
||||||
|
virtual VOID SetStatusChangeEndpointCallBack(PVOID CallBack,PVOID Context) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// AcquireDeviceLock
|
||||||
|
//
|
||||||
|
// Description: acquires the device lock
|
||||||
|
|
||||||
|
virtual KIRQL AcquireDeviceLock(void) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// ReleaseLock
|
||||||
|
//
|
||||||
|
// Description: releases the device lock
|
||||||
|
|
||||||
|
virtual void ReleaseDeviceLock(KIRQL OldLevel) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef IUSBHardwareDevice *PUSBHARDWAREDEVICE;
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================================================
|
||||||
|
//
|
||||||
|
// class IDMAMemoryManager
|
||||||
|
//
|
||||||
|
// Description: This class provides access to the dma buffer. It provides methods to
|
||||||
|
// allocate and free from the dma buffer
|
||||||
|
//
|
||||||
|
|
||||||
|
DECLARE_INTERFACE_(IDMAMemoryManager, IUnknown)
|
||||||
|
{
|
||||||
|
DEFINE_ABSTRACT_UNKNOWN()
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Initialize
|
||||||
|
//
|
||||||
|
// Description: initializes the memory manager
|
||||||
|
|
||||||
|
virtual NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Device,
|
||||||
|
IN PKSPIN_LOCK Lock,
|
||||||
|
IN ULONG DmaBufferSize,
|
||||||
|
IN PVOID VirtualBase,
|
||||||
|
IN PHYSICAL_ADDRESS PhysicalAddress,
|
||||||
|
IN ULONG DefaultBlockSize) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Allocate
|
||||||
|
//
|
||||||
|
// Description: allocates block of memory from allocator
|
||||||
|
|
||||||
|
virtual NTSTATUS Allocate(IN ULONG Size,
|
||||||
|
OUT PVOID *OutVirtualBase,
|
||||||
|
OUT PPHYSICAL_ADDRESS OutPhysicalAddress) = 0;
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Free
|
||||||
|
//
|
||||||
|
// Description: releases memory block
|
||||||
|
|
||||||
|
virtual NTSTATUS Release(IN PVOID VirtualBase,
|
||||||
|
IN ULONG Size) = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef IDMAMemoryManager *PDMAMEMORYMANAGER;
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================================================
|
||||||
|
//
|
||||||
|
// class IUSBRequest
|
||||||
|
//
|
||||||
|
// Description: This class is used to issue request to usb controller. The class is
|
||||||
|
// initialized using InitializeXXX methods. You also need to call SetEndpoint to define the endpoint
|
||||||
|
// In addition you can call SetCompletionDetails if you need to wait for the end of
|
||||||
|
// the request or want to complete an irp. You call AddUSBRequest to add the request to the queue.
|
||||||
|
// Once the request is completed the CompletionCallback is invoked. The CompletionCallback
|
||||||
|
// will take care of any completion details which have been set. If the request is cancelled, the
|
||||||
|
// CancelCallback routine is invoked.
|
||||||
|
//
|
||||||
|
|
||||||
|
struct _QUEUE_HEAD;
|
||||||
|
|
||||||
|
DECLARE_INTERFACE_(IUSBRequest, IUnknown)
|
||||||
|
{
|
||||||
|
DEFINE_ABSTRACT_UNKNOWN()
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// InitializeWithSetupPacket
|
||||||
|
//
|
||||||
|
// Description: initializes the request packet with an setup packet
|
||||||
|
// If there is a TransferBuffer, the TransferBufferLength contains the length of the buffer
|
||||||
|
|
||||||
|
|
||||||
|
virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager,
|
||||||
|
IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
|
||||||
|
IN UCHAR DeviceAddress,
|
||||||
|
IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor,
|
||||||
|
IN OUT ULONG TransferBufferLength,
|
||||||
|
IN OUT PMDL TransferBuffer) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// InitializeWithIrp
|
||||||
|
//
|
||||||
|
// Description: initializes the request with an IRP
|
||||||
|
// The irp contains an URB block which contains all necessary information
|
||||||
|
|
||||||
|
virtual NTSTATUS InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager,
|
||||||
|
IN OUT PIRP Irp) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// IsRequestComplete
|
||||||
|
//
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetTransferType
|
||||||
|
//
|
||||||
|
// Description: returns the type of the request: control, bulk, iso, interrupt
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef IUSBRequest *PUSBREQUEST;
|
||||||
|
|
||||||
|
//=========================================================================================
|
||||||
|
//
|
||||||
|
// class IUSBQueue
|
||||||
|
//
|
||||||
|
// Description: This class manages pending requests
|
||||||
|
//
|
||||||
|
|
||||||
|
DECLARE_INTERFACE_(IUSBQueue, IUnknown)
|
||||||
|
{
|
||||||
|
DEFINE_ABSTRACT_UNKNOWN()
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Initialize
|
||||||
|
//
|
||||||
|
// Description: initializes the object
|
||||||
|
|
||||||
|
virtual NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Hardware,
|
||||||
|
IN PDMA_ADAPTER AdapterObject,
|
||||||
|
IN PDMAMEMORYMANAGER MemManager,
|
||||||
|
IN OPTIONAL PKSPIN_LOCK Lock) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetPendingRequestCount
|
||||||
|
//
|
||||||
|
// Description: returns the number of pending requests true from IsRequestComplete
|
||||||
|
|
||||||
|
virtual ULONG GetPendingRequestCount() = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// AddUSBRequest
|
||||||
|
//
|
||||||
|
// Description: adds an usb request to the queue.
|
||||||
|
// Returns status success when successful
|
||||||
|
|
||||||
|
virtual NTSTATUS AddUSBRequest(IUSBRequest * Request) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// CancelRequests()
|
||||||
|
//
|
||||||
|
// Description: cancels all requests
|
||||||
|
|
||||||
|
virtual NTSTATUS CancelRequests() = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// CreateUSBRequest
|
||||||
|
//
|
||||||
|
// Description: creates an usb request
|
||||||
|
|
||||||
|
virtual NTSTATUS CreateUSBRequest(IUSBRequest **OutRequest) = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef IUSBQueue *PUSBQUEUE;
|
||||||
|
|
||||||
|
//=========================================================================================
|
||||||
|
//
|
||||||
|
// class IHubController
|
||||||
|
//
|
||||||
|
// Description: This class implements a hub controller
|
||||||
|
//
|
||||||
|
|
||||||
|
DECLARE_INTERFACE_(IHubController, IUnknown)
|
||||||
|
{
|
||||||
|
DEFINE_ABSTRACT_UNKNOWN()
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Initialize
|
||||||
|
//
|
||||||
|
// Description: Initializes the hub controller
|
||||||
|
|
||||||
|
virtual NTSTATUS Initialize(IN PDRIVER_OBJECT DriverObject,
|
||||||
|
IN PHCDCONTROLLER Controller,
|
||||||
|
IN PUSBHARDWAREDEVICE Device,
|
||||||
|
IN BOOLEAN IsRootHubDevice,
|
||||||
|
IN ULONG DeviceAddress) = 0;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetHubControllerDeviceObject
|
||||||
|
//
|
||||||
|
// Description: Returns the hub controller device object
|
||||||
|
|
||||||
|
virtual NTSTATUS GetHubControllerDeviceObject(PDEVICE_OBJECT * HubDeviceObject) = 0;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetHubControllerSymbolicLink
|
||||||
|
//
|
||||||
|
// Description: Returns the symbolic link of the root hub
|
||||||
|
|
||||||
|
virtual NTSTATUS GetHubControllerSymbolicLink(ULONG BufferLength, PVOID Buffer, PULONG RequiredLength) = 0;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef IHubController *PHUBCONTROLLER;
|
||||||
|
|
||||||
|
//=========================================================================================
|
||||||
|
//
|
||||||
|
// class IDispatchIrp
|
||||||
|
//
|
||||||
|
// Description: This class is used to handle irp dispatch requests
|
||||||
|
//
|
||||||
|
|
||||||
|
DECLARE_INTERFACE_(IDispatchIrp, IUnknown)
|
||||||
|
{
|
||||||
|
DEFINE_ABSTRACT_UNKNOWN()
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// HandlePnp
|
||||||
|
//
|
||||||
|
// Description: This function handles all pnp requests
|
||||||
|
|
||||||
|
virtual NTSTATUS HandlePnp(IN PDEVICE_OBJECT DeviceObject,
|
||||||
|
IN OUT PIRP Irp) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// HandlePower
|
||||||
|
//
|
||||||
|
// Description: This function handles all power pnp requests
|
||||||
|
//
|
||||||
|
virtual NTSTATUS HandlePower(IN PDEVICE_OBJECT DeviceObject,
|
||||||
|
IN OUT PIRP Irp) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// HandleDeviceControl
|
||||||
|
//
|
||||||
|
// Description: handles device io control requests
|
||||||
|
|
||||||
|
virtual NTSTATUS HandleDeviceControl(IN PDEVICE_OBJECT DeviceObject,
|
||||||
|
IN OUT PIRP Irp) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef IDispatchIrp *PDISPATCHIRP;
|
||||||
|
|
||||||
|
//=========================================================================================
|
||||||
|
//
|
||||||
|
// class IUSBDevice
|
||||||
|
//
|
||||||
|
// Description: This class is used to abstract details of a usb device
|
||||||
|
//
|
||||||
|
|
||||||
|
DECLARE_INTERFACE_(IUSBDevice, IUnknown)
|
||||||
|
{
|
||||||
|
DEFINE_ABSTRACT_UNKNOWN()
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Initialize
|
||||||
|
//
|
||||||
|
// Description: Initializes the usb device
|
||||||
|
|
||||||
|
virtual NTSTATUS Initialize(IN PHUBCONTROLLER HubController,
|
||||||
|
IN PUSBHARDWAREDEVICE Device,
|
||||||
|
IN PVOID Parent,
|
||||||
|
IN ULONG Port,
|
||||||
|
IN ULONG PortStatus) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// IsHub
|
||||||
|
//
|
||||||
|
// Description: returns true when device is a hub
|
||||||
|
|
||||||
|
virtual BOOLEAN IsHub() = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetParent
|
||||||
|
//
|
||||||
|
// Description: gets the parent device of the this device
|
||||||
|
|
||||||
|
virtual NTSTATUS GetParent(PVOID * Parent) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetDeviceAddress
|
||||||
|
//
|
||||||
|
// Description: gets the device address of the this device
|
||||||
|
|
||||||
|
virtual UCHAR GetDeviceAddress() = 0;
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetPort
|
||||||
|
//
|
||||||
|
// Description: gets the port to which this device is connected
|
||||||
|
|
||||||
|
virtual ULONG GetPort() = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetSpeed
|
||||||
|
//
|
||||||
|
// Description: gets the speed of the device
|
||||||
|
|
||||||
|
virtual USB_DEVICE_SPEED GetSpeed() = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetType
|
||||||
|
//
|
||||||
|
// Description: gets the type of the device, either 1.1 or 2.0 device
|
||||||
|
|
||||||
|
virtual USB_DEVICE_TYPE GetType() = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetState
|
||||||
|
//
|
||||||
|
// Description: gets the device state
|
||||||
|
|
||||||
|
virtual ULONG GetState() = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// SetDeviceHandleData
|
||||||
|
//
|
||||||
|
// Description: sets device handle data
|
||||||
|
|
||||||
|
virtual void SetDeviceHandleData(PVOID Data) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// SetDeviceAddress
|
||||||
|
//
|
||||||
|
// Description: sets device handle data
|
||||||
|
|
||||||
|
virtual NTSTATUS SetDeviceAddress(UCHAR DeviceAddress) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetDeviceDescriptor
|
||||||
|
//
|
||||||
|
// Description: sets device handle data
|
||||||
|
|
||||||
|
virtual void GetDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetConfigurationValue
|
||||||
|
//
|
||||||
|
// Description: gets current selected configuration index
|
||||||
|
|
||||||
|
virtual UCHAR GetConfigurationValue() = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// SubmitIrp
|
||||||
|
//
|
||||||
|
// Description: submits an irp containing an urb
|
||||||
|
|
||||||
|
virtual NTSTATUS SubmitIrp(PIRP Irp) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetConfigurationDescriptors
|
||||||
|
//
|
||||||
|
// Description: returns one or more configuration descriptors
|
||||||
|
|
||||||
|
virtual VOID GetConfigurationDescriptors(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptorBuffer,
|
||||||
|
IN ULONG BufferLength,
|
||||||
|
OUT PULONG OutBufferLength) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Description: returns length of configuration descriptors
|
||||||
|
//
|
||||||
|
virtual ULONG GetConfigurationDescriptorsLength() = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// SubmitSetupPacket
|
||||||
|
//
|
||||||
|
// Description: submits an setup packet. The usb device will then create an usb request from it and submit it to the queue
|
||||||
|
|
||||||
|
virtual NTSTATUS SubmitSetupPacket(IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
|
||||||
|
IN OUT ULONG BufferLength,
|
||||||
|
OUT PVOID Buffer) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// SelectConfiguration
|
||||||
|
//
|
||||||
|
// Description: selects a configuration
|
||||||
|
|
||||||
|
virtual NTSTATUS SelectConfiguration(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
|
||||||
|
IN PUSBD_INTERFACE_INFORMATION Interface,
|
||||||
|
OUT USBD_CONFIGURATION_HANDLE *ConfigurationHandle) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// SelectConfiguration
|
||||||
|
//
|
||||||
|
// Description: selects a interface of an configuration
|
||||||
|
|
||||||
|
virtual NTSTATUS SelectInterface(IN USBD_CONFIGURATION_HANDLE ConfigurationHandle,
|
||||||
|
IN OUT PUSBD_INTERFACE_INFORMATION Interface) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef IUSBDevice *PUSBDEVICE;
|
||||||
|
|
||||||
|
#endif
|
358
drivers/usb/usbohci/memory_manager.cpp
Normal file
358
drivers/usb/usbohci/memory_manager.cpp
Normal file
|
@ -0,0 +1,358 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
|
||||||
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
|
* FILE: drivers/usb/usbohci/memory_manager.cpp
|
||||||
|
* PURPOSE: USB OHCI device driver.
|
||||||
|
* PROGRAMMERS:
|
||||||
|
* Michael Martin (michael.martin@reactos.org)
|
||||||
|
* Johannes Anderwald (johannes.anderwald@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "usbohci.h"
|
||||||
|
|
||||||
|
class CDMAMemoryManager : public IDMAMemoryManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
|
||||||
|
|
||||||
|
STDMETHODIMP_(ULONG) AddRef()
|
||||||
|
{
|
||||||
|
InterlockedIncrement(&m_Ref);
|
||||||
|
return m_Ref;
|
||||||
|
}
|
||||||
|
STDMETHODIMP_(ULONG) Release()
|
||||||
|
{
|
||||||
|
InterlockedDecrement(&m_Ref);
|
||||||
|
|
||||||
|
if (!m_Ref)
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return m_Ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDMAMemoryManager interface functions
|
||||||
|
virtual NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Device, IN PKSPIN_LOCK Lock, IN ULONG DmaBufferSize, IN PVOID VirtualBase, IN PHYSICAL_ADDRESS PhysicalAddress, IN ULONG DefaultBlockSize);
|
||||||
|
virtual NTSTATUS Allocate(IN ULONG Size, OUT PVOID *OutVirtualBase, OUT PPHYSICAL_ADDRESS OutPhysicalAddress);
|
||||||
|
virtual NTSTATUS Release(IN PVOID VirtualBase, IN ULONG Size);
|
||||||
|
|
||||||
|
// constructor / destructor
|
||||||
|
CDMAMemoryManager(IUnknown *OuterUnknown){}
|
||||||
|
virtual ~CDMAMemoryManager(){}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
LONG m_Ref;
|
||||||
|
PUSBHARDWAREDEVICE m_Device;
|
||||||
|
PKSPIN_LOCK m_Lock;
|
||||||
|
LONG m_DmaBufferSize;
|
||||||
|
PVOID m_VirtualBase;
|
||||||
|
PHYSICAL_ADDRESS m_PhysicalAddress;
|
||||||
|
ULONG m_BlockSize;
|
||||||
|
|
||||||
|
PULONG m_BitmapBuffer;
|
||||||
|
RTL_BITMAP m_Bitmap;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
NTSTATUS
|
||||||
|
STDMETHODCALLTYPE
|
||||||
|
CDMAMemoryManager::QueryInterface(
|
||||||
|
IN REFIID refiid,
|
||||||
|
OUT PVOID* Output)
|
||||||
|
{
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CDMAMemoryManager::Initialize(
|
||||||
|
IN PUSBHARDWAREDEVICE Device,
|
||||||
|
IN PKSPIN_LOCK Lock,
|
||||||
|
IN ULONG DmaBufferSize,
|
||||||
|
IN PVOID VirtualBase,
|
||||||
|
IN PHYSICAL_ADDRESS PhysicalAddress,
|
||||||
|
IN ULONG DefaultBlockSize)
|
||||||
|
{
|
||||||
|
ULONG BitmapLength;
|
||||||
|
|
||||||
|
//
|
||||||
|
// sanity checks
|
||||||
|
//
|
||||||
|
PC_ASSERT(DmaBufferSize >= PAGE_SIZE);
|
||||||
|
PC_ASSERT(DmaBufferSize % PAGE_SIZE == 0);
|
||||||
|
PC_ASSERT(DefaultBlockSize == 32 || DefaultBlockSize == 64 || DefaultBlockSize == 128);
|
||||||
|
|
||||||
|
//
|
||||||
|
// calculate bitmap length
|
||||||
|
//
|
||||||
|
BitmapLength = (DmaBufferSize / DefaultBlockSize) / 8;
|
||||||
|
|
||||||
|
//
|
||||||
|
// allocate bitmap buffer
|
||||||
|
//
|
||||||
|
m_BitmapBuffer = (PULONG)ExAllocatePoolWithTag(NonPagedPool, BitmapLength, TAG_USBOHCI);
|
||||||
|
if (!m_BitmapBuffer)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// no memory
|
||||||
|
//
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// initialize bitmap
|
||||||
|
//
|
||||||
|
RtlInitializeBitMap(&m_Bitmap, m_BitmapBuffer, BitmapLength * 8);
|
||||||
|
|
||||||
|
//
|
||||||
|
// clear all bits
|
||||||
|
//
|
||||||
|
RtlClearAllBits(&m_Bitmap);
|
||||||
|
|
||||||
|
//
|
||||||
|
// initialize rest of memory allocator
|
||||||
|
//
|
||||||
|
m_PhysicalAddress = PhysicalAddress;
|
||||||
|
m_VirtualBase = VirtualBase;
|
||||||
|
m_DmaBufferSize = DmaBufferSize;
|
||||||
|
m_BitmapBuffer = m_BitmapBuffer;
|
||||||
|
m_Lock = Lock;
|
||||||
|
m_BlockSize = DefaultBlockSize;
|
||||||
|
|
||||||
|
/* done */
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CDMAMemoryManager::Allocate(
|
||||||
|
IN ULONG Size,
|
||||||
|
OUT PVOID *OutVirtualAddress,
|
||||||
|
OUT PPHYSICAL_ADDRESS OutPhysicalAddress)
|
||||||
|
{
|
||||||
|
ULONG Length, BlockCount, FreeIndex, StartPage, EndPage;
|
||||||
|
KIRQL OldLevel;
|
||||||
|
ULONG BlocksPerPage;
|
||||||
|
|
||||||
|
//
|
||||||
|
// sanity checks
|
||||||
|
//
|
||||||
|
ASSERT(Size <= PAGE_SIZE);
|
||||||
|
//ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
|
||||||
|
|
||||||
|
//
|
||||||
|
// align request
|
||||||
|
//
|
||||||
|
Length = (Size + m_BlockSize -1) & ~(m_BlockSize -1);
|
||||||
|
|
||||||
|
//
|
||||||
|
// sanity check
|
||||||
|
//
|
||||||
|
ASSERT(Length);
|
||||||
|
|
||||||
|
//
|
||||||
|
// convert to block count
|
||||||
|
//
|
||||||
|
BlockCount = Length / m_BlockSize;
|
||||||
|
|
||||||
|
//
|
||||||
|
// acquire lock
|
||||||
|
//
|
||||||
|
KeAcquireSpinLock(m_Lock, &OldLevel);
|
||||||
|
|
||||||
|
//
|
||||||
|
// helper variable
|
||||||
|
//
|
||||||
|
BlocksPerPage = PAGE_SIZE / m_BlockSize;
|
||||||
|
|
||||||
|
//
|
||||||
|
// start search
|
||||||
|
//
|
||||||
|
FreeIndex = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// search for an free index
|
||||||
|
//
|
||||||
|
FreeIndex = RtlFindClearBits(&m_Bitmap, BlockCount, FreeIndex);
|
||||||
|
|
||||||
|
//
|
||||||
|
// check if there was a block found
|
||||||
|
//
|
||||||
|
if (FreeIndex == MAXULONG)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// no free block found
|
||||||
|
//
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// check that the allocation does not spawn over page boundaries
|
||||||
|
//
|
||||||
|
StartPage = (FreeIndex * m_BlockSize);
|
||||||
|
StartPage = (StartPage != 0 ? StartPage / PAGE_SIZE : 0);
|
||||||
|
EndPage = ((FreeIndex + BlockCount) * m_BlockSize) / PAGE_SIZE;
|
||||||
|
|
||||||
|
//
|
||||||
|
// does the request start and end on the same page
|
||||||
|
//
|
||||||
|
if (StartPage == EndPage)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// reserve block
|
||||||
|
//
|
||||||
|
RtlSetBits(&m_Bitmap, FreeIndex, BlockCount);
|
||||||
|
|
||||||
|
//
|
||||||
|
// reserve block
|
||||||
|
//
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if ((BlockCount == BlocksPerPage) && (FreeIndex % BlocksPerPage == 0))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// the request equals PAGE_SIZE and is aligned at page boundary
|
||||||
|
// reserve block
|
||||||
|
//
|
||||||
|
RtlSetBits(&m_Bitmap, FreeIndex, BlockCount);
|
||||||
|
|
||||||
|
//
|
||||||
|
// reserve block
|
||||||
|
//
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// request spawned over page boundary
|
||||||
|
// restart search on next page
|
||||||
|
//
|
||||||
|
FreeIndex = (EndPage * PAGE_SIZE) / m_BlockSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(TRUE);
|
||||||
|
|
||||||
|
//
|
||||||
|
// release lock
|
||||||
|
//
|
||||||
|
KeReleaseSpinLock(m_Lock, OldLevel);
|
||||||
|
|
||||||
|
//
|
||||||
|
// did allocation succeed
|
||||||
|
//
|
||||||
|
if (FreeIndex == MAXULONG)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// failed to allocate block, requestor must retry
|
||||||
|
//
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// return result
|
||||||
|
//
|
||||||
|
*OutVirtualAddress = (PVOID)((ULONG_PTR)m_VirtualBase + FreeIndex * m_BlockSize);
|
||||||
|
OutPhysicalAddress->QuadPart = m_PhysicalAddress.QuadPart + FreeIndex * m_BlockSize;
|
||||||
|
|
||||||
|
//
|
||||||
|
// clear block
|
||||||
|
//
|
||||||
|
RtlZeroMemory(*OutVirtualAddress, Length);
|
||||||
|
|
||||||
|
//
|
||||||
|
// done
|
||||||
|
//
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CDMAMemoryManager::Release(
|
||||||
|
IN PVOID VirtualAddress,
|
||||||
|
IN ULONG Size)
|
||||||
|
{
|
||||||
|
KIRQL OldLevel;
|
||||||
|
ULONG BlockOffset = 0, BlockLength;
|
||||||
|
|
||||||
|
//
|
||||||
|
// sanity checks
|
||||||
|
//
|
||||||
|
PC_ASSERT(VirtualAddress);
|
||||||
|
PC_ASSERT((ULONG_PTR)VirtualAddress >= (ULONG_PTR)m_VirtualBase);
|
||||||
|
PC_ASSERT((ULONG_PTR)m_VirtualBase + m_DmaBufferSize > (ULONG_PTR)m_VirtualBase);
|
||||||
|
|
||||||
|
//
|
||||||
|
// calculate block length
|
||||||
|
//
|
||||||
|
BlockLength = ((ULONG_PTR)VirtualAddress - (ULONG_PTR)m_VirtualBase);
|
||||||
|
|
||||||
|
//
|
||||||
|
// check if its the first block
|
||||||
|
//
|
||||||
|
if (BlockLength)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// divide by base block size
|
||||||
|
//
|
||||||
|
BlockOffset = BlockLength / m_BlockSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// align length to block size
|
||||||
|
//
|
||||||
|
Size = (Size + m_BlockSize - 1) & ~(m_BlockSize - 1);
|
||||||
|
|
||||||
|
//
|
||||||
|
// acquire lock
|
||||||
|
//
|
||||||
|
KeAcquireSpinLock(m_Lock, &OldLevel);
|
||||||
|
|
||||||
|
//
|
||||||
|
// release buffer
|
||||||
|
//
|
||||||
|
RtlClearBits(&m_Bitmap, BlockOffset, Size);
|
||||||
|
|
||||||
|
//
|
||||||
|
// release lock
|
||||||
|
//
|
||||||
|
KeReleaseSpinLock(m_Lock, OldLevel);
|
||||||
|
|
||||||
|
//
|
||||||
|
// done
|
||||||
|
//
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CreateDMAMemoryManager(
|
||||||
|
PDMAMEMORYMANAGER *OutMemoryManager)
|
||||||
|
{
|
||||||
|
CDMAMemoryManager* This;
|
||||||
|
|
||||||
|
//
|
||||||
|
// allocate controller
|
||||||
|
//
|
||||||
|
This = new(NonPagedPool, TAG_USBOHCI) CDMAMemoryManager(0);
|
||||||
|
if (!This)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// failed to allocate
|
||||||
|
//
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// add reference count
|
||||||
|
//
|
||||||
|
This->AddRef();
|
||||||
|
|
||||||
|
//
|
||||||
|
// return result
|
||||||
|
//
|
||||||
|
*OutMemoryManager = (PDMAMEMORYMANAGER)This;
|
||||||
|
|
||||||
|
//
|
||||||
|
// done
|
||||||
|
//
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
134
drivers/usb/usbohci/misc.cpp
Normal file
134
drivers/usb/usbohci/misc.cpp
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
|
||||||
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
|
* FILE: drivers/usb/usbohci/misc.cpp
|
||||||
|
* PURPOSE: USB OHCI device driver.
|
||||||
|
* PROGRAMMERS:
|
||||||
|
* Michael Martin (michael.martin@reactos.org)
|
||||||
|
* Johannes Anderwald (johannes.anderwald@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "usbohci.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// driver verifier
|
||||||
|
//
|
||||||
|
IO_COMPLETION_ROUTINE SyncForwardIrpCompletionRoutine;
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
SyncForwardIrpCompletionRoutine(
|
||||||
|
PDEVICE_OBJECT DeviceObject,
|
||||||
|
PIRP Irp,
|
||||||
|
PVOID Context)
|
||||||
|
{
|
||||||
|
if (Irp->PendingReturned)
|
||||||
|
{
|
||||||
|
KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
|
||||||
|
}
|
||||||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
SyncForwardIrp(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||||
|
{
|
||||||
|
KEVENT Event;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
//
|
||||||
|
// initialize event
|
||||||
|
//
|
||||||
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
||||||
|
|
||||||
|
//
|
||||||
|
// copy irp stack location
|
||||||
|
//
|
||||||
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
||||||
|
|
||||||
|
//
|
||||||
|
// set completion routine
|
||||||
|
//
|
||||||
|
IoSetCompletionRoutine(Irp, SyncForwardIrpCompletionRoutine, &Event, TRUE, TRUE, TRUE);
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// call driver
|
||||||
|
//
|
||||||
|
Status = IoCallDriver(DeviceObject, Irp);
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// check if pending
|
||||||
|
//
|
||||||
|
if (Status == STATUS_PENDING)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// wait for the request to finish
|
||||||
|
//
|
||||||
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
||||||
|
|
||||||
|
//
|
||||||
|
// copy status code
|
||||||
|
//
|
||||||
|
Status = Irp->IoStatus.Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// done
|
||||||
|
//
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
GetBusInterface(
|
||||||
|
PDEVICE_OBJECT DeviceObject,
|
||||||
|
PBUS_INTERFACE_STANDARD busInterface)
|
||||||
|
{
|
||||||
|
KEVENT Event;
|
||||||
|
NTSTATUS Status;
|
||||||
|
PIRP Irp;
|
||||||
|
IO_STATUS_BLOCK IoStatus;
|
||||||
|
PIO_STACK_LOCATION Stack;
|
||||||
|
|
||||||
|
if ((!DeviceObject) || (!busInterface))
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
|
||||||
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
||||||
|
|
||||||
|
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
|
||||||
|
DeviceObject,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
&Event,
|
||||||
|
&IoStatus);
|
||||||
|
|
||||||
|
if (Irp == NULL)
|
||||||
|
{
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stack=IoGetNextIrpStackLocation(Irp);
|
||||||
|
Stack->MajorFunction = IRP_MJ_PNP;
|
||||||
|
Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
||||||
|
Stack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
|
||||||
|
Stack->Parameters.QueryInterface.InterfaceType = (LPGUID)&GUID_BUS_INTERFACE_STANDARD;
|
||||||
|
Stack->Parameters.QueryInterface.Version = 1;
|
||||||
|
Stack->Parameters.QueryInterface.Interface = (PINTERFACE)busInterface;
|
||||||
|
Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
||||||
|
Irp->IoStatus.Status=STATUS_NOT_SUPPORTED ;
|
||||||
|
|
||||||
|
Status=IoCallDriver(DeviceObject, Irp);
|
||||||
|
|
||||||
|
if (Status == STATUS_PENDING)
|
||||||
|
{
|
||||||
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
||||||
|
|
||||||
|
Status=IoStatus.Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
24
drivers/usb/usbohci/purecall.cpp
Normal file
24
drivers/usb/usbohci/purecall.cpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
|
||||||
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
|
* FILE: drivers/usb/usbohci/purecall.cpp
|
||||||
|
* PURPOSE: USB OHCI device driver.
|
||||||
|
* PROGRAMMERS:
|
||||||
|
* Michael Martin (michael.martin@reactos.org)
|
||||||
|
* Johannes Anderwald (johannes.anderwald@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "usbohci.h"
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void
|
||||||
|
__cxa_pure_virtual()
|
||||||
|
{
|
||||||
|
// put error handling here
|
||||||
|
|
||||||
|
DbgBreakPoint();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
1286
drivers/usb/usbohci/usb_device.cpp
Normal file
1286
drivers/usb/usbohci/usb_device.cpp
Normal file
File diff suppressed because it is too large
Load diff
208
drivers/usb/usbohci/usb_queue.cpp
Normal file
208
drivers/usb/usbohci/usb_queue.cpp
Normal file
|
@ -0,0 +1,208 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
|
||||||
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
|
* FILE: drivers/usb/usbohci/usb_queue.cpp
|
||||||
|
* PURPOSE: USB OHCI device driver.
|
||||||
|
* PROGRAMMERS:
|
||||||
|
* Michael Martin (michael.martin@reactos.org)
|
||||||
|
* Johannes Anderwald (johannes.anderwald@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "usbohci.h"
|
||||||
|
#include "hardware.h"
|
||||||
|
|
||||||
|
class CUSBQueue : public IUSBQueue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
|
||||||
|
|
||||||
|
STDMETHODIMP_(ULONG) AddRef()
|
||||||
|
{
|
||||||
|
InterlockedIncrement(&m_Ref);
|
||||||
|
return m_Ref;
|
||||||
|
}
|
||||||
|
STDMETHODIMP_(ULONG) Release()
|
||||||
|
{
|
||||||
|
InterlockedDecrement(&m_Ref);
|
||||||
|
|
||||||
|
if (!m_Ref)
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return m_Ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Hardware, PDMA_ADAPTER AdapterObject, IN PDMAMEMORYMANAGER MemManager, IN OPTIONAL PKSPIN_LOCK Lock);
|
||||||
|
virtual ULONG GetPendingRequestCount();
|
||||||
|
virtual NTSTATUS AddUSBRequest(IUSBRequest * Request);
|
||||||
|
virtual NTSTATUS CancelRequests();
|
||||||
|
virtual NTSTATUS CreateUSBRequest(IUSBRequest **OutRequest);
|
||||||
|
|
||||||
|
// constructor / destructor
|
||||||
|
CUSBQueue(IUnknown *OuterUnknown){}
|
||||||
|
virtual ~CUSBQueue(){}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
LONG m_Ref; // reference count
|
||||||
|
KSPIN_LOCK m_Lock; // list lock
|
||||||
|
};
|
||||||
|
|
||||||
|
//=================================================================================================
|
||||||
|
// COM
|
||||||
|
//
|
||||||
|
NTSTATUS
|
||||||
|
STDMETHODCALLTYPE
|
||||||
|
CUSBQueue::QueryInterface(
|
||||||
|
IN REFIID refiid,
|
||||||
|
OUT PVOID* Output)
|
||||||
|
{
|
||||||
|
if (IsEqualGUIDAligned(refiid, IID_IUnknown))
|
||||||
|
{
|
||||||
|
*Output = PVOID(PUNKNOWN(this));
|
||||||
|
PUNKNOWN(*Output)->AddRef();
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBQueue::Initialize(
|
||||||
|
IN PUSBHARDWAREDEVICE Hardware,
|
||||||
|
IN PDMA_ADAPTER AdapterObject,
|
||||||
|
IN PDMAMEMORYMANAGER MemManager,
|
||||||
|
IN OPTIONAL PKSPIN_LOCK Lock)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG
|
||||||
|
CUSBQueue::GetPendingRequestCount()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Loop through the pending list and iterrate one for each QueueHead that
|
||||||
|
// has a IRP to complete.
|
||||||
|
//
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBQueue::AddUSBRequest(
|
||||||
|
IUSBRequest * Request)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
ULONG Type;
|
||||||
|
KIRQL OldLevel;
|
||||||
|
|
||||||
|
//
|
||||||
|
// sanity check
|
||||||
|
//
|
||||||
|
ASSERT(Request != NULL);
|
||||||
|
|
||||||
|
//
|
||||||
|
// get request type
|
||||||
|
//
|
||||||
|
Type = Request->GetTransferType();
|
||||||
|
|
||||||
|
//
|
||||||
|
// check if supported
|
||||||
|
//
|
||||||
|
switch(Type)
|
||||||
|
{
|
||||||
|
case USB_ENDPOINT_TYPE_ISOCHRONOUS:
|
||||||
|
case USB_ENDPOINT_TYPE_INTERRUPT:
|
||||||
|
/* NOT IMPLEMENTED IN QUEUE */
|
||||||
|
Status = STATUS_NOT_SUPPORTED;
|
||||||
|
break;
|
||||||
|
case USB_ENDPOINT_TYPE_BULK:
|
||||||
|
case USB_ENDPOINT_TYPE_CONTROL:
|
||||||
|
Status = STATUS_SUCCESS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* BUG */
|
||||||
|
PC_ASSERT(FALSE);
|
||||||
|
Status = STATUS_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// check for success
|
||||||
|
//
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// request not supported, please try later
|
||||||
|
//
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// add extra reference which is released when the request is completed
|
||||||
|
//
|
||||||
|
Request->AddRef();
|
||||||
|
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBQueue::CancelRequests()
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED
|
||||||
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBQueue::CreateUSBRequest(
|
||||||
|
IUSBRequest **OutRequest)
|
||||||
|
{
|
||||||
|
PUSBREQUEST UsbRequest;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
*OutRequest = NULL;
|
||||||
|
Status = InternalCreateUSBRequest(&UsbRequest);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
*OutRequest = UsbRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CreateUSBQueue(
|
||||||
|
PUSBQUEUE *OutUsbQueue)
|
||||||
|
{
|
||||||
|
PUSBQUEUE This;
|
||||||
|
|
||||||
|
//
|
||||||
|
// allocate controller
|
||||||
|
//
|
||||||
|
This = new(NonPagedPool, TAG_USBOHCI) CUSBQueue(0);
|
||||||
|
if (!This)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// failed to allocate
|
||||||
|
//
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// add reference count
|
||||||
|
//
|
||||||
|
This->AddRef();
|
||||||
|
|
||||||
|
//
|
||||||
|
// return result
|
||||||
|
//
|
||||||
|
*OutUsbQueue = (PUSBQUEUE)This;
|
||||||
|
|
||||||
|
//
|
||||||
|
// done
|
||||||
|
//
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
548
drivers/usb/usbohci/usb_request.cpp
Normal file
548
drivers/usb/usbohci/usb_request.cpp
Normal file
|
@ -0,0 +1,548 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
|
||||||
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
|
* FILE: drivers/usb/usbohci/usb_request.cpp
|
||||||
|
* PURPOSE: USB OHCI device driver.
|
||||||
|
* PROGRAMMERS:
|
||||||
|
* Michael Martin (michael.martin@reactos.org)
|
||||||
|
* Johannes Anderwald (johannes.anderwald@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define INITGUID
|
||||||
|
|
||||||
|
#include "usbohci.h"
|
||||||
|
#include "hardware.h"
|
||||||
|
|
||||||
|
class CUSBRequest : public IUSBRequest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
|
||||||
|
|
||||||
|
STDMETHODIMP_(ULONG) AddRef()
|
||||||
|
{
|
||||||
|
InterlockedIncrement(&m_Ref);
|
||||||
|
return m_Ref;
|
||||||
|
}
|
||||||
|
STDMETHODIMP_(ULONG) Release()
|
||||||
|
{
|
||||||
|
InterlockedDecrement(&m_Ref);
|
||||||
|
|
||||||
|
if (!m_Ref)
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return m_Ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IUSBRequest interface functions
|
||||||
|
virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, IN UCHAR DeviceAddress, IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN OUT ULONG TransferBufferLength, IN OUT PMDL TransferBuffer);
|
||||||
|
virtual NTSTATUS InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager, IN OUT PIRP Irp);
|
||||||
|
virtual BOOLEAN IsRequestComplete();
|
||||||
|
virtual ULONG GetTransferType();
|
||||||
|
virtual VOID GetResultStatus(OUT OPTIONAL NTSTATUS *NtStatusCode, OUT OPTIONAL PULONG UrbStatusCode);
|
||||||
|
virtual BOOLEAN IsRequestInitialized();
|
||||||
|
virtual BOOLEAN IsQueueHeadComplete(struct _QUEUE_HEAD * QueueHead);
|
||||||
|
|
||||||
|
|
||||||
|
// local functions
|
||||||
|
ULONG InternalGetTransferType();
|
||||||
|
UCHAR InternalGetPidDirection();
|
||||||
|
UCHAR GetDeviceAddress();
|
||||||
|
NTSTATUS BuildSetupPacket();
|
||||||
|
NTSTATUS BuildSetupPacketFromURB();
|
||||||
|
|
||||||
|
// constructor / destructor
|
||||||
|
CUSBRequest(IUnknown *OuterUnknown){}
|
||||||
|
virtual ~CUSBRequest(){}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
LONG m_Ref;
|
||||||
|
|
||||||
|
//
|
||||||
|
// memory manager for allocating setup packet / queue head / transfer descriptors
|
||||||
|
//
|
||||||
|
PDMAMEMORYMANAGER m_DmaManager;
|
||||||
|
|
||||||
|
//
|
||||||
|
// caller provided irp packet containing URB request
|
||||||
|
//
|
||||||
|
PIRP m_Irp;
|
||||||
|
|
||||||
|
//
|
||||||
|
// transfer buffer length
|
||||||
|
//
|
||||||
|
ULONG m_TransferBufferLength;
|
||||||
|
|
||||||
|
//
|
||||||
|
// current transfer length
|
||||||
|
//
|
||||||
|
ULONG m_TransferBufferLengthCompleted;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Total Transfer Length
|
||||||
|
//
|
||||||
|
ULONG m_TotalBytesTransferred;
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
//
|
||||||
|
// device address for callers who initialized it with device address
|
||||||
|
//
|
||||||
|
UCHAR m_DeviceAddress;
|
||||||
|
|
||||||
|
//
|
||||||
|
// store end point address
|
||||||
|
//
|
||||||
|
PUSB_ENDPOINT_DESCRIPTOR m_EndpointDescriptor;
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
NTSTATUS
|
||||||
|
STDMETHODCALLTYPE
|
||||||
|
CUSBRequest::QueryInterface(
|
||||||
|
IN REFIID refiid,
|
||||||
|
OUT PVOID* Output)
|
||||||
|
{
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
NTSTATUS
|
||||||
|
CUSBRequest::InitializeWithSetupPacket(
|
||||||
|
IN PDMAMEMORYMANAGER DmaManager,
|
||||||
|
IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
|
||||||
|
IN UCHAR DeviceAddress,
|
||||||
|
IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor,
|
||||||
|
IN OUT ULONG TransferBufferLength,
|
||||||
|
IN OUT PMDL TransferBuffer)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// sanity checks
|
||||||
|
//
|
||||||
|
PC_ASSERT(DmaManager);
|
||||||
|
PC_ASSERT(SetupPacket);
|
||||||
|
|
||||||
|
//
|
||||||
|
// initialize packet
|
||||||
|
//
|
||||||
|
m_DmaManager = DmaManager;
|
||||||
|
m_SetupPacket = SetupPacket;
|
||||||
|
m_TransferBufferLength = TransferBufferLength;
|
||||||
|
m_TransferBufferMDL = TransferBuffer;
|
||||||
|
m_DeviceAddress = DeviceAddress;
|
||||||
|
m_EndpointDescriptor = EndpointDescriptor;
|
||||||
|
m_TotalBytesTransferred = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Set Length Completed to 0
|
||||||
|
//
|
||||||
|
m_TransferBufferLengthCompleted = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// allocate completion event
|
||||||
|
//
|
||||||
|
m_CompletionEvent = (PKEVENT)ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_USBOHCI);
|
||||||
|
if (!m_CompletionEvent)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// failed to allocate completion event
|
||||||
|
//
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// initialize completion event
|
||||||
|
//
|
||||||
|
KeInitializeEvent(m_CompletionEvent, NotificationEvent, FALSE);
|
||||||
|
|
||||||
|
//
|
||||||
|
// done
|
||||||
|
//
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
NTSTATUS
|
||||||
|
CUSBRequest::InitializeWithIrp(
|
||||||
|
IN PDMAMEMORYMANAGER DmaManager,
|
||||||
|
IN OUT PIRP Irp)
|
||||||
|
{
|
||||||
|
PIO_STACK_LOCATION IoStack;
|
||||||
|
PURB Urb;
|
||||||
|
|
||||||
|
//
|
||||||
|
// sanity checks
|
||||||
|
//
|
||||||
|
PC_ASSERT(DmaManager);
|
||||||
|
PC_ASSERT(Irp);
|
||||||
|
|
||||||
|
m_DmaManager = DmaManager;
|
||||||
|
m_TotalBytesTransferred = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// get current irp stack location
|
||||||
|
//
|
||||||
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||||
|
|
||||||
|
//
|
||||||
|
// sanity check
|
||||||
|
//
|
||||||
|
PC_ASSERT(IoStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL);
|
||||||
|
PC_ASSERT(IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_SUBMIT_URB);
|
||||||
|
PC_ASSERT(IoStack->Parameters.Others.Argument1 != 0);
|
||||||
|
|
||||||
|
//
|
||||||
|
// get urb
|
||||||
|
//
|
||||||
|
Urb = (PURB)IoStack->Parameters.Others.Argument1;
|
||||||
|
|
||||||
|
//
|
||||||
|
// store irp
|
||||||
|
//
|
||||||
|
m_Irp = Irp;
|
||||||
|
|
||||||
|
//
|
||||||
|
// check function type
|
||||||
|
//
|
||||||
|
switch (Urb->UrbHeader.Function)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// luckily those request have the same structure layout
|
||||||
|
//
|
||||||
|
case URB_FUNCTION_CLASS_INTERFACE:
|
||||||
|
case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
|
||||||
|
case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// bulk interrupt transfer
|
||||||
|
//
|
||||||
|
if (Urb->UrbBulkOrInterruptTransfer.TransferBufferLength)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Check if there is a MDL
|
||||||
|
//
|
||||||
|
if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// sanity check
|
||||||
|
//
|
||||||
|
PC_ASSERT(Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create one using TransferBuffer
|
||||||
|
//
|
||||||
|
DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", Urb->UrbBulkOrInterruptTransfer.TransferBuffer, Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
|
||||||
|
m_TransferBufferMDL = IoAllocateMdl(Urb->UrbBulkOrInterruptTransfer.TransferBuffer,
|
||||||
|
Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
|
||||||
|
FALSE,
|
||||||
|
FALSE,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!m_TransferBufferMDL)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// failed to allocate mdl
|
||||||
|
//
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// build mdl for non paged pool
|
||||||
|
// FIXME: Does hub driver already do this when passing MDL?
|
||||||
|
//
|
||||||
|
MmBuildMdlForNonPagedPool(m_TransferBufferMDL);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Keep that ehci created the MDL and needs to free it.
|
||||||
|
//
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_TransferBufferMDL = Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// save buffer length
|
||||||
|
//
|
||||||
|
m_TransferBufferLength = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Set Length Completed to 0
|
||||||
|
//
|
||||||
|
m_TransferBufferLengthCompleted = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// get endpoint descriptor
|
||||||
|
//
|
||||||
|
m_EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbBulkOrInterruptTransfer.PipeHandle;
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
DPRINT1("URB Function: not supported %x\n", Urb->UrbHeader.Function);
|
||||||
|
PC_ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// done
|
||||||
|
//
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
BOOLEAN
|
||||||
|
CUSBRequest::IsRequestComplete()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// FIXME: check if request was split
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check if the transfer was completed, only valid for Bulk Transfers
|
||||||
|
//
|
||||||
|
if ((m_TransferBufferLengthCompleted < m_TransferBufferLength)
|
||||||
|
&& (GetTransferType() == USB_ENDPOINT_TYPE_BULK))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Transfer not completed
|
||||||
|
//
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
ULONG
|
||||||
|
CUSBRequest::GetTransferType()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// call internal implementation
|
||||||
|
//
|
||||||
|
return InternalGetTransferType();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
ULONG
|
||||||
|
CUSBRequest::InternalGetTransferType()
|
||||||
|
{
|
||||||
|
ULONG TransferType;
|
||||||
|
|
||||||
|
//
|
||||||
|
// check if an irp is provided
|
||||||
|
//
|
||||||
|
if (m_Irp)
|
||||||
|
{
|
||||||
|
ASSERT(m_EndpointDescriptor);
|
||||||
|
|
||||||
|
//
|
||||||
|
// end point is defined in the low byte of bmAttributes
|
||||||
|
//
|
||||||
|
TransferType = (m_EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// initialized with setup packet, must be a control transfer
|
||||||
|
//
|
||||||
|
TransferType = USB_ENDPOINT_TYPE_CONTROL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// done
|
||||||
|
//
|
||||||
|
return TransferType;
|
||||||
|
}
|
||||||
|
|
||||||
|
UCHAR
|
||||||
|
CUSBRequest::InternalGetPidDirection()
|
||||||
|
{
|
||||||
|
ASSERT(m_Irp);
|
||||||
|
ASSERT(m_EndpointDescriptor);
|
||||||
|
|
||||||
|
//
|
||||||
|
// end point is defined in the low byte of bEndpointAddress
|
||||||
|
//
|
||||||
|
return (m_EndpointDescriptor->bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK) >> 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
UCHAR
|
||||||
|
CUSBRequest::GetDeviceAddress()
|
||||||
|
{
|
||||||
|
PIO_STACK_LOCATION IoStack;
|
||||||
|
PURB Urb;
|
||||||
|
PUSBDEVICE UsbDevice;
|
||||||
|
|
||||||
|
//
|
||||||
|
// check if there is an irp provided
|
||||||
|
//
|
||||||
|
if (!m_Irp)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// used provided address
|
||||||
|
//
|
||||||
|
return m_DeviceAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// get current stack location
|
||||||
|
//
|
||||||
|
IoStack = IoGetCurrentIrpStackLocation(m_Irp);
|
||||||
|
|
||||||
|
//
|
||||||
|
// get contained urb
|
||||||
|
//
|
||||||
|
Urb = (PURB)IoStack->Parameters.Others.Argument1;
|
||||||
|
|
||||||
|
//
|
||||||
|
// check if there is a pipe handle provided
|
||||||
|
//
|
||||||
|
if (Urb->UrbHeader.UsbdDeviceHandle)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// there is a device handle provided
|
||||||
|
//
|
||||||
|
UsbDevice = (PUSBDEVICE)Urb->UrbHeader.UsbdDeviceHandle;
|
||||||
|
|
||||||
|
//
|
||||||
|
// return device address
|
||||||
|
//
|
||||||
|
return UsbDevice->GetDeviceAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// no device handle provided, it is the host root bus
|
||||||
|
//
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
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::IsQueueHeadComplete(
|
||||||
|
struct _QUEUE_HEAD * QueueHead)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
NTSTATUS
|
||||||
|
InternalCreateUSBRequest(
|
||||||
|
PUSBREQUEST *OutRequest)
|
||||||
|
{
|
||||||
|
PUSBREQUEST This;
|
||||||
|
|
||||||
|
//
|
||||||
|
// allocate requests
|
||||||
|
//
|
||||||
|
This = new(NonPagedPool, TAG_USBOHCI) 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;
|
||||||
|
}
|
144
drivers/usb/usbohci/usbohci.cpp
Normal file
144
drivers/usb/usbohci/usbohci.cpp
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
|
||||||
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
|
* FILE: drivers/usb/usbohci/usbohci.cpp
|
||||||
|
* PURPOSE: USB OHCI device driver.
|
||||||
|
* PROGRAMMERS:
|
||||||
|
* Michael Martin (michael.martin@reactos.org)
|
||||||
|
* Johannes Anderwald (johannes.anderwald@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "usbohci.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// driver verifier
|
||||||
|
//
|
||||||
|
DRIVER_ADD_DEVICE OHCI_AddDevice;
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
OHCI_AddDevice(
|
||||||
|
PDRIVER_OBJECT DriverObject,
|
||||||
|
PDEVICE_OBJECT PhysicalDeviceObject)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
PHCDCONTROLLER HcdController;
|
||||||
|
|
||||||
|
DPRINT1("OHCI_AddDevice\n");
|
||||||
|
|
||||||
|
/* first create the controller object */
|
||||||
|
Status = CreateHCDController(&HcdController);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* failed to create hcd */
|
||||||
|
DPRINT1("AddDevice: Failed to create hcd with %x\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize the hcd */
|
||||||
|
Status = HcdController->Initialize(NULL, // FIXME
|
||||||
|
DriverObject,
|
||||||
|
PhysicalDeviceObject);
|
||||||
|
|
||||||
|
/* check for success */
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* failed to initialize device */
|
||||||
|
DPRINT1("AddDevice: failed to initialize\n");
|
||||||
|
|
||||||
|
/* release object */
|
||||||
|
HcdController->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
OHCI_Dispatch(
|
||||||
|
PDEVICE_OBJECT DeviceObject,
|
||||||
|
PIRP Irp)
|
||||||
|
{
|
||||||
|
PCOMMON_DEVICE_EXTENSION DeviceExtension;
|
||||||
|
PIO_STACK_LOCATION IoStack;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
//
|
||||||
|
// get common device extension
|
||||||
|
//
|
||||||
|
DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||||
|
|
||||||
|
//
|
||||||
|
// get current stack location
|
||||||
|
//
|
||||||
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||||
|
|
||||||
|
//
|
||||||
|
// sanity checks
|
||||||
|
//
|
||||||
|
PC_ASSERT(DeviceExtension->Dispatcher);
|
||||||
|
|
||||||
|
switch(IoStack->MajorFunction)
|
||||||
|
{
|
||||||
|
case IRP_MJ_PNP:
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// dispatch pnp
|
||||||
|
//
|
||||||
|
return DeviceExtension->Dispatcher->HandlePnp(DeviceObject, Irp);
|
||||||
|
}
|
||||||
|
|
||||||
|
case IRP_MJ_POWER:
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// dispatch pnp
|
||||||
|
//
|
||||||
|
return DeviceExtension->Dispatcher->HandlePower(DeviceObject, Irp);
|
||||||
|
}
|
||||||
|
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
|
||||||
|
case IRP_MJ_DEVICE_CONTROL:
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// dispatch pnp
|
||||||
|
//
|
||||||
|
return DeviceExtension->Dispatcher->HandleDeviceControl(DeviceObject, Irp);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
DPRINT1("OHCI_Dispatch> Major %lu Minor %lu unhandeled\n", IoStack->MajorFunction, IoStack->MinorFunction);
|
||||||
|
Status = STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// complete request
|
||||||
|
//
|
||||||
|
Irp->IoStatus.Information = 0;
|
||||||
|
Irp->IoStatus.Status = Status;
|
||||||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern
|
||||||
|
"C"
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
DriverEntry(
|
||||||
|
PDRIVER_OBJECT DriverObject,
|
||||||
|
PUNICODE_STRING RegistryPath)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* initialize driver object*/
|
||||||
|
DriverObject->DriverExtension->AddDevice = OHCI_AddDevice;
|
||||||
|
|
||||||
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = OHCI_Dispatch;
|
||||||
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = OHCI_Dispatch;
|
||||||
|
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = OHCI_Dispatch;
|
||||||
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = OHCI_Dispatch;
|
||||||
|
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = OHCI_Dispatch;
|
||||||
|
DriverObject->MajorFunction[IRP_MJ_PNP] = OHCI_Dispatch;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
103
drivers/usb/usbohci/usbohci.h
Normal file
103
drivers/usb/usbohci/usbohci.h
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
#ifndef USBOHCI_H__
|
||||||
|
#define USBOHCI_H__
|
||||||
|
|
||||||
|
#include <ntddk.h>
|
||||||
|
#define NDEBUG
|
||||||
|
#include <debug.h>
|
||||||
|
#include <hubbusif.h>
|
||||||
|
#include <usbbusif.h>
|
||||||
|
#include <usbioctl.h>
|
||||||
|
//
|
||||||
|
// FIXME:
|
||||||
|
// #include <usbprotocoldefs.h>
|
||||||
|
//
|
||||||
|
#include <usb.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <wdmguid.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// FIXME:
|
||||||
|
// the following includes are required to get kcom to compile
|
||||||
|
//
|
||||||
|
#include <portcls.h>
|
||||||
|
#include <dmusicks.h>
|
||||||
|
#include <kcom.h>
|
||||||
|
|
||||||
|
#include "interfaces.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// flags for handling USB_REQUEST_SET_FEATURE / USB_REQUEST_GET_FEATURE
|
||||||
|
//
|
||||||
|
#define PORT_ENABLE 1
|
||||||
|
#define PORT_SUSPEND 2
|
||||||
|
#define PORT_OVER_CURRENT 3
|
||||||
|
#define PORT_RESET 4
|
||||||
|
#define PORT_POWER 8
|
||||||
|
#define C_PORT_CONNECTION 16
|
||||||
|
#define C_PORT_ENABLE 17
|
||||||
|
#define C_PORT_SUSPEND 18
|
||||||
|
#define C_PORT_OVER_CURRENT 19
|
||||||
|
#define C_PORT_RESET 20
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
BOOLEAN IsFDO; // is device a FDO or PDO
|
||||||
|
BOOLEAN IsHub; // is device a hub / child - not yet used
|
||||||
|
PDISPATCHIRP Dispatcher; // dispatches the code
|
||||||
|
}COMMON_DEVICE_EXTENSION, *PCOMMON_DEVICE_EXTENSION;
|
||||||
|
|
||||||
|
//
|
||||||
|
// tag for allocations
|
||||||
|
//
|
||||||
|
#define TAG_USBOHCI 'ICHE'
|
||||||
|
|
||||||
|
//
|
||||||
|
// assert for c++ - taken from portcls
|
||||||
|
//
|
||||||
|
#define PC_ASSERT(exp) \
|
||||||
|
(VOID)((!(exp)) ? \
|
||||||
|
RtlAssert((PVOID) #exp, (PVOID)__FILE__, __LINE__, NULL ), FALSE : TRUE)
|
||||||
|
|
||||||
|
//
|
||||||
|
// hcd_controller.cpp
|
||||||
|
//
|
||||||
|
NTSTATUS CreateHCDController(PHCDCONTROLLER *HcdController);
|
||||||
|
|
||||||
|
//
|
||||||
|
// hardware.cpp
|
||||||
|
//
|
||||||
|
NTSTATUS CreateUSBHardware(PUSBHARDWAREDEVICE *OutHardware);
|
||||||
|
|
||||||
|
//
|
||||||
|
// misc.cpp
|
||||||
|
//
|
||||||
|
NTSTATUS NTAPI SyncForwardIrp(PDEVICE_OBJECT DeviceObject, PIRP Irp);
|
||||||
|
NTSTATUS NTAPI GetBusInterface(PDEVICE_OBJECT DeviceObject, PBUS_INTERFACE_STANDARD busInterface);
|
||||||
|
|
||||||
|
//
|
||||||
|
// root_hub_controller.cpp
|
||||||
|
//
|
||||||
|
NTSTATUS CreateHubController(PHUBCONTROLLER * OutHubController);
|
||||||
|
|
||||||
|
//
|
||||||
|
// memory_manager.cpp
|
||||||
|
//
|
||||||
|
NTSTATUS CreateDMAMemoryManager(PDMAMEMORYMANAGER *OutMemoryManager);
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// usb_device.cpp
|
||||||
|
//
|
||||||
|
NTSTATUS CreateUSBDevice(PUSBDEVICE *OutDevice);
|
||||||
|
|
||||||
|
//
|
||||||
|
// usb_queue.cpp
|
||||||
|
//
|
||||||
|
NTSTATUS CreateUSBQueue(PUSBQUEUE *OutUsbQueue);
|
||||||
|
|
||||||
|
//
|
||||||
|
// usb_request.cpp
|
||||||
|
//
|
||||||
|
NTSTATUS InternalCreateUSBRequest(PUSBREQUEST *OutRequest);
|
||||||
|
|
||||||
|
#endif
|
5
drivers/usb/usbohci/usbohci.rc
Normal file
5
drivers/usb/usbohci/usbohci.rc
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#define REACTOS_VERSION_DLL
|
||||||
|
#define REACTOS_STR_FILE_DESCRIPTION "USBOHCI Driver API\0"
|
||||||
|
#define REACTOS_STR_INTERNAL_NAME "usbohci\0"
|
||||||
|
#define REACTOS_STR_ORIGINAL_FILENAME "usbohci.sys\0"
|
||||||
|
#include <reactos/version.rc>
|
Loading…
Add table
Add a link
Reference in a new issue