diff --git a/drivers/usb/usbohci/CMakeLists.txt b/drivers/usb/usbohci/CMakeLists.txt new file mode 100644 index 00000000000..74fa494af22 --- /dev/null +++ b/drivers/usb/usbohci/CMakeLists.txt @@ -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) \ No newline at end of file diff --git a/drivers/usb/usbohci/hardware.cpp b/drivers/usb/usbohci/hardware.cpp new file mode 100644 index 00000000000..40536afc5c9 --- /dev/null +++ b/drivers/usb/usbohci/hardware.cpp @@ -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; +} diff --git a/drivers/usb/usbohci/hardware.h b/drivers/usb/usbohci/hardware.h new file mode 100644 index 00000000000..726ee3832de --- /dev/null +++ b/drivers/usb/usbohci/hardware.h @@ -0,0 +1,213 @@ +#pragma once + +#include + +// +// 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 \ No newline at end of file diff --git a/drivers/usb/usbohci/hcd_controller.cpp b/drivers/usb/usbohci/hcd_controller.cpp new file mode 100644 index 00000000000..e5a28151984 --- /dev/null +++ b/drivers/usb/usbohci/hcd_controller.cpp @@ -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; +} diff --git a/drivers/usb/usbohci/hub_controller.cpp b/drivers/usb/usbohci/hub_controller.cpp new file mode 100644 index 00000000000..fbd009cbbf9 --- /dev/null +++ b/drivers/usb/usbohci/hub_controller.cpp @@ -0,0 +1,3193 @@ +/* + * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface + * LICENSE: GPL - See COPYING in the top level directory + * FILE: drivers/usb/usbohci/hub_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" + +VOID StatusChangeEndpointCallBack( + PVOID Context); + +class CHubController : public IHubController, + 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; + } + + // IHubController interface functions + virtual NTSTATUS Initialize(IN PDRIVER_OBJECT DriverObject, IN PHCDCONTROLLER Controller, IN PUSBHARDWAREDEVICE Device, IN BOOLEAN IsRootHubDevice, IN ULONG DeviceAddress); + virtual NTSTATUS GetHubControllerDeviceObject(PDEVICE_OBJECT * HubDeviceObject); + virtual NTSTATUS GetHubControllerSymbolicLink(ULONG BufferLength, PVOID Buffer, PULONG RequiredLength); + + // IDispatchIrp interface functions + virtual NTSTATUS HandlePnp(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp); + virtual NTSTATUS HandlePower(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp); + virtual NTSTATUS HandleDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp); + + // local functions + NTSTATUS HandleQueryInterface(PIO_STACK_LOCATION IoStack); + NTSTATUS SetDeviceInterface(BOOLEAN bEnable); + NTSTATUS CreatePDO(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT * OutDeviceObject); + PUSBHARDWAREDEVICE GetUsbHardware(); + ULONG AcquireDeviceAddress(); + VOID ReleaseDeviceAddress(ULONG DeviceAddress); + BOOLEAN ValidateUsbDevice(PUSBDEVICE UsbDevice); + NTSTATUS AddUsbDevice(PUSBDEVICE UsbDevice); + NTSTATUS RemoveUsbDevice(PUSBDEVICE UsbDevice); + VOID SetNotification(PVOID CallbackContext, PRH_INIT_CALLBACK CallbackRoutine); + // internal ioctl routines + NTSTATUS HandleGetDescriptor(IN OUT PIRP Irp, PURB Urb); + NTSTATUS HandleClassDevice(IN OUT PIRP Irp, PURB Urb); + NTSTATUS HandleGetStatusFromDevice(IN OUT PIRP Irp, PURB Urb); + NTSTATUS HandleSelectConfiguration(IN OUT PIRP Irp, PURB Urb); + NTSTATUS HandleSelectInterface(IN OUT PIRP Irp, PURB Urb); + NTSTATUS HandleClassOther(IN OUT PIRP Irp, PURB Urb); + NTSTATUS HandleClassInterface(IN OUT PIRP Irp, PURB Urb); + NTSTATUS HandleBulkOrInterruptTransfer(IN OUT PIRP Irp, PURB Urb); + + friend VOID StatusChangeEndpointCallBack(PVOID Context); + + // constructor / destructor + CHubController(IUnknown *OuterUnknown){} + virtual ~CHubController(){} + +protected: + LONG m_Ref; + PHCDCONTROLLER m_Controller; + PUSBHARDWAREDEVICE m_Hardware; + BOOLEAN m_IsRootHubDevice; + ULONG m_DeviceAddress; + + BOOLEAN m_InterfaceEnabled; + UNICODE_STRING m_HubDeviceInterfaceString; + + PDEVICE_OBJECT m_HubControllerDeviceObject; + PDRIVER_OBJECT m_DriverObject; + + PVOID m_HubCallbackContext; + PRH_INIT_CALLBACK m_HubCallbackRoutine; + + USB_DEVICE_DESCRIPTOR m_DeviceDescriptor; + + KSPIN_LOCK m_Lock; + RTL_BITMAP m_DeviceAddressBitmap; + PULONG m_DeviceAddressBitmapBuffer; + LIST_ENTRY m_UsbDeviceList; + PIRP m_PendingSCEIrp; + + //Internal Functions + BOOLEAN QueryStatusChageEndpoint(PIRP Irp); +}; + +typedef struct +{ + LIST_ENTRY Entry; + PUSBDEVICE Device; +}USBDEVICE_ENTRY, *PUSBDEVICE_ENTRY; + +/* Lifted from Linux with slight changes */ +const UCHAR ROOTHUB2_DEVICE_DESCRIPTOR [] = +{ + 0x12, /* bLength; */ + USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType; Device */ + 0x00, 0x20, /* bcdUSB; v1.1 */ + USB_DEVICE_CLASS_HUB, /* bDeviceClass; HUB_CLASSCODE */ + 0x01, /* bDeviceSubClass; */ + 0x00, /* bDeviceProtocol; [ low/full speeds only ] */ + 0x08, /* bMaxPacketSize0; 8 Bytes */ + /* Fill Vendor and Product in when init root hub */ + 0x00, 0x00, /* idVendor; */ + 0x00, 0x00, /* idProduct; */ + 0x00, 0x00, /* bcdDevice */ + 0x00, /* iManufacturer; */ + 0x00, /* iProduct; */ + 0x00, /* iSerialNumber; */ + 0x01 /* bNumConfigurations; */ + +}; + +const USB_CONFIGURATION_DESCRIPTOR ROOTHUB2_CONFIGURATION_DESCRIPTOR = +{ + sizeof(USB_CONFIGURATION_DESCRIPTOR), + USB_CONFIGURATION_DESCRIPTOR_TYPE, + sizeof(USB_CONFIGURATION_DESCRIPTOR) + sizeof(USB_INTERFACE_DESCRIPTOR) + sizeof(USB_ENDPOINT_DESCRIPTOR), + 1, + 1, + 0, + 0x40, /* self powered */ + 0x0 +}; + +const USB_INTERFACE_DESCRIPTOR ROOTHUB2_INTERFACE_DESCRIPTOR = +{ + sizeof(USB_INTERFACE_DESCRIPTOR), /* bLength */ + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType; Interface */ + 0, /* bInterfaceNumber; */ + 0, /* bAlternateSetting; */ + 0x1, /* bNumEndpoints; */ + 0x09, /* bInterfaceClass; HUB_CLASSCODE */ + 0x01, /* bInterfaceSubClass; */ + 0x00, /* bInterfaceProtocol: */ + 0x00, /* iInterface; */ +}; + +const USB_ENDPOINT_DESCRIPTOR ROOTHUB2_ENDPOINT_DESCRIPTOR = +{ + sizeof(USB_ENDPOINT_DESCRIPTOR), /* bLength */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ + 0x81, /* bEndPointAddress */ + USB_ENDPOINT_TYPE_INTERRUPT, /* bmAttributes */ + 0x01, /* wMaxPacketSize */ + 0xC /* bInterval */ +}; + +//---------------------------------------------------------------------------------------- +NTSTATUS +STDMETHODCALLTYPE +CHubController::QueryInterface( + IN REFIID refiid, + OUT PVOID* Output) +{ + return STATUS_UNSUCCESSFUL; +} +//---------------------------------------------------------------------------------------- +NTSTATUS +CHubController::Initialize( + IN PDRIVER_OBJECT DriverObject, + IN PHCDCONTROLLER Controller, + IN PUSBHARDWAREDEVICE Device, + IN BOOLEAN IsRootHubDevice, + IN ULONG DeviceAddress) +{ + NTSTATUS Status; + PCOMMON_DEVICE_EXTENSION DeviceExtension; + USHORT VendorID, DeviceID; + ULONG Dummy1; + + DPRINT1("CHubController::Initialize\n"); + + // + // initialize members + // + m_Controller = Controller; + m_Hardware = Device; + m_IsRootHubDevice = IsRootHubDevice; + m_DeviceAddress = DeviceAddress; + m_DriverObject = DriverObject; + KeInitializeSpinLock(&m_Lock); + InitializeListHead(&m_UsbDeviceList); + + // + // allocate device address bitmap buffer + // + m_DeviceAddressBitmapBuffer = (PULONG)ExAllocatePoolWithTag(NonPagedPool, 16, TAG_USBOHCI); + if (!m_DeviceAddressBitmapBuffer) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // initialize device address bitmap + // + RtlInitializeBitMap(&m_DeviceAddressBitmap, m_DeviceAddressBitmapBuffer, 128); + RtlClearAllBits(&m_DeviceAddressBitmap); + + + // + // create PDO + // + Status = CreatePDO(m_DriverObject, &m_HubControllerDeviceObject); + if (!NT_SUCCESS(Status)) + { + // + // failed to create hub device object + // + return Status; + } + + // + // get device extension + // + DeviceExtension = (PCOMMON_DEVICE_EXTENSION)m_HubControllerDeviceObject->DeviceExtension; + + // + // initialize device extension + // + DeviceExtension->IsFDO = FALSE; + DeviceExtension->IsHub = TRUE; //FIXME + DeviceExtension->Dispatcher = PDISPATCHIRP(this); + + // + // intialize device descriptor + // + C_ASSERT(sizeof(USB_DEVICE_DESCRIPTOR) == sizeof(ROOTHUB2_DEVICE_DESCRIPTOR)); + RtlMoveMemory(&m_DeviceDescriptor, ROOTHUB2_DEVICE_DESCRIPTOR, sizeof(USB_DEVICE_DESCRIPTOR)); + + if (NT_SUCCESS(m_Hardware->GetDeviceDetails(&VendorID, &DeviceID, &Dummy1, &Dummy1))) + { + // + // update device descriptor + // + m_DeviceDescriptor.idVendor = VendorID; + m_DeviceDescriptor.idProduct = DeviceID; + m_DeviceDescriptor.bcdUSB = 0x110; //FIXME + } + + // + // Set the SCE Callback that the Hardware Device will call on port status change + // + Device->SetStatusChangeEndpointCallBack((PVOID)StatusChangeEndpointCallBack, this); + + // + // clear init flag + // + m_HubControllerDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + return STATUS_SUCCESS; +} + +// +// Queries the ports to see if there has been a device connected or removed. +// +BOOLEAN +CHubController::QueryStatusChageEndpoint( + PIRP Irp) +{ + ULONG PortCount, PortId; + PIO_STACK_LOCATION IoStack; + USHORT PortStatus, PortChange; + PURB Urb; + PUCHAR TransferBuffer; + UCHAR Changed = FALSE; + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + ASSERT(IoStack); + + // + // Get the Urb + // + Urb = (PURB)IoStack->Parameters.Others.Argument1; + ASSERT(Urb); + + // + // Get the number of ports and check each one for device connected + // + m_Hardware->GetDeviceDetails(NULL, NULL, &PortCount, NULL); + DPRINT1("SCE Request %p TransferBufferLength %lu Flags %x MDL %p\n", Urb->UrbBulkOrInterruptTransfer.TransferBuffer, Urb->UrbBulkOrInterruptTransfer.TransferBufferLength, Urb->UrbBulkOrInterruptTransfer.TransferFlags, Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL); + + TransferBuffer = (PUCHAR)Urb->UrbBulkOrInterruptTransfer.TransferBuffer; + + // + // Loop the ports + // + for (PortId = 0; PortId < PortCount; PortId++) + { + m_Hardware->GetPortStatus(PortId, &PortStatus, &PortChange); + + DPRINT1("Port %d: Status %x, Change %x\n", PortId, PortStatus, PortChange); + + + // + // If theres a flag in PortChange return TRUE so the SCE Irp will be completed + // + if (PortChange != 0) + { + DPRINT1("Change state on port %d\n", PortId); + // Set the value for the port number + *TransferBuffer = 1 << ((PortId + 1) & 7); + Changed = TRUE; + } + } + + return Changed; +} + +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::GetHubControllerDeviceObject(PDEVICE_OBJECT * HubDeviceObject) +{ + // + // store controller object + // + *HubDeviceObject = m_HubControllerDeviceObject; + + return STATUS_SUCCESS; +} +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::GetHubControllerSymbolicLink( + ULONG BufferLength, + PVOID Buffer, + PULONG RequiredLength) +{ + if (!m_InterfaceEnabled) + { + // + // device interface not yet enabled + // + return STATUS_UNSUCCESSFUL; + } + + if (BufferLength < (ULONG)m_HubDeviceInterfaceString.Length - 8) + { + // + // buffer too small + // length is without '\??\' + // + *RequiredLength = m_HubDeviceInterfaceString.Length- 8; + + // + // done + // + return STATUS_BUFFER_OVERFLOW; + } + + // + // copy symbolic link + // + RtlCopyMemory(Buffer, &m_HubDeviceInterfaceString.Buffer[4], m_HubDeviceInterfaceString.Length - 8); + + // + // store length, length is without '\??\' + // + *RequiredLength = m_HubDeviceInterfaceString.Length - 8; + + // + // done + // + return STATUS_SUCCESS; +} + +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::HandlePnp( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + PCOMMON_DEVICE_EXTENSION DeviceExtension; + PDEVICE_CAPABILITIES DeviceCapabilities; + PPNP_BUS_INFORMATION BusInformation; + PDEVICE_RELATIONS DeviceRelations; + NTSTATUS Status; + ULONG Index = 0, Length; + USHORT VendorID, DeviceID; + ULONG HiSpeed, NumPorts; + WCHAR Buffer[300]; + LPWSTR DeviceName; + + // + // get device extension + // + DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // sanity check + // + ASSERT(DeviceExtension->IsFDO == FALSE); + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + switch(IoStack->MinorFunction) + { + case IRP_MN_START_DEVICE: + { + DPRINT1("CHubController::HandlePnp IRP_MN_START_DEVICE\n"); + // + // register device interface + // + Status = SetDeviceInterface(TRUE); + break; + } + case IRP_MN_QUERY_ID: + { + DPRINT1("CHubController::HandlePnp IRP_MN_QUERY_ID Type %x\n", IoStack->Parameters.QueryId.IdType); + + if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID) + { + if (m_Hardware) + { + // + // query device id + // + Status = m_Hardware->GetDeviceDetails(&VendorID, &DeviceID, &NumPorts, &HiSpeed); + + if (HiSpeed == 0x200) + { + // + // USB 2.0 hub + // + swprintf(Buffer, L"USB\\ROOT_HUB20"); + } + else + { + // + // USB 1.1 hub + // + swprintf(Buffer, L"USB\\ROOT_HUB"); + } + + DPRINT1("Name %S\n", Buffer); + + // + // calculate length + // + Length = (wcslen(Buffer) + 1); + + // + // allocate buffer + // + DeviceName = (LPWSTR)ExAllocatePoolWithTag(PagedPool, Length * sizeof(WCHAR), TAG_USBOHCI); + + if (!DeviceName) + { + // + // no memory + // + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + // + // copy device name + // + wcscpy(DeviceName, Buffer); + + // + // store result + // + Irp->IoStatus.Information = (ULONG_PTR)DeviceName; + Status = STATUS_SUCCESS; + break; + } + Status = STATUS_UNSUCCESSFUL; + PC_ASSERT(0); + break; + } + + if (IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs) + { + if (m_Hardware) + { + // + // query device id + // + Status = m_Hardware->GetDeviceDetails(&VendorID, &DeviceID, &NumPorts, &HiSpeed); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("CHubController::HandlePnp> failed to get hardware id %x\n", Status); + VendorID = 0x8086; + DeviceID = 0x3A37; + } + + if (HiSpeed == 0x200) + { + // + // USB 2.0 hub + // + Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB20&VID%04x&PID%04x&REV0000", VendorID, DeviceID) + 1; + Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB20&VID%04x&PID%04x", VendorID, DeviceID) + 1; + Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB20") + 1; + } + else + { + // + // USB 1.1 hub + // + Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB&VID%04x&PID%04x&REV0000", VendorID, DeviceID) + 1; + Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB&VID%04x&PID%04x", VendorID, DeviceID) + 1; + Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB") + 1; + } + + Buffer[Index] = UNICODE_NULL; + Index++; + + + DPRINT1("Name %S\n", Buffer); + + // + // allocate buffer + // + DeviceName = (LPWSTR)ExAllocatePoolWithTag(PagedPool, Index * sizeof(WCHAR), TAG_USBOHCI); + + if (!DeviceName) + { + // + // no memory + // + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + // + // copy device name + // + RtlMoveMemory(DeviceName, Buffer, Index * sizeof(WCHAR)); + + // + // store result + // + Irp->IoStatus.Information = (ULONG_PTR)DeviceName; + Status = STATUS_SUCCESS; + break; + } + } + Status = STATUS_SUCCESS; + break; + } + case IRP_MN_QUERY_CAPABILITIES: + { + DPRINT1("CHubController::HandlePnp IRP_MN_QUERY_CAPABILITIES\n"); + + DeviceCapabilities = (PDEVICE_CAPABILITIES)IoStack->Parameters.DeviceCapabilities.Capabilities; + + DeviceCapabilities->LockSupported = FALSE; + DeviceCapabilities->EjectSupported = FALSE; + DeviceCapabilities->Removable = FALSE; + DeviceCapabilities->DockDevice = FALSE; + DeviceCapabilities->UniqueID = FALSE; + DeviceCapabilities->SilentInstall = FALSE; + DeviceCapabilities->RawDeviceOK = FALSE; + DeviceCapabilities->SurpriseRemovalOK = FALSE; + DeviceCapabilities->Address = 0; + DeviceCapabilities->UINumber = 0; + DeviceCapabilities->DeviceD2 = 1; + + /* FIXME */ + DeviceCapabilities->HardwareDisabled = FALSE; + DeviceCapabilities->NoDisplayInUI = FALSE; + DeviceCapabilities->DeviceState[0] = PowerDeviceD0; + for (Index = 0; Index < PowerSystemMaximum; Index++) + DeviceCapabilities->DeviceState[Index] = PowerDeviceD3; + DeviceCapabilities->DeviceWake = PowerDeviceUnspecified; + DeviceCapabilities->D1Latency = 0; + DeviceCapabilities->D2Latency = 0; + DeviceCapabilities->D3Latency = 0; + + Status = STATUS_SUCCESS; + break; + } + case IRP_MN_QUERY_INTERFACE: + { + DPRINT1("CHubController::HandlePnp IRP_MN_QUERY_INTERFACE\n"); + + // + // handle device interface requests + // + Status = HandleQueryInterface(IoStack); + break; + } + case IRP_MN_REMOVE_DEVICE: + { + DPRINT1("CHubController::HandlePnp IRP_MN_REMOVE_DEVICE\n"); + + // + // deactivate device interface for BUS PDO + // + SetDeviceInterface(FALSE); + + // + // complete the request first + // + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + // + // now delete device + // + IoDeleteDevice(m_HubControllerDeviceObject); + + // + // nullify pointer + // + m_HubControllerDeviceObject = 0; + + // + // done + // + return STATUS_SUCCESS; + } + case IRP_MN_QUERY_DEVICE_RELATIONS: + { + DPRINT1("CHubController::HandlePnp IRP_MN_QUERY_DEVICE_RELATIONS Type %x\n", IoStack->Parameters.QueryDeviceRelations.Type); + + if (IoStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation) + { + // + // allocate device relations + // + DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(PagedPool, sizeof(DEVICE_RELATIONS), TAG_USBOHCI); + if (!DeviceRelations) + { + // + // no memory + // + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + // + // initialize device relations + // + DeviceRelations->Count = 1; + DeviceRelations->Objects[0] = DeviceObject; + ObReferenceObject(DeviceObject); + + // + // done + // + Status = STATUS_SUCCESS; + Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; + } + else + { + // + // not handled + // + Status = Irp->IoStatus.Status; + } + break; + } + case IRP_MN_QUERY_BUS_INFORMATION: + { + DPRINT1("CHubController::HandlePnp IRP_MN_QUERY_BUS_INFORMATION\n"); + + // + // allocate buffer for bus information + // + BusInformation = (PPNP_BUS_INFORMATION)ExAllocatePool(PagedPool, sizeof(PNP_BUS_INFORMATION)); + if (BusInformation) + { + // + // copy BUS guid + // + RtlMoveMemory(&BusInformation->BusTypeGuid, &GUID_BUS_TYPE_USB, sizeof(GUID)); + + // + // set bus type + // + BusInformation->LegacyBusType = PNPBus; + BusInformation->BusNumber = 0; + + Status = STATUS_SUCCESS; + Irp->IoStatus.Information = (ULONG_PTR)BusInformation; + } + else + { + // + // no memory + // + Status = STATUS_INSUFFICIENT_RESOURCES; + } + break; + } + case IRP_MN_STOP_DEVICE: + { + DPRINT1("CHubController::HandlePnp IRP_MN_STOP_DEVICE\n"); + // + // stop device + // + Status = STATUS_SUCCESS; + break; + } + default: + { + // + // ignore request with default status + // + Status = Irp->IoStatus.Status; + break; + } + } + + // + // complete request + // + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + // + // done + // + return Status; +} + +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::HandlePower( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp) +{ + UNIMPLEMENTED + Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NOT_IMPLEMENTED; +} +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::HandleBulkOrInterruptTransfer( + IN OUT PIRP Irp, + PURB Urb) +{ + PUSBDEVICE UsbDevice; + PUSB_ENDPOINT_DESCRIPTOR EndPointDesc = NULL; + // + // First check if the request is for the Status Change Endpoint + // + + // + // Is the Request for the root hub + // + if (Urb->UrbHeader.UsbdDeviceHandle == 0) + { + ASSERT(m_PendingSCEIrp == NULL); + if (QueryStatusChageEndpoint(Irp)) + { + StatusChangeEndpointCallBack(this); + return STATUS_SUCCESS; + } + + // + // Else pend the IRP, to be completed when a device connects or disconnects. + // + DPRINT1("Pending SCE Irp\n");; + m_PendingSCEIrp = Irp; + IoMarkIrpPending(Irp); + return STATUS_PENDING; + } + + // + // Check PipeHandle to determine if this is a Bulk or Interrupt Transfer Request + // + EndPointDesc = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbBulkOrInterruptTransfer.PipeHandle; + + switch(EndPointDesc->bmAttributes & 0x0F) + { + case USB_ENDPOINT_TYPE_CONTROL: + DPRINT1("Control Transfer is not expected!!!\n"); + return STATUS_INVALID_DEVICE_REQUEST; + case USB_ENDPOINT_TYPE_BULK: + DPRINT("Initiating Bulk Transfer\n"); + break; + case USB_ENDPOINT_TYPE_ISOCHRONOUS: + case USB_ENDPOINT_TYPE_INTERRUPT: + DPRINT1("Not Supported\n"); + break; + default: + DPRINT1("Unknown EndPoint Type!\n"); + break; + } + + // + // check if this is a valid usb device handle + // + PC_ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))); + + // + // get device + // + UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); + + return UsbDevice->SubmitIrp(Irp); +} + +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::HandleClassOther( + IN OUT PIRP Irp, + PURB Urb) +{ + NTSTATUS Status = STATUS_NOT_IMPLEMENTED; + USHORT PortStatus = 0, PortChange = 0; + PUSHORT Buffer; + ULONG NumPort; + ULONG PortId; + + DPRINT("CHubController::HandleClassOther> Request %x Value %x\n", Urb->UrbControlVendorClassRequest.Request, Urb->UrbControlVendorClassRequest.Value); + + // + // get number of ports available + // + Status = m_Hardware->GetDeviceDetails(NULL, NULL, &NumPort, NULL); + PC_ASSERT(Status == STATUS_SUCCESS); + + // + // sanity check + // + PC_ASSERT(Urb->UrbControlVendorClassRequest.Index - 1 < (USHORT)NumPort); + + // + // port range reported start from 1 -n + // convert back port id so it matches the hardware + // + PortId = Urb->UrbControlVendorClassRequest.Index - 1; + + // + // check request code + // + switch(Urb->UrbControlVendorClassRequest.Request) + { + case USB_REQUEST_GET_STATUS: + { + // + // sanity check + // + PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBufferLength == sizeof(USHORT) * 2); + PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBuffer); + + // + // get port status + // + Status = m_Hardware->GetPortStatus(PortId, &PortStatus, &PortChange); + + if (NT_SUCCESS(Status)) + { + // + // request contains buffer of 2 ushort which are used from submitting port status and port change status + // + DPRINT("PortId %x PortStatus %x PortChange %x\n", PortId, PortStatus, PortChange); + Buffer = (PUSHORT)Urb->UrbControlVendorClassRequest.TransferBuffer; + + // + // store status, then port change + // + *Buffer = PortStatus; + Buffer++; + *Buffer = PortChange; + } + + // + // done + // + break; + } + case USB_REQUEST_CLEAR_FEATURE: + { + switch (Urb->UrbControlVendorClassRequest.Value) + { + case C_PORT_CONNECTION: + Status = m_Hardware->ClearPortStatus(PortId, C_PORT_CONNECTION); + break; + case C_PORT_RESET: + Status= m_Hardware->ClearPortStatus(PortId, C_PORT_RESET); + break; + default: + DPRINT("Unknown Value for Clear Feature %x \n", Urb->UrbControlVendorClassRequest.Value); + break; + } + + Status = STATUS_SUCCESS; + break; + } + case USB_REQUEST_SET_FEATURE: + { + // + // request set feature + // + switch(Urb->UrbControlVendorClassRequest.Value) + { + case PORT_ENABLE: + { + // + // port enable is a no-op for OHCI + // + Status = STATUS_SUCCESS; + break; + } + + case PORT_SUSPEND: + { + // + // set suspend port feature + // + Status = m_Hardware->SetPortFeature(PortId, PORT_SUSPEND); + break; + } + case PORT_POWER: + { + // + // set power feature on port + // + Status = m_Hardware->SetPortFeature(PortId, PORT_POWER); + break; + } + + case PORT_RESET: + { + // + // reset port feature + // + Status = m_Hardware->SetPortFeature(PortId, PORT_RESET); + PC_ASSERT(Status == STATUS_SUCCESS); + break; + } + default: + DPRINT1("Unsupported request id %x\n", Urb->UrbControlVendorClassRequest.Value); + PC_ASSERT(FALSE); + } + break; + } + default: + DPRINT1("CHubController::HandleClassOther Unknown request code %x\n", Urb->UrbControlVendorClassRequest.Request); + PC_ASSERT(0); + Status = STATUS_INVALID_DEVICE_REQUEST; + } + return Status; +} + +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::HandleSelectConfiguration( + IN OUT PIRP Irp, + PURB Urb) +{ + PUSBDEVICE UsbDevice; + PUSBD_INTERFACE_INFORMATION InterfaceInfo; + + // + // is the request for the Root Hub + // + if (Urb->UrbHeader.UsbdDeviceHandle == NULL) + { + // + // FIXME: support setting device to unconfigured state + // + PC_ASSERT(Urb->UrbSelectConfiguration.ConfigurationDescriptor); + + // + // set device handle + // + Urb->UrbSelectConfiguration.ConfigurationHandle = (PVOID)&ROOTHUB2_CONFIGURATION_DESCRIPTOR; + + // + // copy interface info + // + InterfaceInfo = &Urb->UrbSelectConfiguration.Interface; + + InterfaceInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)&ROOTHUB2_INTERFACE_DESCRIPTOR; + InterfaceInfo->Class = ROOTHUB2_INTERFACE_DESCRIPTOR.bInterfaceClass; + InterfaceInfo->SubClass = ROOTHUB2_INTERFACE_DESCRIPTOR.bInterfaceSubClass; + InterfaceInfo->Protocol = ROOTHUB2_INTERFACE_DESCRIPTOR.bInterfaceProtocol; + InterfaceInfo->Reserved = 0; + + // + // sanity check + // + PC_ASSERT(InterfaceInfo->NumberOfPipes == 1); + + // + // copy pipe info + // + InterfaceInfo->Pipes[0].MaximumPacketSize = ROOTHUB2_ENDPOINT_DESCRIPTOR.wMaxPacketSize; + InterfaceInfo->Pipes[0].EndpointAddress = ROOTHUB2_ENDPOINT_DESCRIPTOR.bEndpointAddress; + InterfaceInfo->Pipes[0].Interval = ROOTHUB2_ENDPOINT_DESCRIPTOR.bInterval; + InterfaceInfo->Pipes[0].PipeType = (USBD_PIPE_TYPE)(ROOTHUB2_ENDPOINT_DESCRIPTOR.bmAttributes & USB_ENDPOINT_TYPE_MASK); + InterfaceInfo->Pipes[0].PipeHandle = (PVOID)&ROOTHUB2_ENDPOINT_DESCRIPTOR; + + return STATUS_SUCCESS; + } + else + { + // + // check if this is a valid usb device handle + // + PC_ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))); + + // + // get device + // + UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); + + // + // select configuration + // + return UsbDevice->SelectConfiguration(Urb->UrbSelectConfiguration.ConfigurationDescriptor, &Urb->UrbSelectConfiguration.Interface, &Urb->UrbSelectConfiguration.ConfigurationHandle); + } +} + +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::HandleSelectInterface( + IN OUT PIRP Irp, + PURB Urb) +{ + PUSBDEVICE UsbDevice; + + // + // sanity check + // + PC_ASSERT(Urb->UrbSelectInterface.ConfigurationHandle); + + // + // is the request for the Root Hub + // + if (Urb->UrbHeader.UsbdDeviceHandle == NULL) + { + // + // no op for root hub + // + return STATUS_SUCCESS; + } + else + { + // + // check if this is a valid usb device handle + // + PC_ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))); + + // + // get device + // + UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); + + // + // select interface + // + return UsbDevice->SelectInterface(Urb->UrbSelectInterface.ConfigurationHandle, &Urb->UrbSelectInterface.Interface); + } +} + +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::HandleGetStatusFromDevice( + IN OUT PIRP Irp, + PURB Urb) +{ + PUSHORT Status; + + // + // sanity checks + // + PC_ASSERT(Urb->UrbControlGetStatusRequest.Index == 0); + PC_ASSERT(Urb->UrbControlGetStatusRequest.TransferBufferLength >= sizeof(USHORT)); + PC_ASSERT(Urb->UrbControlGetStatusRequest.TransferBuffer); + PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle == NULL); + + // + // get status buffer + // + Status = (PUSHORT)Urb->UrbControlGetStatusRequest.TransferBuffer; + + // + // FIXME need more flags ? + // + *Status = USB_PORT_STATUS_CONNECT; + + // + // done + // + return STATUS_SUCCESS; +} + +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::HandleClassDevice( + IN OUT PIRP Irp, + IN OUT PURB Urb) +{ + NTSTATUS Status = STATUS_NOT_IMPLEMENTED; + PUSB_HUB_DESCRIPTOR UsbHubDescriptor; + ULONG PortCount, Dummy2; + USHORT Dummy1; + + DPRINT("CHubController::HandleClassDevice Request %x Class %x\n", Urb->UrbControlVendorClassRequest.Request, Urb->UrbControlVendorClassRequest.Value >> 8); + + // + // check class request type + // + switch(Urb->UrbControlVendorClassRequest.Request) + { + case USB_REQUEST_GET_DESCRIPTOR: + { + switch (Urb->UrbControlVendorClassRequest.Value >> 8) + { + case USB_DEVICE_CLASS_RESERVED: // FALL THROUGH + case USB_DEVICE_CLASS_HUB: + { + // + // sanity checks + // + PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBuffer); + PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBufferLength >= sizeof(USB_HUB_DESCRIPTOR)); + + // + // get hub descriptor + // + UsbHubDescriptor = (PUSB_HUB_DESCRIPTOR)Urb->UrbControlVendorClassRequest.TransferBuffer; + + // + // one hub is handled + // + UsbHubDescriptor->bDescriptorLength = sizeof(USB_HUB_DESCRIPTOR); + Urb->UrbControlVendorClassRequest.TransferBufferLength = sizeof(USB_HUB_DESCRIPTOR); + + // + // type should 0x29 according to msdn + // + UsbHubDescriptor->bDescriptorType = 0x29; + + // + // get port count + // + Status = m_Hardware->GetDeviceDetails(&Dummy1, &Dummy1, &PortCount, &Dummy2); + PC_ASSERT(Status == STATUS_SUCCESS); + + // + // FIXME: retrieve values + // + UsbHubDescriptor->bNumberOfPorts = (UCHAR)PortCount; + UsbHubDescriptor->wHubCharacteristics = 0x00; + UsbHubDescriptor->bPowerOnToPowerGood = 0x01; + UsbHubDescriptor->bHubControlCurrent = 0x00; + + // + // done + // + Status = STATUS_SUCCESS; + break; + } + default: + DPRINT1("CHubController::HandleClassDevice Class %x not implemented\n", Urb->UrbControlVendorClassRequest.Value >> 8); + break; + } + break; + } + default: + DPRINT1("CHubController::HandleClassDevice Type %x not implemented\n", Urb->UrbControlVendorClassRequest.Request); + } + + return Status; +} +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::HandleGetDescriptor( + IN OUT PIRP Irp, + IN OUT PURB Urb) +{ + NTSTATUS Status = STATUS_NOT_IMPLEMENTED; + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; + PUCHAR Buffer; + PUSBDEVICE UsbDevice; + ULONG Length; + + DPRINT("CHubController::HandleGetDescriptor\n"); + + // + // check descriptor type + // + switch(Urb->UrbControlDescriptorRequest.DescriptorType) + { + case USB_DEVICE_DESCRIPTOR_TYPE: + { + // + // sanity check + // + PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength >= sizeof(USB_DEVICE_DESCRIPTOR)); + PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer); + + if (Urb->UrbHeader.UsbdDeviceHandle == NULL) + { + // + // copy root hub device descriptor + // + RtlCopyMemory((PUCHAR)Urb->UrbControlDescriptorRequest.TransferBuffer, &m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR)); + Status = STATUS_SUCCESS; + } + else + { + // + // check if this is a valid usb device handle + // + PC_ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))); + + // + // get device + // + UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); + + // + // retrieve device descriptor from device + // + UsbDevice->GetDeviceDescriptor((PUSB_DEVICE_DESCRIPTOR)Urb->UrbControlDescriptorRequest.TransferBuffer); + Status = STATUS_SUCCESS; + } + break; + } + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + { + // + // sanity checks + // + PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer); + PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength >= sizeof(USB_CONFIGURATION_DESCRIPTOR)); + + if (Urb->UrbHeader.UsbdDeviceHandle == NULL) + { + // + // request is for the root bus controller + // + RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer, &ROOTHUB2_CONFIGURATION_DESCRIPTOR, sizeof(USB_CONFIGURATION_DESCRIPTOR)); + + // + // get configuration descriptor, very retarded! + // + ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)Urb->UrbControlDescriptorRequest.TransferBuffer; + + // + // check if buffer can hold interface and endpoint descriptor + // + if (ConfigurationDescriptor->wTotalLength > Urb->UrbControlDescriptorRequest.TransferBufferLength) + { + // + // buffer too small + // + Status = STATUS_SUCCESS; + ASSERT(FALSE); + break; + } + + // + // copy interface descriptor template + // + Buffer = (PUCHAR)(ConfigurationDescriptor + 1); + RtlCopyMemory(Buffer, &ROOTHUB2_INTERFACE_DESCRIPTOR, sizeof(USB_INTERFACE_DESCRIPTOR)); + + // + // copy end point descriptor template + // + Buffer += sizeof(USB_INTERFACE_DESCRIPTOR); + RtlCopyMemory(Buffer, &ROOTHUB2_ENDPOINT_DESCRIPTOR, sizeof(USB_ENDPOINT_DESCRIPTOR)); + + // + // done + // + Status = STATUS_SUCCESS; + + } + else + { + DPRINT1("Length %u\n", Urb->UrbControlDescriptorRequest.TransferBufferLength); + + // + // check if this is a valid usb device handle + // + PC_ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))); + + // + // get device + // + UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); + + if (sizeof(USB_CONFIGURATION_DESCRIPTOR) > Urb->UrbControlDescriptorRequest.TransferBufferLength) + { + // + // buffer too small + // + Urb->UrbControlDescriptorRequest.TransferBufferLength = UsbDevice->GetConfigurationDescriptorsLength(); + + // + // bail out + // + Status = STATUS_SUCCESS; + break; + } + + // + // perform work in IUSBDevice + // + UsbDevice->GetConfigurationDescriptors((PUSB_CONFIGURATION_DESCRIPTOR)Urb->UrbControlDescriptorRequest.TransferBuffer, Urb->UrbControlDescriptorRequest.TransferBufferLength, &Length); + + // + // sanity check + // + PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength >= Length); + + // + // store result size + // + Urb->UrbControlDescriptorRequest.TransferBufferLength = Length; + Status = STATUS_SUCCESS; + } + break; + } + case USB_STRING_DESCRIPTOR_TYPE: + { + // + // sanity check + // + PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer); + PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength); + + + // + // check if this is a valid usb device handle + // + PC_ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))); + + // + // get device + // + UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); + + // + // unimplemented + // + ASSERT(FALSE); + break; + } + default: + DPRINT1("CHubController::HandleGetDescriptor DescriptorType %x unimplemented\n", Urb->UrbControlDescriptorRequest.DescriptorType); + break; + } + + // + // done + // + return Status; +} + +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::HandleClassInterface( + IN OUT PIRP Irp, + IN OUT PURB Urb) +{ + USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup; + NTSTATUS Status; + PUSBDEVICE UsbDevice; + + // + // sanity check + // + PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBuffer); + PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBufferLength); + PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle); + + // + // check if this is a valid usb device handle + // + PC_ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))); + + // + // get device + // + UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); + + + DPRINT1("URB_FUNCTION_CLASS_INTERFACE\n"); + DPRINT1("TransferFlags %x\n", Urb->UrbControlVendorClassRequest.TransferFlags); + DPRINT1("TransferBufferLength %x\n", Urb->UrbControlVendorClassRequest.TransferBufferLength); + DPRINT1("TransferBuffer %x\n", Urb->UrbControlVendorClassRequest.TransferBuffer); + DPRINT1("TransferBufferMDL %x\n", Urb->UrbControlVendorClassRequest.TransferBufferMDL); + DPRINT1("RequestTypeReservedBits %x\n", Urb->UrbControlVendorClassRequest.RequestTypeReservedBits); + DPRINT1("Request %x\n", Urb->UrbControlVendorClassRequest.Request); + DPRINT1("Value %x\n", Urb->UrbControlVendorClassRequest.Value); + DPRINT1("Index %x\n", Urb->UrbControlVendorClassRequest.Index); + + // + // initialize setup packet + // + CtrlSetup.bmRequestType.B = 0xa1; //FIXME: Const. + CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request; + CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value; + CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index; + CtrlSetup.wLength = Urb->UrbControlVendorClassRequest.TransferBufferLength; + + // + // issue request + // + Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlVendorClassRequest.TransferBufferLength, Urb->UrbControlVendorClassRequest.TransferBuffer); + + // + // assert on failure + // + PC_ASSERT(NT_SUCCESS(Status)); + + + // + // done + // + return Status; +} + +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::HandleDeviceControl( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + PCOMMON_DEVICE_EXTENSION DeviceExtension; + PURB Urb; + NTSTATUS Status = STATUS_NOT_IMPLEMENTED; + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // get device extension + // + DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // determine which request should be performed + // + switch(IoStack->Parameters.DeviceIoControl.IoControlCode) + { + case IOCTL_INTERNAL_USB_SUBMIT_URB: + { + // + // get urb + // + Urb = (PURB)IoStack->Parameters.Others.Argument1; + PC_ASSERT(Urb); + + switch (Urb->UrbHeader.Function) + { + case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: + Status = HandleGetDescriptor(Irp, Urb); + break; + case URB_FUNCTION_CLASS_DEVICE: + Status = HandleClassDevice(Irp, Urb); + break; + case URB_FUNCTION_GET_STATUS_FROM_DEVICE: + Status = HandleGetStatusFromDevice(Irp, Urb); + break; + case URB_FUNCTION_SELECT_CONFIGURATION: + Status = HandleSelectConfiguration(Irp, Urb); + break; + case URB_FUNCTION_SELECT_INTERFACE: + Status = HandleSelectInterface(Irp, Urb); + break; + case URB_FUNCTION_CLASS_OTHER: + Status = HandleClassOther(Irp, Urb); + break; + case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: + Status = HandleBulkOrInterruptTransfer(Irp, Urb); + break; + case URB_FUNCTION_CLASS_INTERFACE: + Status = HandleClassInterface(Irp, Urb); + break; + default: + DPRINT1("IOCTL_INTERNAL_USB_SUBMIT_URB Function %x NOT IMPLEMENTED\n", Urb->UrbHeader.Function); + break; + } + // + // request completed + // + break; + } + case IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE: + { + DPRINT("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE %p\n", this); + + if (IoStack->Parameters.Others.Argument1) + { + // + // store object as device handle + // + *(PVOID *)IoStack->Parameters.Others.Argument1 = (PVOID)this; + Status = STATUS_SUCCESS; + } + else + { + // + // mis-behaving hub driver + // + Status = STATUS_INVALID_DEVICE_REQUEST; + } + + // + // request completed + // + break; + } + case IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO: + { + DPRINT("IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO\n"); + + // + // this is the first request send, it delivers the PDO to the caller + // + if (IoStack->Parameters.Others.Argument1) + { + // + // store root hub pdo object + // + *(PVOID *)IoStack->Parameters.Others.Argument1 = DeviceObject; + } + + if (IoStack->Parameters.Others.Argument2) + { + // + // documentation claims to deliver the hcd controller object, although it is wrong + // + *(PVOID *)IoStack->Parameters.Others.Argument2 = DeviceObject; + } + + // + // request completed + // + Status = STATUS_SUCCESS; + break; + } + case IOCTL_INTERNAL_USB_GET_HUB_COUNT: + { + DPRINT("IOCTL_INTERNAL_USB_GET_HUB_COUNT\n"); + + // + // after IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO is delivered, the usbhub driver + // requests this ioctl to deliver the number of presents. + + if (IoStack->Parameters.Others.Argument1) + { + // + // FIXME / verify: there is only one hub + // + *(PULONG)IoStack->Parameters.Others.Argument1 = 1; + } + + // + // request completed + // + Status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof(ULONG); + break; + } + case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION: + { + DPRINT1("IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION UNIMPLEMENTED\n"); + Status = STATUS_SUCCESS; + break; + } + default: + { + DPRINT1("HandleDeviceControl>Type: IoCtl %x InputBufferLength %lu OutputBufferLength %lu NOT IMPLEMENTED\n", + IoStack->Parameters.DeviceIoControl.IoControlCode, + IoStack->Parameters.DeviceIoControl.InputBufferLength, + IoStack->Parameters.DeviceIoControl.OutputBufferLength); + break; + } + } + if (Status != STATUS_PENDING) + { + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + + return Status; +} + +//----------------------------------------------------------------------------------------- +PUSBHARDWAREDEVICE +CHubController::GetUsbHardware() +{ + return m_Hardware; +} + +//----------------------------------------------------------------------------------------- +ULONG +CHubController::AcquireDeviceAddress() +{ + KIRQL OldLevel; + ULONG DeviceAddress; + + // + // acquire device lock + // + KeAcquireSpinLock(&m_Lock, &OldLevel); + + // + // find address + // + DeviceAddress = RtlFindClearBits(&m_DeviceAddressBitmap, 1, 0); + if (DeviceAddress != MAXULONG) + { + // + // reserve address + // + RtlSetBits(&m_DeviceAddressBitmap, DeviceAddress, 1); + + // + // device addresses start from 0x1 - 0xFF + // + DeviceAddress++; + } + + // + // release spin lock + // + KeReleaseSpinLock(&m_Lock, OldLevel); + + // + // return device address + // + return DeviceAddress; +} +//----------------------------------------------------------------------------------------- +VOID +CHubController::ReleaseDeviceAddress( + ULONG DeviceAddress) +{ + KIRQL OldLevel; + + // + // acquire device lock + // + KeAcquireSpinLock(&m_Lock, &OldLevel); + + // + // sanity check + // + PC_ASSERT(DeviceAddress != 0); + + // + // convert back to bit number + // + DeviceAddress--; + + // + // clear bit + // + RtlClearBits(&m_DeviceAddressBitmap, DeviceAddress, 1); + + // + // release lock + // + KeReleaseSpinLock(&m_Lock, OldLevel); +} +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::RemoveUsbDevice( + PUSBDEVICE UsbDevice) +{ + PUSBDEVICE_ENTRY DeviceEntry; + PLIST_ENTRY Entry; + NTSTATUS Status = STATUS_UNSUCCESSFUL; + KIRQL OldLevel; + + // + // acquire lock + // + KeAcquireSpinLock(&m_Lock, &OldLevel); + + // + // point to first entry + // + Entry = m_UsbDeviceList.Flink; + + // + // find matching entry + // + while(Entry != &m_UsbDeviceList) + { + // + // get entry + // + DeviceEntry = (PUSBDEVICE_ENTRY)CONTAINING_RECORD(Entry, USBDEVICE_ENTRY, Entry); + + // + // is it current entry + // + if (DeviceEntry->Device == UsbDevice) + { + // + // remove entry + // + RemoveEntryList(Entry); + + // + // free entry + // + ExFreePoolWithTag(DeviceEntry, TAG_USBOHCI); + + // + // done + // + Status = STATUS_SUCCESS; + break; + } + + // + // goto next device + // + Entry = Entry->Flink; + } + + // + // release lock + // + KeReleaseSpinLock(&m_Lock, OldLevel); + + // + // return result + // + return Status; +} +//----------------------------------------------------------------------------------------- +BOOLEAN +CHubController::ValidateUsbDevice(PUSBDEVICE UsbDevice) +{ + PUSBDEVICE_ENTRY DeviceEntry; + PLIST_ENTRY Entry; + KIRQL OldLevel; + BOOLEAN Result = FALSE; + + // + // acquire lock + // + KeAcquireSpinLock(&m_Lock, &OldLevel); + + // + // point to first entry + // + Entry = m_UsbDeviceList.Flink; + + // + // find matching entry + // + while(Entry != &m_UsbDeviceList) + { + // + // get entry + // + DeviceEntry = (PUSBDEVICE_ENTRY)CONTAINING_RECORD(Entry, USBDEVICE_ENTRY, Entry); + + // + // is it current entry + // + if (DeviceEntry->Device == UsbDevice) + { + // + // device is valid + // + Result = TRUE; + break; + } + + // + // goto next device + // + Entry = Entry->Flink; + } + + // + // release lock + // + KeReleaseSpinLock(&m_Lock, OldLevel); + + // + // return result + // + return Result; + +} + +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::AddUsbDevice( + PUSBDEVICE UsbDevice) +{ + PUSBDEVICE_ENTRY DeviceEntry; + KIRQL OldLevel; + + // + // allocate device entry + // + DeviceEntry = (PUSBDEVICE_ENTRY)ExAllocatePoolWithTag(NonPagedPool, sizeof(USBDEVICE_ENTRY), TAG_USBOHCI); + if (!DeviceEntry) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // initialize entry + // + DeviceEntry->Device = UsbDevice; + + // + // acquire lock + // + KeAcquireSpinLock(&m_Lock, &OldLevel); + + // + // insert entry + // + InsertTailList(&m_UsbDeviceList, &DeviceEntry->Entry); + + // + // release spin lock + // + KeReleaseSpinLock(&m_Lock, OldLevel); + + // + // done + // + return STATUS_SUCCESS; +} + +//----------------------------------------------------------------------------------------- +VOID +CHubController::SetNotification( + PVOID CallbackContext, + PRH_INIT_CALLBACK CallbackRoutine) +{ + KIRQL OldLevel; + + // + // acquire hub controller lock + // + KeAcquireSpinLock(&m_Lock, &OldLevel); + + // + // now set the callback routine and context of the hub + // + m_HubCallbackContext = CallbackContext; + m_HubCallbackRoutine = CallbackRoutine; + + // + // release hub controller lock + // + KeReleaseSpinLock(&m_Lock, OldLevel); +} + +//================================================================================================= +// +// Generic Interface functions +// +VOID +USB_BUSIFFN +USBI_InterfaceReference( + PVOID BusContext) +{ + CHubController * Controller = (CHubController*)BusContext; + + DPRINT1("USBH_InterfaceReference\n"); + + // + // add reference + // + Controller->AddRef(); +} + +VOID +USB_BUSIFFN +USBI_InterfaceDereference( + PVOID BusContext) +{ + CHubController * Controller = (CHubController*)BusContext; + + DPRINT1("USBH_InterfaceDereference\n"); + + // + // release + // + Controller->Release(); +} +//================================================================================================= +// +// USB Hub Interface functions +// +NTSTATUS +USB_BUSIFFN +USBHI_CreateUsbDevice( + PVOID BusContext, + PUSB_DEVICE_HANDLE *NewDevice, + PUSB_DEVICE_HANDLE HubDeviceHandle, + USHORT PortStatus, + USHORT PortNumber) +{ + PUSBDEVICE NewUsbDevice; + CHubController * Controller; + NTSTATUS Status; + + DPRINT1("USBHI_CreateUsbDevice\n"); + + // + // first get hub controller + // + Controller = (CHubController *)BusContext; + + // + // sanity check + // + PC_ASSERT(Controller); + PC_ASSERT(BusContext == HubDeviceHandle); + + // + // now allocate usb device + // + Status = CreateUSBDevice(&NewUsbDevice); + + // + // check for success + // + if (!NT_SUCCESS(Status)) + { + // + // release controller + // + Controller->Release(); + DPRINT1("USBHI_CreateUsbDevice: failed to create usb device %x\n", Status); + return Status; + } + + // + // now initialize device + // + Status = NewUsbDevice->Initialize(PHUBCONTROLLER(Controller), Controller->GetUsbHardware(),PVOID(Controller), PortNumber, PortStatus); + + // + // check for success + // + if (!NT_SUCCESS(Status)) + { + // + // release usb device + // + NewUsbDevice->Release(); + DPRINT1("USBHI_CreateUsbDevice: failed to initialize usb device %x\n", Status); + return Status; + } + + // + // insert into list + // + Status = Controller->AddUsbDevice(NewUsbDevice); + // + // check for success + // + if (!NT_SUCCESS(Status)) + { + // + // release usb device + // + NewUsbDevice->Release(); + + DPRINT1("USBHI_CreateUsbDevice: failed to add usb device %x\n", Status); + return Status; + } + + // + // store the handle + // + *NewDevice = NewUsbDevice; + + // + // done + // + return STATUS_SUCCESS; +} + +NTSTATUS +USB_BUSIFFN +USBHI_InitializeUsbDevice( + PVOID BusContext, + PUSB_DEVICE_HANDLE DeviceHandle) +{ + PUSBDEVICE UsbDevice; + CHubController * Controller; + ULONG DeviceAddress; + NTSTATUS Status; + ULONG Index = 0; + + DPRINT1("USBHI_InitializeUsbDevice\n"); + + // + // first get controller + // + Controller = (CHubController *)BusContext; + PC_ASSERT(Controller); + + // + // get device object + // + UsbDevice = (PUSBDEVICE)DeviceHandle; + PC_ASSERT(UsbDevice); + + // + // validate device handle + // + if (!Controller->ValidateUsbDevice(UsbDevice)) + { + DPRINT1("USBHI_InitializeUsbDevice invalid device handle %p\n", DeviceHandle); + + // + // invalid device handle + // + return STATUS_DEVICE_NOT_CONNECTED; + } + + // + // now reserve an address + // + DeviceAddress = Controller->AcquireDeviceAddress(); + + // + // is the device address valid + // + if (DeviceAddress == MAXULONG) + { + // + // failed to get an device address from the device address pool + // + DPRINT1("USBHI_InitializeUsbDevice failed to get device address\n"); + return STATUS_DEVICE_DATA_ERROR; + } + + do + { + // + // now set the device address + // + Status = UsbDevice->SetDeviceAddress((UCHAR)DeviceAddress); + + if (NT_SUCCESS(Status)) + break; + + }while(Index++ < 3 ); + + // + // check for failure + // + if (!NT_SUCCESS(Status)) + { + // + // failed to set device address + // + DPRINT1("USBHI_InitializeUsbDevice failed to set address with %x\n", Status); + + // + // release address + // + Controller->ReleaseDeviceAddress(DeviceAddress); + + // + // return error + // + return STATUS_DEVICE_DATA_ERROR; + } + + // + // done + // + return STATUS_SUCCESS; +} + +NTSTATUS +USB_BUSIFFN +USBHI_GetUsbDescriptors( + PVOID BusContext, + PUSB_DEVICE_HANDLE DeviceHandle, + PUCHAR DeviceDescriptorBuffer, + PULONG DeviceDescriptorBufferLength, + PUCHAR ConfigDescriptorBuffer, + PULONG ConfigDescriptorBufferLength) +{ + PUSBDEVICE UsbDevice; + CHubController * Controller; + + DPRINT1("USBHI_GetUsbDescriptors\n"); + + // + // sanity check + // + PC_ASSERT(DeviceDescriptorBuffer); + PC_ASSERT(DeviceDescriptorBufferLength); + PC_ASSERT(*DeviceDescriptorBufferLength >= sizeof(USB_DEVICE_DESCRIPTOR)); + PC_ASSERT(ConfigDescriptorBufferLength); + PC_ASSERT(*ConfigDescriptorBufferLength >= sizeof(USB_CONFIGURATION_DESCRIPTOR)); + + // + // first get controller + // + Controller = (CHubController *)BusContext; + PC_ASSERT(Controller); + + + // + // get device object + // + UsbDevice = (PUSBDEVICE)DeviceHandle; + PC_ASSERT(UsbDevice); + + // + // validate device handle + // + if (!Controller->ValidateUsbDevice(UsbDevice)) + { + DPRINT1("USBHI_GetUsbDescriptors invalid device handle %p\n", DeviceHandle); + + // + // invalid device handle + // + return STATUS_DEVICE_NOT_CONNECTED; + } + + // + // get device descriptor + // + UsbDevice->GetDeviceDescriptor((PUSB_DEVICE_DESCRIPTOR)DeviceDescriptorBuffer); + + // + // store result length + // + *DeviceDescriptorBufferLength = sizeof(USB_DEVICE_DESCRIPTOR); + + // + // get configuration descriptor + // + UsbDevice->GetConfigurationDescriptors((PUSB_CONFIGURATION_DESCRIPTOR)ConfigDescriptorBuffer, *ConfigDescriptorBufferLength, ConfigDescriptorBufferLength); + + // + // complete the request + // + return STATUS_SUCCESS; +} + +NTSTATUS +USB_BUSIFFN +USBHI_RemoveUsbDevice( + PVOID BusContext, + PUSB_DEVICE_HANDLE DeviceHandle, + ULONG Flags) +{ + PUSBDEVICE UsbDevice; + CHubController * Controller; + NTSTATUS Status; + + DPRINT1("USBHI_RemoveUsbDevice\n"); + + // + // first get controller + // + Controller = (CHubController *)BusContext; + PC_ASSERT(Controller); + + // + // get device object + // + UsbDevice = (PUSBDEVICE)DeviceHandle; + PC_ASSERT(UsbDevice); + + // + // validate device handle + // + if (!Controller->ValidateUsbDevice(UsbDevice)) + { + DPRINT1("USBHI_RemoveUsbDevice invalid device handle %p\n", DeviceHandle); + + // + // invalid device handle + // + return STATUS_DEVICE_NOT_CONNECTED; + } + + // + // check if there were flags passed + // + if (Flags & USBD_KEEP_DEVICE_DATA || Flags & USBD_MARK_DEVICE_BUSY) + { + // + // ignore flags for now + // + return STATUS_SUCCESS; + } + + // + // remove device + // + Status = Controller->RemoveUsbDevice(UsbDevice); + if (!NT_SUCCESS(Status)) + { + // + // invalid device handle + // + DPRINT1("USBHI_RemoveUsbDevice Invalid device handle %p\n", UsbDevice); + PC_ASSERT(0); + return STATUS_DEVICE_NOT_CONNECTED; + } + + // + // release usb device + // + UsbDevice->Release(); + + // + // done + // + return STATUS_SUCCESS; +} + +NTSTATUS +USB_BUSIFFN +USBHI_RestoreUsbDevice( + PVOID BusContext, + PUSB_DEVICE_HANDLE OldDeviceHandle, + PUSB_DEVICE_HANDLE NewDeviceHandle) +{ + PUSBDEVICE OldUsbDevice, NewUsbDevice; + CHubController * Controller; + + DPRINT1("USBHI_RestoreUsbDevice\n"); + + // + // first get controller + // + Controller = (CHubController *)BusContext; + PC_ASSERT(Controller); + + // + // get device object + // + OldUsbDevice = (PUSBDEVICE)OldDeviceHandle; + NewUsbDevice = (PUSBDEVICE)NewDeviceHandle; + PC_ASSERT(OldUsbDevice); + PC_ASSERT(NewDeviceHandle); + + // + // validate device handle + // + PC_ASSERT(Controller->ValidateUsbDevice(NewUsbDevice)); + PC_ASSERT(Controller->ValidateUsbDevice(OldUsbDevice)); + + DPRINT1("NewUsbDevice: DeviceAddress %x\n", NewUsbDevice->GetDeviceAddress()); + + + DPRINT1("OldUsbDevice: DeviceAddress %x\n", OldUsbDevice->GetDeviceAddress()); + + PC_ASSERT(FALSE); + + // + // remove old device handle + // + USBHI_RemoveUsbDevice(BusContext, OldDeviceHandle, 0); + + return STATUS_SUCCESS; +} + +NTSTATUS +USB_BUSIFFN +USBHI_QueryDeviceInformation( + PVOID BusContext, + PUSB_DEVICE_HANDLE DeviceHandle, + PVOID DeviceInformationBuffer, + ULONG DeviceInformationBufferLength, + PULONG LengthReturned) +{ + PUSB_DEVICE_INFORMATION_0 DeviceInfo; + PUSBDEVICE UsbDevice; + CHubController * Controller; + + DPRINT1("USBHI_QueryDeviceInformation %p\n", BusContext); + + // + // sanity check + // + PC_ASSERT(DeviceInformationBufferLength >= sizeof(USB_DEVICE_INFORMATION_0)); + PC_ASSERT(DeviceInformationBuffer); + PC_ASSERT(LengthReturned); + + // + // get controller object + // + Controller = (CHubController*)BusContext; + PC_ASSERT(Controller); + + // + // get device object + // + UsbDevice = (PUSBDEVICE)DeviceHandle; + PC_ASSERT(UsbDevice); + + if (BusContext != DeviceHandle) + { + // + // validate device handle + // + if (!Controller->ValidateUsbDevice(UsbDevice)) + { + DPRINT1("USBHI_QueryDeviceInformation invalid device handle %p\n", DeviceHandle); + + // + // invalid device handle + // + return STATUS_DEVICE_NOT_CONNECTED; + } + + // + // access information buffer + // + DeviceInfo = (PUSB_DEVICE_INFORMATION_0)DeviceInformationBuffer; + + // + // initialize with default values + // + DeviceInfo->InformationLevel = 0; + DeviceInfo->ActualLength = sizeof(USB_DEVICE_INFORMATION_0); + DeviceInfo->PortNumber = UsbDevice->GetPort(); + DeviceInfo->CurrentConfigurationValue = UsbDevice->GetConfigurationValue(); + DeviceInfo->DeviceAddress = UsbDevice->GetDeviceAddress(); + DeviceInfo->HubAddress = 0; //FIXME + DeviceInfo->DeviceSpeed = UsbDevice->GetSpeed(); + DeviceInfo->DeviceType = UsbDevice->GetType(); + DeviceInfo->NumberOfOpenPipes = 0; //FIXME + + // + // get device descriptor + // + UsbDevice->GetDeviceDescriptor(&DeviceInfo->DeviceDescriptor); + + // + // FIXME return pipe information + // + + // + // store result length + // + *LengthReturned = sizeof(USB_DEVICE_INFORMATION_0); + + return STATUS_SUCCESS; + } + + // + // access information buffer + // + DeviceInfo = (PUSB_DEVICE_INFORMATION_0)DeviceInformationBuffer; + + // + // initialize with default values + // + DeviceInfo->InformationLevel = 0; + DeviceInfo->ActualLength = sizeof(USB_DEVICE_INFORMATION_0); + DeviceInfo->PortNumber = 0; + DeviceInfo->CurrentConfigurationValue = 0; //FIXME; + DeviceInfo->DeviceAddress = 0; + DeviceInfo->HubAddress = 0; //FIXME + DeviceInfo->DeviceSpeed = UsbFullSpeed; //FIXME + DeviceInfo->DeviceType = Usb11Device; //FIXME + DeviceInfo->NumberOfOpenPipes = 0; //FIXME + + // + // get device descriptor + // + RtlMoveMemory(&DeviceInfo->DeviceDescriptor, ROOTHUB2_DEVICE_DESCRIPTOR, sizeof(USB_DEVICE_DESCRIPTOR)); + + // + // FIXME return pipe information + // + + // + // store result length + // +#ifdef _MSC_VER + *LengthReturned = FIELD_OFFSET(USB_DEVICE_INFORMATION_0, PipeList[DeviceInfo->NumberOfOpenPipes]); +#else + *LengthReturned = sizeof(USB_DEVICE_INFORMATION_0) + (DeviceInfo->NumberOfOpenPipes > 1 ? (DeviceInfo->NumberOfOpenPipes - 1) * sizeof(USB_PIPE_INFORMATION_0) : 0); +#endif + // + // done + // + return STATUS_SUCCESS; +} + +NTSTATUS +USB_BUSIFFN +USBHI_GetControllerInformation( + PVOID BusContext, + PVOID ControllerInformationBuffer, + ULONG ControllerInformationBufferLength, + PULONG LengthReturned) +{ + PUSB_CONTROLLER_INFORMATION_0 ControllerInfo; + + DPRINT1("USBHI_GetControllerInformation\n"); + + // + // sanity checks + // + PC_ASSERT(ControllerInformationBuffer); + PC_ASSERT(ControllerInformationBufferLength >= sizeof(USB_CONTROLLER_INFORMATION_0)); + + // + // get controller info buffer + // + ControllerInfo = (PUSB_CONTROLLER_INFORMATION_0)ControllerInformationBuffer; + + // + // FIXME only version 0 is supported for now + // + PC_ASSERT(ControllerInfo->InformationLevel == 0); + + // + // fill in information + // + ControllerInfo->ActualLength = sizeof(USB_CONTROLLER_INFORMATION_0); + ControllerInfo->SelectiveSuspendEnabled = FALSE; //FIXME + ControllerInfo->IsHighSpeedController = FALSE; + + // + // set length returned + // + *LengthReturned = ControllerInfo->ActualLength; + + // + // done + // + return STATUS_SUCCESS; +} + +NTSTATUS +USB_BUSIFFN +USBHI_ControllerSelectiveSuspend( + PVOID BusContext, + BOOLEAN Enable) +{ + UNIMPLEMENTED + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +USB_BUSIFFN +USBHI_GetExtendedHubInformation( + PVOID BusContext, + PDEVICE_OBJECT HubPhysicalDeviceObject, + PVOID HubInformationBuffer, + ULONG HubInformationBufferLength, + PULONG LengthReturned) +{ + PUSB_EXTHUB_INFORMATION_0 HubInfo; + CHubController * Controller; + PUSBHARDWAREDEVICE Hardware; + ULONG Index; + ULONG NumPort, Dummy2; + USHORT Dummy1; + NTSTATUS Status; + + DPRINT1("USBHI_GetExtendedHubInformation\n"); + + // + // sanity checks + // + PC_ASSERT(HubInformationBuffer); + PC_ASSERT(HubInformationBufferLength == sizeof(USB_EXTHUB_INFORMATION_0)); + PC_ASSERT(LengthReturned); + + // + // get hub controller + // + Controller = (CHubController *)BusContext; + PC_ASSERT(Controller); + + // + // get usb hardware device + // + Hardware = Controller->GetUsbHardware(); + + // + // retrieve number of ports + // + Status = Hardware->GetDeviceDetails(&Dummy1, &Dummy1, &NumPort, &Dummy2); + if (!NT_SUCCESS(Status)) + { + // + // failed to get hardware details, ouch ;) + // + DPRINT1("USBHI_GetExtendedHubInformation failed to get hardware details with %x\n", Status); + return Status; + } + + // + // get hub information buffer + // + HubInfo = (PUSB_EXTHUB_INFORMATION_0)HubInformationBuffer; + + // + // initialize hub information + // + HubInfo->InformationLevel = 0; + + // + // store port count + // + HubInfo->NumberOfPorts = NumPort; + + // + // initialize port information + // + for(Index = 0; Index < NumPort; Index++) + { + HubInfo->Port[Index].PhysicalPortNumber = Index + 1; + HubInfo->Port[Index].PortLabelNumber = Index + 1; + HubInfo->Port[Index].VidOverride = 0; + HubInfo->Port[Index].PidOverride = 0; + HubInfo->Port[Index].PortAttributes = 0; //FIXME + } + + // + // store result length + // +#ifdef _MSC_VER + *LengthReturned = FIELD_OFFSET(USB_EXTHUB_INFORMATION_0, Port[HubInfo->NumberOfPorts]); +#else + *LengthReturned = FIELD_OFFSET(USB_EXTHUB_INFORMATION_0, Port) + sizeof(USB_EXTPORT_INFORMATION_0) * HubInfo->NumberOfPorts; +#endif + + // + // done + // + return STATUS_SUCCESS; +} + +NTSTATUS +USB_BUSIFFN +USBHI_GetRootHubSymbolicName( + PVOID BusContext, + PVOID HubSymNameBuffer, + ULONG HubSymNameBufferLength, + PULONG HubSymNameActualLength) +{ + UNIMPLEMENTED + return STATUS_NOT_IMPLEMENTED; +} + +PVOID +USB_BUSIFFN +USBHI_GetDeviceBusContext( + PVOID HubBusContext, + PVOID DeviceHandle) +{ + UNIMPLEMENTED + return NULL; +} + +NTSTATUS +USB_BUSIFFN +USBHI_RootHubInitNotification( + PVOID BusContext, + PVOID CallbackContext, + PRH_INIT_CALLBACK CallbackRoutine) +{ + CHubController * Controller; + + DPRINT("USBHI_RootHubInitNotification %p \n", CallbackContext); + + // + // get controller object + // + Controller = (CHubController*)BusContext; + PC_ASSERT(Controller); + + // + // set notification routine + // + Controller->SetNotification(CallbackContext, CallbackRoutine); + + // + // FIXME: determine when to perform callback + // + CallbackRoutine(CallbackContext); + + // + // done + // + return STATUS_SUCCESS; +} + +VOID +USB_BUSIFFN +USBHI_FlushTransfers( + PVOID BusContext, + PVOID DeviceHandle) +{ + UNIMPLEMENTED +} + +VOID +USB_BUSIFFN +USBHI_SetDeviceHandleData( + PVOID BusContext, + PVOID DeviceHandle, + PDEVICE_OBJECT UsbDevicePdo) +{ + PUSBDEVICE UsbDevice; + CHubController * Controller; + + // + // get controller + // + Controller = (CHubController *)BusContext; + PC_ASSERT(Controller); + + // + // get device handle + // + UsbDevice = (PUSBDEVICE)DeviceHandle; + + // + // validate device handle + // + if (!Controller->ValidateUsbDevice(UsbDevice)) + { + DPRINT1("USBHI_SetDeviceHandleData DeviceHandle %p is invalid\n", DeviceHandle); + + // + // invalid handle + // + return; + } + else + { + // + // usbhub sends this request as a part of the Pnp startup sequence + // looks like we need apply a dragon voodoo to fixup the device stack + // otherwise usbhub will cause a bugcheck + // + DPRINT1("USBHI_SetDeviceHandleData %p\n", UsbDevicePdo); + + // + // sanity check + // + PC_ASSERT(UsbDevicePdo->AttachedDevice); + + // + // should be usbstor + // fixup device stack voodoo part #2 + // + UsbDevicePdo->AttachedDevice->StackSize++; + + // + // set device handle data + // + UsbDevice->SetDeviceHandleData(UsbDevicePdo); + } +} + +//================================================================================================= +// +// USB Device Interface functions +// + +VOID +USB_BUSIFFN +USBDI_GetUSBDIVersion( + PVOID BusContext, + PUSBD_VERSION_INFORMATION VersionInformation, + PULONG HcdCapabilites) +{ + CHubController * Controller; + PUSBHARDWAREDEVICE Device; + ULONG Speed, Dummy2; + USHORT Dummy1; + + DPRINT1("USBDI_GetUSBDIVersion\n"); + + // + // get controller + // + Controller = (CHubController*)BusContext; + + // + // get usb hardware + // + Device = Controller->GetUsbHardware(); + PC_ASSERT(Device); + + if (VersionInformation) + { + // + // windows xp supported + // + VersionInformation->USBDI_Version = 0x00000500; + + // + // get device speed + // + Device->GetDeviceDetails(&Dummy1, &Dummy1, &Dummy2, &Speed); + + // + // store speed details + // + VersionInformation->Supported_USB_Version = Speed; + } + + // + // no flags supported + // + *HcdCapabilites = 0; +} + +NTSTATUS +USB_BUSIFFN +USBDI_QueryBusTime( + PVOID BusContext, + PULONG CurrentFrame) +{ + UNIMPLEMENTED + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +USB_BUSIFFN +USBDI_SubmitIsoOutUrb( + PVOID BusContext, + PURB Urb) +{ + UNIMPLEMENTED + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +USB_BUSIFFN +USBDI_QueryBusInformation( + PVOID BusContext, + ULONG Level, + PVOID BusInformationBuffer, + PULONG BusInformationBufferLength, + PULONG BusInformationActualLength) +{ + UNIMPLEMENTED + return STATUS_NOT_IMPLEMENTED; +} + +BOOLEAN +USB_BUSIFFN +USBDI_IsDeviceHighSpeed( + PVOID BusContext) +{ + CHubController * Controller; + PUSBHARDWAREDEVICE Device; + ULONG Speed, Dummy2; + USHORT Dummy1; + + DPRINT1("USBDI_IsDeviceHighSpeed\n"); + + // + // get controller + // + Controller = (CHubController*)BusContext; + + // + // get usb hardware + // + Device = Controller->GetUsbHardware(); + PC_ASSERT(Device); + + // + // get device speed + // + Device->GetDeviceDetails(&Dummy1, &Dummy1, &Dummy2, &Speed); + + // + // USB 2.0 equals 0x200 + // + return (Speed == 0x200); +} + +NTSTATUS +USB_BUSIFFN +USBDI_EnumLogEntry( + PVOID BusContext, + ULONG DriverTag, + ULONG EnumTag, + ULONG P1, + ULONG P2) +{ + UNIMPLEMENTED + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +CHubController::HandleQueryInterface( + PIO_STACK_LOCATION IoStack) +{ + PUSB_BUS_INTERFACE_HUB_V5 InterfaceHub; + PUSB_BUS_INTERFACE_USBDI_V2 InterfaceDI; + UNICODE_STRING GuidBuffer; + NTSTATUS Status; + + if (IsEqualGUIDAligned(*IoStack->Parameters.QueryInterface.InterfaceType, USB_BUS_INTERFACE_HUB_GUID)) + { + // + // get request parameters + // + InterfaceHub = (PUSB_BUS_INTERFACE_HUB_V5)IoStack->Parameters.QueryInterface.Interface; + InterfaceHub->Version = IoStack->Parameters.QueryInterface.Version; + + // + // check version + // + if (IoStack->Parameters.QueryInterface.Version >= 6) + { + DPRINT1("USB_BUS_INTERFACE_HUB_GUID version %x not supported!\n", IoStack->Parameters.QueryInterface.Version); + + // + // version not supported + // + return STATUS_NOT_SUPPORTED; + } + + // + // Interface version 0 + // + if (IoStack->Parameters.QueryInterface.Version >= 0) + { + InterfaceHub->Size = IoStack->Parameters.QueryInterface.Size; + InterfaceHub->BusContext = PVOID(this); + InterfaceHub->InterfaceReference = USBI_InterfaceReference; + InterfaceHub->InterfaceDereference = USBI_InterfaceDereference; + } + + // + // Interface version 1 + // + if (IoStack->Parameters.QueryInterface.Version >= 1) + { + InterfaceHub->CreateUsbDevice = USBHI_CreateUsbDevice; + InterfaceHub->InitializeUsbDevice = USBHI_InitializeUsbDevice; + InterfaceHub->GetUsbDescriptors = USBHI_GetUsbDescriptors; + InterfaceHub->RemoveUsbDevice = USBHI_RemoveUsbDevice; + InterfaceHub->RestoreUsbDevice = USBHI_RestoreUsbDevice; + InterfaceHub->QueryDeviceInformation = USBHI_QueryDeviceInformation; + } + + // + // Interface version 2 + // + if (IoStack->Parameters.QueryInterface.Version >= 2) + { + InterfaceHub->GetControllerInformation = USBHI_GetControllerInformation; + InterfaceHub->ControllerSelectiveSuspend = USBHI_ControllerSelectiveSuspend; + InterfaceHub->GetExtendedHubInformation = USBHI_GetExtendedHubInformation; + InterfaceHub->GetRootHubSymbolicName = USBHI_GetRootHubSymbolicName; + InterfaceHub->GetDeviceBusContext = USBHI_GetDeviceBusContext; + } + + // + // Interface version 3 + // + if (IoStack->Parameters.QueryInterface.Version >= 3) + { + InterfaceHub->RootHubInitNotification = USBHI_RootHubInitNotification; + } + + // + // Interface version 4 + // + if (IoStack->Parameters.QueryInterface.Version >= 4) + { + InterfaceHub->FlushTransfers = USBHI_FlushTransfers; + } + + // + // Interface version 5 + // + if (IoStack->Parameters.QueryInterface.Version >= 5) + { + InterfaceHub->SetDeviceHandleData = USBHI_SetDeviceHandleData; + } + + // + // request completed + // + return STATUS_SUCCESS; + } + else if (IsEqualGUIDAligned(*IoStack->Parameters.QueryInterface.InterfaceType, USB_BUS_INTERFACE_USBDI_GUID)) + { + // + // get request parameters + // + InterfaceDI = (PUSB_BUS_INTERFACE_USBDI_V2) IoStack->Parameters.QueryInterface.Interface; + InterfaceDI->Version = IoStack->Parameters.QueryInterface.Version; + + // + // check version + // + if (IoStack->Parameters.QueryInterface.Version >= 3) + { + DPRINT1("USB_BUS_INTERFACE_USBDI_GUID version %x not supported!\n", IoStack->Parameters.QueryInterface.Version); + + // + // version not supported + // + return STATUS_NOT_SUPPORTED; + } + + // + // interface version 0 + // + if (IoStack->Parameters.QueryInterface.Version >= 0) + { + InterfaceDI->Size = IoStack->Parameters.QueryInterface.Size; + InterfaceDI->BusContext = PVOID(this); + InterfaceDI->InterfaceReference = USBI_InterfaceReference; + InterfaceDI->InterfaceDereference = USBI_InterfaceDereference; + InterfaceDI->GetUSBDIVersion = USBDI_GetUSBDIVersion; + InterfaceDI->QueryBusTime = USBDI_QueryBusTime; + InterfaceDI->SubmitIsoOutUrb = USBDI_SubmitIsoOutUrb; + InterfaceDI->QueryBusInformation = USBDI_QueryBusInformation; + } + + // + // interface version 1 + // + if (IoStack->Parameters.QueryInterface.Version >= 1) + { + InterfaceDI->IsDeviceHighSpeed = USBDI_IsDeviceHighSpeed; + } + + // + // interface version 2 + // + if (IoStack->Parameters.QueryInterface.Version >= 2) + { + InterfaceDI->EnumLogEntry = USBDI_EnumLogEntry; + } + + // + // request completed + // + return STATUS_SUCCESS; + } + else + { + // + // convert guid to string + // + Status = RtlStringFromGUID(*IoStack->Parameters.QueryInterface.InterfaceType, &GuidBuffer); + if (NT_SUCCESS(Status)) + { + // + // print interface + // + DPRINT1("HandleQueryInterface UNKNOWN INTERFACE GUID: %wZ Version %x\n", &GuidBuffer, IoStack->Parameters.QueryInterface.Version); + + // + // free guid buffer + // + RtlFreeUnicodeString(&GuidBuffer); + } + } + return STATUS_NOT_SUPPORTED; +} + +NTSTATUS +CHubController::SetDeviceInterface( + BOOLEAN Enable) +{ + NTSTATUS Status = STATUS_SUCCESS; + + if (Enable) + { + // + // register device interface + // + Status = IoRegisterDeviceInterface(m_HubControllerDeviceObject, &GUID_DEVINTERFACE_USB_HUB, 0, &m_HubDeviceInterfaceString); + + if (NT_SUCCESS(Status)) + { + // + // now enable the device interface + // + Status = IoSetDeviceInterfaceState(&m_HubDeviceInterfaceString, TRUE); + + // + // enable interface + // + m_InterfaceEnabled = TRUE; + } + } + else if (m_InterfaceEnabled) + { + // + // disable device interface + // + Status = IoSetDeviceInterfaceState(&m_HubDeviceInterfaceString, FALSE); + + if (NT_SUCCESS(Status)) + { + // + // now delete interface string + // + RtlFreeUnicodeString(&m_HubDeviceInterfaceString); + } + + // + // disable interface + // + m_InterfaceEnabled = FALSE; + } + + // + // done + // + return Status; +} + +NTSTATUS +CHubController::CreatePDO( + 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\\USBPDO-%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("CreatePDO: Failed to create %wZ, Status %x\n", &DeviceName, Status); + return Status; + } + } + + DPRINT1("CHubController::CreatePDO: DeviceName %wZ\n", &DeviceName); + + // + // fixup device stack voodoo part #1 + // + (*OutDeviceObject)->StackSize++; + + /* done */ + return Status; +} + + + +NTSTATUS +CreateHubController( + PHUBCONTROLLER *OutHcdController) +{ + PHUBCONTROLLER This; + + // + // allocate controller + // + This = new(NonPagedPool, TAG_USBOHCI) CHubController(0); + if (!This) + { + // + // failed to allocate + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // add reference count + // + This->AddRef(); + + // + // return result + // + *OutHcdController = (PHUBCONTROLLER)This; + + // + // done + // + return STATUS_SUCCESS; +} + +VOID StatusChangeEndpointCallBack(PVOID Context) +{ + CHubController* This; + PIRP Irp; + This = (CHubController*)Context; + + ASSERT(This); + + Irp = This->m_PendingSCEIrp; + if (!Irp) + { + DPRINT1("There was no pending IRP for SCE. Did the usb hub 2.0 driver (usbhub2) load?\n"); + return; + } + + This->m_PendingSCEIrp = NULL; + This->QueryStatusChageEndpoint(Irp); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); +} diff --git a/drivers/usb/usbohci/interfaces.h b/drivers/usb/usbohci/interfaces.h new file mode 100644 index 00000000000..ac781d949d9 --- /dev/null +++ b/drivers/usb/usbohci/interfaces.h @@ -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 diff --git a/drivers/usb/usbohci/memory_manager.cpp b/drivers/usb/usbohci/memory_manager.cpp new file mode 100644 index 00000000000..0e6ffdddab7 --- /dev/null +++ b/drivers/usb/usbohci/memory_manager.cpp @@ -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; +} + diff --git a/drivers/usb/usbohci/misc.cpp b/drivers/usb/usbohci/misc.cpp new file mode 100644 index 00000000000..d4380da3eca --- /dev/null +++ b/drivers/usb/usbohci/misc.cpp @@ -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; +} + diff --git a/drivers/usb/usbohci/purecall.cpp b/drivers/usb/usbohci/purecall.cpp new file mode 100644 index 00000000000..75bc6f8e819 --- /dev/null +++ b/drivers/usb/usbohci/purecall.cpp @@ -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(); + + } +} + diff --git a/drivers/usb/usbohci/usb_device.cpp b/drivers/usb/usbohci/usb_device.cpp new file mode 100644 index 00000000000..d5e74e751ce --- /dev/null +++ b/drivers/usb/usbohci/usb_device.cpp @@ -0,0 +1,1286 @@ +/* + * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface + * LICENSE: GPL - See COPYING in the top level directory + * FILE: drivers/usb/usbohci/usb_device.cpp + * PURPOSE: USB OHCI device driver. + * PROGRAMMERS: + * Michael Martin (michael.martin@reactos.org) + * Johannes Anderwald (johannes.anderwald@reactos.org) + */ + +#define INITGUID +#include "usbohci.h" + +typedef struct _USB_ENDPOINT +{ + USB_ENDPOINT_DESCRIPTOR EndPointDescriptor; +} USB_ENDPOINT, *PUSB_ENDPOINT; + +typedef struct _USB_INTERFACE +{ + USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + USB_ENDPOINT *EndPoints; +} USB_INTERFACE, *PUSB_INTERFACE; + +typedef struct _USB_CONFIGURATION +{ + USB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; + USB_INTERFACE *Interfaces; +} USB_CONFIGURATION, *PUSB_CONFIGURATION; + + +class CUSBDevice : public IUSBDevice +{ +public: + 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; + } + + // IUSBDevice interface functions + virtual NTSTATUS Initialize(IN PHUBCONTROLLER HubController, IN PUSBHARDWAREDEVICE Device, IN PVOID Parent, IN ULONG Port, IN ULONG PortStatus); + virtual BOOLEAN IsHub(); + virtual NTSTATUS GetParent(PVOID * Parent); + virtual UCHAR GetDeviceAddress(); + virtual ULONG GetPort(); + virtual USB_DEVICE_SPEED GetSpeed(); + virtual USB_DEVICE_TYPE GetType(); + virtual ULONG GetState(); + virtual void SetDeviceHandleData(PVOID Data); + virtual NTSTATUS SetDeviceAddress(UCHAR DeviceAddress); + virtual void GetDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor); + virtual UCHAR GetConfigurationValue(); + virtual NTSTATUS SubmitIrp(PIRP Irp); + virtual VOID GetConfigurationDescriptors(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptorBuffer, IN ULONG BufferLength, OUT PULONG OutBufferLength); + virtual ULONG GetConfigurationDescriptorsLength(); + virtual NTSTATUS SubmitSetupPacket(IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, OUT ULONG BufferLength, OUT PVOID Buffer); + virtual NTSTATUS SelectConfiguration(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, IN PUSBD_INTERFACE_INFORMATION Interface, OUT USBD_CONFIGURATION_HANDLE *ConfigurationHandle); + virtual NTSTATUS SelectInterface(IN USBD_CONFIGURATION_HANDLE ConfigurationHandle, IN OUT PUSBD_INTERFACE_INFORMATION Interface); + + // local function + virtual NTSTATUS CommitIrp(PIRP Irp); + virtual NTSTATUS CommitSetupPacket(PUSB_DEFAULT_PIPE_SETUP_PACKET Packet, IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN ULONG BufferLength, IN OUT PMDL Mdl); + virtual NTSTATUS CreateConfigurationDescriptor(ULONG ConfigurationIndex); + virtual NTSTATUS CreateDeviceDescriptor(); + virtual VOID DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor); + virtual VOID DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor); + + // constructor / destructor + CUSBDevice(IUnknown *OuterUnknown){} + virtual ~CUSBDevice(){} + +protected: + LONG m_Ref; + PHUBCONTROLLER m_HubController; + PUSBHARDWAREDEVICE m_Device; + PVOID m_Parent; + ULONG m_Port; + UCHAR m_DeviceAddress; + PVOID m_Data; + UCHAR m_ConfigurationIndex; + KSPIN_LOCK m_Lock; + USB_DEVICE_DESCRIPTOR m_DeviceDescriptor; + ULONG m_PortStatus; + PUSBQUEUE m_Queue; + PDMAMEMORYMANAGER m_DmaManager; + + PUSB_CONFIGURATION m_ConfigurationDescriptors; +}; + +//---------------------------------------------------------------------------------------- +NTSTATUS +STDMETHODCALLTYPE +CUSBDevice::QueryInterface( + IN REFIID refiid, + OUT PVOID* Output) +{ + return STATUS_UNSUCCESSFUL; +} + +//---------------------------------------------------------------------------------------- +NTSTATUS +CUSBDevice::Initialize( + IN PHUBCONTROLLER HubController, + IN PUSBHARDWAREDEVICE Device, + IN PVOID Parent, + IN ULONG Port, + IN ULONG PortStatus) +{ + NTSTATUS Status; + + // + // initialize members + // + m_HubController = HubController; + m_Device = Device; + m_Parent = Parent; + m_Port = Port; + m_PortStatus = PortStatus; + + // + // initialize device lock + // + KeInitializeSpinLock(&m_Lock); + + // + // no device address has been set yet + // + m_DeviceAddress = 0; + + // + // get usb request queue + // + Status = m_Device->GetUSBQueue(&m_Queue); + if (!NT_SUCCESS(Status)) + { + // + // failed to get usb queue + // + DPRINT1("CUSBDevice::Initialize GetUsbQueue failed with %x\n", Status); + return Status; + } + + // + // get dma manager + // + Status = m_Device->GetDMA(&m_DmaManager); + if (!NT_SUCCESS(Status)) + { + // + // failed to get dma manager + // + DPRINT1("CUSBDevice::Initialize GetDMA failed with %x\n", Status); + return Status; + } + + // + // sanity check + // + PC_ASSERT(m_DmaManager); + + // + // get device descriptor + // + Status = CreateDeviceDescriptor(); + if (!NT_SUCCESS(Status)) + { + // + // failed to get device descriptor + // + DPRINT1("CUSBDevice::Initialize Failed to get device descriptor with %x\n", Status); + return Status; + } + + // + // done + // + return Status; +} + +//---------------------------------------------------------------------------------------- +BOOLEAN +CUSBDevice::IsHub() +{ + // + // USB Standard Device Class see http://www.usb.org/developers/defined_class/#BaseClass09h + // for details + // + return (m_DeviceDescriptor.bDeviceClass == 0x09 && m_DeviceDescriptor.bDeviceSubClass == 0x00); +} + +//---------------------------------------------------------------------------------------- +NTSTATUS +CUSBDevice::GetParent( + PVOID * Parent) +{ + // + // returns parent + // + *Parent = m_Parent; + + // + // done + // + return STATUS_SUCCESS; +} + +//---------------------------------------------------------------------------------------- +UCHAR +CUSBDevice::GetDeviceAddress() +{ + // + // get device address + // + return m_DeviceAddress; +} + +//---------------------------------------------------------------------------------------- +ULONG +CUSBDevice::GetPort() +{ + // + // get port to which this device is connected to + // + return m_Port; +} + +//---------------------------------------------------------------------------------------- +USB_DEVICE_SPEED +CUSBDevice::GetSpeed() +{ + if (m_PortStatus & USB_PORT_STATUS_LOW_SPEED) + { + // + // low speed device + // + return UsbLowSpeed; + } + else if (m_PortStatus & USB_PORT_STATUS_HIGH_SPEED) + { + // + // high speed device + // + return UsbHighSpeed; + } + + // + // default to full speed + // + return UsbFullSpeed; +} + +//---------------------------------------------------------------------------------------- +USB_DEVICE_TYPE +CUSBDevice::GetType() +{ + // + // device is encoded into bcdUSB + // + if (m_DeviceDescriptor.bcdUSB == 0x110) + { + // + // USB 1.1 device + // + return Usb11Device; + } + else if (m_DeviceDescriptor.bcdUSB == 0x200) + { + // + // USB 2.0 device + // + return Usb20Device; + } + + DPRINT1("CUSBDevice::GetType Unknown bcdUSB Type %x\n", m_DeviceDescriptor.bcdUSB); + PC_ASSERT(FALSE); + + return Usb11Device; +} + +//---------------------------------------------------------------------------------------- +ULONG +CUSBDevice::GetState() +{ + UNIMPLEMENTED + return FALSE; +} + +//---------------------------------------------------------------------------------------- +void +CUSBDevice::SetDeviceHandleData( + PVOID Data) +{ + // + // set device data, for debugging issues + // + m_Data = Data; +} + +//---------------------------------------------------------------------------------------- +NTSTATUS +CUSBDevice::SetDeviceAddress( + UCHAR DeviceAddress) +{ + PUSB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup; + NTSTATUS Status; + UCHAR OldAddress; + ULONG Index; + + DPRINT1("CUSBDevice::SetDeviceAddress Address %d\n", DeviceAddress); + + CtrlSetup = (PUSB_DEFAULT_PIPE_SETUP_PACKET)ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET), TAG_USBOHCI); + if (!CtrlSetup) + return STATUS_INSUFFICIENT_RESOURCES; + + // + // zero request + // + RtlZeroMemory(CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); + + // + // initialize request + // + CtrlSetup->bRequest = USB_REQUEST_SET_ADDRESS; + CtrlSetup->wValue.W = (USHORT)DeviceAddress; + + // + // set device address + // + Status = CommitSetupPacket(CtrlSetup, 0, 0, 0); + + // + // free setup packet + // + ExFreePoolWithTag(CtrlSetup, TAG_USBOHCI); + + // + // check for success + // + if (!NT_SUCCESS(Status)) + { + // + // failed to set device address + // + DPRINT1("CUSBDevice::SetDeviceAddress> failed to set device address with %x Address %x\n", Status, DeviceAddress); + return Status; + } + + // + // lets have a short nap + // + KeStallExecutionProcessor(300); + + // + // back up old address + // + OldAddress = m_DeviceAddress; + + // + // store new device address + // + m_DeviceAddress = DeviceAddress; + + // + // check that setting device address succeeded by retrieving the device descriptor + // + Status = CreateDeviceDescriptor(); + if (!NT_SUCCESS(Status)) + { + // + // failed to retrieve device descriptor + // + DPRINT1("CUSBbDevice::SetDeviceAddress> failed to retrieve device descriptor with device address set Error %x\n", Status); + m_DeviceAddress = OldAddress; + + // + // return error status + // + return Status; + } + + // + // sanity checks + // + PC_ASSERT(m_DeviceDescriptor.bNumConfigurations); + + // + // allocate configuration descriptor + // + m_ConfigurationDescriptors = (PUSB_CONFIGURATION) ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_CONFIGURATION) * m_DeviceDescriptor.bNumConfigurations, TAG_USBOHCI); + + // + // zero configuration descriptor + // + RtlZeroMemory(m_ConfigurationDescriptors, sizeof(USB_CONFIGURATION) * m_DeviceDescriptor.bNumConfigurations); + + // + // retrieve the configuration descriptors + // + for(Index = 0; Index < m_DeviceDescriptor.bNumConfigurations; Index++) + { + // + // retrieve configuration descriptors from device + // + Status = CreateConfigurationDescriptor(Index); + if (!NT_SUCCESS(Status)) + { + DPRINT1("CUSBDevice::SetDeviceAddress> failed to retrieve configuration %lu\n", Index); + break; + } + } + + // + // done + // + return Status; + +} + +//---------------------------------------------------------------------------------------- +void +CUSBDevice::GetDeviceDescriptor( + PUSB_DEVICE_DESCRIPTOR DeviceDescriptor) +{ + RtlMoveMemory(DeviceDescriptor, &m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR)); +} + +//---------------------------------------------------------------------------------------- +UCHAR +CUSBDevice::GetConfigurationValue() +{ + // + // return configuration index + // + return m_ConfigurationIndex; +} + +//---------------------------------------------------------------------------------------- +NTSTATUS +CUSBDevice::CommitIrp( + PIRP Irp) +{ + NTSTATUS Status; + PUSBREQUEST Request; + + if (!m_Queue || !m_DmaManager) + { + // + // no queue, wtf? + // + DPRINT1("CUSBDevice::CommitUrb> no queue / dma !!!\n"); + return STATUS_UNSUCCESSFUL; + } + + // + // build usb request + // + Status = m_Queue->CreateUSBRequest(&Request); + if (!NT_SUCCESS(Status)) + { + // + // failed to build request + // + DPRINT1("CUSBDevice::CommitSetupPacket> CreateUSBRequest failed with %x\n", Status); + return Status; + } + + // + // initialize request + // + Status = Request->InitializeWithIrp(m_DmaManager, Irp); + + // + // mark irp as pending + // + IoMarkIrpPending(Irp); + + // + // now add the request + // + Status = m_Queue->AddUSBRequest(Request); + if (!NT_SUCCESS(Status)) + { + // + // failed to add request + // + DPRINT1("CUSBDevice::CommitSetupPacket> failed add request to queue with %x\n", Status); + Request->Release(); + return Status; + } + + // + // done + // + return STATUS_PENDING; +} + +//---------------------------------------------------------------------------------------- +NTSTATUS +CUSBDevice::SubmitIrp( + PIRP Irp) +{ + KIRQL OldLevel; + NTSTATUS Status; + + // + // acquire device lock + // + KeAcquireSpinLock(&m_Lock, &OldLevel); + + // + // commit urb + // + Status = CommitIrp(Irp); + + // + // release lock + // + KeReleaseSpinLock(&m_Lock, OldLevel); + + return Status; +} +//---------------------------------------------------------------------------------------- +NTSTATUS +CUSBDevice::CommitSetupPacket( + IN PUSB_DEFAULT_PIPE_SETUP_PACKET Packet, + IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, + IN ULONG BufferLength, + IN OUT PMDL Mdl) +{ + NTSTATUS Status; + PUSBREQUEST Request; + + if (!m_Queue) + { + // + // no queue, wtf? + // + DPRINT1("CUSBDevice::CommitSetupPacket> no queue!!!\n"); + return STATUS_UNSUCCESSFUL; + } + + // + // build usb request + // + Status = m_Queue->CreateUSBRequest(&Request); + if (!NT_SUCCESS(Status)) + { + // + // failed to build request + // + DPRINT1("CUSBDevice::CommitSetupPacket> CreateUSBRequest failed with %x\n", Status); + return Status; + } + + // + // initialize request + // + Status = Request->InitializeWithSetupPacket(m_DmaManager, Packet, m_DeviceAddress, EndpointDescriptor, BufferLength, Mdl); + if (!NT_SUCCESS(Status)) + { + // + // failed to initialize request + // + DPRINT1("CUSBDevice::CommitSetupPacket> failed to initialize usb request with %x\n", Status); + Request->Release(); + return Status; + } + + // + // now add the request + // + Status = m_Queue->AddUSBRequest(Request); + if (!NT_SUCCESS(Status)) + { + // + // failed to add request + // + DPRINT1("CUSBDevice::CommitSetupPacket> failed add request to queue with %x\n", Status); + Request->Release(); + return Status; + } + + // + // get the result code when the operation has been finished + // + Request->GetResultStatus(&Status, NULL); + + // + // release request + // + Request->Release(); + + // + // done + // + return Status; +} + +//---------------------------------------------------------------------------------------- +NTSTATUS +CUSBDevice::CreateDeviceDescriptor() +{ + USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup; + PMDL Mdl; + NTSTATUS Status; + + // + // zero descriptor + // + RtlZeroMemory(&m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR)); + RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); + + // + // setup request + // + CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR; + CtrlSetup.wValue.HiByte = USB_DEVICE_DESCRIPTOR_TYPE; + CtrlSetup.wLength = sizeof(USB_DEVICE_DESCRIPTOR); + CtrlSetup.bmRequestType.B = 0x80; + + // + // allocate mdl describing the device descriptor + // + Mdl = IoAllocateMdl(&m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR), FALSE, FALSE, 0); + if (!Mdl) + { + // + // failed to allocate mdl + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // build mdl for non paged pool + // + MmBuildMdlForNonPagedPool(Mdl); + + // + // commit setup packet + // + Status = CommitSetupPacket(&CtrlSetup, 0, sizeof(USB_DEVICE_DESCRIPTOR), Mdl); + + // + // now free the mdl + // + IoFreeMdl(Mdl); + + if (NT_SUCCESS(Status)) + { + // + // informal dbg print + // + DumpDeviceDescriptor(&m_DeviceDescriptor); + } + + // + // done + // + return Status; + +} + +//---------------------------------------------------------------------------------------- +NTSTATUS +CUSBDevice::CreateConfigurationDescriptor( + ULONG Index) +{ + PVOID Buffer; + USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup; + NTSTATUS Status; + PMDL Mdl; + ULONG InterfaceIndex, EndPointIndex; + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + PUSB_ENDPOINT_DESCRIPTOR EndPointDescriptor; + + + // + // sanity checks + // + PC_ASSERT(m_ConfigurationDescriptors); + + // + // first allocate a buffer which should be enough to store all different interfaces and endpoints + // + Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_USBOHCI); + if (!Buffer) + { + // + // failed to allocate buffer + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // build setup packet + // + CtrlSetup.bmRequestType._BM.Recipient = BMREQUEST_TO_DEVICE; + CtrlSetup.bmRequestType._BM.Type = BMREQUEST_STANDARD; + CtrlSetup.bmRequestType._BM.Reserved = 0; + CtrlSetup.bmRequestType._BM.Dir = BMREQUEST_DEVICE_TO_HOST; + CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR; + CtrlSetup.wValue.LowByte = 0; + CtrlSetup.wValue.HiByte = USB_CONFIGURATION_DESCRIPTOR_TYPE; + CtrlSetup.wIndex.W = 0; + CtrlSetup.wLength = PAGE_SIZE; + + // + // FIXME: where put configuration index? + // + + // + // now build MDL describing the buffer + // + Mdl = IoAllocateMdl(Buffer, PAGE_SIZE, FALSE, FALSE, 0); + if (!Mdl) + { + // + // failed to allocate mdl + // + ExFreePoolWithTag(Buffer, TAG_USBOHCI); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // build mdl for non paged pool + // + MmBuildMdlForNonPagedPool(Mdl); + + // + // commit packet + // + Status = CommitSetupPacket(&CtrlSetup, 0, PAGE_SIZE, Mdl); + if (!NT_SUCCESS(Status)) + { + // + // failed to issue request, cleanup + // + IoFreeMdl(Mdl); + ExFreePool(Buffer); + return Status; + } + + // + // now free the mdl + // + IoFreeMdl(Mdl); + + // + // get configuration descriptor + // + ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)Buffer; + + // + // informal debug print + // + DumpConfigurationDescriptor(ConfigurationDescriptor); + + // + // sanity check + // + PC_ASSERT(ConfigurationDescriptor->bLength == sizeof(USB_CONFIGURATION_DESCRIPTOR)); + PC_ASSERT(ConfigurationDescriptor->wTotalLength <= PAGE_SIZE); + PC_ASSERT(ConfigurationDescriptor->bNumInterfaces); + + // + // request is complete, initialize configuration descriptor + // + RtlCopyMemory(&m_ConfigurationDescriptors[Index].ConfigurationDescriptor, ConfigurationDescriptor, ConfigurationDescriptor->bLength); + + // + // now allocate interface descriptors + // + m_ConfigurationDescriptors[Index].Interfaces = (PUSB_INTERFACE)ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_INTERFACE) * ConfigurationDescriptor->bNumInterfaces, TAG_USBOHCI); + if (!m_ConfigurationDescriptors[Index].Interfaces) + { + // + // failed to allocate interface descriptors + // + ExFreePool(Buffer); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // zero interface descriptor + // + RtlZeroMemory(m_ConfigurationDescriptors[Index].Interfaces, sizeof(USB_INTERFACE) * ConfigurationDescriptor->bNumInterfaces); + + // + // get first interface descriptor + // + InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)(ConfigurationDescriptor + 1); + + // + // setup interface descriptors + // + for(InterfaceIndex = 0; InterfaceIndex < ConfigurationDescriptor->bNumInterfaces; InterfaceIndex++) + { + // + // sanity check + // + PC_ASSERT(InterfaceDescriptor->bLength == sizeof(USB_INTERFACE_DESCRIPTOR)); + PC_ASSERT(InterfaceDescriptor->bNumEndpoints); + + // + // copy current interface descriptor + // + RtlCopyMemory(&m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].InterfaceDescriptor, InterfaceDescriptor, InterfaceDescriptor->bLength); + + // + // allocate end point descriptors + // + m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].EndPoints = (PUSB_ENDPOINT)ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_ENDPOINT) * InterfaceDescriptor->bNumEndpoints, TAG_USBOHCI); + if (!m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].EndPoints) + { + // + // failed to allocate endpoint + // + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + // + // zero memory + // + RtlZeroMemory(m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].EndPoints, sizeof(USB_ENDPOINT) * InterfaceDescriptor->bNumEndpoints); + + // + // initialize end point descriptors + // + EndPointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)(InterfaceDescriptor + 1); + + for(EndPointIndex = 0; EndPointIndex < InterfaceDescriptor->bNumEndpoints; EndPointIndex++) + { + // + // sanity check + // + PC_ASSERT(EndPointDescriptor->bLength == sizeof(USB_ENDPOINT_DESCRIPTOR)); + + // + // copy endpoint descriptor + // + RtlCopyMemory(&m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].EndPoints[EndPointIndex].EndPointDescriptor, EndPointDescriptor, EndPointDescriptor->bLength); + + // + // move to next offset + // + EndPointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)EndPointDescriptor + EndPointDescriptor->bLength); + } + + // + // update interface descriptor offset + // + InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)EndPointDescriptor; + } + + // + // free buffer + // + ExFreePoolWithTag(Buffer, TAG_USBOHCI); + + // + // done + // + return Status; +} +//---------------------------------------------------------------------------------------- +VOID +CUSBDevice::GetConfigurationDescriptors( + IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptorBuffer, + IN ULONG BufferLength, + OUT PULONG OutBufferLength) +{ + PVOID Buffer; + ULONG InterfaceIndex, EndpointIndex; + + // + // sanity check + // + PC_ASSERT(BufferLength >= sizeof(USB_CONFIGURATION_DESCRIPTOR)); + PC_ASSERT(ConfigDescriptorBuffer); + PC_ASSERT(OutBufferLength); + + // + // reset copied length + // + *OutBufferLength = 0; + + // + // FIXME: support multiple configurations + // + PC_ASSERT(m_DeviceDescriptor.bNumConfigurations == 1); + + // + // copy first configuration descriptor + // + RtlCopyMemory(ConfigDescriptorBuffer, &m_ConfigurationDescriptors[0].ConfigurationDescriptor, sizeof(USB_CONFIGURATION_DESCRIPTOR)); + + // + // subtract length + // + BufferLength -= sizeof(USB_CONFIGURATION_DESCRIPTOR); + *OutBufferLength += sizeof(USB_CONFIGURATION_DESCRIPTOR); + + // + // increment offset + // + Buffer = (PVOID)(ConfigDescriptorBuffer + 1); + + for(InterfaceIndex = 0; InterfaceIndex < m_ConfigurationDescriptors[0].ConfigurationDescriptor.bNumInterfaces; InterfaceIndex++) + { + if (BufferLength < sizeof(USB_INTERFACE_DESCRIPTOR)) + { + // + // no more room in buffer + // + return; + } + + // + // copy interface descriptor + // + RtlCopyMemory(Buffer, &m_ConfigurationDescriptors[0].Interfaces[InterfaceIndex].InterfaceDescriptor, sizeof(USB_INTERFACE_DESCRIPTOR)); + + // + // increment offset + // + Buffer = (PVOID)((ULONG_PTR)Buffer + sizeof(USB_INTERFACE_DESCRIPTOR)); + BufferLength -= sizeof(USB_INTERFACE_DESCRIPTOR); + *OutBufferLength += sizeof(USB_INTERFACE_DESCRIPTOR); + + // + // does the interface have endpoints + // + if (m_ConfigurationDescriptors[0].Interfaces[InterfaceIndex].InterfaceDescriptor.bNumEndpoints) + { + // + // is enough space available + // + if (BufferLength < sizeof(USB_ENDPOINT_DESCRIPTOR) * m_ConfigurationDescriptors[0].Interfaces[InterfaceIndex].InterfaceDescriptor.bNumEndpoints) + { + // + // no buffer + // + return; + } + + // + // copy end points + // + for(EndpointIndex = 0; EndpointIndex < m_ConfigurationDescriptors[0].Interfaces[InterfaceIndex].InterfaceDescriptor.bNumEndpoints; EndpointIndex++) + { + // + // copy endpoint + // + RtlCopyMemory(Buffer, &m_ConfigurationDescriptors[0].Interfaces[InterfaceIndex].EndPoints[EndpointIndex].EndPointDescriptor, sizeof(USB_ENDPOINT_DESCRIPTOR)); + + // + // increment buffer offset + // + Buffer = (PVOID)((ULONG_PTR)Buffer + sizeof(USB_ENDPOINT_DESCRIPTOR)); + BufferLength -= sizeof(USB_ENDPOINT_DESCRIPTOR); + *OutBufferLength += sizeof(USB_ENDPOINT_DESCRIPTOR); + } + } + } +} + +//---------------------------------------------------------------------------------------- +ULONG +CUSBDevice::GetConfigurationDescriptorsLength() +{ + // + // FIXME: support multiple configurations + // + PC_ASSERT(m_DeviceDescriptor.bNumConfigurations == 1); + + return m_ConfigurationDescriptors[0].ConfigurationDescriptor.wTotalLength; +} +//---------------------------------------------------------------------------------------- +VOID +CUSBDevice::DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor) +{ + DPRINT1("Dumping Device Descriptor %x\n", DeviceDescriptor); + DPRINT1("bLength %x\n", DeviceDescriptor->bLength); + DPRINT1("bDescriptorType %x\n", DeviceDescriptor->bDescriptorType); + DPRINT1("bcdUSB %x\n", DeviceDescriptor->bcdUSB); + DPRINT1("bDeviceClass %x\n", DeviceDescriptor->bDeviceClass); + DPRINT1("bDeviceSubClass %x\n", DeviceDescriptor->bDeviceSubClass); + DPRINT1("bDeviceProtocol %x\n", DeviceDescriptor->bDeviceProtocol); + DPRINT1("bMaxPacketSize0 %x\n", DeviceDescriptor->bMaxPacketSize0); + DPRINT1("idVendor %x\n", DeviceDescriptor->idVendor); + DPRINT1("idProduct %x\n", DeviceDescriptor->idProduct); + DPRINT1("bcdDevice %x\n", DeviceDescriptor->bcdDevice); + DPRINT1("iManufacturer %x\n", DeviceDescriptor->iManufacturer); + DPRINT1("iProduct %x\n", DeviceDescriptor->iProduct); + DPRINT1("iSerialNumber %x\n", DeviceDescriptor->iSerialNumber); + DPRINT1("bNumConfigurations %x\n", DeviceDescriptor->bNumConfigurations); +} + +//---------------------------------------------------------------------------------------- +VOID +CUSBDevice::DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor) +{ + DPRINT1("Dumping ConfigurationDescriptor %x\n", ConfigurationDescriptor); + DPRINT1("bLength %x\n", ConfigurationDescriptor->bLength); + DPRINT1("bDescriptorType %x\n", ConfigurationDescriptor->bDescriptorType); + DPRINT1("wTotalLength %x\n", ConfigurationDescriptor->wTotalLength); + DPRINT1("bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces); + DPRINT1("bConfigurationValue %x\n", ConfigurationDescriptor->bConfigurationValue); + DPRINT1("iConfiguration %x\n", ConfigurationDescriptor->iConfiguration); + DPRINT1("bmAttributes %x\n", ConfigurationDescriptor->bmAttributes); + DPRINT1("MaxPower %x\n", ConfigurationDescriptor->MaxPower); +} +//---------------------------------------------------------------------------------------- +NTSTATUS +CUSBDevice::SubmitSetupPacket( + IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, + IN OUT ULONG BufferLength, + OUT PVOID Buffer) +{ + NTSTATUS Status; + PMDL Mdl; + + // + // allocate mdl + // + Mdl = IoAllocateMdl(Buffer, BufferLength, FALSE, FALSE, 0); + + // + // HACK HACK HACK: assume the buffer is build from non paged pool + // + MmBuildMdlForNonPagedPool(Mdl); + + // + // commit setup packet + // + Status = CommitSetupPacket(SetupPacket, 0, BufferLength, Mdl); + + // + // free mdl + // + IoFreeMdl(Mdl); + + // + // done + // + return Status; +} + +//---------------------------------------------------------------------------------------- +NTSTATUS +CUSBDevice::SelectConfiguration( + IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, + IN PUSBD_INTERFACE_INFORMATION InterfaceInfo, + OUT USBD_CONFIGURATION_HANDLE *ConfigurationHandle) +{ + ULONG ConfigurationIndex = 0; + ULONG InterfaceIndex, PipeIndex; + USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup; + NTSTATUS Status; + + // + // FIXME: support multiple configurations + // + PC_ASSERT(m_DeviceDescriptor.bNumConfigurations == 1); + PC_ASSERT(ConfigurationDescriptor->iConfiguration == m_ConfigurationDescriptors[ConfigurationIndex].ConfigurationDescriptor.iConfiguration); + + // + // sanity check + // + PC_ASSERT(ConfigurationDescriptor->bNumInterfaces <= m_ConfigurationDescriptors[ConfigurationIndex].ConfigurationDescriptor.bNumInterfaces); + + // + // copy interface info and pipe info + // + for(InterfaceIndex = 0; InterfaceIndex < ConfigurationDescriptor->bNumInterfaces; InterfaceIndex++) + { + // + // sanity check: is the info pre-layed out + // + PC_ASSERT(InterfaceInfo->NumberOfPipes == m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex].InterfaceDescriptor.bNumEndpoints); + PC_ASSERT(InterfaceInfo->Length != 0); +#ifdef _MSC_VER + PC_ASSERT(InterfaceInfo->Length == FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes[InterfaceInfo->NumberOfPipes])); +#endif + + // + // copy interface info + // + InterfaceInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)&m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex]; + InterfaceInfo->Class = m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex].InterfaceDescriptor.bInterfaceClass; + InterfaceInfo->SubClass = m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex].InterfaceDescriptor.bInterfaceSubClass; + InterfaceInfo->Protocol = m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex].InterfaceDescriptor.bInterfaceProtocol; + InterfaceInfo->Reserved = 0; + + // + // copy endpoint info + // + for(PipeIndex = 0; PipeIndex < InterfaceInfo->NumberOfPipes; PipeIndex++) + { + // + // copy pipe info + // + InterfaceInfo->Pipes[PipeIndex].MaximumPacketSize = m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex].EndPoints[PipeIndex].EndPointDescriptor.wMaxPacketSize; + InterfaceInfo->Pipes[PipeIndex].EndpointAddress = m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex].EndPoints[PipeIndex].EndPointDescriptor.bEndpointAddress; + InterfaceInfo->Pipes[PipeIndex].Interval = m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex].EndPoints[PipeIndex].EndPointDescriptor.bInterval; + InterfaceInfo->Pipes[PipeIndex].PipeType = (USBD_PIPE_TYPE)m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex].EndPoints[PipeIndex].EndPointDescriptor.bmAttributes; + InterfaceInfo->Pipes[PipeIndex].PipeHandle = (PVOID)&m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex].EndPoints[PipeIndex].EndPointDescriptor; + } + + // + // move offset + // + InterfaceInfo = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)PtrToUlong(InterfaceInfo) + InterfaceInfo->Length); + } + + // + // now build setup packet + // + RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); + CtrlSetup.bRequest = USB_REQUEST_SET_CONFIGURATION; + CtrlSetup.wValue.W = ConfigurationDescriptor->bConfigurationValue; + + // + // select configuration + // + Status = CommitSetupPacket(&CtrlSetup, 0, 0, 0); + + // + // informal debug print + // + DPRINT1("CUsbDevice::SelectConfiguration New Configuration %x Old Configuration %x Result %x\n", ConfigurationDescriptor->iConfiguration, m_ConfigurationIndex, Status); + + if (NT_SUCCESS(Status)) + { + // + // store configuration device index + // + m_ConfigurationIndex = ConfigurationDescriptor->iConfiguration; + + // + // store configuration handle + // + *ConfigurationHandle = &m_ConfigurationDescriptors[ConfigurationIndex]; + } + + // + // done + // + return Status; +} + +//---------------------------------------------------------------------------------------- +NTSTATUS +CUSBDevice::SelectInterface( + IN USBD_CONFIGURATION_HANDLE ConfigurationHandle, + IN OUT PUSBD_INTERFACE_INFORMATION InterfaceInfo) +{ + ULONG ConfigurationIndex = 0; + PUSB_CONFIGURATION Configuration; + ULONG PipeIndex; + USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup; + NTSTATUS Status; + + // + // FIXME support multiple configurations + // + PC_ASSERT(&m_ConfigurationDescriptors[ConfigurationIndex] == (PUSB_CONFIGURATION)ConfigurationHandle); + + // + // get configuration struct + // + Configuration = (PUSB_CONFIGURATION)ConfigurationHandle; + + // + // sanity checks + // + PC_ASSERT(Configuration->ConfigurationDescriptor.bNumInterfaces > InterfaceInfo->InterfaceNumber); + PC_ASSERT(Configuration->Interfaces[InterfaceInfo->InterfaceNumber].InterfaceDescriptor.bNumEndpoints == InterfaceInfo->NumberOfPipes); +#ifdef _MSC_VER + PC_ASSERT(InterfaceInfo->Length == FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes[InterfaceInfo->NumberOfPipes])); +#endif + + // + // copy pipe handles + // + for(PipeIndex = 0; PipeIndex < InterfaceInfo->NumberOfPipes; PipeIndex++) + { + // + // copy pipe handle + // + DPRINT1("PipeIndex %lu\n", PipeIndex); + DPRINT1("EndpointAddress %x\n", InterfaceInfo->Pipes[PipeIndex].EndpointAddress); + DPRINT1("Interval %d\n", InterfaceInfo->Pipes[PipeIndex].Interval); + DPRINT1("MaximumPacketSize %d\n", InterfaceInfo->Pipes[PipeIndex].MaximumPacketSize); + DPRINT1("MaximumTransferSize %d\n", InterfaceInfo->Pipes[PipeIndex].MaximumTransferSize); + DPRINT1("PipeFlags %d\n", InterfaceInfo->Pipes[PipeIndex].PipeFlags); + DPRINT1("PipeType %dd\n", InterfaceInfo->Pipes[PipeIndex].PipeType); + DPRINT1("UsbEndPoint %x\n", Configuration->Interfaces[InterfaceInfo->InterfaceNumber].EndPoints[PipeIndex].EndPointDescriptor.bEndpointAddress); + PC_ASSERT(Configuration->Interfaces[InterfaceInfo->InterfaceNumber].EndPoints[PipeIndex].EndPointDescriptor.bEndpointAddress == InterfaceInfo->Pipes[PipeIndex].EndpointAddress); + + InterfaceInfo->Pipes[PipeIndex].PipeHandle = &Configuration->Interfaces[InterfaceInfo->InterfaceNumber].EndPoints[PipeIndex].EndPointDescriptor; + + if (Configuration->Interfaces[InterfaceInfo->InterfaceNumber].EndPoints[PipeIndex].EndPointDescriptor.bmAttributes & (USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_TYPE_INTERRUPT)) + { + // + // FIXME: check if enough bandwidth is available + // + } + } + + // + // initialize setup packet + // + RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); + CtrlSetup.bRequest = USB_REQUEST_SET_INTERFACE; + CtrlSetup.wValue.W = Configuration->Interfaces[InterfaceInfo->InterfaceNumber].InterfaceDescriptor.bAlternateSetting; + CtrlSetup.wIndex.W = Configuration->Interfaces[InterfaceInfo->InterfaceNumber].InterfaceDescriptor.bInterfaceNumber; + CtrlSetup.bmRequestType.B = 0x01; + + // + // issue request + // + Status = CommitSetupPacket(&CtrlSetup, 0, 0, 0); + + // + // informal debug print + // + DPRINT1("CUSBDevice::SelectInterface AlternateSetting %x InterfaceNumber %x Status %x\n", InterfaceInfo->AlternateSetting, InterfaceInfo->InterfaceNumber, Status); + + // + // done + // + return Status; +} + +//---------------------------------------------------------------------------------------- +NTSTATUS +CreateUSBDevice( + PUSBDEVICE *OutDevice) +{ + CUSBDevice * This; + + // + // allocate controller + // + This = new(NonPagedPool, TAG_USBOHCI) CUSBDevice(0); + if (!This) + { + // + // failed to allocate + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // add reference count + // + This->AddRef(); + + // + // return result + // + *OutDevice = (PUSBDEVICE)This; + + // + // done + // + return STATUS_SUCCESS; +} + diff --git a/drivers/usb/usbohci/usb_queue.cpp b/drivers/usb/usbohci/usb_queue.cpp new file mode 100644 index 00000000000..9509a34bbb9 --- /dev/null +++ b/drivers/usb/usbohci/usb_queue.cpp @@ -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; +} diff --git a/drivers/usb/usbohci/usb_request.cpp b/drivers/usb/usbohci/usb_request.cpp new file mode 100644 index 00000000000..5ede8db513c --- /dev/null +++ b/drivers/usb/usbohci/usb_request.cpp @@ -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; +} diff --git a/drivers/usb/usbohci/usbohci.cpp b/drivers/usb/usbohci/usbohci.cpp new file mode 100644 index 00000000000..9d79e3cfbc5 --- /dev/null +++ b/drivers/usb/usbohci/usbohci.cpp @@ -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; +} diff --git a/drivers/usb/usbohci/usbohci.h b/drivers/usb/usbohci/usbohci.h new file mode 100644 index 00000000000..2743c472038 --- /dev/null +++ b/drivers/usb/usbohci/usbohci.h @@ -0,0 +1,103 @@ +#ifndef USBOHCI_H__ +#define USBOHCI_H__ + +#include +#define NDEBUG +#include +#include +#include +#include +// +// FIXME: +// #include +// +#include +#include +#include + +// +// FIXME: +// the following includes are required to get kcom to compile +// +#include +#include +#include + +#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 diff --git a/drivers/usb/usbohci/usbohci.rc b/drivers/usb/usbohci/usbohci.rc new file mode 100644 index 00000000000..000ffdee9f9 --- /dev/null +++ b/drivers/usb/usbohci/usbohci.rc @@ -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