/* * 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) */ #include "libusb.h" #define NDEBUG #include VOID NTAPI 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); virtual NTSTATUS HandleSystemControl(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 HandleVendorDevice(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 NTAPI 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; LPCSTR m_USBType; //Internal Functions BOOLEAN QueryStatusChangeEndpoint(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; // // initialize members // m_Controller = Controller; m_Hardware = Device; m_IsRootHubDevice = IsRootHubDevice; m_DeviceAddress = DeviceAddress; m_DriverObject = DriverObject; m_USBType = m_Hardware->GetUSBType(); 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::QueryStatusChangeEndpoint( 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); DPRINT("[%s] SCE Request %p TransferBufferLength %lu Flags %x MDL %p\n", m_USBType, 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); DPRINT("[%s] Port %d: Status %x, Change %x\n", m_USBType, PortId, PortStatus, PortChange); // // If there's a flag in PortChange return TRUE so the SCE Irp will be completed // if (PortChange != 0) { DPRINT1("[%s] Change state on port %d\n", m_USBType, 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; 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 current stack location // IoStack = IoGetCurrentIrpStackLocation(Irp); switch(IoStack->MinorFunction) { case IRP_MN_START_DEVICE: { DPRINT("[%s] HandlePnp IRP_MN_START_DEVICE\n", m_USBType); // // 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("[%s] HandlePnp IRP_MN_QUERY_ID Type %x\n", m_USBType, 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"); } // // 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("[%s] HandlePnp> failed to get hardware id %x\n", m_USBType, 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++; // // 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; } } // Here we should leave Status as is. Status = Irp->IoStatus.Status; break; } case IRP_MN_QUERY_CAPABILITIES: { DPRINT("[%s] HandlePnp IRP_MN_QUERY_CAPABILITIES\n", m_USBType); 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("[%s] HandlePnp IRP_MN_QUERY_INTERFACE\n", m_USBType); // // handle device interface requests // Status = HandleQueryInterface(IoStack); // // If a bus driver does not export the requested interface, it // should leave Status as is. // if (Status == STATUS_NOT_SUPPORTED) Status = Irp->IoStatus.Status; break; } case IRP_MN_REMOVE_DEVICE: { DPRINT("[%s] HandlePnp IRP_MN_REMOVE_DEVICE\n", m_USBType); // // 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("[%s] HandlePnp IRP_MN_QUERY_DEVICE_RELATIONS Type %x\n", m_USBType, 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("[%s] HandlePnp IRP_MN_QUERY_BUS_INFORMATION\n", m_USBType); // // 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("[%s] HandlePnp IRP_MN_STOP_DEVICE\n", m_USBType); // // stop device // Status = STATUS_SUCCESS; break; } case IRP_MN_SURPRISE_REMOVAL: { DPRINT("[%s] HandlePnp IRP_MN_SURPRISE_REMOVAL\n", m_USBType); 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) { NTSTATUS Status; Status = Irp->IoStatus.Status; PoStartNextPowerIrp(Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; } //----------------------------------------------------------------------------------------- NTSTATUS CHubController::HandleSystemControl( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp) { NTSTATUS Status; Status = Irp->IoStatus.Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; } //----------------------------------------------------------------------------------------- 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("[%s] Error No EndpointDesc\n", m_USBType); Urb->UrbIsochronousTransfer.Hdr.Status = USBD_STATUS_INVALID_PIPE_HANDLE; return STATUS_INVALID_PARAMETER; } // // sanity checks // ASSERT(EndPointDesc); DPRINT("[%s] HandleIsochronousTransfer EndPointDesc %p Address %x bmAttributes %x\n", m_USBType, EndPointDesc, EndPointDesc->bEndpointAddress, EndPointDesc->bmAttributes); 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("[%s] HandleIsochronousTransfer invalid device handle %p\n", m_USBType, 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 == PVOID(this) || Urb->UrbHeader.UsbdDeviceHandle == NULL) { ASSERT(m_PendingSCEIrp == NULL); if (QueryStatusChangeEndpoint(Irp)) { // // We've seen a change already, so return immediately // return STATUS_SUCCESS; } // // Else pend the IRP, to be completed when a device connects or disconnects. // DPRINT("[%s] Pending SCE Irp\n", m_USBType); 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("[%s] HandleBulkOrInterruptTransfer invalid device handle %p\n", m_USBType, 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("[%s] HandleClassOther> Request %x Value %x\n", m_USBType, 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("[%s] PortId %x PortStatus %x PortChange %x\n", m_USBType, 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("[%s] Unknown Value for Clear Feature %x \n", m_USBType, 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("[%s] Unsupported request id %x\n", m_USBType, Urb->UrbControlVendorClassRequest.Value); PC_ASSERT(FALSE); } break; } default: DPRINT1("[%s] HandleClassOther Unknown request code %x\n", m_USBType, 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; NTSTATUS Status; // // 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("[%s] HandleSelectConfiguration invalid device handle %p\n", m_USBType, Urb->UrbHeader.UsbdDeviceHandle); // // invalid device handle // return STATUS_DEVICE_NOT_CONNECTED; } // // get device // UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); // // select configuration // Status = UsbDevice->SelectConfiguration(Urb->UrbSelectConfiguration.ConfigurationDescriptor, &Urb->UrbSelectConfiguration.Interface, &Urb->UrbSelectConfiguration.ConfigurationHandle); if (NT_SUCCESS(Status)) { // successfully configured device Urb->UrbSelectConfiguration.Hdr.Status = USBD_STATUS_SUCCESS; } return Status; } } //----------------------------------------------------------------------------------------- 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("[%s] HandleSelectInterface invalid device handle %p\n", m_USBType, 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 == PVOID(this) || 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("[%s] HandleGetStatusFromDevice invalid device handle %p\n", m_USBType, 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("[%s] HandleGetStatusFromDevice Status %x Length %lu DeviceStatus %x\n", m_USBType, 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("[%s] HandleClassDevice Request %x Class %x\n", m_USBType, 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("[%s] HandleClassDevice invalid device handle %p\n", m_USBType, 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.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: { if (Urb->UrbHeader.UsbdDeviceHandle == PVOID(this) || Urb->UrbHeader.UsbdDeviceHandle == NULL) { // // 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; } else { if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))) { DPRINT1("[%s] HandleClassDevice invalid device handle %p\n", m_USBType, Urb->UrbHeader.UsbdDeviceHandle); // // invalid device handle // return STATUS_DEVICE_NOT_CONNECTED; } // // FIXME: implement support for real hubs // UNIMPLEMENTED; Status = STATUS_NOT_IMPLEMENTED; } break; } default: DPRINT1("[%s] HandleClassDevice Class %x not implemented\n", m_USBType, Urb->UrbControlVendorClassRequest.Value >> 8); break; } break; } default: { // // check if this is a valid usb device handle // if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))) { DPRINT1("[%s] HandleClassDevice invalid device handle %p\n", m_USBType, Urb->UrbHeader.UsbdDeviceHandle); // // invalid device handle // return STATUS_DEVICE_NOT_CONNECTED; } // // get device // UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); // // generate setup packet // CtrlSetup.bmRequestType.B = 0; CtrlSetup.bmRequestType.Recipient = BMREQUEST_TO_DEVICE; CtrlSetup.bmRequestType.Type = BMREQUEST_CLASS; CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request; CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value; CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index; CtrlSetup.wLength = (USHORT)Urb->UrbControlVendorClassRequest.TransferBufferLength; if (Urb->UrbControlVendorClassRequest.TransferFlags & USBD_TRANSFER_DIRECTION_IN) { // // data direction is device to host // CtrlSetup.bmRequestType.Dir = BMREQUEST_DEVICE_TO_HOST; } // // submit setup packet // Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer); ASSERT(Status == STATUS_SUCCESS); break; } } 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("[%s] HandleGetDescriptorFromInterface invalid device handle %p\n", m_USBType, 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); if (!NT_SUCCESS(Status)) { DPRINT1("[%s] HandleGetDescriptorFromInterface failed with %x\n", m_USBType, Status); } // // done // return Status; } //----------------------------------------------------------------------------------------- NTSTATUS CHubController::HandleGetDescriptor( IN OUT PIRP Irp, IN OUT PURB Urb) { NTSTATUS Status = STATUS_NOT_IMPLEMENTED; USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup; PUCHAR Buffer; PUSBDEVICE UsbDevice; ULONG Length, BufferLength; DPRINT("[%s] HandleGetDescriptor Type %x\n", m_USBType, Urb->UrbControlDescriptorRequest.DescriptorType); // // 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 == PVOID(this) || Urb->UrbHeader.UsbdDeviceHandle == NULL) { // // copy root hub device descriptor // RtlCopyMemory((PUCHAR)Urb->UrbControlDescriptorRequest.TransferBuffer, &m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR)); Irp->IoStatus.Information = sizeof(USB_DEVICE_DESCRIPTOR); Urb->UrbControlDescriptorRequest.Hdr.Status = USBD_STATUS_SUCCESS; Status = STATUS_SUCCESS; } else { // // check if this is a valid usb device handle // if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))) { DPRINT1("[%s] HandleGetDescriptor invalid device handle %p\n", m_USBType, 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); Irp->IoStatus.Information = sizeof(USB_DEVICE_DESCRIPTOR); Urb->UrbControlDescriptorRequest.Hdr.Status = USBD_STATUS_SUCCESS; Status = STATUS_SUCCESS; } break; } case USB_CONFIGURATION_DESCRIPTOR_TYPE: { // // sanity checks // PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer); // // From MSDN // The caller must allocate a buffer large enough to hold all of this information or the data is truncated without error. // BufferLength = Urb->UrbControlDescriptorRequest.TransferBufferLength; Buffer = (PUCHAR) Urb->UrbControlDescriptorRequest.TransferBuffer; if (Urb->UrbHeader.UsbdDeviceHandle == PVOID(this) || Urb->UrbHeader.UsbdDeviceHandle == NULL) { // // request is for the root bus controller // Length = BufferLength > sizeof(USB_CONFIGURATION_DESCRIPTOR) ? sizeof(USB_CONFIGURATION_DESCRIPTOR) : BufferLength; RtlCopyMemory(Buffer, &ROOTHUB2_CONFIGURATION_DESCRIPTOR, Length); // // Check if we still have some space left // if(Length == BufferLength) { // // We copied all we could // Status = STATUS_SUCCESS; break; } // // Go further // Buffer += Length; BufferLength -= Length; // // copy interface descriptor template // Length = BufferLength > sizeof(USB_INTERFACE_DESCRIPTOR) ? sizeof(USB_INTERFACE_DESCRIPTOR) : BufferLength; RtlCopyMemory(Buffer, &ROOTHUB2_INTERFACE_DESCRIPTOR, Length); // // Check if we still have some space left // if(Length == BufferLength) { // // We copied all we could // Status = STATUS_SUCCESS; break; } // // Go further // Buffer += Length; BufferLength -= Length; // // copy end point descriptor template // Length = BufferLength > sizeof(USB_ENDPOINT_DESCRIPTOR) ? sizeof(USB_ENDPOINT_DESCRIPTOR) : BufferLength; RtlCopyMemory(Buffer, &ROOTHUB2_ENDPOINT_DESCRIPTOR, Length); // // done // Status = STATUS_SUCCESS; } else { // // check if this is a valid usb device handle // if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))) { DPRINT1("[%s] USB_CONFIGURATION_DESCRIPTOR_TYPE invalid device handle %p\n", m_USBType, Urb->UrbHeader.UsbdDeviceHandle); // // invalid device handle // return STATUS_DEVICE_NOT_CONNECTED; } // // get device // UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); // // Allocate temporary buffer // BufferLength = UsbDevice->GetConfigurationDescriptorsLength(); Buffer = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, BufferLength, TAG_USBLIB); if(!Buffer) { Status = STATUS_NO_MEMORY; break; } // // perform work in IUSBDevice // UsbDevice->GetConfigurationDescriptors((PUSB_CONFIGURATION_DESCRIPTOR)Buffer, BufferLength, &Length); // // Copy what we can // Length = Urb->UrbControlDescriptorRequest.TransferBufferLength > Length ? Length : Urb->UrbControlDescriptorRequest.TransferBufferLength; RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer, Buffer, Length); // // Free temporary buffer // ExFreePoolWithTag(Buffer, TAG_USBLIB); // // store result size // Irp->IoStatus.Information = Length; Urb->UrbControlDescriptorRequest.TransferBufferLength = Length; Urb->UrbControlDescriptorRequest.Hdr.Status = USBD_STATUS_SUCCESS; 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("[%s] USB_STRING_DESCRIPTOR_TYPE invalid device handle %p\n", m_USBType, 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("[%s] CHubController::HandleGetDescriptor DescriptorType %x unimplemented\n", m_USBType, 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("[%s] HandleClassEndpoint invalid device handle %p\n", m_USBType, 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 = (USHORT)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::HandleVendorDevice( IN OUT PIRP Irp, IN OUT PURB Urb) { NTSTATUS Status = STATUS_NOT_IMPLEMENTED; PUSBDEVICE UsbDevice; USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup; //DPRINT("CHubController::HandleVendorDevice Request %x\n", Urb->UrbControlVendorClassRequest.Request); // // sanity check // PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle); // // check if this is a valid usb device handle // if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))) { DPRINT1("[%s] HandleVendorDevice invalid device handle %p\n", m_USBType, Urb->UrbHeader.UsbdDeviceHandle); // // invalid device handle // return STATUS_DEVICE_NOT_CONNECTED; } // // get device // UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); // // initialize setup packet // CtrlSetup.bmRequestType.B = 0; CtrlSetup.bmRequestType.Recipient = BMREQUEST_TO_DEVICE; CtrlSetup.bmRequestType.Type = BMREQUEST_VENDOR; CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request; CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value; CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index; CtrlSetup.wLength = (USHORT)Urb->UrbControlVendorClassRequest.TransferBufferLength; if (Urb->UrbControlVendorClassRequest.TransferFlags & USBD_TRANSFER_DIRECTION_IN) { // // data direction is device to host // CtrlSetup.bmRequestType.Dir = BMREQUEST_DEVICE_TO_HOST; } // // issue request // Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlVendorClassRequest.TransferBufferLength, Urb->UrbControlVendorClassRequest.TransferBuffer); if (NT_SUCCESS(Status)) { // success Urb->UrbControlVendorClassRequest.Hdr.Status = USBD_STATUS_SUCCESS; Irp->IoStatus.Information = Urb->UrbControlVendorClassRequest.TransferBufferLength; } 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("[%s] HandleSyncResetAndClearStall invalid device handle %p\n", m_USBType, Urb->UrbHeader.UsbdDeviceHandle); // // invalid device handle // return STATUS_DEVICE_NOT_CONNECTED; } // // abort pipe // Status = HandleAbortPipe(Irp, Urb); if (!NT_SUCCESS(Status)) { // // failed // DPRINT1("[%s] failed to reset pipe %x\n", m_USBType, 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("[%s] URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL Status %x\n", m_USBType, Status); // // reset data toggle // if (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("[%s] HandleAbortPipe invalid device handle %p\n", m_USBType, 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("[%s] URB_FUNCTION_ABORT_PIPE Status %x\n", m_USBType, 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("[%s] HandleClearStall invalid device handle %p\n", m_USBType, 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("[%s] URB_FUNCTION_SYNC_CLEAR_STALL\n", m_USBType); // // 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("[%s] URB_FUNCTION_CLEAR_STALL Status %x\n", m_USBType, 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("[%s] HandleClassInterface invalid device handle %p\n", m_USBType, Urb->UrbHeader.UsbdDeviceHandle); // // invalid device handle // return STATUS_DEVICE_NOT_CONNECTED; } // // get device // UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); DPRINT("URB_FUNCTION_CLASS_INTERFACE\n"); DPRINT("TransferFlags %x\n", Urb->UrbControlVendorClassRequest.TransferFlags); DPRINT("TransferBufferLength %x\n", Urb->UrbControlVendorClassRequest.TransferBufferLength); DPRINT("TransferBuffer %x\n", Urb->UrbControlVendorClassRequest.TransferBuffer); DPRINT("TransferBufferMDL %x\n", Urb->UrbControlVendorClassRequest.TransferBufferMDL); DPRINT("RequestTypeReservedBits %x\n", Urb->UrbControlVendorClassRequest.RequestTypeReservedBits); DPRINT("Request %x\n", Urb->UrbControlVendorClassRequest.Request); DPRINT("Value %x\n", Urb->UrbControlVendorClassRequest.Value); DPRINT("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 = (USHORT)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("[%s] URB_FUNCTION_CLASS_INTERFACE failed with Urb Status %x\n", m_USBType, Urb->UrbHeader.Status); } // // done // return Status; } //----------------------------------------------------------------------------------------- NTSTATUS CHubController::HandleDeviceControl( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp) { PIO_STACK_LOCATION IoStack; PURB Urb; NTSTATUS Status = STATUS_NOT_IMPLEMENTED; // // get current stack location // IoStack = IoGetCurrentIrpStackLocation(Irp); // // 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; case URB_FUNCTION_VENDOR_DEVICE: Status = HandleVendorDevice(Irp, Urb); break; default: DPRINT1("[%s] IOCTL_INTERNAL_USB_SUBMIT_URB Function %x NOT IMPLEMENTED\n", m_USBType, Urb->UrbHeader.Function); break; } // // request completed // break; } case IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE: { DPRINT("[%s] IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE %p\n", m_USBType, 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("[%s] IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO\n", m_USBType); // // 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("[%s] IOCTL_INTERNAL_USB_GET_HUB_COUNT\n", m_USBType); // // 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("[%s] IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION UNIMPLEMENTED\n", m_USBType); Status = STATUS_SUCCESS; break; } default: { DPRINT1("[%s] HandleDeviceControl>Type: IoCtl %x InputBufferLength %lu OutputBufferLength %lu NOT IMPLEMENTED\n", m_USBType, 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; DPRINT("USBI_InterfaceReference\n"); // // add reference // Controller->AddRef(); } VOID USB_BUSIFFN USBI_InterfaceDereference( PVOID BusContext) { CHubController * Controller = (CHubController*)BusContext; DPRINT("USBI_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; DPRINT("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; DPRINT("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; DPRINT("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); 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; DPRINT("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; DPRINT("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; DPRINT("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; DPRINT("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; } WORKER_THREAD_ROUTINE InitRootHub; VOID NTAPI InitRootHub(IN PVOID Context) { PINIT_ROOT_HUB_CONTEXT WorkItem; // // get context // WorkItem = (PINIT_ROOT_HUB_CONTEXT)Context; // // perform callback // WorkItem->CallbackRoutine(WorkItem->CallbackContext); // // free contextg // ExFreePoolWithTag(Context, TAG_USBLIB); } NTSTATUS USB_BUSIFFN USBHI_RootHubInitNotification( PVOID BusContext, PVOID CallbackContext, PRH_INIT_CALLBACK CallbackRoutine) { CHubController * Controller; PINIT_ROOT_HUB_CONTEXT WorkItem; DPRINT("USBHI_RootHubInitNotification %p \n", CallbackContext); // // get controller object // Controller = (CHubController*)BusContext; PC_ASSERT(Controller); // // set notification routine // Controller->SetNotification(CallbackContext, CallbackRoutine); // // Create and initialize work item data // WorkItem = (PINIT_ROOT_HUB_CONTEXT)ExAllocatePoolWithTag(NonPagedPool, sizeof(INIT_ROOT_HUB_CONTEXT), TAG_USBLIB); if (!WorkItem) { DPRINT1("Failed to allocate memory!n"); return STATUS_INSUFFICIENT_RESOURCES; } // // init context // WorkItem->CallbackRoutine = CallbackRoutine; WorkItem->CallbackContext = CallbackContext; // // Queue the work item to handle initializing the device // ExInitializeWorkItem(&WorkItem->WorkItem, InitRootHub, (PVOID)WorkItem); ExQueueWorkItem(&WorkItem->WorkItem, DelayedWorkQueue); // // 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; DPRINT("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; DPRINT("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 // 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; } InterfaceHub->InterfaceReference(InterfaceHub->BusContext); // // 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 // 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; } InterfaceDI->InterfaceReference(InterfaceDI->BusContext); // // 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, NULL, &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; } } DPRINT("CHubController::CreatePDO: DeviceName %wZ\n", &DeviceName); // // fixup device stack voodoo part #1 // (*OutDeviceObject)->StackSize++; /* done */ return Status; } NTSTATUS NTAPI 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 NTAPI 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->QueryStatusChangeEndpoint(Irp); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); }