/* * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface * LICENSE: GPL - See COPYING in the top level directory * FILE: drivers/usb/usbehci/hub_controller.cpp * PURPOSE: USB EHCI device driver. * PROGRAMMERS: * Michael Martin (michael.martin@reactos.org) * Johannes Anderwald (johannes.anderwald@reactos.org) */ #define INITGUID #include "usbehci.h" VOID StatusChangeEndpointCallBack( PVOID Context); class CHubController : public IHubController, public IDispatchIrp { public: STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); STDMETHODIMP_(ULONG) AddRef() { InterlockedIncrement(&m_Ref); return m_Ref; } STDMETHODIMP_(ULONG) Release() { InterlockedDecrement(&m_Ref); if (!m_Ref) { delete this; return 0; } return m_Ref; } // IHubController interface functions virtual NTSTATUS Initialize(IN PDRIVER_OBJECT DriverObject, IN PHCDCONTROLLER Controller, IN PUSBHARDWAREDEVICE Device, IN BOOLEAN IsRootHubDevice, IN ULONG DeviceAddress); virtual NTSTATUS GetHubControllerDeviceObject(PDEVICE_OBJECT * HubDeviceObject); virtual NTSTATUS GetHubControllerSymbolicLink(ULONG BufferLength, PVOID Buffer, PULONG RequiredLength); // IDispatchIrp interface functions virtual NTSTATUS HandlePnp(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp); virtual NTSTATUS HandlePower(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp); virtual NTSTATUS HandleDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp); // local functions NTSTATUS HandleQueryInterface(PIO_STACK_LOCATION IoStack); NTSTATUS SetDeviceInterface(BOOLEAN bEnable); NTSTATUS CreatePDO(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT * OutDeviceObject); PUSBHARDWAREDEVICE GetUsbHardware(); ULONG AcquireDeviceAddress(); VOID ReleaseDeviceAddress(ULONG DeviceAddress); BOOLEAN ValidateUsbDevice(PUSBDEVICE UsbDevice); NTSTATUS AddUsbDevice(PUSBDEVICE UsbDevice); NTSTATUS RemoveUsbDevice(PUSBDEVICE UsbDevice); VOID SetNotification(PVOID CallbackContext, PRH_INIT_CALLBACK CallbackRoutine); // internal ioctl routines NTSTATUS HandleGetDescriptor(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleClassDevice(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleGetStatusFromDevice(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleSelectConfiguration(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleSelectInterface(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleClassOther(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleClassInterface(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleBulkOrInterruptTransfer(IN OUT PIRP Irp, PURB Urb); friend VOID StatusChangeEndpointCallBack(PVOID Context); // constructor / destructor CHubController(IUnknown *OuterUnknown){} virtual ~CHubController(){} protected: LONG m_Ref; PHCDCONTROLLER m_Controller; PUSBHARDWAREDEVICE m_Hardware; BOOLEAN m_IsRootHubDevice; ULONG m_DeviceAddress; BOOLEAN m_InterfaceEnabled; UNICODE_STRING m_HubDeviceInterfaceString; PDEVICE_OBJECT m_HubControllerDeviceObject; PDRIVER_OBJECT m_DriverObject; PVOID m_HubCallbackContext; PRH_INIT_CALLBACK m_HubCallbackRoutine; USB_DEVICE_DESCRIPTOR m_DeviceDescriptor; KSPIN_LOCK m_Lock; RTL_BITMAP m_DeviceAddressBitmap; PULONG m_DeviceAddressBitmapBuffer; LIST_ENTRY m_UsbDeviceList; PIRP m_PendingSCEIrp; //Internal Functions BOOLEAN QueryStatusChageEndpoint(PIRP Irp); }; typedef struct { LIST_ENTRY Entry; PUSBDEVICE Device; }USBDEVICE_ENTRY, *PUSBDEVICE_ENTRY; /* Lifted from Linux with slight changes */ const UCHAR ROOTHUB2_DEVICE_DESCRIPTOR [] = { 0x12, /* bLength; */ USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType; Device */ 0x00, 0x20, /* bcdUSB; v1.1 */ USB_DEVICE_CLASS_HUB, /* bDeviceClass; HUB_CLASSCODE */ 0x01, /* bDeviceSubClass; */ 0x00, /* bDeviceProtocol; [ low/full speeds only ] */ 0x08, /* bMaxPacketSize0; 8 Bytes */ /* Fill Vendor and Product in when init root hub */ 0x00, 0x00, /* idVendor; */ 0x00, 0x00, /* idProduct; */ 0x00, 0x00, /* bcdDevice */ 0x00, /* iManufacturer; */ 0x00, /* iProduct; */ 0x00, /* iSerialNumber; */ 0x01 /* bNumConfigurations; */ }; const UCHAR ROOTHUB2_CONFIGURATION_DESCRIPTOR [] = { /* one configuration */ 0x09, /* bLength; */ 0x02, /* bDescriptorType; Configuration */ 0x19, 0x00, /* wTotalLength; */ 0x01, /* bNumInterfaces; (1) */ 0x23, /* bConfigurationValue; */ 0x00, /* iConfiguration; */ 0x40, /* bmAttributes; */ 0x00 /* MaxPower; */ }; const UCHAR ROOTHUB2_INTERFACE_DESCRIPTOR [] = { /* one interface */ 0x09, /* bLength: Interface; */ 0x04, /* bDescriptorType; Interface */ 0x00, /* bInterfaceNumber; */ 0x00, /* bAlternateSetting; */ 0x01, /* bNumEndpoints; */ 0x09, /* bInterfaceClass; HUB_CLASSCODE */ 0x01, /* bInterfaceSubClass; */ 0x00, /* bInterfaceProtocol: */ 0x00 /* iInterface; */ }; const UCHAR ROOTHUB2_ENDPOINT_DESCRIPTOR [] = { /* one endpoint (status change endpoint) */ 0x07, /* bLength; */ 0x05, /* bDescriptorType; Endpoint */ 0x81, /* bEndpointAddress; IN Endpoint 1 */ 0x03, /* bmAttributes; Interrupt */ 0x08, 0x00, /* wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ 0xFF /* bInterval; (255ms -- usb 2.0 spec) */ }; //---------------------------------------------------------------------------------------- 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_USBEHCI); 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; // // get current stack location // IoStack = IoGetCurrentIrpStackLocation(Irp); ASSERT(IoStack); // // Get the Urb // Urb = (PURB)IoStack->Parameters.Others.Argument1; ASSERT(Urb); // // Get the number of ports and check each one for device connected // m_Hardware->GetDeviceDetails(NULL, NULL, &PortCount, NULL); DPRINT1("SCE Request\n"); ((PULONG)Urb->UrbBulkOrInterruptTransfer.TransferBuffer)[0] = 0; for (PortId = 0; PortId < PortCount; PortId++) { m_Hardware->GetPortStatus(PortId, &PortStatus, &PortChange); DPRINT1("Port %d: Status %x, Change %x\n", PortId, PortStatus, PortChange); // // Loop the ports // if ((PortStatus & USB_PORT_STATUS_CONNECT) && (PortChange & USB_PORT_STATUS_CONNECT)) { DPRINT1("Device is connected on port %d\n", PortId); // Set the value for the port number ((PUCHAR)Urb->UrbBulkOrInterruptTransfer.TransferBuffer)[0] = 1 << ((PortId + 1) & 7); } } // // If there were changes then return TRUE // if (((PULONG)Urb->UrbBulkOrInterruptTransfer.TransferBuffer)[0] != 0) return TRUE; return FALSE; } //----------------------------------------------------------------------------------------- NTSTATUS CHubController::GetHubControllerDeviceObject(PDEVICE_OBJECT * HubDeviceObject) { // // store controller object // *HubDeviceObject = m_HubControllerDeviceObject; return STATUS_SUCCESS; } //----------------------------------------------------------------------------------------- NTSTATUS CHubController::GetHubControllerSymbolicLink( ULONG BufferLength, PVOID Buffer, PULONG RequiredLength) { if (!m_InterfaceEnabled) { // // device interface not yet enabled // return STATUS_UNSUCCESSFUL; } if (BufferLength < (ULONG)m_HubDeviceInterfaceString.Length - 8) { // // buffer too small // length is without '\??\' // *RequiredLength = m_HubDeviceInterfaceString.Length- 8; // // done // return STATUS_BUFFER_OVERFLOW; } // // copy symbolic link // RtlCopyMemory(Buffer, &m_HubDeviceInterfaceString.Buffer[4], m_HubDeviceInterfaceString.Length - 8); // // store length, length is without '\??\' // *RequiredLength = m_HubDeviceInterfaceString.Length - 8; // // done // return STATUS_SUCCESS; } //----------------------------------------------------------------------------------------- NTSTATUS CHubController::HandlePnp( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp) { PIO_STACK_LOCATION IoStack; PCOMMON_DEVICE_EXTENSION DeviceExtension; PDEVICE_CAPABILITIES DeviceCapabilities; PPNP_BUS_INFORMATION BusInformation; PDEVICE_RELATIONS DeviceRelations; NTSTATUS Status; ULONG Index = 0, Length; USHORT VendorID, DeviceID; ULONG HiSpeed, NumPorts; WCHAR Buffer[300]; LPWSTR DeviceName; // // get device extension // DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension; // // sanity check // ASSERT(DeviceExtension->IsFDO == FALSE); // // get current stack location // IoStack = IoGetCurrentIrpStackLocation(Irp); switch(IoStack->MinorFunction) { case IRP_MN_START_DEVICE: { DPRINT1("CHubController::HandlePnp IRP_MN_START_DEVICE\n"); // // register device interface // Status = SetDeviceInterface(TRUE); break; } case IRP_MN_QUERY_ID: { DPRINT1("CHubController::HandlePnp IRP_MN_QUERY_ID Type %x\n", IoStack->Parameters.QueryId.IdType); if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID) { if (m_Hardware) { // // query device id // Status = m_Hardware->GetDeviceDetails(&VendorID, &DeviceID, &NumPorts, &HiSpeed); if (HiSpeed == 0x200) { // // USB 2.0 hub // swprintf(Buffer, L"USB\\ROOT_HUB20"); } else { // // USB 1.1 hub // swprintf(Buffer, L"USB\\ROOT_HUB"); } DPRINT1("Name %S\n", Buffer); // // calculate length // Length = (wcslen(Buffer) + 1); // // allocate buffer // DeviceName = (LPWSTR)ExAllocatePoolWithTag(PagedPool, Length * sizeof(WCHAR), TAG_USBEHCI); if (!DeviceName) { // // no memory // Status = STATUS_INSUFFICIENT_RESOURCES; break; } // // copy device name // wcscpy(DeviceName, Buffer); // // store result // Irp->IoStatus.Information = (ULONG_PTR)DeviceName; Status = STATUS_SUCCESS; break; } Status = STATUS_UNSUCCESSFUL; PC_ASSERT(0); break; } if (IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs) { if (m_Hardware) { // // query device id // Status = m_Hardware->GetDeviceDetails(&VendorID, &DeviceID, &NumPorts, &HiSpeed); if (!NT_SUCCESS(Status)) { DPRINT1("CHubController::HandlePnp> failed to get hardware id %x\n", Status); VendorID = 0x8086; DeviceID = 0x3A37; } if (HiSpeed == 0x200) { // // USB 2.0 hub // Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB20&VID%04x&PID%04x&REV0000", VendorID, DeviceID) + 1; Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB20&VID%04x&PID%04x", VendorID, DeviceID) + 1; Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB20") + 1; } else { // // USB 1.1 hub // Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB&VID%04x&PID%04x&REV0000", VendorID, DeviceID) + 1; Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB&VID%04x&PID%04x", VendorID, DeviceID) + 1; Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB") + 1; } Buffer[Index] = UNICODE_NULL; Index++; DPRINT1("Name %S\n", Buffer); // // allocate buffer // DeviceName = (LPWSTR)ExAllocatePoolWithTag(PagedPool, Index * sizeof(WCHAR), TAG_USBEHCI); if (!DeviceName) { // // no memory // Status = STATUS_INSUFFICIENT_RESOURCES; break; } // // copy device name // RtlMoveMemory(DeviceName, Buffer, Index * sizeof(WCHAR)); // // store result // Irp->IoStatus.Information = (ULONG_PTR)DeviceName; Status = STATUS_SUCCESS; break; } } Status = STATUS_SUCCESS; break; } case IRP_MN_QUERY_CAPABILITIES: { DPRINT1("CHubController::HandlePnp IRP_MN_QUERY_CAPABILITIES\n"); DeviceCapabilities = (PDEVICE_CAPABILITIES)IoStack->Parameters.DeviceCapabilities.Capabilities; DeviceCapabilities->LockSupported = FALSE; DeviceCapabilities->EjectSupported = FALSE; DeviceCapabilities->Removable = FALSE; DeviceCapabilities->DockDevice = FALSE; DeviceCapabilities->UniqueID = FALSE; DeviceCapabilities->SilentInstall = FALSE; DeviceCapabilities->RawDeviceOK = FALSE; DeviceCapabilities->SurpriseRemovalOK = FALSE; DeviceCapabilities->Address = 0; DeviceCapabilities->UINumber = 0; DeviceCapabilities->DeviceD2 = 1; /* FIXME */ DeviceCapabilities->HardwareDisabled = FALSE; DeviceCapabilities->NoDisplayInUI = FALSE; DeviceCapabilities->DeviceState[0] = PowerDeviceD0; for (Index = 0; Index < PowerSystemMaximum; Index++) DeviceCapabilities->DeviceState[Index] = PowerDeviceD3; DeviceCapabilities->DeviceWake = PowerDeviceUnspecified; DeviceCapabilities->D1Latency = 0; DeviceCapabilities->D2Latency = 0; DeviceCapabilities->D3Latency = 0; Status = STATUS_SUCCESS; break; } case IRP_MN_QUERY_INTERFACE: { DPRINT1("CHubController::HandlePnp IRP_MN_QUERY_INTERFACE\n"); // // handle device interface requests // Status = HandleQueryInterface(IoStack); break; } case IRP_MN_REMOVE_DEVICE: { DPRINT1("CHubController::HandlePnp IRP_MN_REMOVE_DEVICE\n"); // // deactivate device interface for BUS PDO // SetDeviceInterface(FALSE); // // complete the request first // Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); // // now delete device // IoDeleteDevice(m_HubControllerDeviceObject); // // nullify pointer // m_HubControllerDeviceObject = 0; // // done // return STATUS_SUCCESS; } case IRP_MN_QUERY_DEVICE_RELATIONS: { DPRINT1("CHubController::HandlePnp IRP_MN_QUERY_DEVICE_RELATIONS Type %x\n", IoStack->Parameters.QueryDeviceRelations.Type); if (IoStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation) { // // allocate device relations // DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(PagedPool, sizeof(DEVICE_RELATIONS), TAG_USBEHCI); if (!DeviceRelations) { // // no memory // Status = STATUS_INSUFFICIENT_RESOURCES; break; } // // initialize device relations // DeviceRelations->Count = 1; DeviceRelations->Objects[0] = DeviceObject; ObReferenceObject(DeviceObject); // // done // Status = STATUS_SUCCESS; Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; } else { // // not handled // Status = Irp->IoStatus.Status; } break; } case IRP_MN_QUERY_BUS_INFORMATION: { DPRINT1("CHubController::HandlePnp IRP_MN_QUERY_BUS_INFORMATION\n"); // // allocate buffer for bus information // BusInformation = (PPNP_BUS_INFORMATION)ExAllocatePool(PagedPool, sizeof(PNP_BUS_INFORMATION)); if (BusInformation) { // // copy BUS guid // RtlMoveMemory(&BusInformation->BusTypeGuid, &GUID_BUS_TYPE_USB, sizeof(GUID)); // // set bus type // BusInformation->LegacyBusType = PNPBus; BusInformation->BusNumber = 0; Status = STATUS_SUCCESS; Irp->IoStatus.Information = (ULONG_PTR)BusInformation; } else { // // no memory // Status = STATUS_INSUFFICIENT_RESOURCES; } break; } case IRP_MN_STOP_DEVICE: { DPRINT1("CHubController::HandlePnp IRP_MN_STOP_DEVICE\n"); // // stop device // Status = STATUS_SUCCESS; break; } default: { // // ignore request with default status // Status = Irp->IoStatus.Status; break; } } // // complete request // Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); // // done // return Status; } //----------------------------------------------------------------------------------------- NTSTATUS CHubController::HandlePower( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp) { UNIMPLEMENTED Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_NOT_IMPLEMENTED; } //----------------------------------------------------------------------------------------- NTSTATUS CHubController::HandleBulkOrInterruptTransfer( IN OUT PIRP Irp, PURB Urb) { PUSBDEVICE UsbDevice; PUSB_ENDPOINT_DESCRIPTOR EndPointDesc = NULL; // // First check if the request is for the Status Change Endpoint // // // Is the Request for the root hub // if (Urb->UrbHeader.UsbdDeviceHandle == 0) { ASSERT(m_PendingSCEIrp == NULL); if (QueryStatusChageEndpoint(Irp)) { return STATUS_SUCCESS; } // // Else pend the IRP, to be completed when a device connects or disconnects. // DPRINT1("Pending SCE Irp\n");; m_PendingSCEIrp = Irp; IoMarkIrpPending(Irp); return STATUS_PENDING; } // // Check PipeHandle to determine if this is a Bulk or Interrupt Transfer Request // EndPointDesc = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbBulkOrInterruptTransfer.PipeHandle; switch(EndPointDesc->bmAttributes & 0x0F) { case USB_ENDPOINT_TYPE_CONTROL: DPRINT1("Control Transfer is not expected!!!\n"); return STATUS_INVALID_DEVICE_REQUEST; case USB_ENDPOINT_TYPE_BULK: DPRINT("Initiating Bulk Transfer\n"); break; case USB_ENDPOINT_TYPE_ISOCHRONOUS: case USB_ENDPOINT_TYPE_INTERRUPT: DPRINT1("Not Supported\n"); break; default: DPRINT1("Unknown EndPoint Type!\n"); break; } // // check if this is a valid usb device handle // PC_ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))); // // get device // UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); return UsbDevice->SubmitIrp(Irp); } //----------------------------------------------------------------------------------------- NTSTATUS CHubController::HandleClassOther( IN OUT PIRP Irp, PURB Urb) { NTSTATUS Status = STATUS_NOT_IMPLEMENTED; USHORT PortStatus = 0, PortChange = 0; PUSHORT Buffer; ULONG NumPort; ULONG PortId; //DPRINT1("CHubController::HandleClassOther> Request %x Value %x not implemented\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 // Buffer = (PUSHORT)Urb->UrbControlVendorClassRequest.TransferBuffer; // // store status, then port change // *Buffer = PortStatus; Buffer++; *Buffer = PortChange; } // // done // break; } case USB_REQUEST_CLEAR_FEATURE: { switch (Urb->UrbControlVendorClassRequest.Value) { case C_PORT_CONNECTION: Status = m_Hardware->ClearPortStatus(PortId, C_PORT_CONNECTION); break; case C_PORT_RESET: Status= m_Hardware->ClearPortStatus(PortId, C_PORT_RESET); break; default: DPRINT("Unknown Value for Clear Feature %x \n", Urb->UrbControlVendorClassRequest.Value); break; } Status = STATUS_SUCCESS; break; } case USB_REQUEST_SET_FEATURE: { // // request set feature // switch(Urb->UrbControlVendorClassRequest.Value) { case PORT_ENABLE: { // // port enable is a no-op for 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("Unsupported request id %x\n", Urb->UrbControlVendorClassRequest.Value); PC_ASSERT(FALSE); } break; } default: DPRINT1("CHubController::HandleClassOther Unknown request code %x\n", Urb->UrbControlVendorClassRequest.Request); PC_ASSERT(0); Status = STATUS_INVALID_DEVICE_REQUEST; } return Status; } //----------------------------------------------------------------------------------------- NTSTATUS CHubController::HandleSelectConfiguration( IN OUT PIRP Irp, PURB Urb) { PUSBDEVICE UsbDevice; // // 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; // // TODO: copy interface info // return STATUS_SUCCESS; } else { // // check if this is a valid usb device handle // PC_ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))); // // get device // UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); // // select configuration // return UsbDevice->SelectConfiguration(Urb->UrbSelectConfiguration.ConfigurationDescriptor, &Urb->UrbSelectConfiguration.Interface, &Urb->UrbSelectConfiguration.ConfigurationHandle); } } //----------------------------------------------------------------------------------------- NTSTATUS CHubController::HandleSelectInterface( IN OUT PIRP Irp, PURB Urb) { PUSBDEVICE UsbDevice; // // sanity check // PC_ASSERT(Urb->UrbSelectInterface.ConfigurationHandle); // // is the request for the Root Hub // if (Urb->UrbHeader.UsbdDeviceHandle == NULL) { // // no op for root hub // return STATUS_SUCCESS; } else { // // check if this is a valid usb device handle // PC_ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))); // // get device // UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); // // select interface // return UsbDevice->SelectInterface(Urb->UrbSelectInterface.ConfigurationHandle, &Urb->UrbSelectInterface.Interface); } } //----------------------------------------------------------------------------------------- NTSTATUS CHubController::HandleGetStatusFromDevice( IN OUT PIRP Irp, PURB Urb) { PUSHORT Status; // // sanity checks // PC_ASSERT(Urb->UrbControlGetStatusRequest.Index == 0); PC_ASSERT(Urb->UrbControlGetStatusRequest.TransferBufferLength >= sizeof(USHORT)); PC_ASSERT(Urb->UrbControlGetStatusRequest.TransferBuffer); PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle == NULL); // // get status buffer // Status = (PUSHORT)Urb->UrbControlGetStatusRequest.TransferBuffer; // // FIXME need more flags ? // *Status = USB_PORT_STATUS_CONNECT; // // done // return STATUS_SUCCESS; } //----------------------------------------------------------------------------------------- NTSTATUS CHubController::HandleClassDevice( IN OUT PIRP Irp, IN OUT PURB Urb) { NTSTATUS Status = STATUS_NOT_IMPLEMENTED; PUSB_HUB_DESCRIPTOR UsbHubDescriptor; ULONG PortCount, Dummy2; USHORT Dummy1; // // check class request type // switch(Urb->UrbControlVendorClassRequest.Request) { case USB_REQUEST_GET_DESCRIPTOR: { switch (Urb->UrbControlVendorClassRequest.Value >> 8) { case USB_DEVICE_CLASS_RESERVED: // FALL THROUGH case USB_DEVICE_CLASS_HUB: { // // sanity checks // PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBuffer); PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBufferLength >= sizeof(USB_HUB_DESCRIPTOR)); // // get hub descriptor // UsbHubDescriptor = (PUSB_HUB_DESCRIPTOR)Urb->UrbControlVendorClassRequest.TransferBuffer; // // one hub is handled // UsbHubDescriptor->bDescriptorLength = sizeof(USB_HUB_DESCRIPTOR); Urb->UrbControlVendorClassRequest.TransferBufferLength = sizeof(USB_HUB_DESCRIPTOR); // // type should 0x29 according to msdn // UsbHubDescriptor->bDescriptorType = 0x29; // // get port count // Status = m_Hardware->GetDeviceDetails(&Dummy1, &Dummy1, &PortCount, &Dummy2); PC_ASSERT(Status == STATUS_SUCCESS); // // FIXME: retrieve values // UsbHubDescriptor->bNumberOfPorts = (UCHAR)PortCount; UsbHubDescriptor->wHubCharacteristics = 0x0012; UsbHubDescriptor->bPowerOnToPowerGood = 0x01; UsbHubDescriptor->bHubControlCurrent = 0x00; // // done // Status = STATUS_SUCCESS; break; } default: DPRINT1("CHubController::HandleClassDevice Class %x not implemented\n", Urb->UrbControlVendorClassRequest.Value >> 8); break; } break; } default: DPRINT1("CHubController::HandleClassDevice Type %x not implemented\n", Urb->UrbControlVendorClassRequest.Request); } return Status; } //----------------------------------------------------------------------------------------- NTSTATUS CHubController::HandleGetDescriptor( IN OUT PIRP Irp, IN OUT PURB Urb) { NTSTATUS Status = STATUS_NOT_IMPLEMENTED; PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup; PUCHAR Buffer; PUSBDEVICE UsbDevice; ULONG Length; // // check descriptor type // switch(Urb->UrbControlDescriptorRequest.DescriptorType) { case USB_DEVICE_DESCRIPTOR_TYPE: { // // sanity check // PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength >= sizeof(USB_DEVICE_DESCRIPTOR)); PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer); if (Urb->UrbHeader.UsbdDeviceHandle == NULL) { // // copy root hub device descriptor // RtlCopyMemory((PUCHAR)Urb->UrbControlDescriptorRequest.TransferBuffer, &m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR)); Status = STATUS_SUCCESS; } else { // // check if this is a valid usb device handle // PC_ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))); // // get device // UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); // // retrieve device descriptor from device // UsbDevice->GetDeviceDescriptor((PUSB_DEVICE_DESCRIPTOR)Urb->UrbControlDescriptorRequest.TransferBuffer); Status = STATUS_SUCCESS; } break; } case USB_CONFIGURATION_DESCRIPTOR_TYPE: { // // sanity checks // PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer); PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength >= sizeof(USB_CONFIGURATION_DESCRIPTOR)); if (Urb->UrbHeader.UsbdDeviceHandle == NULL) { // // request is for the root bus controller // C_ASSERT(sizeof(ROOTHUB2_CONFIGURATION_DESCRIPTOR) == sizeof(USB_CONFIGURATION_DESCRIPTOR)); 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; break; } // // copy interface descriptor template // Buffer = (PUCHAR)(ConfigurationDescriptor + 1); C_ASSERT(sizeof(ROOTHUB2_INTERFACE_DESCRIPTOR) == sizeof(USB_INTERFACE_DESCRIPTOR)); RtlCopyMemory(Buffer, ROOTHUB2_INTERFACE_DESCRIPTOR, sizeof(USB_INTERFACE_DESCRIPTOR)); // // copy end point descriptor template // Buffer += sizeof(USB_INTERFACE_DESCRIPTOR); C_ASSERT(sizeof(ROOTHUB2_ENDPOINT_DESCRIPTOR) == sizeof(USB_ENDPOINT_DESCRIPTOR)); RtlCopyMemory(Buffer, ROOTHUB2_ENDPOINT_DESCRIPTOR, sizeof(USB_ENDPOINT_DESCRIPTOR)); // // done // Status = STATUS_SUCCESS; } else { DPRINT1("Length %u\n", Urb->UrbControlDescriptorRequest.TransferBufferLength); // // check if this is a valid usb device handle // PC_ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))); // // get device // UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); if (sizeof(USB_CONFIGURATION_DESCRIPTOR) > Urb->UrbControlDescriptorRequest.TransferBufferLength) { // // buffer too small // Urb->UrbControlDescriptorRequest.TransferBufferLength = UsbDevice->GetConfigurationDescriptorsLength(); // // bail out // Status = STATUS_SUCCESS; break; } // // perform work in IUSBDevice // UsbDevice->GetConfigurationDescriptors((PUSB_CONFIGURATION_DESCRIPTOR)Urb->UrbControlDescriptorRequest.TransferBuffer, Urb->UrbControlDescriptorRequest.TransferBufferLength, &Length); // // sanity check // PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength >= Length); // // store result size // Urb->UrbControlDescriptorRequest.TransferBufferLength = Length; Status = STATUS_SUCCESS; } break; } case USB_STRING_DESCRIPTOR_TYPE: { // // sanity check // PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer); PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength); // // check if this is a valid usb device handle // PC_ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))); // // get device // UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); // // 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("CHubController::HandleGetDescriptor DescriptorType %x unimplemented\n", Urb->UrbControlDescriptorRequest.DescriptorType); break; } // // done // return Status; } //----------------------------------------------------------------------------------------- NTSTATUS CHubController::HandleClassInterface( IN OUT PIRP Irp, IN OUT PURB Urb) { USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup; NTSTATUS Status; PUSBDEVICE UsbDevice; // // sanity check // PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBuffer); PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBufferLength); PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle); // // check if this is a valid usb device handle // PC_ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))); // // get device // UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); DPRINT1("URB_FUNCTION_CLASS_INTERFACE\n"); DPRINT1("TransferFlags %x\n", Urb->UrbControlVendorClassRequest.TransferFlags); DPRINT1("TransferBufferLength %x\n", Urb->UrbControlVendorClassRequest.TransferBufferLength); DPRINT1("TransferBuffer %x\n", Urb->UrbControlVendorClassRequest.TransferBuffer); DPRINT1("TransferBufferMDL %x\n", Urb->UrbControlVendorClassRequest.TransferBufferMDL); DPRINT1("RequestTypeReservedBits %x\n", Urb->UrbControlVendorClassRequest.RequestTypeReservedBits); DPRINT1("Request %x\n", Urb->UrbControlVendorClassRequest.Request); DPRINT1("Value %x\n", Urb->UrbControlVendorClassRequest.Value); DPRINT1("Index %x\n", Urb->UrbControlVendorClassRequest.Index); // // initialize setup packet // CtrlSetup.bmRequestType.B = 0xa1; //FIXME: Const. CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request; CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value; CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index; CtrlSetup.wLength = Urb->UrbControlVendorClassRequest.TransferBufferLength; // // issue request // Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlVendorClassRequest.TransferBufferLength, Urb->UrbControlVendorClassRequest.TransferBuffer); // // assert on failure // PC_ASSERT(NT_SUCCESS(Status)); // // done // return Status; } //----------------------------------------------------------------------------------------- NTSTATUS CHubController::HandleDeviceControl( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp) { PIO_STACK_LOCATION IoStack; PCOMMON_DEVICE_EXTENSION DeviceExtension; PURB Urb; NTSTATUS Status = STATUS_NOT_IMPLEMENTED; // // get current stack location // IoStack = IoGetCurrentIrpStackLocation(Irp); // // get device extension // DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension; // // determine which request should be performed // switch(IoStack->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_INTERNAL_USB_SUBMIT_URB: { // // get urb // Urb = (PURB)IoStack->Parameters.Others.Argument1; PC_ASSERT(Urb); switch (Urb->UrbHeader.Function) { case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: Status = HandleGetDescriptor(Irp, Urb); break; case URB_FUNCTION_CLASS_DEVICE: Status = HandleClassDevice(Irp, Urb); break; case URB_FUNCTION_GET_STATUS_FROM_DEVICE: Status = HandleGetStatusFromDevice(Irp, Urb); break; case URB_FUNCTION_SELECT_CONFIGURATION: Status = HandleSelectConfiguration(Irp, Urb); break; case URB_FUNCTION_SELECT_INTERFACE: Status = HandleSelectInterface(Irp, Urb); break; case URB_FUNCTION_CLASS_OTHER: Status = HandleClassOther(Irp, Urb); break; case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: Status = HandleBulkOrInterruptTransfer(Irp, Urb); break; case URB_FUNCTION_CLASS_INTERFACE: Status = HandleClassInterface(Irp, Urb); break; default: DPRINT1("IOCTL_INTERNAL_USB_SUBMIT_URB Function %x NOT IMPLEMENTED\n", Urb->UrbHeader.Function); break; } // // request completed // break; } case IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE: { DPRINT("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE\n"); if (IoStack->Parameters.Others.Argument1) { // // store object as device handle // *(PVOID *)IoStack->Parameters.Others.Argument1 = (PVOID)this; Status = STATUS_SUCCESS; } else { // // mis-behaving hub driver // Status = STATUS_INVALID_DEVICE_REQUEST; } // // request completed // break; } case IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO: { DPRINT("IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO\n"); // // this is the first request send, it delivers the PDO to the caller // if (IoStack->Parameters.Others.Argument1) { // // store root hub pdo object // *(PVOID *)IoStack->Parameters.Others.Argument1 = DeviceObject; } if (IoStack->Parameters.Others.Argument2) { // // documentation claims to deliver the hcd controller object, although it is wrong // *(PVOID *)IoStack->Parameters.Others.Argument2 = DeviceObject; } // // request completed // Status = STATUS_SUCCESS; break; } case IOCTL_INTERNAL_USB_GET_HUB_COUNT: { DPRINT("IOCTL_INTERNAL_USB_GET_HUB_COUNT\n"); // // after IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO is delivered, the usbhub driver // requests this ioctl to deliver the number of presents. if (IoStack->Parameters.Others.Argument1) { // // FIXME / verify: there is only one hub // *(PULONG)IoStack->Parameters.Others.Argument1 = 1; } // // request completed // Status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(ULONG); break; } case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION: { DPRINT1("IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION UNIMPLEMENTED\n"); Status = STATUS_SUCCESS; break; } default: { DPRINT1("HandleDeviceControl>Type: IoCtl %x InputBufferLength %lu OutputBufferLength %lu NOT IMPLEMENTED\n", IoStack->Parameters.DeviceIoControl.IoControlCode, IoStack->Parameters.DeviceIoControl.InputBufferLength, IoStack->Parameters.DeviceIoControl.OutputBufferLength); break; } } if (Status != STATUS_PENDING) { Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); } return Status; } //----------------------------------------------------------------------------------------- PUSBHARDWAREDEVICE CHubController::GetUsbHardware() { return m_Hardware; } //----------------------------------------------------------------------------------------- ULONG CHubController::AcquireDeviceAddress() { KIRQL OldLevel; ULONG DeviceAddress; // // acquire device lock // KeAcquireSpinLock(&m_Lock, &OldLevel); // // find address // DeviceAddress = RtlFindClearBits(&m_DeviceAddressBitmap, 1, 0); if (DeviceAddress != MAXULONG) { // // reserve address // RtlSetBits(&m_DeviceAddressBitmap, DeviceAddress, 1); // // device addresses start from 0x1 - 0xFF // DeviceAddress++; } // // release spin lock // KeReleaseSpinLock(&m_Lock, OldLevel); // // return device address // return DeviceAddress; } //----------------------------------------------------------------------------------------- VOID CHubController::ReleaseDeviceAddress( ULONG DeviceAddress) { KIRQL OldLevel; // // acquire device lock // KeAcquireSpinLock(&m_Lock, &OldLevel); // // sanity check // PC_ASSERT(DeviceAddress != 0); // // convert back to bit number // DeviceAddress--; // // clear bit // RtlClearBits(&m_DeviceAddressBitmap, DeviceAddress, 1); // // release lock // KeReleaseSpinLock(&m_Lock, OldLevel); } //----------------------------------------------------------------------------------------- NTSTATUS CHubController::RemoveUsbDevice( PUSBDEVICE UsbDevice) { PUSBDEVICE_ENTRY DeviceEntry; PLIST_ENTRY Entry; NTSTATUS Status = STATUS_UNSUCCESSFUL; KIRQL OldLevel; // // acquire lock // KeAcquireSpinLock(&m_Lock, &OldLevel); // // point to first entry // Entry = m_UsbDeviceList.Flink; // // find matching entry // while(Entry != &m_UsbDeviceList) { // // get entry // DeviceEntry = (PUSBDEVICE_ENTRY)CONTAINING_RECORD(Entry, USBDEVICE_ENTRY, Entry); // // is it current entry // if (DeviceEntry->Device == UsbDevice) { // // remove entry // RemoveEntryList(Entry); // // free entry // ExFreePoolWithTag(DeviceEntry, TAG_USBEHCI); // // 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_USBEHCI); if (!DeviceEntry) { // // no memory // return STATUS_INSUFFICIENT_RESOURCES; } // // initialize entry // DeviceEntry->Device = UsbDevice; // // acquire lock // KeAcquireSpinLock(&m_Lock, &OldLevel); // // insert entry // InsertTailList(&m_UsbDeviceList, &DeviceEntry->Entry); // // release spin lock // KeReleaseSpinLock(&m_Lock, OldLevel); // // done // return STATUS_SUCCESS; } //----------------------------------------------------------------------------------------- VOID CHubController::SetNotification( PVOID CallbackContext, PRH_INIT_CALLBACK CallbackRoutine) { KIRQL OldLevel; // // acquire hub controller lock // KeAcquireSpinLock(&m_Lock, &OldLevel); // // now set the callback routine and context of the hub // m_HubCallbackContext = CallbackContext; m_HubCallbackRoutine = CallbackRoutine; // // release hub controller lock // KeReleaseSpinLock(&m_Lock, OldLevel); } //================================================================================================= // // Generic Interface functions // VOID USB_BUSIFFN USBI_InterfaceReference( PVOID BusContext) { CHubController * Controller = (CHubController*)BusContext; DPRINT1("USBH_InterfaceReference\n"); // // add reference // Controller->AddRef(); } VOID USB_BUSIFFN USBI_InterfaceDereference( PVOID BusContext) { CHubController * Controller = (CHubController*)BusContext; DPRINT1("USBH_InterfaceDereference\n"); // // release // Controller->Release(); } //================================================================================================= // // USB Hub Interface functions // NTSTATUS USB_BUSIFFN USBHI_CreateUsbDevice( PVOID BusContext, PUSB_DEVICE_HANDLE *NewDevice, PUSB_DEVICE_HANDLE HubDeviceHandle, USHORT PortStatus, USHORT PortNumber) { PUSBDEVICE NewUsbDevice; CHubController * Controller; NTSTATUS Status; DPRINT1("USBHI_CreateUsbDevice\n"); // // first get hub controller // Controller = (CHubController *)BusContext; // // sanity check // PC_ASSERT(Controller); PC_ASSERT(BusContext == HubDeviceHandle); // // now allocate usb device // Status = CreateUSBDevice(&NewUsbDevice); // // check for success // if (!NT_SUCCESS(Status)) { // // release controller // Controller->Release(); DPRINT1("USBHI_CreateUsbDevice: failed to create usb device %x\n", Status); return Status; } // // now initialize device // Status = NewUsbDevice->Initialize(PHUBCONTROLLER(Controller), Controller->GetUsbHardware(),PVOID(Controller), PortNumber, PortStatus); // // check for success // if (!NT_SUCCESS(Status)) { // // release usb device // NewUsbDevice->Release(); DPRINT1("USBHI_CreateUsbDevice: failed to initialize usb device %x\n", Status); return Status; } // // insert into list // Status = Controller->AddUsbDevice(NewUsbDevice); // // check for success // if (!NT_SUCCESS(Status)) { // // release usb device // NewUsbDevice->Release(); DPRINT1("USBHI_CreateUsbDevice: failed to add usb device %x\n", Status); return Status; } // // store the handle // *NewDevice = NewUsbDevice; // // done // return STATUS_SUCCESS; } NTSTATUS USB_BUSIFFN USBHI_InitializeUsbDevice( PVOID BusContext, PUSB_DEVICE_HANDLE DeviceHandle) { PUSBDEVICE UsbDevice; CHubController * Controller; ULONG DeviceAddress; NTSTATUS Status; ULONG Index = 0; DPRINT1("USBHI_InitializeUsbDevice\n"); // // first get controller // Controller = (CHubController *)BusContext; PC_ASSERT(Controller); // // get device object // UsbDevice = (PUSBDEVICE)DeviceHandle; PC_ASSERT(UsbDevice); // // validate device handle // if (!Controller->ValidateUsbDevice(UsbDevice)) { DPRINT1("USBHI_InitializeUsbDevice invalid device handle %p\n", DeviceHandle); // // invalid device handle // return STATUS_DEVICE_NOT_CONNECTED; } // // now reserve an address // DeviceAddress = Controller->AcquireDeviceAddress(); // // is the device address valid // if (DeviceAddress == MAXULONG) { // // failed to get an device address from the device address pool // DPRINT1("USBHI_InitializeUsbDevice failed to get device address\n"); return STATUS_DEVICE_DATA_ERROR; } do { // // now set the device address // Status = UsbDevice->SetDeviceAddress((UCHAR)DeviceAddress); if (NT_SUCCESS(Status)) break; }while(Index++ < 3 ); // // check for failure // if (!NT_SUCCESS(Status)) { // // failed to set device address // DPRINT1("USBHI_InitializeUsbDevice failed to set address with %x\n", Status); // // release address // Controller->ReleaseDeviceAddress(DeviceAddress); // // return error // return STATUS_DEVICE_DATA_ERROR; } // // done // return STATUS_SUCCESS; } NTSTATUS USB_BUSIFFN USBHI_GetUsbDescriptors( PVOID BusContext, PUSB_DEVICE_HANDLE DeviceHandle, PUCHAR DeviceDescriptorBuffer, PULONG DeviceDescriptorBufferLength, PUCHAR ConfigDescriptorBuffer, PULONG ConfigDescriptorBufferLength) { PUSBDEVICE UsbDevice; CHubController * Controller; DPRINT1("USBHI_GetUsbDescriptors\n"); // // sanity check // PC_ASSERT(DeviceDescriptorBuffer); PC_ASSERT(DeviceDescriptorBufferLength); PC_ASSERT(*DeviceDescriptorBufferLength >= sizeof(USB_DEVICE_DESCRIPTOR)); PC_ASSERT(ConfigDescriptorBufferLength); PC_ASSERT(*ConfigDescriptorBufferLength >= sizeof(USB_CONFIGURATION_DESCRIPTOR)); // // first get controller // Controller = (CHubController *)BusContext; PC_ASSERT(Controller); // // get device object // UsbDevice = (PUSBDEVICE)DeviceHandle; PC_ASSERT(UsbDevice); // // validate device handle // if (!Controller->ValidateUsbDevice(UsbDevice)) { DPRINT1("USBHI_GetUsbDescriptors invalid device handle %p\n", DeviceHandle); // // invalid device handle // return STATUS_DEVICE_NOT_CONNECTED; } // // get device descriptor // UsbDevice->GetDeviceDescriptor((PUSB_DEVICE_DESCRIPTOR)DeviceDescriptorBuffer); // // store result length // *DeviceDescriptorBufferLength = sizeof(USB_DEVICE_DESCRIPTOR); // // get configuration descriptor // UsbDevice->GetConfigurationDescriptors((PUSB_CONFIGURATION_DESCRIPTOR)ConfigDescriptorBuffer, *ConfigDescriptorBufferLength, ConfigDescriptorBufferLength); // // complete the request // return STATUS_SUCCESS; } NTSTATUS USB_BUSIFFN USBHI_RemoveUsbDevice( PVOID BusContext, PUSB_DEVICE_HANDLE DeviceHandle, ULONG Flags) { PUSBDEVICE UsbDevice; CHubController * Controller; NTSTATUS Status; DPRINT1("USBHI_RemoveUsbDevice\n"); // // first get controller // Controller = (CHubController *)BusContext; PC_ASSERT(Controller); // // get device object // UsbDevice = (PUSBDEVICE)DeviceHandle; PC_ASSERT(UsbDevice); // // validate device handle // if (!Controller->ValidateUsbDevice(UsbDevice)) { DPRINT1("USBHI_RemoveUsbDevice invalid device handle %p\n", DeviceHandle); // // invalid device handle // return STATUS_DEVICE_NOT_CONNECTED; } // // check if there were flags passed // if (Flags & USBD_KEEP_DEVICE_DATA || Flags & USBD_MARK_DEVICE_BUSY) { // // ignore flags for now // return STATUS_SUCCESS; } // // remove device // Status = Controller->RemoveUsbDevice(UsbDevice); if (!NT_SUCCESS(Status)) { // // invalid device handle // DPRINT1("USBHI_RemoveUsbDevice Invalid device handle %p\n", UsbDevice); PC_ASSERT(0); return STATUS_DEVICE_NOT_CONNECTED; } // // release usb device // UsbDevice->Release(); // // done // return STATUS_SUCCESS; } NTSTATUS USB_BUSIFFN USBHI_RestoreUsbDevice( PVOID BusContext, PUSB_DEVICE_HANDLE OldDeviceHandle, PUSB_DEVICE_HANDLE NewDeviceHandle) { PUSBDEVICE OldUsbDevice, NewUsbDevice; CHubController * Controller; NTSTATUS Status; DPRINT1("USBHI_RestoreUsbDevice\n"); // // first get controller // Controller = (CHubController *)BusContext; PC_ASSERT(Controller); // // get device object // OldUsbDevice = (PUSBDEVICE)OldDeviceHandle; NewUsbDevice = (PUSBDEVICE)NewDeviceHandle; PC_ASSERT(OldUsbDevice); PC_ASSERT(NewDeviceHandle); // // validate device handle // PC_ASSERT(Controller->ValidateUsbDevice(NewUsbDevice)); PC_ASSERT(Controller->ValidateUsbDevice(OldUsbDevice)); DPRINT1("NewUsbDevice: DeviceAddress %x\n", NewUsbDevice->GetDeviceAddress()); DPRINT1("OldUsbDevice: DeviceAddress %x\n", OldUsbDevice->GetDeviceAddress()); PC_ASSERT(FALSE); // // remove old device handle // USBHI_RemoveUsbDevice(BusContext, OldDeviceHandle, 0); return STATUS_SUCCESS; } NTSTATUS USB_BUSIFFN USBHI_QueryDeviceInformation( PVOID BusContext, PUSB_DEVICE_HANDLE DeviceHandle, PVOID DeviceInformationBuffer, ULONG DeviceInformationBufferLength, PULONG LengthReturned) { PUSB_DEVICE_INFORMATION_0 DeviceInfo; PUSBDEVICE UsbDevice; CHubController * Controller; DPRINT1("USBHI_QueryDeviceInformation %p\n", BusContext); // // sanity check // PC_ASSERT(DeviceInformationBufferLength >= sizeof(USB_DEVICE_INFORMATION_0)); PC_ASSERT(DeviceInformationBuffer); PC_ASSERT(LengthReturned); // // get controller object // Controller = (CHubController*)BusContext; PC_ASSERT(Controller); // // get device object // UsbDevice = (PUSBDEVICE)DeviceHandle; PC_ASSERT(UsbDevice); if (BusContext != DeviceHandle) { // // validate device handle // if (!Controller->ValidateUsbDevice(UsbDevice)) { DPRINT1("USBHI_QueryDeviceInformation invalid device handle %p\n", DeviceHandle); // // invalid device handle // return STATUS_DEVICE_NOT_CONNECTED; } // // access information buffer // DeviceInfo = (PUSB_DEVICE_INFORMATION_0)DeviceInformationBuffer; // // initialize with default values // DeviceInfo->InformationLevel = 0; DeviceInfo->ActualLength = sizeof(USB_DEVICE_INFORMATION_0); DeviceInfo->PortNumber = UsbDevice->GetPort(); DeviceInfo->CurrentConfigurationValue = UsbDevice->GetConfigurationValue(); DeviceInfo->DeviceAddress = UsbDevice->GetDeviceAddress(); DeviceInfo->HubAddress = 0; //FIXME DeviceInfo->DeviceSpeed = UsbDevice->GetSpeed(); DeviceInfo->DeviceType = UsbDevice->GetType(); DeviceInfo->NumberOfOpenPipes = 0; //FIXME // // get device descriptor // UsbDevice->GetDeviceDescriptor(&DeviceInfo->DeviceDescriptor); // // FIXME return pipe information // // // store result length // *LengthReturned = sizeof(USB_DEVICE_INFORMATION_0); return STATUS_SUCCESS; } // // access information buffer // DeviceInfo = (PUSB_DEVICE_INFORMATION_0)DeviceInformationBuffer; // // initialize with default values // DeviceInfo->InformationLevel = 0; DeviceInfo->ActualLength = sizeof(USB_DEVICE_INFORMATION_0); DeviceInfo->PortNumber = 0; DeviceInfo->CurrentConfigurationValue = 0; //FIXME; DeviceInfo->DeviceAddress = 0; DeviceInfo->HubAddress = 0; //FIXME DeviceInfo->DeviceSpeed = UsbHighSpeed; //FIXME DeviceInfo->DeviceType = Usb20Device; //FIXME DeviceInfo->NumberOfOpenPipes = 0; //FIXME // // FIXME get device descriptor // // // FIXME return pipe information // // // store result length // *LengthReturned = sizeof(USB_DEVICE_INFORMATION_0); // // 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) { UNIMPLEMENTED return STATUS_SUCCESS; } NTSTATUS USB_BUSIFFN USBHI_RootHubInitNotification( PVOID BusContext, PVOID CallbackContext, PRH_INIT_CALLBACK CallbackRoutine) { CHubController * Controller; DPRINT1("USBHI_RootHubInitNotification\n"); // // 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); // // fixup device stack voodoo part #1 // UsbDevicePdo->StackSize++; // // 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; } 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); /* done */ return Status; } NTSTATUS CreateHubController( PHUBCONTROLLER *OutHcdController) { PHUBCONTROLLER This; // // allocate controller // This = new(NonPagedPool, TAG_USBEHCI) 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); }