/* * PROJECT: ReactOS USB Port Driver * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) * PURPOSE: USBPort device functions * COPYRIGHT: Copyright 2017 Vadim Galyant */ #include "usbport.h" #define NDEBUG #include NTSTATUS NTAPI USBPORT_SendSetupPacket(IN PUSBPORT_DEVICE_HANDLE DeviceHandle, IN PDEVICE_OBJECT FdoDevice, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, IN PVOID Buffer, IN ULONG Length, IN OUT PULONG TransferedLen, IN OUT PUSBD_STATUS pUSBDStatus) { PURB Urb; PMDL Mdl; USBD_STATUS USBDStatus; KEVENT Event; NTSTATUS Status; DPRINT("USBPORT_SendSetupPacket: DeviceHandle - %p, FdoDevice - %p, SetupPacket - %p, Buffer - %p, Length - %x, TransferedLen - %x, pUSBDStatus - %x\n", DeviceHandle, FdoDevice, SetupPacket, Buffer, Length, TransferedLen, pUSBDStatus); KeInitializeEvent(&Event, NotificationEvent, FALSE); Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _URB_CONTROL_TRANSFER), USB_PORT_TAG); if (Urb) { InterlockedIncrement(&DeviceHandle->DeviceHandleLock); RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_TRANSFER)); RtlCopyMemory(Urb->UrbControlTransfer.SetupPacket, SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); Urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_TRANSFER); Urb->UrbHeader.Function = URB_FUNCTION_CONTROL_TRANSFER; Urb->UrbHeader.UsbdDeviceHandle = DeviceHandle; Urb->UrbHeader.UsbdFlags = 0; Urb->UrbControlTransfer.PipeHandle = &DeviceHandle->PipeHandle; Urb->UrbControlTransfer.TransferBufferLength = Length; Urb->UrbControlTransfer.TransferBuffer = Buffer; Urb->UrbControlTransfer.TransferBufferMDL = NULL; Urb->UrbControlTransfer.TransferFlags = USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION; if (SetupPacket->bmRequestType.Dir != BMREQUEST_DEVICE_TO_HOST) { Urb->UrbControlTransfer.TransferFlags &= ~USBD_TRANSFER_DIRECTION_IN; } Status = STATUS_SUCCESS; if (Length) { Mdl = IoAllocateMdl(Buffer, Length, FALSE, FALSE, NULL); Urb->UrbControlTransfer.TransferBufferMDL = Mdl; if (Mdl) { Urb->UrbHeader.UsbdFlags |= USBD_FLAG_ALLOCATED_MDL; MmBuildMdlForNonPagedPool(Mdl); } else { Status = USBPORT_USBDStatusToNtStatus(NULL, USBD_STATUS_INSUFFICIENT_RESOURCES); } } if (NT_SUCCESS(Status)) { USBDStatus = USBPORT_AllocateTransfer(FdoDevice, Urb, NULL, NULL, &Event); if (USBD_SUCCESS(USBDStatus)) { InterlockedIncrement(&DeviceHandle->DeviceHandleLock); USBPORT_QueueTransferUrb(Urb); KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); USBDStatus = Urb->UrbHeader.Status; } Status = USBPORT_USBDStatusToNtStatus(Urb, USBDStatus); if (TransferedLen) *TransferedLen = Urb->UrbControlTransfer.TransferBufferLength; if (pUSBDStatus) *pUSBDStatus = USBDStatus; } InterlockedDecrement(&DeviceHandle->DeviceHandleLock); ExFreePoolWithTag(Urb, USB_PORT_TAG); } else { if (pUSBDStatus) *pUSBDStatus = USBD_STATUS_INSUFFICIENT_RESOURCES; Status = USBPORT_USBDStatusToNtStatus(NULL, USBD_STATUS_INSUFFICIENT_RESOURCES); } DPRINT("USBPORT_SendSetupPacket: Status - %x\n", Status); return Status; } ULONG NTAPI USBPORT_GetInterfaceLength(IN PUSB_INTERFACE_DESCRIPTOR iDescriptor, IN ULONG_PTR EndDescriptors) { SIZE_T Length; PUSB_ENDPOINT_DESCRIPTOR Descriptor; ULONG ix; DPRINT("USBPORT_GetInterfaceLength ... \n"); Length = iDescriptor->bLength; Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)iDescriptor + Length); if (iDescriptor->bNumEndpoints) { for (ix = 0; ix < iDescriptor->bNumEndpoints; ix++) { while ((Descriptor->bDescriptorType != USB_ENDPOINT_DESCRIPTOR_TYPE) && (Descriptor->bLength > 0)) { Length += Descriptor->bLength; Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)Descriptor + Descriptor->bLength); } Length += Descriptor->bLength; Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)Descriptor + Descriptor->bLength); } } while (((ULONG_PTR)Descriptor < EndDescriptors) && (Descriptor->bDescriptorType != USB_INTERFACE_DESCRIPTOR_TYPE) && (Descriptor->bLength > 0)) { Length += Descriptor->bLength; Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)Descriptor + Descriptor->bLength); } return Length; } PUSB_INTERFACE_DESCRIPTOR NTAPI USBPORT_ParseConfigurationDescriptor(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor, IN UCHAR InterfaceNumber, IN UCHAR Alternate, OUT PBOOLEAN HasAlternates) { PUSB_CONFIGURATION_DESCRIPTOR TmpDescriptor; PUSB_INTERFACE_DESCRIPTOR iDescriptor; PUSB_INTERFACE_DESCRIPTOR OutDescriptor = NULL; ULONG_PTR Descriptor = (ULONG_PTR)ConfigDescriptor; ULONG_PTR EndDescriptors; ULONG ix; DPRINT("USBPORT_ParseConfigurationDescriptor ... \n"); if (HasAlternates) *HasAlternates = FALSE; for (TmpDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)((ULONG_PTR)ConfigDescriptor + ConfigDescriptor->bLength); TmpDescriptor->bDescriptorType != USB_INTERFACE_DESCRIPTOR_TYPE && TmpDescriptor->bLength > 0; TmpDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)((ULONG_PTR)TmpDescriptor + TmpDescriptor->bLength)) ; iDescriptor = (PUSB_INTERFACE_DESCRIPTOR)TmpDescriptor; EndDescriptors = (ULONG_PTR)ConfigDescriptor + ConfigDescriptor->wTotalLength; while ((Descriptor < EndDescriptors) && (iDescriptor->bInterfaceNumber != InterfaceNumber)) { Descriptor = (ULONG_PTR)iDescriptor + USBPORT_GetInterfaceLength(iDescriptor, EndDescriptors); iDescriptor = (PUSB_INTERFACE_DESCRIPTOR)Descriptor; } ix = 0; while (Descriptor < EndDescriptors && iDescriptor->bInterfaceNumber == InterfaceNumber) { if (iDescriptor->bAlternateSetting == Alternate) OutDescriptor = iDescriptor; Descriptor = (ULONG_PTR)iDescriptor + USBPORT_GetInterfaceLength(iDescriptor, EndDescriptors); iDescriptor = (PUSB_INTERFACE_DESCRIPTOR)Descriptor; ++ix; } if ((ix > 1) && HasAlternates) *HasAlternates = TRUE; return OutDescriptor; } USBD_STATUS NTAPI USBPORT_OpenInterface(IN PURB Urb, IN PUSBPORT_DEVICE_HANDLE DeviceHandle, IN PDEVICE_OBJECT FdoDevice, IN PUSBPORT_CONFIGURATION_HANDLE ConfigHandle, IN PUSBD_INTERFACE_INFORMATION InterfaceInfo, IN OUT PUSBPORT_INTERFACE_HANDLE *iHandle, IN BOOLEAN SendSetInterface) { PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; PUSBPORT_INTERFACE_HANDLE InterfaceHandle = NULL; PUSBPORT_PIPE_HANDLE PipeHandle; PUSB_ENDPOINT_DESCRIPTOR Descriptor; PUSBD_PIPE_INFORMATION PipeInfo; BOOLEAN HasAlternates; ULONG NumEndpoints; SIZE_T Length; USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; SIZE_T HandleLength; BOOLEAN IsAllocated = FALSE; USHORT MaxPacketSize; USHORT wMaxPacketSize; ULONG ix; USBD_STATUS USBDStatus = USBD_STATUS_SUCCESS; NTSTATUS Status; DPRINT("USBPORT_OpenInterface: ...\n"); InterfaceDescriptor = USBPORT_ParseConfigurationDescriptor(ConfigHandle->ConfigurationDescriptor, InterfaceInfo->InterfaceNumber, InterfaceInfo->AlternateSetting, &HasAlternates); NumEndpoints = InterfaceDescriptor->bNumEndpoints; Length = FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes) + NumEndpoints * sizeof(USBD_PIPE_INFORMATION); if (HasAlternates && SendSetInterface) { RtlZeroMemory(&SetupPacket, sizeof(SetupPacket)); SetupPacket.bmRequestType.Dir = BMREQUEST_HOST_TO_DEVICE; SetupPacket.bmRequestType.Type = BMREQUEST_STANDARD; SetupPacket.bmRequestType.Recipient = BMREQUEST_TO_INTERFACE; SetupPacket.bRequest = USB_REQUEST_SET_INTERFACE; SetupPacket.wValue.W = InterfaceInfo->AlternateSetting; SetupPacket.wIndex.W = InterfaceInfo->InterfaceNumber; SetupPacket.wLength = 0; USBPORT_SendSetupPacket(DeviceHandle, FdoDevice, &SetupPacket, NULL, 0, NULL, &USBDStatus); if (!USBD_SUCCESS(USBDStatus)) { goto Exit; } } if (*iHandle) { InterfaceHandle = *iHandle; } else { HandleLength = FIELD_OFFSET(USBPORT_INTERFACE_HANDLE, PipeHandle) + NumEndpoints * sizeof(USBPORT_PIPE_HANDLE); InterfaceHandle = ExAllocatePoolWithTag(NonPagedPool, HandleLength, USB_PORT_TAG); if (!InterfaceHandle) { USBDStatus = USBD_STATUS_INSUFFICIENT_RESOURCES; goto Exit; } RtlZeroMemory(InterfaceHandle, HandleLength); for (ix = 0; ix < NumEndpoints; ++ix) { PipeHandle = &InterfaceHandle->PipeHandle[ix]; PipeHandle->Flags = PIPE_HANDLE_FLAG_CLOSED; PipeHandle->Endpoint = NULL; } IsAllocated = TRUE; } InterfaceHandle->AlternateSetting = InterfaceInfo->AlternateSetting; RtlCopyMemory(&InterfaceHandle->InterfaceDescriptor, InterfaceDescriptor, sizeof(USB_INTERFACE_DESCRIPTOR)); InterfaceInfo->Class = InterfaceDescriptor->bInterfaceClass; InterfaceInfo->SubClass = InterfaceDescriptor->bInterfaceSubClass; InterfaceInfo->Protocol = InterfaceDescriptor->bInterfaceProtocol; InterfaceInfo->Reserved = 0; InterfaceInfo->NumberOfPipes = InterfaceDescriptor->bNumEndpoints; Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength); for (ix = 0; ix < NumEndpoints; ++ix) { PipeHandle = &InterfaceHandle->PipeHandle[ix]; while (Descriptor->bDescriptorType != USB_ENDPOINT_DESCRIPTOR_TYPE) { if (Descriptor->bLength == 0) { break; } else { Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)Descriptor + Descriptor->bLength); } } if (InterfaceInfo->Pipes[ix].PipeFlags & USBD_PF_CHANGE_MAX_PACKET) { Descriptor->wMaxPacketSize = InterfaceInfo->Pipes[ix].MaximumPacketSize; } RtlCopyMemory(&PipeHandle->EndpointDescriptor, Descriptor, sizeof(USB_ENDPOINT_DESCRIPTOR)); PipeHandle->Flags = PIPE_HANDLE_FLAG_CLOSED; PipeHandle->PipeFlags = InterfaceInfo->Pipes[ix].PipeFlags; PipeHandle->Endpoint = NULL; wMaxPacketSize = Descriptor->wMaxPacketSize; /* USB 2.0 Specification, 5.9 High-Speed, High Bandwidth Endpoints */ MaxPacketSize = (wMaxPacketSize & 0x7FF) * (((wMaxPacketSize >> 11) & 3) + 1); InterfaceInfo->Pipes[ix].EndpointAddress = Descriptor->bEndpointAddress; InterfaceInfo->Pipes[ix].PipeType = Descriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK; InterfaceInfo->Pipes[ix].MaximumPacketSize = MaxPacketSize; InterfaceInfo->Pipes[ix].PipeHandle = (USBD_PIPE_HANDLE)-1; InterfaceInfo->Pipes[ix].Interval = Descriptor->bInterval; Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)Descriptor + Descriptor->bLength); } if (USBD_SUCCESS(USBDStatus)) { for (ix = 0; ix < NumEndpoints; ++ix) { PipeInfo = &InterfaceInfo->Pipes[ix]; PipeHandle = &InterfaceHandle->PipeHandle[ix]; Status = USBPORT_OpenPipe(FdoDevice, DeviceHandle, PipeHandle, &USBDStatus); if (!NT_SUCCESS(Status)) break; PipeInfo->PipeHandle = PipeHandle; } if (NumEndpoints) { USBPORT_USBDStatusToNtStatus(Urb, USBDStatus); } } Exit: if (USBD_SUCCESS(USBDStatus)) { InterfaceInfo->InterfaceHandle = InterfaceHandle; *iHandle = InterfaceHandle; InterfaceInfo->Length = Length; } else { if (InterfaceHandle) { if (NumEndpoints) { DPRINT1("USBPORT_OpenInterface: USBDStatus - %lx\n", USBDStatus); } if (IsAllocated) ExFreePoolWithTag(InterfaceHandle, USB_PORT_TAG); } } return USBDStatus; } VOID NTAPI USBPORT_CloseConfiguration(IN PUSBPORT_DEVICE_HANDLE DeviceHandle, IN PDEVICE_OBJECT FdoDevice) { PUSBPORT_CONFIGURATION_HANDLE ConfigHandle; PLIST_ENTRY iHandleList; PUSBPORT_INTERFACE_HANDLE iHandle; ULONG NumEndpoints; PUSBPORT_PIPE_HANDLE PipeHandle; DPRINT("USBPORT_CloseConfiguration: ... \n"); ConfigHandle = DeviceHandle->ConfigHandle; if (ConfigHandle) { iHandleList = &ConfigHandle->InterfaceHandleList; while (!IsListEmpty(iHandleList)) { iHandle = CONTAINING_RECORD(iHandleList->Flink, USBPORT_INTERFACE_HANDLE, InterfaceLink); DPRINT("USBPORT_CloseConfiguration: iHandle - %p\n", iHandle); RemoveHeadList(iHandleList); NumEndpoints = iHandle->InterfaceDescriptor.bNumEndpoints; PipeHandle = &iHandle->PipeHandle[0]; while (NumEndpoints > 0) { USBPORT_ClosePipe(DeviceHandle, FdoDevice, PipeHandle); PipeHandle += 1; --NumEndpoints; } ExFreePoolWithTag(iHandle, USB_PORT_TAG); } ExFreePoolWithTag(ConfigHandle, USB_PORT_TAG); DeviceHandle->ConfigHandle = NULL; } } NTSTATUS NTAPI USBPORT_InitInterfaceInfo(IN PUSBD_INTERFACE_INFORMATION InterfaceInfo, IN PUSBPORT_CONFIGURATION_HANDLE ConfigHandle) { PUSB_INTERFACE_DESCRIPTOR Descriptor; PUSBD_PIPE_INFORMATION Pipe; SIZE_T Length; ULONG PipeFlags; ULONG NumberOfPipes; USBD_STATUS USBDStatus = USBD_STATUS_SUCCESS; DPRINT("USBPORT_InitInterfaceInfo: InterfaceInfo - %p, ConfigHandle - %p\n", InterfaceInfo, ConfigHandle); Descriptor = USBPORT_ParseConfigurationDescriptor(ConfigHandle->ConfigurationDescriptor, InterfaceInfo->InterfaceNumber, InterfaceInfo->AlternateSetting, NULL); Length = sizeof(USBD_INTERFACE_INFORMATION) + sizeof(USBD_PIPE_INFORMATION); if (Descriptor) { NumberOfPipes = Descriptor->bNumEndpoints; Length = FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes) + NumberOfPipes * sizeof(USBD_PIPE_INFORMATION); if (InterfaceInfo->Length >= Length) { InterfaceInfo->Class = 0; InterfaceInfo->SubClass = 0; InterfaceInfo->Protocol = 0; InterfaceInfo->Reserved = 0; InterfaceInfo->InterfaceHandle = 0; InterfaceInfo->NumberOfPipes = NumberOfPipes; Pipe = InterfaceInfo->Pipes; while (NumberOfPipes > 0) { Pipe->EndpointAddress = 0; Pipe->Interval = 0; Pipe->PipeType = 0; Pipe->PipeHandle = 0; PipeFlags = Pipe->PipeFlags; if (PipeFlags & ~USBD_PF_VALID_MASK) USBDStatus = USBD_STATUS_INVALID_PIPE_FLAGS; if (!(PipeFlags & USBD_PF_CHANGE_MAX_PACKET)) Pipe->MaximumPacketSize = 0; Pipe += 1; --NumberOfPipes; } } else { USBDStatus = USBD_STATUS_BUFFER_TOO_SMALL; } } else { USBDStatus = USBD_STATUS_INTERFACE_NOT_FOUND; } InterfaceInfo->Length = Length; return USBDStatus; } NTSTATUS NTAPI USBPORT_HandleSelectConfiguration(IN PDEVICE_OBJECT FdoDevice, IN PIRP Irp, IN PURB Urb) { PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor; PUSBPORT_DEVICE_HANDLE DeviceHandle; PUSBPORT_CONFIGURATION_HANDLE ConfigHandle = NULL; PUSBD_INTERFACE_INFORMATION InterfaceInfo; PUSBPORT_INTERFACE_HANDLE InterfaceHandle; ULONG iNumber; ULONG ix; USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; NTSTATUS Status; USBD_STATUS USBDStatus; PUSBPORT_DEVICE_EXTENSION FdoExtension; DPRINT("USBPORT_HandleSelectConfiguration: ConfigDescriptor %p\n", Urb->UrbSelectConfiguration.ConfigurationDescriptor); FdoExtension = FdoDevice->DeviceExtension; KeWaitForSingleObject(&FdoExtension->DeviceSemaphore, Executive, KernelMode, FALSE, NULL); DeviceHandle = Urb->UrbHeader.UsbdDeviceHandle; ConfigDescriptor = Urb->UrbSelectConfiguration.ConfigurationDescriptor; if (!ConfigDescriptor) { DPRINT("USBPORT_HandleSelectConfiguration: ConfigDescriptor == NULL\n"); RtlZeroMemory(&SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); SetupPacket.bmRequestType.B = 0; SetupPacket.bRequest = USB_REQUEST_SET_CONFIGURATION; SetupPacket.wValue.W = 0; SetupPacket.wIndex.W = 0; SetupPacket.wLength = 0; USBPORT_SendSetupPacket(DeviceHandle, FdoDevice, &SetupPacket, NULL, 0, NULL, NULL); Status = USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_SUCCESS); goto Exit; } USBPORT_DumpingConfiguration(ConfigDescriptor); InterfaceInfo = &Urb->UrbSelectConfiguration.Interface; iNumber = 0; do { ++iNumber; InterfaceInfo = (PUSBD_INTERFACE_INFORMATION) ((ULONG_PTR)InterfaceInfo + InterfaceInfo->Length); } while ((ULONG_PTR)InterfaceInfo < (ULONG_PTR)Urb + Urb->UrbHeader.Length); if ((iNumber <= 0) || (iNumber != ConfigDescriptor->bNumInterfaces)) { Status = USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_INVALID_CONFIGURATION_DESCRIPTOR); goto Exit; } ConfigHandle = ExAllocatePoolWithTag(NonPagedPool, ConfigDescriptor->wTotalLength + sizeof(USBPORT_CONFIGURATION_HANDLE), USB_PORT_TAG); if (!ConfigHandle) { Status = USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_INSUFFICIENT_RESOURCES); goto Exit; } RtlZeroMemory(ConfigHandle, ConfigDescriptor->wTotalLength + sizeof(USBPORT_CONFIGURATION_HANDLE)); InitializeListHead(&ConfigHandle->InterfaceHandleList); ConfigHandle->ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)(ConfigHandle + 1); RtlCopyMemory(ConfigHandle->ConfigurationDescriptor, ConfigDescriptor, ConfigDescriptor->wTotalLength); RtlZeroMemory(&SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); SetupPacket.bmRequestType.B = 0; SetupPacket.bRequest = USB_REQUEST_SET_CONFIGURATION; SetupPacket.wValue.W = ConfigDescriptor->bConfigurationValue; SetupPacket.wIndex.W = 0; SetupPacket.wLength = 0; USBPORT_SendSetupPacket(DeviceHandle, FdoDevice, &SetupPacket, NULL, 0, NULL, &USBDStatus); if (USBD_ERROR(USBDStatus)) { Status = USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_SET_CONFIG_FAILED); goto Exit; } if (iNumber <= 0) { Status = USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_SUCCESS); goto Exit; } InterfaceInfo = &Urb->UrbSelectConfiguration.Interface; for (ix = 0; ix < iNumber; ++ix) { USBDStatus = USBPORT_InitInterfaceInfo(InterfaceInfo, ConfigHandle); InterfaceHandle = NULL; if (USBD_SUCCESS(USBDStatus)) { USBDStatus = USBPORT_OpenInterface(Urb, DeviceHandle, FdoDevice, ConfigHandle, InterfaceInfo, &InterfaceHandle, TRUE); } if (InterfaceHandle) { InsertTailList(&ConfigHandle->InterfaceHandleList, &InterfaceHandle->InterfaceLink); } if (USBD_ERROR(USBDStatus)) break; InterfaceInfo = (PUSBD_INTERFACE_INFORMATION) ((ULONG_PTR)InterfaceInfo + InterfaceInfo->Length); } if (ix >= iNumber) { Status = USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_SUCCESS); } else { Status = USBPORT_USBDStatusToNtStatus(Urb, USBDStatus); } Exit: if (NT_SUCCESS(Status)) { Urb->UrbSelectConfiguration.ConfigurationHandle = ConfigHandle; DeviceHandle->ConfigHandle = ConfigHandle; } else { DPRINT1("USBPORT_HandleSelectConfiguration: Status %x\n", Status); } KeReleaseSemaphore(&FdoExtension->DeviceSemaphore, LOW_REALTIME_PRIORITY, 1, FALSE); return Status; } VOID NTAPI USBPORT_AddDeviceHandle(IN PDEVICE_OBJECT FdoDevice, IN PUSBPORT_DEVICE_HANDLE DeviceHandle) { PUSBPORT_DEVICE_EXTENSION FdoExtension; DPRINT("USBPORT_AddDeviceHandle: ... \n"); FdoExtension = FdoDevice->DeviceExtension; InsertTailList(&FdoExtension->DeviceHandleList, &DeviceHandle->DeviceHandleLink); } VOID NTAPI USBPORT_RemoveDeviceHandle(IN PDEVICE_OBJECT FdoDevice, IN PUSBPORT_DEVICE_HANDLE DeviceHandle) { PUSBPORT_DEVICE_EXTENSION FdoExtension; KIRQL OldIrql; DPRINT("USBPORT_RemoveDeviceHandle \n"); FdoExtension = FdoDevice->DeviceExtension; KeAcquireSpinLock(&FdoExtension->DeviceHandleSpinLock, &OldIrql); RemoveEntryList(&DeviceHandle->DeviceHandleLink); KeReleaseSpinLock(&FdoExtension->DeviceHandleSpinLock, OldIrql); } BOOLEAN NTAPI USBPORT_ValidateDeviceHandle(IN PDEVICE_OBJECT FdoDevice, IN PUSBPORT_DEVICE_HANDLE DeviceHandle) { PUSBPORT_DEVICE_EXTENSION FdoExtension; KIRQL OldIrql; PLIST_ENTRY HandleList; PUSBPORT_DEVICE_HANDLE CurrentHandle; BOOLEAN Result = FALSE; //DPRINT("USBPORT_ValidateDeviceHandle: DeviceHandle - %p\n", DeviceHandle \n"); FdoExtension = FdoDevice->DeviceExtension; KeAcquireSpinLock(&FdoExtension->DeviceHandleSpinLock, &OldIrql); if (DeviceHandle) { HandleList = FdoExtension->DeviceHandleList.Flink; while (HandleList != &FdoExtension->DeviceHandleList) { CurrentHandle = CONTAINING_RECORD(HandleList, USBPORT_DEVICE_HANDLE, DeviceHandleLink); if (CurrentHandle == DeviceHandle) { Result = TRUE; break; } HandleList = HandleList->Flink; } } KeReleaseSpinLock(&FdoExtension->DeviceHandleSpinLock, OldIrql); return Result; } BOOLEAN NTAPI USBPORT_DeviceHasTransfers(IN PDEVICE_OBJECT FdoDevice, IN PUSBPORT_DEVICE_HANDLE DeviceHandle) { PLIST_ENTRY PipeHandleList; PUSBPORT_PIPE_HANDLE PipeHandle; DPRINT("USBPORT_DeviceHasTransfers: ... \n"); PipeHandleList = DeviceHandle->PipeHandleList.Flink; while (PipeHandleList != &DeviceHandle->PipeHandleList) { PipeHandle = CONTAINING_RECORD(PipeHandleList, USBPORT_PIPE_HANDLE, PipeLink); PipeHandleList = PipeHandleList->Flink; if (!(PipeHandle->Flags & PIPE_HANDLE_FLAG_NULL_PACKET_SIZE) && USBPORT_EndpointHasQueuedTransfers(FdoDevice, PipeHandle->Endpoint, NULL)) { return TRUE; } } return FALSE; } VOID NTAPI USBPORT_AbortTransfers(IN PDEVICE_OBJECT FdoDevice, IN PUSBPORT_DEVICE_HANDLE DeviceHandle) { PLIST_ENTRY HandleList; PUSBPORT_PIPE_HANDLE PipeHandle; BOOLEAN Result; DPRINT("USBPORT_AbortAllTransfers: ... \n"); HandleList = DeviceHandle->PipeHandleList.Flink; while (HandleList != &DeviceHandle->PipeHandleList) { PipeHandle = CONTAINING_RECORD(HandleList, USBPORT_PIPE_HANDLE, PipeLink); HandleList = HandleList->Flink; if (!(PipeHandle->Flags & DEVICE_HANDLE_FLAG_ROOTHUB)) { PipeHandle->Endpoint->Flags |= ENDPOINT_FLAG_ABORTING; USBPORT_AbortEndpoint(FdoDevice, PipeHandle->Endpoint, NULL); USBPORT_FlushMapTransfers(FdoDevice); } } while (TRUE) { Result = USBPORT_DeviceHasTransfers(FdoDevice, DeviceHandle); if (!Result) break; USBPORT_Wait(FdoDevice, 100); } } PUSB2_TT_EXTENSION NTAPI USBPORT_GetTt(IN PDEVICE_OBJECT FdoDevice, IN PUSBPORT_DEVICE_HANDLE HubDeviceHandle, OUT PUSHORT OutPort, OUT PUSBPORT_DEVICE_HANDLE * OutHubDeviceHandle) { PUSBPORT_DEVICE_HANDLE DeviceHandle = HubDeviceHandle; ULONG TtCount; PLIST_ENTRY Entry; PUSB2_TT_EXTENSION TtExtension = NULL; DPRINT("USBPORT_GetTt: HubDeviceHandle - %p\n", HubDeviceHandle); *OutHubDeviceHandle = NULL; while (DeviceHandle->DeviceSpeed != UsbHighSpeed) { DPRINT("USBPORT_GetTt: DeviceHandle - %p, DeviceHandle->PortNumber - %X\n", DeviceHandle, DeviceHandle->PortNumber); *OutPort = DeviceHandle->PortNumber; DeviceHandle = DeviceHandle->HubDeviceHandle; if (!DeviceHandle) return NULL; } TtCount = DeviceHandle->TtCount; if (!TtCount) return NULL; if (IsListEmpty(&DeviceHandle->TtList)) return NULL; Entry = DeviceHandle->TtList.Flink; if (TtCount > 1) { while (Entry != &DeviceHandle->TtList) { ASSERT(Entry != NULL); TtExtension = CONTAINING_RECORD(Entry, USB2_TT_EXTENSION, Link); if (TtExtension->TtNumber == *OutPort) break; Entry = Entry->Flink; TtExtension = NULL; } } else { TtExtension = CONTAINING_RECORD(Entry, USB2_TT_EXTENSION, Link); } *OutHubDeviceHandle = DeviceHandle; return TtExtension; } NTSTATUS NTAPI USBPORT_CreateDevice(IN OUT PUSB_DEVICE_HANDLE *pUsbdDeviceHandle, IN PDEVICE_OBJECT FdoDevice, IN PUSBPORT_DEVICE_HANDLE HubDeviceHandle, IN USHORT PortStatus, IN USHORT Port) { PUSBPORT_DEVICE_HANDLE TtDeviceHandle = NULL; PUSB2_TT_EXTENSION TtExtension = NULL; USHORT port; PUSBPORT_DEVICE_HANDLE DeviceHandle; PUSBPORT_PIPE_HANDLE PipeHandle; BOOL IsOpenedPipe; PVOID DeviceDescriptor; USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; ULONG TransferedLen; ULONG DescriptorMinSize; UCHAR MaxPacketSize; PUSBPORT_DEVICE_EXTENSION FdoExtension; PUSBPORT_REGISTRATION_PACKET Packet; NTSTATUS Status; DPRINT("USBPORT_CreateDevice: PortStatus - %p, Port - %x\n", PortStatus, Port); FdoExtension = FdoDevice->DeviceExtension; Packet = &FdoExtension->MiniPortInterface->Packet; KeWaitForSingleObject(&FdoExtension->DeviceSemaphore, Executive, KernelMode, FALSE, NULL); if (!USBPORT_ValidateDeviceHandle(FdoDevice, HubDeviceHandle)) { KeReleaseSemaphore(&FdoExtension->DeviceSemaphore, LOW_REALTIME_PRIORITY, 1, FALSE); DPRINT1("USBPORT_CreateDevice: Not valid hub DeviceHandle\n"); return STATUS_DEVICE_NOT_CONNECTED; } port = Port; if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2 && !(PortStatus & USB_PORT_STATUS_HIGH_SPEED)) { DPRINT1("USBPORT_CreateDevice: USB1 device connected to USB2 port\n"); TtExtension = USBPORT_GetTt(FdoDevice, HubDeviceHandle, &port, &TtDeviceHandle); DPRINT("USBPORT_CreateDevice: TtDeviceHandle - %p, port - %x\n", TtDeviceHandle, port); } KeReleaseSemaphore(&FdoExtension->DeviceSemaphore, LOW_REALTIME_PRIORITY, 1, FALSE); DeviceHandle = ExAllocatePoolWithTag(NonPagedPool, sizeof(USBPORT_DEVICE_HANDLE), USB_PORT_TAG); if (!DeviceHandle) { DPRINT1("USBPORT_CreateDevice: Not allocated DeviceHandle\n"); return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(DeviceHandle, sizeof(USBPORT_DEVICE_HANDLE)); *pUsbdDeviceHandle = NULL; DeviceHandle->TtExtension = TtExtension; DeviceHandle->PortNumber = Port; DeviceHandle->HubDeviceHandle = HubDeviceHandle; if (PortStatus & USB_PORT_STATUS_LOW_SPEED) { DeviceHandle->DeviceSpeed = UsbLowSpeed; } else if (PortStatus & USB_PORT_STATUS_HIGH_SPEED) { DeviceHandle->DeviceSpeed = UsbHighSpeed; } else { DeviceHandle->DeviceSpeed = UsbFullSpeed; } KeWaitForSingleObject(&FdoExtension->DeviceSemaphore, Executive, KernelMode, FALSE, NULL); PipeHandle = &DeviceHandle->PipeHandle; PipeHandle->Flags = PIPE_HANDLE_FLAG_CLOSED; PipeHandle->EndpointDescriptor.bLength = sizeof(PipeHandle->EndpointDescriptor); PipeHandle->EndpointDescriptor.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE; if (DeviceHandle->DeviceSpeed == UsbLowSpeed) { PipeHandle->EndpointDescriptor.wMaxPacketSize = 8; } else { PipeHandle->EndpointDescriptor.wMaxPacketSize = USB_DEFAULT_MAX_PACKET; } InitializeListHead(&DeviceHandle->PipeHandleList); InitializeListHead(&DeviceHandle->TtList); Status = USBPORT_OpenPipe(FdoDevice, DeviceHandle, PipeHandle, NULL); IsOpenedPipe = NT_SUCCESS(Status); if (NT_ERROR(Status)) { DPRINT1("USBPORT_CreateDevice: USBPORT_OpenPipe return - %lx\n", Status); KeReleaseSemaphore(&FdoExtension->DeviceSemaphore, LOW_REALTIME_PRIORITY, 1, FALSE); ExFreePoolWithTag(DeviceHandle, USB_PORT_TAG); return Status; } DeviceDescriptor = ExAllocatePoolWithTag(NonPagedPool, USB_DEFAULT_MAX_PACKET, USB_PORT_TAG); if (!DeviceDescriptor) { DPRINT1("USBPORT_CreateDevice: Not allocated DeviceDescriptor\n"); goto ErrorExit; } RtlZeroMemory(DeviceDescriptor, USB_DEFAULT_MAX_PACKET); RtlZeroMemory(&SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); SetupPacket.bmRequestType.Dir = BMREQUEST_DEVICE_TO_HOST; SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR; SetupPacket.wValue.HiByte = USB_DEVICE_DESCRIPTOR_TYPE; SetupPacket.wLength = USB_DEFAULT_MAX_PACKET; TransferedLen = 0; Status = USBPORT_SendSetupPacket(DeviceHandle, FdoDevice, &SetupPacket, DeviceDescriptor, USB_DEFAULT_MAX_PACKET, &TransferedLen, NULL); RtlCopyMemory(&DeviceHandle->DeviceDescriptor, DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR)); ExFreePoolWithTag(DeviceDescriptor, USB_PORT_TAG); DescriptorMinSize = RTL_SIZEOF_THROUGH_FIELD(USB_DEVICE_DESCRIPTOR, bMaxPacketSize0); if ((TransferedLen == DescriptorMinSize) && !NT_SUCCESS(Status)) { Status = STATUS_SUCCESS; } if (NT_SUCCESS(Status) && (TransferedLen >= DescriptorMinSize)) { if ((DeviceHandle->DeviceDescriptor.bLength >= sizeof(USB_DEVICE_DESCRIPTOR)) && (DeviceHandle->DeviceDescriptor.bDescriptorType == USB_DEVICE_DESCRIPTOR_TYPE)) { MaxPacketSize = DeviceHandle->DeviceDescriptor.bMaxPacketSize0; if (MaxPacketSize == 8 || MaxPacketSize == 16 || MaxPacketSize == 32 || MaxPacketSize == 64) { USBPORT_AddDeviceHandle(FdoDevice, DeviceHandle); *pUsbdDeviceHandle = DeviceHandle; KeReleaseSemaphore(&FdoExtension->DeviceSemaphore, LOW_REALTIME_PRIORITY, 1, FALSE); return Status; } } } DPRINT1("USBPORT_CreateDevice: ERROR!!! TransferedLen - %x, Status - %lx\n", TransferedLen, Status); ErrorExit: if (TtExtension && TtDeviceHandle) { SetupPacket.bmRequestType.Recipient = BMREQUEST_TO_OTHER; SetupPacket.bmRequestType.Reserved = 0; SetupPacket.bmRequestType.Type = BMREQUEST_CLASS; SetupPacket.bmRequestType.Dir = BMREQUEST_HOST_TO_DEVICE; /* Table 11-15. Hub Class Requests */ if (TtDeviceHandle == HubDeviceHandle) { SetupPacket.bRequest = USB_REQUEST_RESET_TT; } else { SetupPacket.bRequest = USB_REQUEST_CLEAR_TT_BUFFER; } SetupPacket.wValue.LowByte = 0; SetupPacket.wValue.HiByte = 0; SetupPacket.wIndex.W = port; SetupPacket.wLength = 0; USBPORT_SendSetupPacket(TtDeviceHandle, FdoDevice, &SetupPacket, NULL, 0, NULL, NULL); } Status = STATUS_DEVICE_DATA_ERROR; if (IsOpenedPipe) { USBPORT_ClosePipe(DeviceHandle, FdoDevice, PipeHandle); } KeReleaseSemaphore(&FdoExtension->DeviceSemaphore, LOW_REALTIME_PRIORITY, 1, FALSE); ExFreePoolWithTag(DeviceHandle, USB_PORT_TAG); return Status; } ULONG NTAPI USBPORT_AllocateUsbAddress(IN PDEVICE_OBJECT FdoDevice) { PUSBPORT_DEVICE_EXTENSION FdoExtension; ULONG BitMapIdx; ULONG BitNumber; ULONG ix; DPRINT("USBPORT_AllocateUsbAddress \n"); FdoExtension = FdoDevice->DeviceExtension; for (ix = 0; ix < 4; ++ix) { BitMapIdx = 1; for (BitNumber = 0; BitNumber < 32; ++BitNumber) { if (!(FdoExtension->UsbAddressBitMap[ix] & BitMapIdx)) { FdoExtension->UsbAddressBitMap[ix] |= BitMapIdx; return 32 * ix + BitNumber; } BitMapIdx <<= 2; } } return 0; } VOID NTAPI USBPORT_FreeUsbAddress(IN PDEVICE_OBJECT FdoDevice, IN USHORT DeviceAddress) { PUSBPORT_DEVICE_EXTENSION FdoExtension; ULONG ix; ULONG BitMapIdx; ULONG BitNumber; USHORT CurrentAddress; DPRINT("USBPORT_FreeUsbAddress: DeviceAddress - %x\n", DeviceAddress); FdoExtension = FdoDevice->DeviceExtension; for (ix = 0; ix < 4; ++ix) { BitMapIdx = 1; CurrentAddress = 32 * ix; for (BitNumber = 0; BitNumber < 32; ++BitNumber) { if (CurrentAddress == DeviceAddress) { FdoExtension->UsbAddressBitMap[ix] &= ~BitMapIdx; return; } BitMapIdx <<= 2; CurrentAddress++; } } } NTSTATUS NTAPI USBPORT_InitializeDevice(IN PUSBPORT_DEVICE_HANDLE DeviceHandle, IN PDEVICE_OBJECT FdoDevice) { PUSBPORT_ENDPOINT Endpoint; USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup; ULONG TransferedLen; USHORT DeviceAddress = 0; UCHAR MaxPacketSize; NTSTATUS Status; PUSBPORT_DEVICE_EXTENSION FdoExtension; DPRINT("USBPORT_InitializeDevice: ... \n"); ASSERT(DeviceHandle != NULL); FdoExtension = FdoDevice->DeviceExtension; KeWaitForSingleObject(&FdoExtension->DeviceSemaphore, Executive, KernelMode, FALSE, NULL); DeviceAddress = USBPORT_AllocateUsbAddress(FdoDevice); ASSERT(DeviceHandle->DeviceAddress == USB_DEFAULT_DEVICE_ADDRESS); RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); CtrlSetup.bRequest = USB_REQUEST_SET_ADDRESS; CtrlSetup.wValue.W = DeviceAddress; Status = USBPORT_SendSetupPacket(DeviceHandle, FdoDevice, &CtrlSetup, NULL, 0, NULL, NULL); DPRINT("USBPORT_InitializeDevice: DeviceAddress - %x. SendSetupPacket Status - %x\n", DeviceAddress, Status); if (!NT_SUCCESS(Status)) goto ExitError; DeviceHandle->DeviceAddress = DeviceAddress; Endpoint = DeviceHandle->PipeHandle.Endpoint; Endpoint->EndpointProperties.TotalMaxPacketSize = DeviceHandle->DeviceDescriptor.bMaxPacketSize0; Endpoint->EndpointProperties.DeviceAddress = DeviceAddress; Status = USBPORT_ReopenPipe(FdoDevice, Endpoint); if (!NT_SUCCESS(Status)) goto ExitError; USBPORT_Wait(FdoDevice, 10); RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR; CtrlSetup.wValue.HiByte = USB_DEVICE_DESCRIPTOR_TYPE; CtrlSetup.wLength = sizeof(USB_DEVICE_DESCRIPTOR); CtrlSetup.bmRequestType.B = 0x80; Status = USBPORT_SendSetupPacket(DeviceHandle, FdoDevice, &CtrlSetup, &DeviceHandle->DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR), &TransferedLen, NULL); if (NT_SUCCESS(Status)) { ASSERT(TransferedLen == sizeof(USB_DEVICE_DESCRIPTOR)); ASSERT(DeviceHandle->DeviceDescriptor.bLength >= sizeof(USB_DEVICE_DESCRIPTOR)); ASSERT(DeviceHandle->DeviceDescriptor.bDescriptorType == USB_DEVICE_DESCRIPTOR_TYPE); MaxPacketSize = DeviceHandle->DeviceDescriptor.bMaxPacketSize0; ASSERT((MaxPacketSize == 8) || (MaxPacketSize == 16) || (MaxPacketSize == 32) || (MaxPacketSize == 64)); if (DeviceHandle->DeviceSpeed == UsbHighSpeed && DeviceHandle->DeviceDescriptor.bDeviceClass == USB_DEVICE_CLASS_HUB) { DeviceHandle->Flags |= DEVICE_HANDLE_FLAG_USB2HUB; } } else { ExitError: DPRINT1("USBPORT_InitializeDevice: ExitError. Status - %x\n", Status); } KeReleaseSemaphore(&FdoExtension->DeviceSemaphore, LOW_REALTIME_PRIORITY, 1, FALSE); return Status; } NTSTATUS NTAPI USBPORT_GetUsbDescriptor(IN PUSBPORT_DEVICE_HANDLE DeviceHandle, IN PDEVICE_OBJECT FdoDevice, IN UCHAR Type, IN PUCHAR ConfigDesc, IN PULONG ConfigDescSize) { USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; DPRINT("USBPORT_GetUsbDescriptor: Type - %x\n"); RtlZeroMemory(&SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); SetupPacket.bmRequestType.Dir = BMREQUEST_DEVICE_TO_HOST; SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR; SetupPacket.wValue.HiByte = Type; SetupPacket.wLength = (USHORT)*ConfigDescSize; return USBPORT_SendSetupPacket(DeviceHandle, FdoDevice, &SetupPacket, ConfigDesc, *ConfigDescSize, ConfigDescSize, NULL); } PUSBPORT_INTERFACE_HANDLE NTAPI USBPORT_GetInterfaceHandle(IN PUSBPORT_CONFIGURATION_HANDLE ConfigurationHandle, IN UCHAR InterfaceNumber) { PUSBPORT_INTERFACE_HANDLE InterfaceHandle; PLIST_ENTRY iHandleList; UCHAR InterfaceNum; DPRINT("USBPORT_GetInterfaceHandle: ConfigurationHandle - %p, InterfaceNumber - %p\n", ConfigurationHandle, InterfaceNumber); iHandleList = ConfigurationHandle->InterfaceHandleList.Flink; while (iHandleList && (iHandleList != &ConfigurationHandle->InterfaceHandleList)) { InterfaceHandle = CONTAINING_RECORD(iHandleList, USBPORT_INTERFACE_HANDLE, InterfaceLink); InterfaceNum = InterfaceHandle->InterfaceDescriptor.bInterfaceNumber; if (InterfaceNum == InterfaceNumber) return InterfaceHandle; iHandleList = InterfaceHandle->InterfaceLink.Flink; } return NULL; } NTSTATUS NTAPI USBPORT_HandleSelectInterface(IN PDEVICE_OBJECT FdoDevice, IN PIRP Irp, IN PURB Urb) { PUSBPORT_DEVICE_HANDLE DeviceHandle; PUSBPORT_CONFIGURATION_HANDLE ConfigurationHandle; PUSBD_INTERFACE_INFORMATION Interface; PUSBPORT_INTERFACE_HANDLE InterfaceHandle; PUSBPORT_INTERFACE_HANDLE iHandle; PUSBPORT_PIPE_HANDLE PipeHandle; USBD_STATUS USBDStatus; USHORT Length; ULONG ix; PUSBPORT_DEVICE_EXTENSION FdoExtension; DPRINT("USBPORT_HandleSelectInterface: ... \n"); FdoExtension = FdoDevice->DeviceExtension; KeWaitForSingleObject(&FdoExtension->DeviceSemaphore, Executive, KernelMode, FALSE, NULL); ConfigurationHandle = Urb->UrbSelectInterface.ConfigurationHandle; Interface = &Urb->UrbSelectInterface.Interface; Length = Interface->Length + sizeof(USBD_PIPE_INFORMATION); Urb->UrbHeader.Length = Length; USBDStatus = USBPORT_InitInterfaceInfo(Interface, ConfigurationHandle); if (USBDStatus) { Interface->InterfaceHandle = (USBD_INTERFACE_HANDLE)-1; return USBPORT_USBDStatusToNtStatus(Urb, USBDStatus); } DeviceHandle = Urb->UrbHeader.UsbdDeviceHandle; InterfaceHandle = USBPORT_GetInterfaceHandle(ConfigurationHandle, Interface->InterfaceNumber); if (InterfaceHandle) { RemoveEntryList(&InterfaceHandle->InterfaceLink); if (InterfaceHandle->InterfaceDescriptor.bNumEndpoints) { PipeHandle = &InterfaceHandle->PipeHandle[0]; for (ix = 0; ix < InterfaceHandle->InterfaceDescriptor.bNumEndpoints; ix++) { USBPORT_ClosePipe(DeviceHandle, FdoDevice, PipeHandle); PipeHandle += 1; } } } iHandle = 0; USBDStatus = USBPORT_OpenInterface(Urb, DeviceHandle, FdoDevice, ConfigurationHandle, Interface, &iHandle, TRUE); if (USBDStatus) { Interface->InterfaceHandle = (USBD_INTERFACE_HANDLE)-1; } else { if (InterfaceHandle) ExFreePoolWithTag(InterfaceHandle, USB_PORT_TAG); Interface->InterfaceHandle = iHandle; InsertTailList(&ConfigurationHandle->InterfaceHandleList, &iHandle->InterfaceLink); } KeReleaseSemaphore(&FdoExtension->DeviceSemaphore, LOW_REALTIME_PRIORITY, 1, FALSE); return USBPORT_USBDStatusToNtStatus(Urb, USBDStatus); } NTSTATUS NTAPI USBPORT_RemoveDevice(IN PDEVICE_OBJECT FdoDevice, IN OUT PUSBPORT_DEVICE_HANDLE DeviceHandle, IN ULONG Flags) { PUSBPORT_DEVICE_EXTENSION FdoExtension; PUSB2_TT_EXTENSION TtExtension; ULONG ix; KIRQL OldIrql; DPRINT("USBPORT_RemoveDevice: DeviceHandle - %p, Flags - %x\n", DeviceHandle, Flags); FdoExtension = FdoDevice->DeviceExtension; if ((Flags & USBD_KEEP_DEVICE_DATA) || (Flags & USBD_MARK_DEVICE_BUSY)) { return STATUS_SUCCESS; } KeWaitForSingleObject(&FdoExtension->DeviceSemaphore, Executive, KernelMode, FALSE, NULL); if (!USBPORT_ValidateDeviceHandle(FdoDevice, DeviceHandle)) { KeReleaseSemaphore(&FdoExtension->DeviceSemaphore, LOW_REALTIME_PRIORITY, 1, FALSE); DPRINT1("USBPORT_RemoveDevice: Not valid device handle\n"); return STATUS_DEVICE_NOT_CONNECTED; } USBPORT_RemoveDeviceHandle(FdoDevice, DeviceHandle); DeviceHandle->Flags |= DEVICE_HANDLE_FLAG_REMOVED; USBPORT_AbortTransfers(FdoDevice, DeviceHandle); DPRINT("USBPORT_RemoveDevice: DeviceHandleLock - %x\n", DeviceHandle->DeviceHandleLock); while (InterlockedDecrement(&DeviceHandle->DeviceHandleLock) >= 0) { InterlockedIncrement(&DeviceHandle->DeviceHandleLock); USBPORT_Wait(FdoDevice, 100); } DPRINT("USBPORT_RemoveDevice: DeviceHandleLock ok\n"); if (DeviceHandle->ConfigHandle) { USBPORT_CloseConfiguration(DeviceHandle, FdoDevice); } USBPORT_ClosePipe(DeviceHandle, FdoDevice, &DeviceHandle->PipeHandle); if (DeviceHandle->DeviceAddress) { USBPORT_FreeUsbAddress(FdoDevice, DeviceHandle->DeviceAddress); } if (!IsListEmpty(&DeviceHandle->TtList)) { DPRINT1("USBPORT_RemoveDevice: DeviceHandle->TtList not empty\n"); } while (!IsListEmpty(&DeviceHandle->TtList)) { TtExtension = CONTAINING_RECORD(DeviceHandle->TtList.Flink, USB2_TT_EXTENSION, Link); RemoveHeadList(&DeviceHandle->TtList); DPRINT("USBPORT_RemoveDevice: TtExtension - %p\n", TtExtension); KeAcquireSpinLock(&FdoExtension->TtSpinLock, &OldIrql); TtExtension->Flags |= USB2_TT_EXTENSION_FLAG_DELETED; if (IsListEmpty(&TtExtension->EndpointList)) { USBPORT_UpdateAllocatedBwTt(TtExtension); for (ix = 0; ix < USB2_FRAMES; ix++) { FdoExtension->Bandwidth[ix] += TtExtension->MaxBandwidth; } DPRINT("USBPORT_RemoveDevice: ExFreePoolWithTag TtExtension - %p\n", TtExtension); ExFreePoolWithTag(TtExtension, USB_PORT_TAG); } KeReleaseSpinLock(&FdoExtension->TtSpinLock, OldIrql); } KeReleaseSemaphore(&FdoExtension->DeviceSemaphore, LOW_REALTIME_PRIORITY, 1, FALSE); if (!(DeviceHandle->Flags & DEVICE_HANDLE_FLAG_ROOTHUB)) { ExFreePoolWithTag(DeviceHandle, USB_PORT_TAG); } return STATUS_SUCCESS; } NTSTATUS NTAPI USBPORT_RestoreDevice(IN PDEVICE_OBJECT FdoDevice, IN OUT PUSBPORT_DEVICE_HANDLE OldDeviceHandle, IN OUT PUSBPORT_DEVICE_HANDLE NewDeviceHandle) { PUSBPORT_DEVICE_EXTENSION FdoExtension; PLIST_ENTRY iHandleList; PUSBPORT_ENDPOINT Endpoint; USBPORT_ENDPOINT_REQUIREMENTS EndpointRequirements = {0}; USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; NTSTATUS Status = STATUS_SUCCESS; USBD_STATUS USBDStatus; KIRQL OldIrql; PUSBPORT_INTERFACE_HANDLE InterfaceHandle; PUSBPORT_PIPE_HANDLE PipeHandle; PUSBPORT_REGISTRATION_PACKET Packet; DPRINT("USBPORT_RestoreDevice: OldDeviceHandle - %p, NewDeviceHandle - %p\n", OldDeviceHandle, NewDeviceHandle); FdoExtension = FdoDevice->DeviceExtension; KeWaitForSingleObject(&FdoExtension->DeviceSemaphore, Executive, KernelMode, FALSE, NULL); if (!USBPORT_ValidateDeviceHandle(FdoDevice, OldDeviceHandle)) { KeReleaseSemaphore(&FdoExtension->DeviceSemaphore, LOW_REALTIME_PRIORITY, 1, FALSE); #ifndef NDEBUG DPRINT("USBPORT_RestoreDevice: OldDeviceHandle not valid\n"); DbgBreakPoint(); #endif return STATUS_DEVICE_NOT_CONNECTED; } if (!USBPORT_ValidateDeviceHandle(FdoDevice, NewDeviceHandle)) { KeReleaseSemaphore(&FdoExtension->DeviceSemaphore, LOW_REALTIME_PRIORITY, 1, FALSE); #ifndef NDEBUG DPRINT("USBPORT_RestoreDevice: NewDeviceHandle not valid\n"); DbgBreakPoint(); #endif return STATUS_DEVICE_NOT_CONNECTED; } USBPORT_RemoveDeviceHandle(FdoDevice, OldDeviceHandle); USBPORT_AbortTransfers(FdoDevice, OldDeviceHandle); while (InterlockedDecrement(&OldDeviceHandle->DeviceHandleLock) >= 0) { InterlockedIncrement(&OldDeviceHandle->DeviceHandleLock); USBPORT_Wait(FdoDevice, 100); } if (sizeof(USB_DEVICE_DESCRIPTOR) == RtlCompareMemory(&NewDeviceHandle->DeviceDescriptor, &OldDeviceHandle->DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR))) { NewDeviceHandle->ConfigHandle = OldDeviceHandle->ConfigHandle; if (OldDeviceHandle->ConfigHandle) { RtlZeroMemory(&SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); SetupPacket.bmRequestType.Dir = BMREQUEST_HOST_TO_DEVICE; SetupPacket.bRequest = USB_REQUEST_SET_CONFIGURATION; SetupPacket.wValue.W = OldDeviceHandle->ConfigHandle->ConfigurationDescriptor->bConfigurationValue; SetupPacket.wIndex.W = 0; SetupPacket.wLength = 0; USBPORT_SendSetupPacket(NewDeviceHandle, FdoDevice, &SetupPacket, NULL, 0, NULL, &USBDStatus); if (USBD_ERROR(USBDStatus)) Status = USBPORT_USBDStatusToNtStatus(NULL, USBDStatus); if (NT_SUCCESS(Status)) { iHandleList = NewDeviceHandle->ConfigHandle->InterfaceHandleList.Flink; while (iHandleList && iHandleList != &NewDeviceHandle->ConfigHandle->InterfaceHandleList) { InterfaceHandle = CONTAINING_RECORD(iHandleList, USBPORT_INTERFACE_HANDLE, InterfaceLink); if (InterfaceHandle->AlternateSetting) { RtlZeroMemory(&SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); SetupPacket.bmRequestType.Dir = BMREQUEST_HOST_TO_DEVICE; SetupPacket.bmRequestType.Type = BMREQUEST_STANDARD; SetupPacket.bmRequestType.Recipient = BMREQUEST_TO_INTERFACE; SetupPacket.bRequest = USB_REQUEST_SET_INTERFACE; SetupPacket.wValue.W = InterfaceHandle->InterfaceDescriptor.bAlternateSetting; SetupPacket.wIndex.W = InterfaceHandle->InterfaceDescriptor.bInterfaceNumber; SetupPacket.wLength = 0; USBPORT_SendSetupPacket(NewDeviceHandle, FdoDevice, &SetupPacket, NULL, 0, NULL, &USBDStatus); } iHandleList = iHandleList->Flink; } } } if (NewDeviceHandle->Flags & DEVICE_HANDLE_FLAG_USB2HUB) { DPRINT1("USBPORT_RestoreDevice: FIXME Transaction Translator\n"); NewDeviceHandle->TtCount = OldDeviceHandle->TtCount; #ifndef NDEBUG DbgBreakPoint(); #endif } while (!IsListEmpty(&OldDeviceHandle->PipeHandleList)) { PipeHandle = CONTAINING_RECORD(OldDeviceHandle->PipeHandleList.Flink, USBPORT_PIPE_HANDLE, PipeLink); DPRINT("USBPORT_RestoreDevice: PipeHandle - %p\n", PipeHandle); USBPORT_RemovePipeHandle(OldDeviceHandle, PipeHandle); if (PipeHandle != &OldDeviceHandle->PipeHandle) { USBPORT_AddPipeHandle(NewDeviceHandle, PipeHandle); if (!(PipeHandle->Flags & PIPE_HANDLE_FLAG_NULL_PACKET_SIZE)) { Endpoint = PipeHandle->Endpoint; Endpoint->DeviceHandle = NewDeviceHandle; Endpoint->EndpointProperties.DeviceAddress = NewDeviceHandle->DeviceAddress; Packet = &FdoExtension->MiniPortInterface->Packet; if (!(Endpoint->Flags & ENDPOINT_FLAG_NUKE)) { KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); Packet->ReopenEndpoint(FdoExtension->MiniPortExt, &Endpoint->EndpointProperties, Endpoint + 1); Packet->SetEndpointDataToggle(FdoExtension->MiniPortExt, Endpoint + 1, 0); Packet->SetEndpointStatus(FdoExtension->MiniPortExt, Endpoint + 1, USBPORT_ENDPOINT_RUN); KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); } else { MiniportCloseEndpoint(FdoDevice, Endpoint); RtlZeroMemory(Endpoint + 1, Packet->MiniPortEndpointSize); RtlZeroMemory((PVOID)Endpoint->EndpointProperties.BufferVA, Endpoint->EndpointProperties.BufferLength); KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); Packet->QueryEndpointRequirements(FdoExtension->MiniPortExt, &Endpoint->EndpointProperties, &EndpointRequirements); KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); MiniportOpenEndpoint(FdoDevice, Endpoint); Endpoint->Flags &= ~(ENDPOINT_FLAG_NUKE | ENDPOINT_FLAG_ABORTING); KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); if (Endpoint->StateLast == USBPORT_ENDPOINT_ACTIVE) { KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportSpinLock); Packet->SetEndpointState(FdoExtension->MiniPortExt, Endpoint + 1, USBPORT_ENDPOINT_ACTIVE); KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportSpinLock); } KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); } } } } USBPORT_AddPipeHandle(OldDeviceHandle, &OldDeviceHandle->PipeHandle); } else { #ifndef NDEBUG DPRINT("USBPORT_RestoreDevice: New DeviceDescriptor != Old DeviceDescriptor\n"); DbgBreakPoint(); #endif Status = STATUS_UNSUCCESSFUL; } USBPORT_ClosePipe(OldDeviceHandle, FdoDevice, &OldDeviceHandle->PipeHandle); if (OldDeviceHandle->DeviceAddress != 0) USBPORT_FreeUsbAddress(FdoDevice, OldDeviceHandle->DeviceAddress); KeReleaseSemaphore(&FdoExtension->DeviceSemaphore, LOW_REALTIME_PRIORITY, 1, FALSE); ExFreePoolWithTag(OldDeviceHandle, USB_PORT_TAG); return Status; } NTSTATUS NTAPI USBPORT_InitializeTT(IN PDEVICE_OBJECT FdoDevice, IN PUSBPORT_DEVICE_HANDLE HubDeviceHandle, IN ULONG TtNumber) { PUSBPORT_DEVICE_EXTENSION FdoExtension; PUSB2_TT_EXTENSION TtExtension; ULONG ix; DPRINT("USBPORT_InitializeTT: HubDeviceHandle - %p, TtNumber - %X\n", HubDeviceHandle, TtNumber); FdoExtension = FdoDevice->DeviceExtension; TtExtension = ExAllocatePoolWithTag(NonPagedPool, sizeof(USB2_TT_EXTENSION), USB_PORT_TAG); if (!TtExtension) { DPRINT1("USBPORT_InitializeTT: ExAllocatePoolWithTag return NULL\n"); return STATUS_INSUFFICIENT_RESOURCES; } DPRINT("USBPORT_InitializeTT: TtExtension - %p\n", TtExtension); RtlZeroMemory(TtExtension, sizeof(USB2_TT_EXTENSION)); TtExtension->DeviceAddress = HubDeviceHandle->DeviceAddress; TtExtension->TtNumber = TtNumber; TtExtension->RootHubPdo = FdoExtension->RootHubPdo; TtExtension->BusBandwidth = TOTAL_USB11_BUS_BANDWIDTH; InitializeListHead(&TtExtension->EndpointList); /* 90% maximum allowed for periodic endpoints */ for (ix = 0; ix < USB2_FRAMES; ix++) { TtExtension->Bandwidth[ix] = TtExtension->BusBandwidth - TtExtension->BusBandwidth / 10; } USBPORT_UpdateAllocatedBwTt(TtExtension); for (ix = 0; ix < USB2_FRAMES; ix++) { FdoExtension->Bandwidth[ix] -= TtExtension->MaxBandwidth; } USB2_InitTT(FdoExtension->Usb2Extension, &TtExtension->Tt); InsertTailList(&HubDeviceHandle->TtList, &TtExtension->Link); return STATUS_SUCCESS; } NTSTATUS NTAPI USBPORT_Initialize20Hub(IN PDEVICE_OBJECT FdoDevice, IN PUSBPORT_DEVICE_HANDLE HubDeviceHandle, IN ULONG TtCount) { NTSTATUS Status; ULONG ix; DPRINT("USBPORT_Initialize20Hub: TtCount - %X\n", TtCount); if (!HubDeviceHandle) { return STATUS_INVALID_PARAMETER; } if (HubDeviceHandle->Flags & DEVICE_HANDLE_FLAG_ROOTHUB) { return STATUS_SUCCESS; } if (TtCount == 0) { HubDeviceHandle->TtCount = 0; return STATUS_SUCCESS; } for (ix = 0; ix < TtCount; ++ix) { Status = USBPORT_InitializeTT(FdoDevice, HubDeviceHandle, ix + 1); if (!NT_SUCCESS(Status)) break; } HubDeviceHandle->TtCount = TtCount; return Status; }