add_subdirectory(csq)
add_subdirectory(hidparser)
add_subdirectory(ip)
+add_subdirectory(libusb)
add_subdirectory(lwip)
add_subdirectory(sound)
--- /dev/null
+set_cpp()
+
+remove_definitions(-D_WIN32_WINNT=0x502)
+add_definitions(-D_WIN32_WINNT=0x600)
+
+
+add_definitions(
+ -DUNICODE -D_UNICODE)
+
+list(APPEND SOURCE
+ hcd_controller.cpp
+ hub_controller.cpp
+ memory_manager.cpp
+ misc.cpp
+ usb_device.cpp
+ purecall.cpp
+ libusb.cpp)
+
+add_library(libusb ${SOURCE})
+add_dependencies(libusb bugcodes)
+
--- /dev/null
+
+#ifndef COMMON_INTERFACES_HPP
+#define COMMON_INTERFACES_HPP
+
+typedef struct _USB_ENDPOINT
+{
+ USB_ENDPOINT_DESCRIPTOR EndPointDescriptor;
+ UCHAR HubAddress;
+ UCHAR HubPort;
+ UCHAR DataToggle;
+} USB_ENDPOINT, *PUSB_ENDPOINT;
+
+typedef struct _USB_INTERFACE
+{
+ LIST_ENTRY ListEntry;
+ PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+ USB_ENDPOINT EndPoints[1];
+} USB_INTERFACE, *PUSB_INTERFACE;
+
+typedef struct
+{
+ PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
+ LIST_ENTRY InterfaceList;
+}USB_CONFIGURATION, *PUSB_CONFIGURATION;
+
+//---------------------------------------------------------------------------
+//
+// 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;
+
+#define DEFINE_ABSTRACT_USBHARDWAREDEVICE() \
+ STDMETHOD_(NTSTATUS, Initialize)( THIS_ \
+ IN PDRIVER_OBJECT DriverObject, \
+ IN PDEVICE_OBJECT FunctionalDeviceObject, \
+ IN PDEVICE_OBJECT PhysicalDeviceObject, \
+ IN PDEVICE_OBJECT LowerDeviceObject) PURE; \
+ \
+ STDMETHOD_(NTSTATUS, PnpStart)( THIS_ \
+ IN PCM_RESOURCE_LIST RawResources, \
+ IN PCM_RESOURCE_LIST TranslatedResources) PURE; \
+ \
+ STDMETHOD_(NTSTATUS, PnpStop)( THIS) PURE; \
+ \
+ STDMETHOD_(NTSTATUS, GetDeviceDetails)( THIS_ \
+ OUT OPTIONAL PUSHORT VendorId, \
+ OUT OPTIONAL PUSHORT DeviceId, \
+ OUT OPTIONAL PULONG NumberOfPorts, \
+ OUT OPTIONAL PULONG Speed) PURE; \
+ \
+ STDMETHOD_(NTSTATUS, GetUSBQueue)( THIS_ \
+ OUT struct IUSBQueue **OutUsbQueue) PURE; \
+ \
+ STDMETHOD_(NTSTATUS, GetDMA)( THIS_ \
+ OUT struct IDMAMemoryManager **OutDMA) PURE; \
+ \
+ STDMETHOD_(NTSTATUS, ResetPort)( THIS_ \
+ IN ULONG PortNumber) PURE; \
+ \
+ STDMETHOD_(NTSTATUS, GetPortStatus)( THIS_ \
+ IN ULONG PortId, \
+ OUT USHORT *PortStatus, \
+ OUT USHORT *PortChange) PURE; \
+ \
+ STDMETHOD_(NTSTATUS, ClearPortStatus)( THIS_ \
+ IN ULONG PortId, \
+ IN ULONG Status) PURE; \
+ \
+ STDMETHOD_(NTSTATUS, SetPortFeature)( THIS_ \
+ IN ULONG PortId, \
+ IN ULONG Feature) PURE; \
+ \
+ STDMETHOD_(VOID, SetStatusChangeEndpointCallBack)( THIS_ \
+ IN PVOID CallBack, \
+ IN PVOID Context) PURE;
+
+
+#define IMP_IUSBHARDWAREDEVICE \
+ STDMETHODIMP_(NTSTATUS) Initialize( \
+ IN PDRIVER_OBJECT DriverObject, \
+ IN PDEVICE_OBJECT FunctionalDeviceObject, \
+ IN PDEVICE_OBJECT PhysicalDeviceObject, \
+ IN PDEVICE_OBJECT LowerDeviceObject); \
+ \
+ STDMETHODIMP_(NTSTATUS) PnpStart( \
+ IN PCM_RESOURCE_LIST RawResources, \
+ IN PCM_RESOURCE_LIST TranslatedResources); \
+ \
+ STDMETHODIMP_(NTSTATUS) PnpStop(VOID); \
+ \
+ STDMETHODIMP_(NTSTATUS) GetDeviceDetails( \
+ OUT OPTIONAL PUSHORT VendorId, \
+ OUT OPTIONAL PUSHORT DeviceId, \
+ OUT OPTIONAL PULONG NumberOfPorts, \
+ OUT OPTIONAL PULONG Speed); \
+ \
+ STDMETHODIMP_(NTSTATUS) GetUSBQueue( \
+ OUT struct IUSBQueue **OutUsbQueue); \
+ \
+ STDMETHODIMP_(NTSTATUS) GetDMA( \
+ OUT struct IDMAMemoryManager **OutDMA); \
+ \
+ STDMETHODIMP_(NTSTATUS) ResetPort( \
+ IN ULONG PortNumber); \
+ \
+ STDMETHODIMP_(NTSTATUS) GetPortStatus( \
+ IN ULONG PortId, \
+ OUT USHORT *PortStatus, \
+ OUT USHORT *PortChange); \
+ \
+ STDMETHODIMP_(NTSTATUS) ClearPortStatus( \
+ IN ULONG PortId, \
+ IN ULONG Status); \
+ \
+ STDMETHODIMP_(NTSTATUS) SetPortFeature( \
+ IN ULONG PortId, \
+ IN ULONG Feature); \
+ \
+ STDMETHODIMP_(VOID) SetStatusChangeEndpointCallBack( \
+ IN PVOID CallBack, \
+ IN PVOID Context);
+
+DECLARE_INTERFACE_(IUSBHardwareDevice, IUnknown)
+{
+ DEFINE_ABSTRACT_UNKNOWN()
+ DEFINE_ABSTRACT_USBHARDWAREDEVICE()
+};
+
+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.
+//
+
+#define DEFINE_ABSTRACT_USBREQUEST() \
+ STDMETHOD_(NTSTATUS, InitializeWithSetupPacket)( THIS_ \
+ IN PDMAMEMORYMANAGER DmaManager, \
+ IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, \
+ IN UCHAR DeviceAddress, \
+ IN OPTIONAL struct _USB_ENDPOINT *EndpointDescriptor, \
+ IN OUT ULONG TransferBufferLength, \
+ IN OUT PMDL TransferBuffer) PURE; \
+ \
+ STDMETHOD_(NTSTATUS, InitializeWithIrp)( THIS_ \
+ IN PDMAMEMORYMANAGER DmaManager, \
+ IN OUT PIRP Irp) PURE; \
+ \
+ STDMETHOD_(BOOLEAN, IsRequestComplete)( THIS) PURE; \
+ \
+ STDMETHOD_(ULONG, GetTransferType)( THIS) PURE; \
+ \
+ STDMETHOD_(VOID, GetResultStatus)( THIS_ \
+ OUT OPTIONAL NTSTATUS * NtStatusCode, \
+ OUT OPTIONAL PULONG UrbStatusCode) PURE;
+
+#define IMP_IUSBREQUEST \
+ STDMETHODIMP_(NTSTATUS) InitializeWithSetupPacket( \
+ IN PDMAMEMORYMANAGER DmaManager, \
+ IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, \
+ IN UCHAR DeviceAddress, \
+ IN OPTIONAL struct _USB_ENDPOINT *EndpointDescriptor, \
+ IN OUT ULONG TransferBufferLength, \
+ IN OUT PMDL TransferBuffer); \
+ \
+ STDMETHODIMP_(NTSTATUS) InitializeWithIrp( \
+ IN PDMAMEMORYMANAGER DmaManager, \
+ IN OUT PIRP Irp); \
+ \
+ STDMETHODIMP_(BOOLEAN) IsRequestComplete(VOID); \
+ \
+ STDMETHODIMP_(ULONG) GetTransferType(VOID); \
+ \
+ STDMETHODIMP_(VOID) GetResultStatus( \
+ OUT OPTIONAL NTSTATUS * NtStatusCode, \
+ OUT OPTIONAL PULONG UrbStatusCode);
+
+DECLARE_INTERFACE_(IUSBRequest, IUnknown)
+{
+ DEFINE_ABSTRACT_UNKNOWN()
+ DEFINE_ABSTRACT_USBREQUEST()
+};
+
+
+typedef IUSBRequest *PUSBREQUEST;
+
+//=========================================================================================
+//
+// class IUSBQueue
+//
+// Description: This class manages pending requests
+//
+
+#define DEFINE_ABSTRACT_USBQUEUE() \
+ STDMETHOD_(NTSTATUS, Initialize)( THIS_ \
+ IN PUSBHARDWAREDEVICE Hardware, \
+ IN PDMA_ADAPTER AdapterObject, \
+ IN PDMAMEMORYMANAGER MemManager, \
+ IN OPTIONAL PKSPIN_LOCK Lock) PURE; \
+ \
+ STDMETHOD_(NTSTATUS, AddUSBRequest)( THIS_ \
+ IN IUSBRequest * Request) PURE; \
+ \
+ STDMETHOD_(NTSTATUS, CreateUSBRequest)( THIS_ \
+ IN IUSBRequest **OutRequest) PURE; \
+ \
+ STDMETHOD_(NTSTATUS, AbortDevicePipe)( THIS_ \
+ IN UCHAR DeviceAddress, \
+ IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor) PURE;
+
+#define IMP_IUSBQUEUE \
+ STDMETHODIMP_(NTSTATUS) Initialize( \
+ IN PUSBHARDWAREDEVICE Hardware, \
+ IN PDMA_ADAPTER AdapterObject, \
+ IN PDMAMEMORYMANAGER MemManager, \
+ IN OPTIONAL PKSPIN_LOCK Lock); \
+ \
+ STDMETHODIMP_(NTSTATUS) AddUSBRequest( \
+ IN IUSBRequest * Request); \
+ \
+ STDMETHODIMP_(NTSTATUS) CreateUSBRequest( \
+ OUT IUSBRequest **OutRequest); \
+ \
+ STDMETHODIMP_(NTSTATUS) AbortDevicePipe( \
+ IN UCHAR DeviceAddress, \
+ IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor);
+
+DECLARE_INTERFACE_(IUSBQueue, IUnknown)
+{
+ DEFINE_ABSTRACT_UNKNOWN()
+ DEFINE_ABSTRACT_USBQUEUE()
+};
+
+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;
+
+//-----------------------------------------------------------------------------------------
+//
+// AbortPipe
+//
+// Description: aborts all pending requsts
+
+ virtual NTSTATUS AbortPipe(IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor) = 0;
+
+};
+
+typedef IUSBDevice *PUSBDEVICE;
+
+#endif
--- /dev/null
+/*
+ * PROJECT: ReactOS Universal Serial Bus Bulk Driver Library
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: lib/drivers/libusb/hcd_controller.cpp
+ * PURPOSE: USB Common Driver Library.
+ * PROGRAMMERS:
+ * Michael Martin (michael.martin@reactos.org)
+ * Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+#define INITGUID
+#include "libusb.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("[USBLIB] 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("[USBLIB] 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("[USBLIB] 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("[USBLIB] 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("[USBLIB] 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:
+ {
+ DPRINT("[USBLIB] 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);
+ }
+
+ DPRINT("[USBLIB] HandlePnp IRP_MN_START FDO: Status %x\n", Status);
+ break;
+ }
+ case IRP_MN_QUERY_DEVICE_RELATIONS:
+ {
+ DPRINT("[USBLIB] 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
+ //
+ Status = STATUS_NOT_SUPPORTED;
+ }
+ break;
+ }
+ case IRP_MN_STOP_DEVICE:
+ {
+ DPRINT("[USBLIB] 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_QUERY_REMOVE_DEVICE:
+ case IRP_MN_QUERY_STOP_DEVICE:
+ {
+#if 0
+ //
+ // sure
+ //
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ //
+ // forward irp to next device object
+ //
+ IoSkipCurrentIrpStackLocation(Irp);
+ return IoCallDriver(m_NextDeviceObject, Irp);
+#else
+ DPRINT1("[USBLIB] Denying controller removal due to reinitialization bugs\n");
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_UNSUCCESSFUL;
+#endif
+ }
+ case IRP_MN_REMOVE_DEVICE:
+ {
+ DPRINT("[USBLIB] HandlePnp IRP_MN_REMOVE_DEVICE FDO\n");
+
+ //
+ // delete the symbolic link
+ //
+ SetSymbolicLink(FALSE);
+
+ //
+ // forward irp to next device object
+ //
+ IoSkipCurrentIrpStackLocation(Irp);
+ IoCallDriver(m_NextDeviceObject, Irp);
+
+ //
+ // detach device from device stack
+ //
+ IoDetachDevice(m_NextDeviceObject);
+
+ //
+ // delete device
+ //
+ IoDeleteDevice(m_FunctionalDeviceObject);
+
+ return STATUS_SUCCESS;
+ }
+ 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("[USBLIB] CreateFDO: Failed to create %wZ, Status %x\n", &DeviceName, Status);
+ return Status;
+ }
+ }
+
+ //
+ // store FDO number
+ //
+ m_FDODeviceNumber = UsbDeviceNumber;
+
+ DPRINT("[USBLIB] 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_USBLIB) 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;
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Universal Serial Bus Bulk Driver Library
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: lib/drivers/libusb/hub_controller.cpp
+ * PURPOSE: USB Common Driver Library.
+ * PROGRAMMERS:
+ * Michael Martin (michael.martin@reactos.org)
+ * Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+
+#define INITGUID
+#include "libusb.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 HandleGetDescriptorFromInterface(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 HandleClassEndpoint(IN OUT PIRP Irp, PURB Urb);
+ NTSTATUS HandleBulkOrInterruptTransfer(IN OUT PIRP Irp, PURB Urb);
+ NTSTATUS HandleIsochronousTransfer(IN OUT PIRP Irp, PURB Urb);
+ NTSTATUS HandleClearStall(IN OUT PIRP Irp, PURB Urb);
+ NTSTATUS HandleSyncResetAndClearStall(IN OUT PIRP Irp, PURB Urb);
+ NTSTATUS HandleAbortPipe(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_USBLIB);
+ 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 = 0x200; //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("[USBLIB] 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("[USBLIB] 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("[USBLIB] 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:
+ {
+ DPRINT("[USBLIB] HandlePnp IRP_MN_START_DEVICE\n");
+ //
+ // register device interface
+ //
+ Status = SetDeviceInterface(TRUE);
+ break;
+ }
+ case IRP_MN_QUERY_STOP_DEVICE:
+ case IRP_MN_QUERY_REMOVE_DEVICE:
+ {
+ //
+ // sure
+ //
+ Status = STATUS_SUCCESS;
+ break;
+ }
+ case IRP_MN_QUERY_ID:
+ {
+ DPRINT("[USBLIB] 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");
+ }
+
+ DPRINT("Name %S\n", Buffer);
+
+ //
+ // calculate length
+ //
+ Length = (wcslen(Buffer) + 1);
+
+ //
+ // allocate buffer
+ //
+ DeviceName = (LPWSTR)ExAllocatePoolWithTag(PagedPool, Length * sizeof(WCHAR), TAG_USBLIB);
+
+ 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("[USBLIB] 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("[USBLIB] Name %S\n", Buffer);
+
+ //
+ // allocate buffer
+ //
+ DeviceName = (LPWSTR)ExAllocatePoolWithTag(PagedPool, Index * sizeof(WCHAR), TAG_USBLIB);
+
+ 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:
+ {
+ DPRINT("[USBLIB] 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 = 1; 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:
+ {
+ DPRINT("[USBLIB] HandlePnp IRP_MN_QUERY_INTERFACE\n");
+
+ //
+ // handle device interface requests
+ //
+ Status = HandleQueryInterface(IoStack);
+ break;
+ }
+ case IRP_MN_REMOVE_DEVICE:
+ {
+ DPRINT("[USBLIB] 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:
+ {
+ DPRINT("[USBLIB] 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_USBLIB);
+ 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:
+ {
+ DPRINT("[USBLIB] 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:
+ {
+ DPRINT("[USBLIB] 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::HandleIsochronousTransfer(
+ IN OUT PIRP Irp,
+ PURB Urb)
+{
+ PUSBDEVICE UsbDevice;
+ PUSB_ENDPOINT_DESCRIPTOR EndPointDesc = NULL;
+
+ //
+ // Check PipeHandle to determine if this is a Bulk or Interrupt Transfer Request
+ //
+ EndPointDesc = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbIsochronousTransfer.PipeHandle;
+
+ if (!EndPointDesc)
+ {
+ DPRINT1("[USBLIB] Error No EndpointDesc\n");
+ Urb->UrbIsochronousTransfer.Hdr.Status = USBD_STATUS_INVALID_PIPE_HANDLE;
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // sanity checks
+ //
+ ASSERT(EndPointDesc);
+ ASSERT((EndPointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_ISOCHRONOUS);
+
+ //
+ // check if this is a valid usb device handle
+ //
+ if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+ {
+ DPRINT1("[USBLIB] HandleIsochronousTransfer invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+ //
+ // invalid device handle
+ //
+ return STATUS_DEVICE_NOT_CONNECTED;
+ }
+
+ //
+ // get device
+ //
+ UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+ return UsbDevice->SubmitIrp(Irp);
+}
+
+//-----------------------------------------------------------------------------------------
+NTSTATUS
+CHubController::HandleBulkOrInterruptTransfer(
+ IN OUT PIRP Irp,
+ PURB Urb)
+{
+ PUSBDEVICE UsbDevice;
+ PUSB_ENDPOINT 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.
+ //
+ DPRINT("[USBLIB] 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)Urb->UrbBulkOrInterruptTransfer.PipeHandle;
+
+ //
+ // sanity checks
+ //
+ ASSERT(EndPointDesc);
+ ASSERT((EndPointDesc->EndPointDescriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK || (EndPointDesc->EndPointDescriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT);
+
+ //
+ // check if this is a valid usb device handle
+ //
+ if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+ {
+ DPRINT1("[USBLIB] HandleBulkOrInterruptTransfer invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+ //
+ // invalid device handle
+ //
+ return STATUS_DEVICE_NOT_CONNECTED;
+ }
+
+ //
+ // 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("[USBLIB] 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("[USBLIB] 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("[USBLIB] Unknown Value for Clear Feature %x \n", Urb->UrbControlVendorClassRequest.Value);
+ break;
+ }
+
+ break;
+ }
+ case USB_REQUEST_SET_FEATURE:
+ {
+ //
+ // request set feature
+ //
+ switch(Urb->UrbControlVendorClassRequest.Value)
+ {
+ case PORT_ENABLE:
+ {
+ //
+ // port enable is a no-op for EHCI
+ //
+ 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("[USBLIB] Unsupported request id %x\n", Urb->UrbControlVendorClassRequest.Value);
+ PC_ASSERT(FALSE);
+ }
+ break;
+ }
+ default:
+ DPRINT1("[USBLIB] 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
+ //
+ if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+ {
+ DPRINT1("[USBLIB] HandleSelectConfiguration invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+ //
+ // invalid device handle
+ //
+ return STATUS_DEVICE_NOT_CONNECTED;
+ }
+
+ //
+ // 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
+ //
+ if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+ {
+ DPRINT1("[USBLIB] HandleSelectInterface invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+ //
+ // invalid device handle
+ //
+ return STATUS_DEVICE_NOT_CONNECTED;
+ }
+
+ //
+ // 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 DeviceStatus;
+ USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
+ NTSTATUS Status;
+ PUSBDEVICE UsbDevice;
+
+ //
+ // sanity checks
+ //
+ PC_ASSERT(Urb->UrbControlGetStatusRequest.TransferBufferLength >= sizeof(USHORT));
+ PC_ASSERT(Urb->UrbControlGetStatusRequest.TransferBuffer);
+
+ //
+ // get status buffer
+ //
+ DeviceStatus = (PUSHORT)Urb->UrbControlGetStatusRequest.TransferBuffer;
+
+
+ if (Urb->UrbHeader.UsbdDeviceHandle == NULL)
+ {
+ //
+ // FIXME need more flags ?
+ //
+ *DeviceStatus = USB_PORT_STATUS_CONNECT;
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // check if this is a valid usb device handle
+ //
+ if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+ {
+ DPRINT1("[USBLIB] HandleGetStatusFromDevice invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+ //
+ // invalid device handle
+ //
+ return STATUS_DEVICE_NOT_CONNECTED;
+ }
+
+ //
+ // get device
+ //
+ UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+
+ //
+ // generate setup packet
+ //
+ CtrlSetup.bRequest = USB_REQUEST_GET_STATUS;
+ CtrlSetup.wValue.LowByte = 0;
+ CtrlSetup.wValue.HiByte = 0;
+ CtrlSetup.wIndex.W = Urb->UrbControlGetStatusRequest.Index;
+ CtrlSetup.wLength = (USHORT)Urb->UrbControlGetStatusRequest.TransferBufferLength;
+ CtrlSetup.bmRequestType.B = 0x80;
+
+
+ if (Urb->UrbHeader.Function == URB_FUNCTION_GET_STATUS_FROM_INTERFACE)
+ {
+ //
+ // add interface type
+ //
+ CtrlSetup.bmRequestType.B |= 0x01;
+ }
+ else if (Urb->UrbHeader.Function == URB_FUNCTION_GET_STATUS_FROM_ENDPOINT)
+ {
+ //
+ // add interface type
+ //
+ CtrlSetup.bmRequestType.B |= 0x02;
+ }
+
+ //
+ // submit setup packet
+ //
+ Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer);
+ ASSERT(Status == STATUS_SUCCESS);
+ DPRINT1("[USBLIB] HandleGetStatusFromDevice Status %x Length %lu DeviceStatus %x\n", Status, Urb->UrbControlDescriptorRequest.TransferBufferLength, *DeviceStatus);
+
+ //
+ // done
+ //
+ return Status;
+}
+
+//-----------------------------------------------------------------------------------------
+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;
+ PUSBDEVICE UsbDevice;
+ USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
+
+ 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_STATUS:
+ {
+ //
+ // check if this is a valid usb device handle
+ //
+ if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+ {
+ DPRINT1("HandleClassDevice invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+ //
+ // invalid device handle
+ //
+ return STATUS_DEVICE_NOT_CONNECTED;
+ }
+
+ //
+ // get device
+ //
+ UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+
+ //
+ // generate setup packet
+ //
+ CtrlSetup.bRequest = USB_REQUEST_GET_STATUS;
+ CtrlSetup.wValue.LowByte = Urb->UrbControlVendorClassRequest.Index;
+ CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value;
+ CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index;
+ CtrlSetup.wLength = (USHORT)Urb->UrbControlGetStatusRequest.TransferBufferLength;
+ CtrlSetup.bmRequestType.B = 0xA0;
+
+ //
+ // submit setup packet
+ //
+ Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer);
+ ASSERT(Status == STATUS_SUCCESS);
+ break;
+ }
+ 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("[USBLIB] HandleClassDevice Class %x not implemented\n", Urb->UrbControlVendorClassRequest.Value >> 8);
+ break;
+ }
+ break;
+ }
+ default:
+ DPRINT1("[USBLIB] HandleClassDevice Type %x not implemented\n", Urb->UrbControlVendorClassRequest.Request);
+ }
+
+ return Status;
+}
+
+//-----------------------------------------------------------------------------------------
+NTSTATUS
+CHubController::HandleGetDescriptorFromInterface(
+ IN OUT PIRP Irp,
+ IN OUT PURB Urb)
+{
+ PUSBDEVICE UsbDevice;
+ USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
+ NTSTATUS Status;
+
+ //
+ // sanity check
+ //
+ ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength);
+ ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer);
+
+ //
+ // check if this is a valid usb device handle
+ //
+ if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+ {
+ DPRINT1("[USBLIB] HandleGetDescriptorFromInterface invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+ //
+ // invalid device handle
+ //
+ return STATUS_DEVICE_NOT_CONNECTED;
+ }
+
+ //
+ // get device
+ //
+ UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+ //
+ // generate setup packet
+ //
+ CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
+ CtrlSetup.wValue.LowByte = Urb->UrbControlDescriptorRequest.Index;
+ CtrlSetup.wValue.HiByte = Urb->UrbControlDescriptorRequest.DescriptorType;
+ CtrlSetup.wIndex.W = Urb->UrbControlDescriptorRequest.LanguageId;
+ CtrlSetup.wLength = (USHORT)Urb->UrbControlDescriptorRequest.TransferBufferLength;
+ CtrlSetup.bmRequestType.B = 0x81;
+
+ //
+ // submit setup packet
+ //
+ Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer);
+ ASSERT(Status == STATUS_SUCCESS);
+
+ //
+ // done
+ //
+ return Status;
+}
+
+//-----------------------------------------------------------------------------------------
+NTSTATUS
+CHubController::HandleGetDescriptor(
+ IN OUT PIRP Irp,
+ IN OUT PURB Urb)
+{
+ NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
+ PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
+ USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
+ PUCHAR Buffer;
+ PUSBDEVICE UsbDevice;
+ ULONG Length;
+
+ DPRINT("[USBLIB] 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
+ //
+ if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+ {
+ DPRINT1("[USBLIB] HandleGetDescriptor invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+ //
+ // invalid device handle
+ //
+ return STATUS_DEVICE_NOT_CONNECTED;
+ }
+
+ //
+ // 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
+ {
+ //
+ // check if this is a valid usb device handle
+ //
+ if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+ {
+ DPRINT1("[USBLIB] USB_CONFIGURATION_DESCRIPTOR_TYPE invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+ //
+ // invalid device handle
+ //
+ return STATUS_DEVICE_NOT_CONNECTED;
+ }
+
+ //
+ // 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);
+
+ //
+ // 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
+ //
+ if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+ {
+ DPRINT1("[USBLIB] USB_STRING_DESCRIPTOR_TYPE invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+ //
+ // invalid device handle
+ //
+ return STATUS_DEVICE_NOT_CONNECTED;
+ }
+
+ //
+ // get device
+ //
+ UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+ //
+ // generate setup packet
+ //
+ CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
+ CtrlSetup.wValue.LowByte = Urb->UrbControlDescriptorRequest.Index;
+ CtrlSetup.wValue.HiByte = Urb->UrbControlDescriptorRequest.DescriptorType;
+ CtrlSetup.wIndex.W = Urb->UrbControlDescriptorRequest.LanguageId;
+ CtrlSetup.wLength = (USHORT)Urb->UrbControlDescriptorRequest.TransferBufferLength;
+ CtrlSetup.bmRequestType.B = 0x80;
+
+ //
+ // submit setup packet
+ //
+ Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer);
+ break;
+ }
+ default:
+ DPRINT1("[USBLIB] CHubController::HandleGetDescriptor DescriptorType %x unimplemented\n", Urb->UrbControlDescriptorRequest.DescriptorType);
+ break;
+ }
+
+ //
+ // done
+ //
+ return Status;
+}
+
+//-----------------------------------------------------------------------------------------
+NTSTATUS
+CHubController::HandleClassEndpoint(
+ 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
+ //
+ if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+ {
+ DPRINT1("[USBLIB] HandleClassEndpoint invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+ //
+ // invalid device handle
+ //
+ return STATUS_DEVICE_NOT_CONNECTED;
+ }
+
+ //
+ // get device
+ //
+ UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+
+ DPRINT1("URB_FUNCTION_CLASS_ENDPOINT\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 = 0x22; //FIXME: Const.
+ CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request;
+ CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value;
+ CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index;
+ CtrlSetup.wLength = Urb->UrbControlVendorClassRequest.TransferBufferLength;
+
+ if (Urb->UrbControlVendorClassRequest.TransferFlags & USBD_TRANSFER_DIRECTION_IN)
+ {
+ //
+ // data direction is device to host
+ //
+ CtrlSetup.bmRequestType.B |= 0x80;
+ }
+
+
+ //
+ // 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::HandleSyncResetAndClearStall(
+ IN OUT PIRP Irp,
+ IN OUT PURB Urb)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PUSB_ENDPOINT EndpointDescriptor;
+ ULONG Type;
+
+ //
+ // sanity check
+ //
+ PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle);
+ PC_ASSERT(Urb->UrbHeader.Length == sizeof(struct _URB_PIPE_REQUEST));
+ PC_ASSERT(Urb->UrbPipeRequest.PipeHandle);
+
+ //
+ // check if this is a valid usb device handle
+ //
+ if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+ {
+ DPRINT1("[USBLIB] HandleSyncResetAndClearStall invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+ //
+ // invalid device handle
+ //
+ return STATUS_DEVICE_NOT_CONNECTED;
+ }
+
+ //
+ // abort pipe
+ //
+ Status = HandleAbortPipe(Irp, Urb);
+ if (!NT_SUCCESS(Status))
+ {
+ //
+ // failed
+ //
+ DPRINT1("[USBLIB] failed to reset pipe %x\n", Status);
+ }
+
+
+ //
+ // get endpoint descriptor
+ //
+ EndpointDescriptor = (PUSB_ENDPOINT)Urb->UrbPipeRequest.PipeHandle;
+
+ //
+ // get type
+ //
+ Type = (EndpointDescriptor->EndPointDescriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK);
+ if (Type != USB_ENDPOINT_TYPE_ISOCHRONOUS)
+ {
+ //
+ // clear stall
+ //
+ Status = HandleClearStall(Irp, Urb);
+ }
+ DPRINT1("[USBLIB] URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL Status %x\n", Status);
+
+ //
+ // reset data toggle
+ //
+ ASSERT(NT_SUCCESS(Status));
+ EndpointDescriptor->DataToggle = 0x0;
+
+ //
+ // done
+ //
+ return Status;
+}
+
+NTSTATUS
+CHubController::HandleAbortPipe(
+ IN OUT PIRP Irp,
+ IN OUT PURB Urb)
+{
+ NTSTATUS Status;
+ PUSBDEVICE UsbDevice;
+ PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
+
+ //
+ // sanity check
+ //
+ PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle);
+ PC_ASSERT(Urb->UrbHeader.Length == sizeof(struct _URB_PIPE_REQUEST));
+ PC_ASSERT(Urb->UrbPipeRequest.PipeHandle);
+
+ //
+ // check if this is a valid usb device handle
+ //
+ if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+ {
+ DPRINT1("[USBLIB] HandleAbortPipe invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+ //
+ // invalid device handle
+ //
+ return STATUS_DEVICE_NOT_CONNECTED;
+ }
+
+ //
+ // get endpoint descriptor
+ //
+ EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbPipeRequest.PipeHandle;
+
+ //
+ // get device
+ //
+ UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+
+ //
+ // issue request
+ //
+ Status = UsbDevice->AbortPipe(EndpointDescriptor);
+ DPRINT1("[USBLIB] URB_FUNCTION_ABORT_PIPE Status %x\n", Status);
+
+ //
+ // done
+ //
+ return Status;
+}
+
+
+//-----------------------------------------------------------------------------------------
+NTSTATUS
+CHubController::HandleClearStall(
+ IN OUT PIRP Irp,
+ IN OUT PURB Urb)
+{
+ USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
+ NTSTATUS Status;
+ PUSBDEVICE UsbDevice;
+ PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
+
+
+ //
+ // sanity check
+ //
+ PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle);
+ PC_ASSERT(Urb->UrbHeader.Length == sizeof(struct _URB_PIPE_REQUEST));
+ PC_ASSERT(Urb->UrbPipeRequest.PipeHandle);
+
+ //
+ // check if this is a valid usb device handle
+ //
+ if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+ {
+ DPRINT1("[USBLIB] HandleClearStall invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+ //
+ // invalid device handle
+ //
+ return STATUS_DEVICE_NOT_CONNECTED;
+ }
+
+ //
+ // get endpoint descriptor
+ //
+ EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbPipeRequest.PipeHandle;
+
+ //
+ // get device
+ //
+ UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+ DPRINT1("[USBLIB] URB_FUNCTION_SYNC_CLEAR_STALL\n");
+
+ //
+ // initialize setup packet
+ //
+ CtrlSetup.bmRequestType.B = 0x02;
+ CtrlSetup.bRequest = USB_REQUEST_CLEAR_FEATURE;
+ CtrlSetup.wValue.W = USB_FEATURE_ENDPOINT_STALL;
+ CtrlSetup.wIndex.W = EndpointDescriptor->bEndpointAddress;
+ CtrlSetup.wLength = 0;
+ CtrlSetup.wValue.W = 0;
+
+ //
+ // issue request
+ //
+ Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, 0, 0);
+
+ DPRINT1("[USBLIB] URB_FUNCTION_CLEAR_STALL Status %x\n", Status);
+
+ //
+ // 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
+ //
+ //ASSERT(Urb->UrbControlVendorClassRequest.TransferBuffer || Urb->UrbControlVendorClassRequest.TransferBufferMDL);
+ //ASSERT(Urb->UrbControlVendorClassRequest.TransferBufferLength);
+ PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle);
+
+ //
+ // check if this is a valid usb device handle
+ //
+ if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+ {
+ DPRINT1("[USBLIB] HandleClassInterface invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+ //
+ // invalid device handle
+ //
+ return STATUS_DEVICE_NOT_CONNECTED;
+ }
+
+ //
+ // 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 = 0x21;
+ CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request;
+ CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value;
+ CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index;
+ CtrlSetup.wLength = Urb->UrbControlVendorClassRequest.TransferBufferLength;
+
+ if (Urb->UrbControlVendorClassRequest.TransferFlags & USBD_TRANSFER_DIRECTION_IN)
+ {
+ //
+ // data direction is device to host
+ //
+ CtrlSetup.bmRequestType.B |= 0x80;
+ }
+
+ //
+ // issue request
+ //
+ Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlVendorClassRequest.TransferBufferLength, Urb->UrbControlVendorClassRequest.TransferBuffer);
+
+ //
+ // assert on failure
+ //
+ if (!NT_SUCCESS(Status))
+ {
+ //
+ // display error
+ //
+ DPRINT1("URB_FUNCTION_CLASS_INTERFACE failed with Urb Status %x\n", Urb->UrbHeader.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_SYNC_RESET_PIPE:
+ case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL:
+ Status = HandleSyncResetAndClearStall(Irp, Urb);
+ break;
+ case URB_FUNCTION_ABORT_PIPE:
+ Status = HandleAbortPipe(Irp, Urb);
+ break;
+ case URB_FUNCTION_SYNC_CLEAR_STALL:
+ Status = HandleClearStall(Irp, Urb);
+ break;
+ case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE:
+ Status = HandleGetDescriptorFromInterface(Irp, Urb);
+ break;
+ 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:
+ case URB_FUNCTION_GET_STATUS_FROM_INTERFACE:
+ case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT:
+ 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_ISOCH_TRANSFER:
+ Status = HandleIsochronousTransfer(Irp, Urb);
+ break;
+ case URB_FUNCTION_CLASS_INTERFACE:
+ Status = HandleClassInterface(Irp, Urb);
+ break;
+ case URB_FUNCTION_CLASS_ENDPOINT:
+ Status = HandleClassEndpoint(Irp, Urb);
+ break;
+ default:
+ DPRINT1("[USBLIB] 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("[USBLIB] 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("[USBLIB] 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("[USBLIB] 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("[USBLIB] IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION UNIMPLEMENTED\n");
+ Status = STATUS_SUCCESS;
+ break;
+ }
+ default:
+ {
+ DPRINT1("[USBLIB] 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_USBLIB);
+
+ //
+ // 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_USBLIB);
+ 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(), HubDeviceHandle, 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());
+
+ //
+ // 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 = UsbHighSpeed; //FIXME
+ DeviceInfo->DeviceType = Usb20Device; //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 = TRUE;
+
+ //
+ // 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 = USB_PORTATTR_SHARED_USB2; //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_Initialize20Hub(
+ PVOID BusContext,
+ PUSB_DEVICE_HANDLE HubDeviceHandle,
+ ULONG TtCount)
+{
+ DPRINT("USBHI_Initialize20Hub HubDeviceHandle %p UNIMPLEMENTED TtCount %lu\n", HubDeviceHandle, TtCount);
+ return STATUS_SUCCESS;
+}
+
+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;
+ InterfaceHub->Initialize20Hub = USBHI_Initialize20Hub;
+
+ }
+
+ //
+ // 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_SUCCESS;
+}
+
+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_USBLIB) 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);
+}
--- /dev/null
+/*
+ * PROJECT: ReactOS Universal Serial Bus Bulk Driver Library
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: lib/drivers/libusb/libusb.cpp
+ * PURPOSE: USB Common Driver Library.
+ * PROGRAMMERS:
+ * Michael Martin (michael.martin@reactos.org)
+ * Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+
+#include "libusb.h"
+
+//
+// driver verifier
+//
+DRIVER_ADD_DEVICE USBLIB_AddDevice;
+
+NTSTATUS
+NTAPI
+USBLIB_AddDevice(
+ PDRIVER_OBJECT DriverObject,
+ PDEVICE_OBJECT PhysicalDeviceObject)
+{
+ NTSTATUS Status;
+ PHCDCONTROLLER HcdController;
+
+ DPRINT1("EHCI_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
+USBLIB_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("EHCI_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;
+}
--- /dev/null
+#ifndef LIBUSB_H__
+#define LIBUSB_H__
+
+#include <ntddk.h>
+#define NDEBUG
+#include <debug.h>
+#include <hubbusif.h>
+#include <usbbusif.h>
+#include <usbioctl.h>
+
+extern "C"
+{
+ #include <usbdlib.h>
+}
+
+
+//
+// FIXME:
+// #include <usbprotocoldefs.h>
+//
+#include <usb.h>
+#include <stdio.h>
+#include <wdmguid.h>
+
+//
+// FIXME:
+// the following includes are required to get kcom to compile
+//
+#include <portcls.h>
+#include <dmusicks.h>
+#include <kcom.h>
+
+#include "common_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_USBLIB 'LBSU'
+
+//
+// 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);
+
+// libusb.cpp
+NTSTATUS NTAPI USBLIB_AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObject);
+NTSTATUS NTAPI USBLIB_Dispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+
+
+
+#endif
--- /dev/null
+/*
+ * PROJECT: ReactOS Universal Serial Bus Bulk Driver Library
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: lib/drivers/libusb/memory_manager.cpp
+ * PURPOSE: USB Common Driver Library.
+ * PROGRAMMERS:
+ * Michael Martin (michael.martin@reactos.org)
+ * Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+
+#include "libusb.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_USBLIB);
+ 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, BlockCount;
+
+ //
+ // 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);
+
+ //
+ // convert to blocks
+ //
+ BlockCount = Size / m_BlockSize;
+ ASSERT(BlockCount);
+
+ //
+ // acquire lock
+ //
+ KeAcquireSpinLock(m_Lock, &OldLevel);
+
+ //
+ // sanity check
+ //
+ ASSERT(RtlAreBitsSet(&m_Bitmap, BlockOffset, BlockCount));
+
+ //
+ // release buffer
+ //
+ RtlClearBits(&m_Bitmap, BlockOffset, BlockCount);
+
+ //
+ // release lock
+ //
+ KeReleaseSpinLock(m_Lock, OldLevel);
+
+ //
+ // done
+ //
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+CreateDMAMemoryManager(
+ PDMAMEMORYMANAGER *OutMemoryManager)
+{
+ CDMAMemoryManager* This;
+
+ //
+ // allocate controller
+ //
+ This = new(NonPagedPool, TAG_USBLIB) 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;
+}
+
--- /dev/null
+/*
+ * PROJECT: ReactOS Universal Serial Bus Bulk Driver Library
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: lib/drivers/libusb/misc.cpp
+ * PURPOSE: USB Common Driver Library.
+ * PROGRAMMERS:
+ * Michael Martin (michael.martin@reactos.org)
+ * Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+
+#include "libusb.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;
+}
+
--- /dev/null
+/*
+ * PROJECT: ReactOS Universal Serial Bus Bulk Driver Library
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: lib/drivers/libusb/purecall.cpp
+ * PURPOSE: USB Common Driver Library.
+ * PROGRAMMERS:
+ * Michael Martin (michael.martin@reactos.org)
+ * Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+
+
+#include "libusb.h"
+
+
+extern "C" {
+ void
+ __cxa_pure_virtual()
+ {
+ // put error handling here
+
+ DbgBreakPoint();
+
+ }
+}
+
--- /dev/null
+/*
+ * PROJECT: ReactOS Universal Serial Bus Bulk Driver Library
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: lib/drivers/libusb/usb_device.cpp
+ * PURPOSE: USB Common Driver Library.
+ * PROGRAMMERS:
+ * Michael Martin (michael.martin@reactos.org)
+ * Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+
+#define INITGUID
+#include "libusb.h"
+
+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);
+ virtual NTSTATUS AbortPipe(IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor);
+
+
+ // local function
+ virtual NTSTATUS CommitIrp(PIRP Irp);
+ virtual NTSTATUS CommitSetupPacket(PUSB_DEFAULT_PIPE_SETUP_PACKET Packet, IN OPTIONAL PUSB_ENDPOINT EndpointDescriptor, IN ULONG BufferLength, IN OUT PMDL Mdl);
+ virtual NTSTATUS CreateConfigurationDescriptor(UCHAR 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;
+ UCHAR Index;
+
+ DPRINT1("CUSBDevice::SetDeviceAddress Address %d\n", DeviceAddress);
+
+ CtrlSetup = (PUSB_DEFAULT_PIPE_SETUP_PACKET)ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET), TAG_USBLIB);
+ 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 = DeviceAddress;
+
+ // set device address
+ Status = CommitSetupPacket(CtrlSetup, 0, 0, 0);
+
+ // free setup packet
+ ExFreePoolWithTag(CtrlSetup, TAG_USBLIB);
+
+ // 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_USBLIB);
+
+ // 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 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;
+ PVOID Buffer;
+
+ //
+ // 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 buffer
+ //
+ Buffer = ExAllocatePool(NonPagedPool, PAGE_SIZE);
+ if (!Buffer)
+ {
+ //
+ // failed to allocate
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // zero buffer
+ //
+ RtlZeroMemory(Buffer, PAGE_SIZE);
+
+ //
+ // allocate mdl describing the device descriptor
+ //
+ Mdl = IoAllocateMdl(Buffer, 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
+ //
+ RtlCopyMemory(&m_DeviceDescriptor, Buffer, sizeof(USB_DEVICE_DESCRIPTOR));
+ DumpDeviceDescriptor(&m_DeviceDescriptor);
+ }
+
+ //
+ // free buffer
+ //
+ ExFreePool(Buffer);
+
+ //
+ // done
+ //
+ return Status;
+
+}
+
+//----------------------------------------------------------------------------------------
+NTSTATUS
+CUSBDevice::CreateConfigurationDescriptor(
+ UCHAR Index)
+{
+ PVOID Buffer;
+ USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
+ NTSTATUS Status;
+ PMDL Mdl;
+ PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
+
+ //
+ // 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_USBLIB);
+ 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 = Index;
+ CtrlSetup.wValue.HiByte = USB_CONFIGURATION_DESCRIPTOR_TYPE;
+ CtrlSetup.wIndex.W = 0;
+ CtrlSetup.wLength = PAGE_SIZE;
+
+ //
+ // now build MDL describing the buffer
+ //
+ Mdl = IoAllocateMdl(Buffer, PAGE_SIZE, FALSE, FALSE, 0);
+ if (!Mdl)
+ {
+ //
+ // failed to allocate mdl
+ //
+ ExFreePoolWithTag(Buffer, TAG_USBLIB);
+ 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
+ //
+ m_ConfigurationDescriptors[Index].ConfigurationDescriptor = ConfigurationDescriptor;
+ InitializeListHead(&m_ConfigurationDescriptors[Index].InterfaceList);
+
+ //
+ // done
+ //
+ return Status;
+}
+//----------------------------------------------------------------------------------------
+VOID
+CUSBDevice::GetConfigurationDescriptors(
+ IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptorBuffer,
+ IN ULONG BufferLength,
+ OUT PULONG OutBufferLength)
+{
+ // sanity check
+ ASSERT(BufferLength >= sizeof(USB_CONFIGURATION_DESCRIPTOR));
+ ASSERT(ConfigDescriptorBuffer);
+ ASSERT(OutBufferLength);
+
+ // reset copied length
+ *OutBufferLength = 0;
+
+ // FIXME: support multiple configurations
+ PC_ASSERT(m_DeviceDescriptor.bNumConfigurations == 1);
+
+ // copy configuration descriptor
+ RtlCopyMemory(ConfigDescriptorBuffer, m_ConfigurationDescriptors[0].ConfigurationDescriptor, min(m_ConfigurationDescriptors[0].ConfigurationDescriptor->wTotalLength, BufferLength));
+ *OutBufferLength = m_ConfigurationDescriptors[0].ConfigurationDescriptor->wTotalLength;
+}
+
+//----------------------------------------------------------------------------------------
+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 = NULL;
+
+ if (BufferLength)
+ {
+ //
+ // allocate mdl
+ //
+ Mdl = IoAllocateMdl(Buffer, BufferLength, FALSE, FALSE, 0);
+ if (!Mdl)
+ {
+ //
+ // no memory
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // HACK HACK HACK: assume the buffer is build from non paged pool
+ //
+ MmBuildMdlForNonPagedPool(Mdl);
+ }
+
+ //
+ // commit setup packet
+ //
+ Status = CommitSetupPacket(SetupPacket, 0, BufferLength, Mdl);
+
+ if (Mdl != NULL)
+ {
+ //
+ // 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 InterfaceIndex, PipeIndex;
+ USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
+ NTSTATUS Status;
+ UCHAR bConfigurationValue = 0;
+ ULONG ConfigurationIndex = 0, Index;
+ UCHAR Found = FALSE;
+ PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+ PUSB_INTERFACE UsbInterface;
+ PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
+ PLIST_ENTRY Entry;
+
+ if (ConfigurationDescriptor)
+ {
+ // find configuration index
+ for(Index = 0; Index < m_DeviceDescriptor.bNumConfigurations; Index++)
+ {
+ if (m_ConfigurationDescriptors[Index].ConfigurationDescriptor->bConfigurationValue == ConfigurationDescriptor->bConfigurationValue)
+ {
+ // found configuration index
+ ConfigurationIndex = Index;
+ Found = TRUE;
+ }
+ }
+
+ if (!Found)
+ {
+ DPRINT1("[USBUHCI] invalid configuration value %lu\n", ConfigurationDescriptor->bConfigurationValue);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // sanity check
+ ASSERT(ConfigurationDescriptor->bNumInterfaces <= m_ConfigurationDescriptors[ConfigurationIndex].ConfigurationDescriptor->bNumInterfaces);
+
+ // get configuration value
+ bConfigurationValue = ConfigurationDescriptor->bConfigurationValue;
+ }
+
+ // now build setup packet
+ RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
+ CtrlSetup.bRequest = USB_REQUEST_SET_CONFIGURATION;
+ CtrlSetup.wValue.W = bConfigurationValue;
+
+ // select configuration
+ Status = CommitSetupPacket(&CtrlSetup, 0, 0, 0);
+
+ if (!ConfigurationDescriptor)
+ {
+ // unconfigure request
+ DPRINT1("CUsbDevice::SelectConfiguration Unconfigure Request Status %x\n", Status);
+ m_ConfigurationIndex = 0;
+ return Status;
+ }
+
+ // informal debug print
+ DPRINT1("CUsbDevice::SelectConfiguration New Configuration %x Old Configuration %x Result %x\n", ConfigurationIndex, m_ConfigurationIndex, Status);
+ if (!NT_SUCCESS(Status))
+ {
+ //
+ // failed
+ //
+ return Status;
+ }
+
+ // destroy old interface info
+ while(!IsListEmpty(&m_ConfigurationDescriptors[m_ConfigurationIndex].InterfaceList))
+ {
+ // remove entry
+ Entry = RemoveHeadList(&m_ConfigurationDescriptors[m_ConfigurationIndex].InterfaceList);
+
+ // get interface info
+ UsbInterface = (PUSB_INTERFACE)CONTAINING_RECORD(Entry, USB_INTERFACE, ListEntry);
+
+ // free interface info
+ ExFreePool(UsbInterface);
+ }
+
+ // sanity check
+ ASSERT(IsListEmpty(&m_ConfigurationDescriptors[ConfigurationIndex].InterfaceList));
+
+ // store new configuration device index
+ m_ConfigurationIndex = ConfigurationIndex;
+
+ // store configuration handle
+ *ConfigurationHandle = &m_ConfigurationDescriptors[ConfigurationIndex];
+
+ // copy interface info and pipe info
+ for(InterfaceIndex = 0; InterfaceIndex < ConfigurationDescriptor->bNumInterfaces; InterfaceIndex++)
+ {
+ // interface info checks
+ ASSERT(InterfaceInfo->Length != 0);
+
+#ifdef _MSC_VER
+ PC_ASSERT(InterfaceInfo->Length == FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes[InterfaceInfo->NumberOfPipes]));
+#endif
+
+ // find interface descriptor
+ InterfaceDescriptor = USBD_ParseConfigurationDescriptor(m_ConfigurationDescriptors[ConfigurationIndex].ConfigurationDescriptor, InterfaceInfo->InterfaceNumber, InterfaceInfo->AlternateSetting);
+
+ // sanity checks
+ ASSERT(InterfaceDescriptor != NULL);
+
+ // check if the number of pipes have been properly set
+ ASSERT(InterfaceInfo->NumberOfPipes == InterfaceDescriptor->bNumEndpoints);
+
+ // copy interface info
+ InterfaceInfo->Class = InterfaceDescriptor->bInterfaceClass;
+ InterfaceInfo->SubClass = InterfaceDescriptor->bInterfaceSubClass;
+ InterfaceInfo->Protocol = InterfaceDescriptor->bInterfaceProtocol;
+ InterfaceInfo->Reserved = 0;
+
+ // allocate interface handle
+ UsbInterface = (PUSB_INTERFACE)ExAllocatePool(NonPagedPool, sizeof(USB_INTERFACE) + (InterfaceInfo->NumberOfPipes - 1) * sizeof(USB_ENDPOINT));
+ if (!UsbInterface)
+ {
+ // failed to allocate memory
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // store handle
+ InterfaceInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)UsbInterface;
+
+ // init interface handle
+ UsbInterface->InterfaceDescriptor = InterfaceDescriptor;
+ InsertTailList(&m_ConfigurationDescriptors[ConfigurationIndex].InterfaceList, &UsbInterface->ListEntry);
+
+ // grab first endpoint descriptor
+ EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR) (InterfaceDescriptor + 1);
+
+ // now copy all endpoint information
+ for(PipeIndex = 0; PipeIndex < InterfaceInfo->NumberOfPipes; PipeIndex++)
+ {
+ while(EndpointDescriptor->bDescriptorType != USB_ENDPOINT_DESCRIPTOR_TYPE && EndpointDescriptor->bLength != sizeof(USB_ENDPOINT_DESCRIPTOR))
+ {
+ // skip intermediate descriptors
+ if (EndpointDescriptor->bLength == 0 || EndpointDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
+ {
+ // bogus configuration descriptor
+ DPRINT1("[USBEHCI] Bogus descriptor found in InterfaceNumber %x Alternate %x EndpointIndex %x bLength %x bDescriptorType %x\n", InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting, PipeIndex,
+ EndpointDescriptor->bLength, EndpointDescriptor->bDescriptorType);
+
+ // failed
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ // move to next descriptor
+ EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)EndpointDescriptor + EndpointDescriptor->bLength);
+ }
+
+ // store in interface info
+ RtlCopyMemory(&UsbInterface->EndPoints[PipeIndex].EndPointDescriptor, EndpointDescriptor, sizeof(USB_ENDPOINT_DESCRIPTOR));
+
+ // copy pipe info
+ InterfaceInfo->Pipes[PipeIndex].MaximumPacketSize = UsbInterface->EndPoints[PipeIndex].EndPointDescriptor.wMaxPacketSize;
+ InterfaceInfo->Pipes[PipeIndex].EndpointAddress = UsbInterface->EndPoints[PipeIndex].EndPointDescriptor.bEndpointAddress;
+ InterfaceInfo->Pipes[PipeIndex].Interval = UsbInterface->EndPoints[PipeIndex].EndPointDescriptor.bInterval;
+ InterfaceInfo->Pipes[PipeIndex].PipeType = (USBD_PIPE_TYPE)UsbInterface->EndPoints[PipeIndex].EndPointDescriptor.bmAttributes;
+ InterfaceInfo->Pipes[PipeIndex].PipeHandle = (PVOID)&UsbInterface->EndPoints[PipeIndex];
+
+ // move to next descriptor
+ EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)EndpointDescriptor + EndpointDescriptor->bLength);
+ }
+
+ // move offset
+ InterfaceInfo = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)PtrToUlong(InterfaceInfo) + InterfaceInfo->Length);
+ }
+
+ //
+ // done
+ //
+ return Status;
+}
+
+//----------------------------------------------------------------------------------------
+NTSTATUS
+CUSBDevice::SelectInterface(
+ IN USBD_CONFIGURATION_HANDLE ConfigurationHandle,
+ IN OUT PUSBD_INTERFACE_INFORMATION InterfaceInfo)
+{
+ ULONG PipeIndex;
+ USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
+ NTSTATUS Status;
+ ULONG Index, ConfigurationIndex = 0, Found = FALSE;
+ PUSB_INTERFACE UsbInterface;
+ PLIST_ENTRY Entry;
+
+ // check if handle is valid
+ for(Index = 0; Index < m_DeviceDescriptor.bNumConfigurations; Index++)
+ {
+ if (&m_ConfigurationDescriptors[Index] == ConfigurationHandle)
+ {
+ // found configuration index
+ ConfigurationIndex = Index;
+ Found = TRUE;
+ }
+ }
+
+ if (!Found)
+ {
+ // invalid handle passed
+ DPRINT1("[USBEHCI] Invalid configuration handle passed %p\n", ConfigurationHandle);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // initialize setup packet
+ RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
+ CtrlSetup.bRequest = USB_REQUEST_SET_INTERFACE;
+ CtrlSetup.wValue.W = InterfaceInfo->AlternateSetting;
+ CtrlSetup.wIndex.W = InterfaceInfo->InterfaceNumber;
+ 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);
+#if 0
+ if (!NT_SUCCESS(Status))
+ {
+ // failed to select interface
+ return Status;
+ }
+#endif
+
+ Status = STATUS_SUCCESS;
+
+
+ // find interface
+ Found = FALSE;
+ Entry = m_ConfigurationDescriptors[ConfigurationIndex].InterfaceList.Flink;
+ while(Entry != &m_ConfigurationDescriptors[ConfigurationIndex].InterfaceList)
+ {
+ // grab interface descriptor
+ UsbInterface = (PUSB_INTERFACE)CONTAINING_RECORD(Entry, USB_INTERFACE, ListEntry);
+ if (UsbInterface->InterfaceDescriptor->bAlternateSetting == InterfaceInfo->AlternateSetting &&
+ UsbInterface->InterfaceDescriptor->bInterfaceNumber == InterfaceInfo->InterfaceNumber)
+ {
+ // found interface
+ Found = TRUE;
+ break;
+ }
+ }
+
+ if (!Found)
+ {
+ // selected interface but interface not found
+ // something is really wrong
+ DPRINT1("[USBEHCI] Error: interface not found!!!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ // assert on pipe length mismatch
+ ASSERT(InterfaceInfo->NumberOfPipes == UsbInterface->InterfaceDescriptor->bNumEndpoints);
+
+ // copy pipe handles
+ for(PipeIndex = 0; PipeIndex < min(InterfaceInfo->NumberOfPipes, UsbInterface->InterfaceDescriptor->bNumEndpoints); 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", InterfaceInfo->Pipes[PipeIndex].EndpointAddress);
+
+ // sanity checks
+ ASSERT(InterfaceInfo->Pipes[PipeIndex].EndpointAddress == UsbInterface->EndPoints[PipeIndex].EndPointDescriptor.bEndpointAddress);
+ ASSERT(InterfaceInfo->Pipes[PipeIndex].Interval == UsbInterface->EndPoints[PipeIndex].EndPointDescriptor.bInterval);
+
+ // store pipe handle
+ InterfaceInfo->Pipes[PipeIndex].PipeHandle = &UsbInterface->EndPoints[PipeIndex];
+
+ // data toggle is reset on select interface requests
+ UsbInterface->EndPoints[PipeIndex].DataToggle = FALSE;
+ }
+
+
+ //
+ // done
+ //
+ return Status;
+}
+
+NTSTATUS
+CUSBDevice::AbortPipe(
+ IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor)
+{
+ //
+ // let it handle usb queue
+ //
+ ASSERT(m_Queue);
+ ASSERT(m_DeviceAddress);
+
+ //
+ // done
+ //
+ return m_Queue->AbortDevicePipe(m_DeviceAddress, EndpointDescriptor);
+}
+
+
+//----------------------------------------------------------------------------------------
+NTSTATUS
+CreateUSBDevice(
+ PUSBDEVICE *OutDevice)
+{
+ CUSBDevice * This;
+
+ //
+ // allocate controller
+ //
+ This = new(NonPagedPool, TAG_USBLIB) 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;
+}
+