mirror of
https://github.com/reactos/reactos.git
synced 2024-11-20 06:15:26 +00:00
5137 lines
142 KiB
C
5137 lines
142 KiB
C
/*
|
|
* PROJECT: ReactOS USB Hub Driver
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
|
* PURPOSE: USBHub main driver functions
|
|
* COPYRIGHT: Copyright 2017 Vadim Galyant <vgal@rambler.ru>
|
|
*/
|
|
|
|
#include "usbhub.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
#define NDEBUG_USBHUB_SCE
|
|
#define NDEBUG_USBHUB_PNP
|
|
#include "dbg_uhub.h"
|
|
|
|
#include <ntddstor.h>
|
|
|
|
PWSTR GenericUSBDeviceString = NULL;
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_Wait(IN ULONG Milliseconds)
|
|
{
|
|
LARGE_INTEGER Interval;
|
|
|
|
DPRINT("USBH_Wait: Milliseconds - %x\n", Milliseconds);
|
|
Interval.QuadPart = -10000LL * Milliseconds - ((ULONGLONG)KeQueryTimeIncrement() - 1);
|
|
return KeDelayExecutionThread(KernelMode, FALSE, &Interval);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_GetConfigValue(IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
DPRINT("USBHUB_GetConfigValue: ... \n");
|
|
|
|
if (ValueType == REG_BINARY)
|
|
{
|
|
*(PUCHAR)EntryContext = *(PUCHAR)ValueData;
|
|
}
|
|
else if (ValueType == REG_DWORD)
|
|
{
|
|
*(PULONG)EntryContext = *(PULONG)ValueData;
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_CompleteIrp(IN PIRP Irp,
|
|
IN NTSTATUS CompleteStatus)
|
|
{
|
|
if (CompleteStatus != STATUS_SUCCESS)
|
|
{
|
|
DPRINT1("USBH_CompleteIrp: Irp - %p, CompleteStatus - %X\n",
|
|
Irp,
|
|
CompleteStatus);
|
|
}
|
|
|
|
Irp->IoStatus.Status = CompleteStatus;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_PassIrp(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
DPRINT_PNP("USBH_PassIrp: DeviceObject - %p, Irp - %p\n",
|
|
DeviceObject,
|
|
Irp);
|
|
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return IoCallDriver(DeviceObject, Irp);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_SyncIrpComplete(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context)
|
|
{
|
|
PUSBHUB_URB_TIMEOUT_CONTEXT HubTimeoutContext;
|
|
KIRQL OldIrql;
|
|
BOOLEAN TimerCancelled;
|
|
|
|
DPRINT("USBH_SyncIrpComplete: ... \n");
|
|
|
|
HubTimeoutContext = Context;
|
|
|
|
KeAcquireSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, &OldIrql);
|
|
HubTimeoutContext->IsNormalCompleted = TRUE;
|
|
TimerCancelled = KeCancelTimer(&HubTimeoutContext->UrbTimeoutTimer);
|
|
KeReleaseSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, OldIrql);
|
|
|
|
if (TimerCancelled)
|
|
{
|
|
KeSetEvent(&HubTimeoutContext->UrbTimeoutEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
IsBitSet(IN PUCHAR BitMapAddress,
|
|
IN USHORT Bit)
|
|
{
|
|
BOOLEAN IsSet;
|
|
|
|
IsSet = (BitMapAddress[Bit / 8] & (1 << (Bit & 7))) != 0;
|
|
DPRINT("IsBitSet: Bit - %lX, IsSet - %x\n", Bit, IsSet);
|
|
return IsSet;
|
|
}
|
|
|
|
PUSBHUB_PORT_PDO_EXTENSION
|
|
NTAPI
|
|
PdoExt(IN PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
PVOID PdoExtension;
|
|
|
|
DPRINT("PdoExt: DeviceObject - %p\n", DeviceObject);
|
|
|
|
if (DeviceObject)
|
|
{
|
|
PdoExtension = DeviceObject->DeviceExtension;
|
|
}
|
|
else
|
|
{
|
|
PdoExtension = NULL;
|
|
}
|
|
|
|
return (PUSBHUB_PORT_PDO_EXTENSION)PdoExtension;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_WriteFailReasonID(IN PDEVICE_OBJECT DeviceObject,
|
|
IN ULONG FailReason)
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE KeyHandle;
|
|
UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"FailReasonID");
|
|
|
|
DPRINT("USBH_WriteFailReason: ID - %x\n", FailReason);
|
|
|
|
Status = IoOpenDeviceRegistryKey(DeviceObject,
|
|
PLUGPLAY_REGKEY_DEVICE,
|
|
STANDARD_RIGHTS_ALL,
|
|
&KeyHandle);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
ZwSetValueKey(KeyHandle,
|
|
&ValueName,
|
|
0,
|
|
REG_DWORD,
|
|
&FailReason,
|
|
sizeof(FailReason));
|
|
|
|
ZwClose(KeyHandle);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_UrbTimeoutDPC(IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2)
|
|
{
|
|
PUSBHUB_URB_TIMEOUT_CONTEXT HubTimeoutContext;
|
|
KIRQL OldIrql;
|
|
BOOL IsCompleted;
|
|
|
|
DPRINT("USBH_TimeoutDPC ... \n");
|
|
|
|
HubTimeoutContext = DeferredContext;
|
|
|
|
KeAcquireSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, &OldIrql);
|
|
IsCompleted = HubTimeoutContext->IsNormalCompleted;
|
|
KeReleaseSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, OldIrql);
|
|
|
|
if (!IsCompleted)
|
|
{
|
|
IoCancelIrp(HubTimeoutContext->Irp);
|
|
}
|
|
|
|
KeSetEvent(&HubTimeoutContext->UrbTimeoutEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_SetPdoRegistryParameter(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PCWSTR ValueName,
|
|
IN PVOID Data,
|
|
IN ULONG DataSize,
|
|
IN ULONG Type,
|
|
IN ULONG DevInstKeyType)
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING ValueNameString;
|
|
HANDLE KeyHandle;
|
|
|
|
DPRINT("USBH_SetPdoRegistryParameter ... \n");
|
|
|
|
RtlInitUnicodeString(&ValueNameString, ValueName);
|
|
|
|
Status = IoOpenDeviceRegistryKey(DeviceObject,
|
|
DevInstKeyType,
|
|
STANDARD_RIGHTS_ALL,
|
|
&KeyHandle);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
ZwSetValueKey(KeyHandle,
|
|
&ValueNameString,
|
|
0,
|
|
Type,
|
|
Data,
|
|
DataSize);
|
|
|
|
ZwClose(KeyHandle);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_SyncSubmitUrb(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PURB Urb)
|
|
{
|
|
KEVENT Event;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION IoStack;
|
|
PUSBHUB_URB_TIMEOUT_CONTEXT HubTimeoutContext;
|
|
BOOLEAN IsWaitTimeout = FALSE;
|
|
LARGE_INTEGER DueTime;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBH_SyncSubmitUrb: ... \n");
|
|
|
|
Urb->UrbHeader.UsbdDeviceHandle = NULL;
|
|
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB,
|
|
DeviceObject,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
TRUE,
|
|
&Event,
|
|
&IoStatusBlock);
|
|
|
|
if (!Irp)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
|
IoStack->Parameters.Others.Argument1 = Urb;
|
|
|
|
HubTimeoutContext = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(USBHUB_URB_TIMEOUT_CONTEXT),
|
|
USB_HUB_TAG);
|
|
|
|
if (HubTimeoutContext)
|
|
{
|
|
RtlZeroMemory(HubTimeoutContext, sizeof(USBHUB_URB_TIMEOUT_CONTEXT));
|
|
|
|
HubTimeoutContext->Irp = Irp;
|
|
HubTimeoutContext->IsNormalCompleted = FALSE;
|
|
|
|
KeInitializeEvent(&HubTimeoutContext->UrbTimeoutEvent,
|
|
NotificationEvent,
|
|
FALSE);
|
|
|
|
KeInitializeSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock);
|
|
KeInitializeTimer(&HubTimeoutContext->UrbTimeoutTimer);
|
|
|
|
KeInitializeDpc(&HubTimeoutContext->UrbTimeoutDPC,
|
|
USBH_UrbTimeoutDPC,
|
|
HubTimeoutContext);
|
|
|
|
DueTime.QuadPart = -5000 * 10000; // Timeout 5 sec.
|
|
|
|
KeSetTimer(&HubTimeoutContext->UrbTimeoutTimer,
|
|
DueTime,
|
|
&HubTimeoutContext->UrbTimeoutDPC);
|
|
|
|
IoSetCompletionRoutine(Irp,
|
|
USBH_SyncIrpComplete,
|
|
HubTimeoutContext,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
IsWaitTimeout = TRUE;
|
|
}
|
|
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
IoStatusBlock.Status = Status;
|
|
}
|
|
|
|
if (IsWaitTimeout)
|
|
{
|
|
KeWaitForSingleObject(&HubTimeoutContext->UrbTimeoutEvent,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
ExFreePoolWithTag(HubTimeoutContext, USB_HUB_TAG);
|
|
}
|
|
|
|
return IoStatusBlock.Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_FdoSyncSubmitUrb(IN PDEVICE_OBJECT FdoDevice,
|
|
IN PURB Urb)
|
|
{
|
|
PUSBHUB_FDO_EXTENSION HubExtension;
|
|
|
|
DPRINT("USBH_FdoSyncSubmitUrb: FdoDevice - %p, Urb - %p\n",
|
|
FdoDevice,
|
|
Urb);
|
|
|
|
HubExtension = FdoDevice->DeviceExtension;
|
|
return USBH_SyncSubmitUrb(HubExtension->LowerDevice, Urb);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_Transact(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PVOID TransferBuffer,
|
|
IN ULONG BufferLen,
|
|
IN BOOLEAN IsDeviceToHost,
|
|
IN USHORT Function,
|
|
IN BM_REQUEST_TYPE RequestType,
|
|
IN UCHAR Request,
|
|
IN USHORT RequestValue,
|
|
IN USHORT RequestIndex)
|
|
{
|
|
struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST * Urb;
|
|
ULONG TransferFlags;
|
|
PVOID Buffer = NULL;
|
|
ULONG Length;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBH_Transact: ... \n");
|
|
|
|
if (BufferLen)
|
|
{
|
|
Length = ALIGN_DOWN_BY(BufferLen + sizeof(ULONG), sizeof(ULONG));
|
|
|
|
Buffer = ExAllocatePoolWithTag(NonPagedPool, Length, USB_HUB_TAG);
|
|
|
|
if (!Buffer)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(Buffer, Length);
|
|
}
|
|
|
|
Urb = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
|
|
USB_HUB_TAG);
|
|
|
|
if (!Urb)
|
|
{
|
|
if (Buffer)
|
|
{
|
|
ExFreePoolWithTag(Buffer, USB_HUB_TAG);
|
|
}
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
|
|
|
|
if (IsDeviceToHost)
|
|
{
|
|
if (BufferLen)
|
|
{
|
|
RtlZeroMemory(TransferBuffer, BufferLen);
|
|
}
|
|
|
|
TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
|
|
}
|
|
else
|
|
{
|
|
if (BufferLen)
|
|
{
|
|
RtlCopyMemory(Buffer, TransferBuffer, BufferLen);
|
|
}
|
|
|
|
TransferFlags = USBD_TRANSFER_DIRECTION_OUT;
|
|
}
|
|
|
|
Urb->Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
|
|
Urb->Hdr.Function = Function;
|
|
Urb->Hdr.UsbdDeviceHandle = NULL;
|
|
|
|
Urb->TransferFlags = TransferFlags;
|
|
Urb->TransferBuffer = BufferLen != 0 ? Buffer : NULL;
|
|
Urb->TransferBufferLength = BufferLen;
|
|
Urb->TransferBufferMDL = NULL;
|
|
Urb->UrbLink = NULL;
|
|
|
|
Urb->RequestTypeReservedBits = RequestType.B;
|
|
Urb->Request = Request;
|
|
Urb->Value = RequestValue;
|
|
Urb->Index = RequestIndex;
|
|
|
|
Status = USBH_FdoSyncSubmitUrb(HubExtension->Common.SelfDevice, (PURB)Urb);
|
|
|
|
if (IsDeviceToHost && BufferLen)
|
|
{
|
|
RtlCopyMemory(TransferBuffer, Buffer, BufferLen);
|
|
}
|
|
|
|
if (Buffer)
|
|
{
|
|
ExFreePoolWithTag(Buffer, USB_HUB_TAG);
|
|
}
|
|
|
|
ExFreePoolWithTag(Urb, USB_HUB_TAG);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_SyncResetPort(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN USHORT Port)
|
|
{
|
|
USB_PORT_STATUS_AND_CHANGE PortStatus;
|
|
KEVENT Event;
|
|
LARGE_INTEGER Timeout;
|
|
ULONG ResetRetry = 0;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBH_SyncResetPort: Port - %x\n", Port);
|
|
|
|
InterlockedIncrement(&HubExtension->PendingRequestCount);
|
|
|
|
KeWaitForSingleObject(&HubExtension->HubPortSemaphore,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
Status = USBH_SyncGetPortStatus(HubExtension,
|
|
Port,
|
|
&PortStatus,
|
|
sizeof(USB_PORT_STATUS_AND_CHANGE));
|
|
|
|
if (NT_SUCCESS(Status) &&
|
|
(PortStatus.PortStatus.Usb20PortStatus.CurrentConnectStatus == 0))
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto Exit;
|
|
}
|
|
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_RESET_PORT_LOCK;
|
|
|
|
while (TRUE)
|
|
{
|
|
BM_REQUEST_TYPE RequestType;
|
|
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
InterlockedExchangePointer((PVOID)&HubExtension->pResetPortEvent,
|
|
&Event);
|
|
|
|
RequestType.B = 0;
|
|
RequestType.Recipient = BMREQUEST_TO_DEVICE;
|
|
RequestType.Type = BMREQUEST_CLASS;
|
|
RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
|
|
|
|
Status = USBH_Transact(HubExtension,
|
|
NULL,
|
|
0,
|
|
BMREQUEST_HOST_TO_DEVICE,
|
|
URB_FUNCTION_CLASS_OTHER,
|
|
RequestType,
|
|
USB_REQUEST_SET_FEATURE,
|
|
USBHUB_FEATURE_PORT_RESET,
|
|
Port);
|
|
|
|
Timeout.QuadPart = -5000 * 10000;
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
InterlockedExchangePointer((PVOID)&HubExtension->pResetPortEvent,
|
|
NULL);
|
|
|
|
USBH_Wait(10);
|
|
HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_RESET_PORT_LOCK;
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
Status = KeWaitForSingleObject(&Event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
&Timeout);
|
|
|
|
if (Status != STATUS_TIMEOUT)
|
|
{
|
|
break;
|
|
}
|
|
|
|
Status = USBH_SyncGetPortStatus(HubExtension,
|
|
Port,
|
|
&PortStatus,
|
|
sizeof(USB_PORT_STATUS_AND_CHANGE));
|
|
|
|
if (!NT_SUCCESS(Status) ||
|
|
(PortStatus.PortStatus.Usb20PortStatus.CurrentConnectStatus == 0) ||
|
|
ResetRetry >= USBHUB_RESET_PORT_MAX_RETRY)
|
|
{
|
|
InterlockedExchangePointer((PVOID)&HubExtension->pResetPortEvent,
|
|
NULL);
|
|
|
|
USBH_Wait(10);
|
|
HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_RESET_PORT_LOCK;
|
|
|
|
Status = STATUS_DEVICE_DATA_ERROR;
|
|
goto Exit;
|
|
}
|
|
|
|
ResetRetry++;
|
|
}
|
|
|
|
Status = USBH_SyncGetPortStatus(HubExtension,
|
|
Port,
|
|
&PortStatus,
|
|
sizeof(USB_PORT_STATUS_AND_CHANGE));
|
|
|
|
if ((PortStatus.PortStatus.Usb20PortStatus.CurrentConnectStatus == 0) &&
|
|
NT_SUCCESS(Status) &&
|
|
HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB)
|
|
{
|
|
Status = STATUS_DEVICE_DATA_ERROR;
|
|
}
|
|
|
|
USBH_Wait(10);
|
|
HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_RESET_PORT_LOCK;
|
|
|
|
Exit:
|
|
|
|
KeReleaseSemaphore(&HubExtension->HubPortSemaphore,
|
|
LOW_REALTIME_PRIORITY,
|
|
1,
|
|
FALSE);
|
|
|
|
if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
|
|
{
|
|
KeSetEvent(&HubExtension->PendingRequestEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_GetDeviceType(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PUSB_DEVICE_HANDLE DeviceHandle,
|
|
OUT USB_DEVICE_TYPE * OutDeviceType)
|
|
{
|
|
PUSB_BUSIFFN_GET_DEVICE_INFORMATION QueryDeviceInformation;
|
|
PUSB_DEVICE_INFORMATION_0 DeviceInfo;
|
|
SIZE_T DeviceInformationBufferLength;
|
|
USB_DEVICE_TYPE DeviceType = Usb11Device;
|
|
ULONG dummy;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBH_GetDeviceType: ... \n");
|
|
|
|
QueryDeviceInformation = HubExtension->BusInterface.QueryDeviceInformation;
|
|
|
|
if (!QueryDeviceInformation)
|
|
{
|
|
DPRINT1("USBH_GetDeviceType: no QueryDeviceInformation()\n");
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
DeviceInformationBufferLength = sizeof(USB_DEVICE_INFORMATION_0);
|
|
|
|
while (TRUE)
|
|
{
|
|
DeviceInfo = ExAllocatePoolWithTag(PagedPool,
|
|
DeviceInformationBufferLength,
|
|
USB_HUB_TAG);
|
|
|
|
if (!DeviceInfo)
|
|
{
|
|
DPRINT1("USBH_GetDeviceType: ExAllocatePoolWithTag() failed\n");
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
RtlZeroMemory(DeviceInfo, DeviceInformationBufferLength);
|
|
|
|
DeviceInfo->InformationLevel = 0;
|
|
|
|
Status = QueryDeviceInformation(HubExtension->BusInterface.BusContext,
|
|
DeviceHandle,
|
|
DeviceInfo,
|
|
DeviceInformationBufferLength,
|
|
&dummy);
|
|
|
|
if (Status != STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
DeviceType = DeviceInfo->DeviceType;
|
|
}
|
|
|
|
ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
|
|
break;
|
|
}
|
|
|
|
DeviceInformationBufferLength = DeviceInfo->ActualLength;
|
|
ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
|
|
}
|
|
|
|
if (OutDeviceType)
|
|
{
|
|
*OutDeviceType = DeviceType;
|
|
DPRINT("USBH_GetDeviceType: DeviceType - %x\n", DeviceType);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBHUB_GetExtendedHubInfo(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PUSB_EXTHUB_INFORMATION_0 HubInfoBuffer)
|
|
{
|
|
PUSB_BUSIFFN_GET_EXTENDED_HUB_INFO GetExtendedHubInformation;
|
|
ULONG dummy = 0;
|
|
|
|
DPRINT("USBHUB_GetExtendedHubInfo: ... \n");
|
|
|
|
GetExtendedHubInformation = HubExtension->BusInterface.GetExtendedHubInformation;
|
|
|
|
return GetExtendedHubInformation(HubExtension->BusInterface.BusContext,
|
|
HubExtension->LowerPDO,
|
|
HubInfoBuffer,
|
|
sizeof(USB_EXTHUB_INFORMATION_0),
|
|
&dummy);
|
|
}
|
|
|
|
PUSBHUB_FDO_EXTENSION
|
|
NTAPI
|
|
USBH_GetRootHubExtension(IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
PDEVICE_OBJECT Device;
|
|
PUSBHUB_FDO_EXTENSION RootHubExtension;
|
|
|
|
DPRINT("USBH_GetRootHubExtension: HubExtension - %p\n", HubExtension);
|
|
|
|
RootHubExtension = HubExtension;
|
|
|
|
if (HubExtension->LowerPDO != HubExtension->RootHubPdo)
|
|
{
|
|
Device = HubExtension->RootHubPdo;
|
|
|
|
do
|
|
{
|
|
Device = Device->AttachedDevice;
|
|
}
|
|
while (Device->DriverObject != HubExtension->Common.SelfDevice->DriverObject);
|
|
|
|
RootHubExtension = Device->DeviceExtension;
|
|
}
|
|
|
|
DPRINT("USBH_GetRootHubExtension: RootHubExtension - %p\n", RootHubExtension);
|
|
|
|
return RootHubExtension;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_SyncGetRootHubPdo(IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PDEVICE_OBJECT * OutPdo1,
|
|
IN OUT PDEVICE_OBJECT * OutPdo2)
|
|
{
|
|
KEVENT Event;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION IoStack;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBH_SyncGetRootHubPdo: ... \n");
|
|
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO,
|
|
DeviceObject,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
TRUE,
|
|
&Event,
|
|
&IoStatusBlock);
|
|
|
|
if (!Irp)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
|
IoStack->Parameters.Others.Argument1 = OutPdo1;
|
|
IoStack->Parameters.Others.Argument2 = OutPdo2;
|
|
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
IoStatusBlock.Status = Status;
|
|
}
|
|
|
|
return IoStatusBlock.Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_SyncGetHubCount(IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PULONG OutHubCount)
|
|
{
|
|
KEVENT Event;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION IoStack;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBH_SyncGetHubCount: *OutHubCount - %x\n", *OutHubCount);
|
|
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_HUB_COUNT,
|
|
DeviceObject,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
TRUE,
|
|
&Event,
|
|
&IoStatusBlock);
|
|
|
|
if (!Irp)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
|
IoStack->Parameters.Others.Argument1 = OutHubCount;
|
|
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
IoStatusBlock.Status = Status;
|
|
}
|
|
|
|
return IoStatusBlock.Status;
|
|
}
|
|
|
|
PUSB_DEVICE_HANDLE
|
|
NTAPI
|
|
USBH_SyncGetDeviceHandle(IN PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
PIRP Irp;
|
|
KEVENT Event;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
PUSB_DEVICE_HANDLE DeviceHandle = NULL;
|
|
PIO_STACK_LOCATION IoStack;
|
|
|
|
DPRINT("USBH_SyncGetDeviceHandle: ... \n");
|
|
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE,
|
|
DeviceObject,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
TRUE,
|
|
&Event,
|
|
&IoStatusBlock);
|
|
|
|
if (!Irp)
|
|
{
|
|
DPRINT1("USBH_SyncGetDeviceHandle: Irp - NULL!\n");
|
|
return NULL;
|
|
}
|
|
|
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
|
IoStack->Parameters.Others.Argument1 = &DeviceHandle;
|
|
|
|
if (IoCallDriver(DeviceObject, Irp) == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
|
|
return DeviceHandle;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_GetDeviceDescriptor(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PUSB_DEVICE_DESCRIPTOR HubDeviceDescriptor)
|
|
{
|
|
struct _URB_CONTROL_DESCRIPTOR_REQUEST * Urb;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBH_GetDeviceDescriptor: ... \n");
|
|
|
|
Urb = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
|
|
USB_HUB_TAG);
|
|
|
|
if (!Urb)
|
|
{
|
|
DPRINT1("USBH_SyncGetDeviceHandle: Urb - NULL!\n");
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
|
|
|
|
Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
|
|
Urb->Hdr.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
|
|
|
|
Urb->TransferBufferLength = sizeof(USB_DEVICE_DESCRIPTOR);
|
|
Urb->TransferBuffer = HubDeviceDescriptor;
|
|
Urb->DescriptorType = USB_DEVICE_DESCRIPTOR_TYPE;
|
|
|
|
Status = USBH_FdoSyncSubmitUrb(DeviceObject, (PURB)Urb);
|
|
|
|
ExFreePoolWithTag(Urb, USB_HUB_TAG);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_SyncGetDeviceConfigurationDescriptor(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor,
|
|
IN ULONG NumberOfBytes,
|
|
IN PULONG OutLength)
|
|
{
|
|
PCOMMON_DEVICE_EXTENSION DeviceExtension;
|
|
struct _URB_CONTROL_DESCRIPTOR_REQUEST * Urb;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBH_SyncGetDeviceConfigurationDescriptor: ... \n");
|
|
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
if (OutLength)
|
|
{
|
|
*OutLength = 0;
|
|
}
|
|
|
|
Urb = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
|
|
USB_HUB_TAG);
|
|
|
|
if (!Urb)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
|
|
|
|
Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
|
|
Urb->Hdr.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
|
|
|
|
Urb->TransferBufferLength = NumberOfBytes;
|
|
Urb->TransferBuffer = ConfigDescriptor;
|
|
Urb->DescriptorType = USB_CONFIGURATION_DESCRIPTOR_TYPE;
|
|
|
|
if (DeviceExtension->ExtensionType == USBH_EXTENSION_TYPE_HUB ||
|
|
DeviceExtension->ExtensionType == USBH_EXTENSION_TYPE_PARENT)
|
|
{
|
|
Status = USBH_FdoSyncSubmitUrb(DeviceObject, (PURB)Urb);
|
|
}
|
|
else
|
|
{
|
|
Status = USBH_SyncSubmitUrb(DeviceObject, (PURB)Urb);
|
|
}
|
|
|
|
if (OutLength)
|
|
{
|
|
*OutLength = Urb->TransferBufferLength;
|
|
}
|
|
|
|
if (Urb)
|
|
{
|
|
ExFreePoolWithTag(Urb, USB_HUB_TAG);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_GetConfigurationDescriptor(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PUSB_CONFIGURATION_DESCRIPTOR * OutDescriptor)
|
|
{
|
|
PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor;
|
|
ULONG ReturnedLen;
|
|
SIZE_T DescriptorLen;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBH_GetConfigurationDescriptor: ... \n");
|
|
|
|
DescriptorLen = MAXUCHAR;
|
|
|
|
while (TRUE)
|
|
{
|
|
ConfigDescriptor = ExAllocatePoolWithTag(NonPagedPool,
|
|
DescriptorLen,
|
|
USB_HUB_TAG);
|
|
|
|
if (!ConfigDescriptor)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
Status = USBH_SyncGetDeviceConfigurationDescriptor(DeviceObject,
|
|
ConfigDescriptor,
|
|
DescriptorLen,
|
|
&ReturnedLen);
|
|
|
|
if (ReturnedLen < sizeof(USB_CONFIGURATION_DESCRIPTOR))
|
|
{
|
|
Status = STATUS_DEVICE_DATA_ERROR;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
break;
|
|
}
|
|
|
|
*OutDescriptor = ConfigDescriptor;
|
|
|
|
if (ConfigDescriptor->wTotalLength <= DescriptorLen)
|
|
{
|
|
break;
|
|
}
|
|
|
|
DescriptorLen = ConfigDescriptor->wTotalLength;
|
|
|
|
ExFreePool(ConfigDescriptor);
|
|
*OutDescriptor = NULL;
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
if (ReturnedLen < ConfigDescriptor->wTotalLength)
|
|
{
|
|
Status = STATUS_DEVICE_DATA_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ConfigDescriptor)
|
|
{
|
|
ExFreePool(ConfigDescriptor);
|
|
}
|
|
|
|
*OutDescriptor = NULL;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_SyncGetHubDescriptor(IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
PUSB_EXTHUB_INFORMATION_0 ExtendedHubInfo;
|
|
ULONG NumberPorts;
|
|
PUSBHUB_PORT_DATA PortData;
|
|
USHORT RequestValue;
|
|
ULONG NumberOfBytes;
|
|
NTSTATUS Status;
|
|
PUSB_HUB_DESCRIPTOR HubDescriptor = NULL;
|
|
ULONG ix;
|
|
ULONG Retry;
|
|
|
|
DPRINT("USBH_SyncGetHubDescriptor: ... \n");
|
|
|
|
ExtendedHubInfo = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(USB_EXTHUB_INFORMATION_0),
|
|
USB_HUB_TAG);
|
|
|
|
if (!ExtendedHubInfo)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
RtlZeroMemory(ExtendedHubInfo, sizeof(USB_EXTHUB_INFORMATION_0));
|
|
|
|
Status = USBHUB_GetExtendedHubInfo(HubExtension, ExtendedHubInfo);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ExFreePoolWithTag(ExtendedHubInfo, USB_HUB_TAG);
|
|
ExtendedHubInfo = NULL;
|
|
}
|
|
|
|
NumberOfBytes = sizeof(USB_HUB_DESCRIPTOR);
|
|
|
|
HubDescriptor = ExAllocatePoolWithTag(NonPagedPool,
|
|
NumberOfBytes,
|
|
USB_HUB_TAG);
|
|
|
|
if (!HubDescriptor)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
RtlZeroMemory(HubDescriptor, NumberOfBytes);
|
|
|
|
RequestValue = 0;
|
|
Retry = 0;
|
|
|
|
while (TRUE)
|
|
{
|
|
while (Retry <= 5)
|
|
{
|
|
BM_REQUEST_TYPE RequestType;
|
|
|
|
RequestType.B = 0;
|
|
RequestType.Recipient = BMREQUEST_TO_DEVICE;
|
|
RequestType.Type = BMREQUEST_STANDARD;
|
|
RequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
|
|
|
|
Status = USBH_Transact(HubExtension,
|
|
HubDescriptor,
|
|
NumberOfBytes,
|
|
BMREQUEST_DEVICE_TO_HOST,
|
|
URB_FUNCTION_CLASS_DEVICE,
|
|
RequestType,
|
|
USB_REQUEST_GET_DESCRIPTOR,
|
|
RequestValue,
|
|
0);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
break;
|
|
}
|
|
|
|
RequestValue = 0x2900; // Hub DescriptorType - 0x29
|
|
|
|
Retry++;
|
|
}
|
|
|
|
if (HubDescriptor->bDescriptorLength <= NumberOfBytes)
|
|
{
|
|
break;
|
|
}
|
|
|
|
NumberOfBytes = HubDescriptor->bDescriptorLength;
|
|
ExFreePoolWithTag(HubDescriptor, USB_HUB_TAG);
|
|
|
|
if (Retry >= 5)
|
|
{
|
|
Status = STATUS_DEVICE_DATA_ERROR;
|
|
HubDescriptor = NULL;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
HubDescriptor = ExAllocatePoolWithTag(NonPagedPool,
|
|
NumberOfBytes,
|
|
USB_HUB_TAG);
|
|
|
|
if (!HubDescriptor)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
RtlZeroMemory(HubDescriptor, NumberOfBytes);
|
|
}
|
|
|
|
NumberPorts = HubDescriptor->bNumberOfPorts;
|
|
|
|
if (HubExtension->PortData)
|
|
{
|
|
PortData = HubExtension->PortData;
|
|
|
|
for (ix = 0; ix < NumberPorts; ix++)
|
|
{
|
|
PortData[ix].PortStatus.AsUlong32 = 0;
|
|
|
|
if (ExtendedHubInfo)
|
|
{
|
|
PortData[ix].PortAttributes = ExtendedHubInfo->Port[ix].PortAttributes;
|
|
}
|
|
else
|
|
{
|
|
PortData[ix].PortAttributes = 0;
|
|
}
|
|
|
|
PortData[ix].ConnectionStatus = NoDeviceConnected;
|
|
|
|
if (PortData[ix].DeviceObject != NULL)
|
|
{
|
|
PortData[ix].ConnectionStatus = DeviceConnected;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PortData = NULL;
|
|
|
|
if (HubDescriptor->bNumberOfPorts)
|
|
{
|
|
PortData = ExAllocatePoolWithTag(NonPagedPool,
|
|
NumberPorts * sizeof(USBHUB_PORT_DATA),
|
|
USB_HUB_TAG);
|
|
}
|
|
|
|
if (!PortData)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
RtlZeroMemory(PortData, NumberPorts * sizeof(USBHUB_PORT_DATA));
|
|
|
|
for (ix = 0; ix < NumberPorts; ix++)
|
|
{
|
|
PortData[ix].ConnectionStatus = NoDeviceConnected;
|
|
|
|
if (ExtendedHubInfo)
|
|
{
|
|
PortData[ix].PortAttributes = ExtendedHubInfo->Port[ix].PortAttributes;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
HubExtension->HubDescriptor = HubDescriptor;
|
|
|
|
HubExtension->PortData = PortData;
|
|
|
|
if (ExtendedHubInfo)
|
|
{
|
|
ExFreePoolWithTag(ExtendedHubInfo, USB_HUB_TAG);
|
|
}
|
|
|
|
return Status;
|
|
|
|
ErrorExit:
|
|
|
|
if (HubDescriptor)
|
|
{
|
|
ExFreePoolWithTag(HubDescriptor, USB_HUB_TAG);
|
|
}
|
|
|
|
if (ExtendedHubInfo)
|
|
{
|
|
ExFreePoolWithTag(ExtendedHubInfo, USB_HUB_TAG);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_SyncGetStringDescriptor(IN PDEVICE_OBJECT DeviceObject,
|
|
IN UCHAR Index,
|
|
IN USHORT LanguageId,
|
|
IN PUSB_STRING_DESCRIPTOR Descriptor,
|
|
IN ULONG NumberOfBytes,
|
|
IN PULONG OutLength,
|
|
IN BOOLEAN IsValidateLength)
|
|
{
|
|
struct _URB_CONTROL_DESCRIPTOR_REQUEST * Urb;
|
|
ULONG TransferedLength;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBH_SyncGetStringDescriptor: Index - %x, LanguageId - %x\n",
|
|
Index,
|
|
LanguageId);
|
|
|
|
Urb = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
|
|
USB_HUB_TAG);
|
|
|
|
if (!Urb)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
|
|
|
|
Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
|
|
Urb->Hdr.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
|
|
|
|
Urb->TransferBuffer = Descriptor;
|
|
Urb->TransferBufferLength = NumberOfBytes;
|
|
|
|
Urb->Index = Index;
|
|
Urb->DescriptorType = USB_STRING_DESCRIPTOR_TYPE;
|
|
Urb->LanguageId = LanguageId;
|
|
|
|
Status = USBH_SyncSubmitUrb(DeviceObject, (PURB)Urb);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ExFreePoolWithTag(Urb, USB_HUB_TAG);
|
|
return Status;
|
|
}
|
|
|
|
TransferedLength = Urb->TransferBufferLength;
|
|
|
|
if (TransferedLength > NumberOfBytes)
|
|
{
|
|
Status = STATUS_DEVICE_DATA_ERROR;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ExFreePoolWithTag(Urb, USB_HUB_TAG);
|
|
return Status;
|
|
}
|
|
|
|
if (OutLength)
|
|
{
|
|
*OutLength = TransferedLength;
|
|
}
|
|
|
|
if (IsValidateLength && TransferedLength != Descriptor->bLength)
|
|
{
|
|
Status = STATUS_DEVICE_DATA_ERROR;
|
|
}
|
|
|
|
ExFreePoolWithTag(Urb, USB_HUB_TAG);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_SyncGetStatus(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PUSHORT OutStatus,
|
|
IN USHORT Function,
|
|
IN USHORT RequestIndex)
|
|
{
|
|
struct _URB_CONTROL_GET_STATUS_REQUEST * Urb;
|
|
NTSTATUS NtStatus;
|
|
USHORT UsbStatus;
|
|
|
|
DPRINT("USBH_SyncGetStatus: ... \n");
|
|
|
|
Urb = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST),
|
|
USB_HUB_TAG);
|
|
|
|
if (!Urb)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST));
|
|
|
|
Urb->Hdr.Length = sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST);
|
|
Urb->Hdr.Function = Function;
|
|
|
|
Urb->TransferBuffer = &UsbStatus;
|
|
Urb->TransferBufferLength = sizeof(UsbStatus);
|
|
Urb->Index = RequestIndex;
|
|
|
|
NtStatus = USBH_FdoSyncSubmitUrb(DeviceObject, (PURB)Urb);
|
|
|
|
*OutStatus = UsbStatus;
|
|
|
|
ExFreePoolWithTag(Urb, USB_HUB_TAG);
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_SyncGetHubStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PUSB_HUB_STATUS_AND_CHANGE HubStatus,
|
|
IN ULONG Length)
|
|
{
|
|
BM_REQUEST_TYPE RequestType;
|
|
|
|
DPRINT("USBH_SyncGetHubStatus\n");
|
|
|
|
RequestType.B = 0;
|
|
RequestType.Recipient = BMREQUEST_TO_DEVICE;
|
|
RequestType.Type = BMREQUEST_CLASS;
|
|
RequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
|
|
|
|
return USBH_Transact(HubExtension,
|
|
HubStatus,
|
|
Length,
|
|
BMREQUEST_DEVICE_TO_HOST,
|
|
URB_FUNCTION_CLASS_DEVICE,
|
|
RequestType,
|
|
USB_REQUEST_GET_STATUS,
|
|
0,
|
|
0);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_SyncClearHubStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN USHORT RequestValue)
|
|
{
|
|
BM_REQUEST_TYPE RequestType;
|
|
|
|
DPRINT("USBH_SyncClearHubStatus: RequestValue - %x\n", RequestValue);
|
|
|
|
RequestType.B = 0;
|
|
RequestType.Recipient = BMREQUEST_TO_DEVICE;
|
|
RequestType.Type = BMREQUEST_CLASS;
|
|
RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
|
|
|
|
return USBH_Transact(HubExtension,
|
|
NULL,
|
|
0,
|
|
BMREQUEST_HOST_TO_DEVICE,
|
|
URB_FUNCTION_CLASS_DEVICE,
|
|
RequestType,
|
|
USB_REQUEST_CLEAR_FEATURE,
|
|
RequestValue,
|
|
0);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_SyncGetPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN USHORT Port,
|
|
IN PUSB_PORT_STATUS_AND_CHANGE PortStatus,
|
|
IN ULONG Length)
|
|
{
|
|
BM_REQUEST_TYPE RequestType;
|
|
|
|
DPRINT("USBH_SyncGetPortStatus: Port - %x\n", Port);
|
|
|
|
RequestType.B = 0;
|
|
RequestType.Recipient = BMREQUEST_TO_OTHER;
|
|
RequestType.Type = BMREQUEST_CLASS;
|
|
RequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
|
|
|
|
return USBH_Transact(HubExtension,
|
|
PortStatus,
|
|
Length,
|
|
BMREQUEST_DEVICE_TO_HOST,
|
|
URB_FUNCTION_CLASS_OTHER,
|
|
RequestType,
|
|
USB_REQUEST_GET_STATUS,
|
|
0,
|
|
Port);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_SyncClearPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN USHORT Port,
|
|
IN USHORT RequestValue)
|
|
{
|
|
BM_REQUEST_TYPE RequestType;
|
|
|
|
DPRINT("USBH_SyncClearPortStatus: Port - %x, RequestValue - %x\n",
|
|
Port,
|
|
RequestValue);
|
|
|
|
RequestType.B = 0;
|
|
RequestType.Recipient = BMREQUEST_TO_OTHER;
|
|
RequestType.Type = BMREQUEST_CLASS;
|
|
RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
|
|
|
|
return USBH_Transact(HubExtension,
|
|
NULL,
|
|
0,
|
|
BMREQUEST_HOST_TO_DEVICE,
|
|
URB_FUNCTION_CLASS_OTHER,
|
|
RequestType,
|
|
USB_REQUEST_CLEAR_FEATURE,
|
|
RequestValue,
|
|
Port);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_SyncPowerOnPort(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN USHORT Port,
|
|
IN BOOLEAN IsWait)
|
|
{
|
|
PUSBHUB_PORT_DATA PortData;
|
|
PUSB_HUB_DESCRIPTOR HubDescriptor;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
BM_REQUEST_TYPE RequestType;
|
|
PUSB_PORT_STATUS_AND_CHANGE PortStatus;
|
|
|
|
DPRINT("USBH_SyncPowerOnPort: Port - %x, IsWait - %x\n", Port, IsWait);
|
|
|
|
ASSERT(Port > 0);
|
|
PortData = &HubExtension->PortData[Port - 1];
|
|
PortStatus = &PortData->PortStatus;
|
|
|
|
if (PortStatus->PortStatus.Usb20PortStatus.CurrentConnectStatus == 1)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
RequestType.B = 0;
|
|
RequestType.Recipient = BMREQUEST_TO_DEVICE;
|
|
RequestType.Type = BMREQUEST_CLASS;
|
|
RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
|
|
|
|
Status = USBH_Transact(HubExtension,
|
|
NULL,
|
|
0,
|
|
BMREQUEST_HOST_TO_DEVICE,
|
|
URB_FUNCTION_CLASS_OTHER,
|
|
RequestType,
|
|
USB_REQUEST_SET_FEATURE,
|
|
USBHUB_FEATURE_PORT_POWER,
|
|
Port);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
if (IsWait)
|
|
{
|
|
HubDescriptor = HubExtension->HubDescriptor;
|
|
USBH_Wait(2 * HubDescriptor->bPowerOnToPowerGood);
|
|
}
|
|
|
|
PortStatus->PortStatus.Usb20PortStatus.CurrentConnectStatus = 1;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_SyncPowerOnPorts(IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
PUSB_HUB_DESCRIPTOR HubDescriptor;
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
USHORT Port;
|
|
UCHAR NumberOfPorts;
|
|
|
|
DPRINT("USBH_SyncPowerOnPorts: ... \n");
|
|
|
|
HubDescriptor = HubExtension->HubDescriptor;
|
|
NumberOfPorts = HubDescriptor->bNumberOfPorts;
|
|
|
|
for (Port = 1; Port <= NumberOfPorts; ++Port)
|
|
{
|
|
Status = USBH_SyncPowerOnPort(HubExtension, Port, 0);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("USBH_SyncPowerOnPorts: USBH_SyncPowerOnPort() failed - %lX\n",
|
|
Status);
|
|
break;
|
|
}
|
|
}
|
|
|
|
USBH_Wait(2 * HubDescriptor->bPowerOnToPowerGood);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_SyncDisablePort(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN USHORT Port)
|
|
{
|
|
PUSBHUB_PORT_DATA PortData;
|
|
NTSTATUS Status;
|
|
BM_REQUEST_TYPE RequestType;
|
|
|
|
DPRINT("USBH_SyncDisablePort ... \n");
|
|
|
|
PortData = &HubExtension->PortData[Port - 1];
|
|
|
|
RequestType.B = 0;
|
|
RequestType.Recipient = BMREQUEST_TO_DEVICE;
|
|
RequestType.Type = BMREQUEST_CLASS;
|
|
RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
|
|
|
|
Status = USBH_Transact(HubExtension,
|
|
NULL,
|
|
0,
|
|
BMREQUEST_HOST_TO_DEVICE,
|
|
URB_FUNCTION_CLASS_OTHER,
|
|
RequestType,
|
|
USB_REQUEST_CLEAR_FEATURE,
|
|
USBHUB_FEATURE_PORT_ENABLE,
|
|
Port);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
PortData->PortStatus.PortStatus.Usb20PortStatus.PortEnabledDisabled = 0;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
USBH_HubIsBusPowered(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PUSB_CONFIGURATION_DESCRIPTOR HubConfigDescriptor)
|
|
{
|
|
BOOLEAN Result;
|
|
USHORT UsbStatus;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBH_HubIsBusPowered: ... \n");
|
|
|
|
Status = USBH_SyncGetStatus(DeviceObject,
|
|
&UsbStatus,
|
|
URB_FUNCTION_GET_STATUS_FROM_DEVICE,
|
|
0);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
Result = (HubConfigDescriptor->bmAttributes & USB_CONFIG_POWERED_MASK)
|
|
== USB_CONFIG_BUS_POWERED;
|
|
}
|
|
else
|
|
{
|
|
Result = (UsbStatus & USB_GETSTATUS_SELF_POWERED) == 0;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_ChangeIndicationAckChangeComplete(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context)
|
|
{
|
|
PUSBHUB_FDO_EXTENSION HubExtension;
|
|
PVOID Event;
|
|
USHORT Port;
|
|
|
|
HubExtension = Context;
|
|
|
|
DPRINT_SCE("USBH_ChangeIndicationAckChangeComplete: ... \n");
|
|
|
|
ASSERT(HubExtension->Port > 0);
|
|
Port = HubExtension->Port - 1;
|
|
|
|
HubExtension->PortData[Port].PortStatus = HubExtension->PortStatus;
|
|
|
|
Event = InterlockedExchangePointer((PVOID)&HubExtension->pResetPortEvent,
|
|
NULL);
|
|
|
|
if (Event)
|
|
{
|
|
KeSetEvent(Event, EVENT_INCREMENT, FALSE);
|
|
}
|
|
|
|
USBH_SubmitStatusChangeTransfer(HubExtension);
|
|
|
|
if (!InterlockedDecrement(&HubExtension->ResetRequestCount))
|
|
{
|
|
KeSetEvent(&HubExtension->ResetEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
}
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_ChangeIndicationAckChange(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PIRP Irp,
|
|
IN struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST * Urb,
|
|
IN USHORT Port,
|
|
IN USHORT RequestValue)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
BM_REQUEST_TYPE RequestType;
|
|
|
|
DPRINT_SCE("USBH_ChangeIndicationAckChange: ... \n");
|
|
|
|
Urb->Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
|
|
Urb->Hdr.Function = URB_FUNCTION_CLASS_OTHER;
|
|
Urb->Hdr.UsbdDeviceHandle = NULL;
|
|
|
|
Urb->TransferFlags = USBD_SHORT_TRANSFER_OK;
|
|
Urb->TransferBufferLength = 0;
|
|
Urb->TransferBuffer = NULL;
|
|
Urb->TransferBufferMDL = NULL;
|
|
Urb->UrbLink = NULL;
|
|
|
|
RequestType.B = 0;
|
|
RequestType.Recipient = BMREQUEST_TO_OTHER;
|
|
RequestType.Type = BMREQUEST_CLASS;
|
|
RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
|
|
|
|
Urb->RequestTypeReservedBits = RequestType.B;
|
|
Urb->Request = USB_REQUEST_CLEAR_FEATURE;
|
|
Urb->Index = Port;
|
|
Urb->Value = RequestValue;
|
|
|
|
IoInitializeIrp(Irp,
|
|
IoSizeOfIrp(HubExtension->LowerDevice->StackSize),
|
|
HubExtension->LowerDevice->StackSize);
|
|
|
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
|
|
|
IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
IoStack->Parameters.Others.Argument1 = Urb;
|
|
IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
|
|
|
|
IoSetCompletionRoutine(Irp,
|
|
USBH_ChangeIndicationAckChangeComplete,
|
|
HubExtension,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
return IoCallDriver(HubExtension->LowerDevice, Irp);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_ChangeIndicationProcessChange(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context)
|
|
{
|
|
PUSBHUB_FDO_EXTENSION HubExtension;
|
|
PUSBHUB_IO_WORK_ITEM WorkItem;
|
|
USHORT RequestValue;
|
|
|
|
HubExtension = Context;
|
|
|
|
DPRINT_SCE("USBH_ChangeIndicationProcessChange: PortStatus - %lX\n",
|
|
HubExtension->PortStatus.AsUlong32);
|
|
|
|
if ((NT_SUCCESS(Irp->IoStatus.Status) ||
|
|
USBD_SUCCESS(HubExtension->SCEWorkerUrb.Hdr.Status)) &&
|
|
(HubExtension->PortStatus.PortChange.Usb20PortChange.ResetChange ||
|
|
HubExtension->PortStatus.PortChange.Usb20PortChange.PortEnableDisableChange))
|
|
{
|
|
if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
|
|
{
|
|
KeSetEvent(&HubExtension->PendingRequestEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
}
|
|
|
|
USBH_FreeWorkItem(HubExtension->WorkItemToQueue);
|
|
|
|
HubExtension->WorkItemToQueue = NULL;
|
|
|
|
if (HubExtension->PortStatus.PortChange.Usb20PortChange.ResetChange)
|
|
{
|
|
RequestValue = USBHUB_FEATURE_C_PORT_RESET;
|
|
}
|
|
else
|
|
{
|
|
RequestValue = USBHUB_FEATURE_C_PORT_ENABLE;
|
|
}
|
|
|
|
USBH_ChangeIndicationAckChange(HubExtension,
|
|
HubExtension->ResetPortIrp,
|
|
&HubExtension->SCEWorkerUrb,
|
|
HubExtension->Port,
|
|
RequestValue);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(HubExtension->WorkItemToQueue != NULL);
|
|
|
|
WorkItem = HubExtension->WorkItemToQueue;
|
|
HubExtension->WorkItemToQueue = NULL;
|
|
|
|
USBH_QueueWorkItem(HubExtension, WorkItem);
|
|
}
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_ChangeIndicationQueryChange(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PIRP Irp,
|
|
IN struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST * Urb,
|
|
IN USHORT Port)
|
|
{
|
|
PUSBHUB_IO_WORK_ITEM WorkItem;
|
|
NTSTATUS Status;
|
|
PIO_STACK_LOCATION IoStack;
|
|
BM_REQUEST_TYPE RequestType;
|
|
|
|
DPRINT_SCE("USBH_ChangeIndicationQueryChange: Port - %x\n", Port);
|
|
|
|
InterlockedIncrement(&HubExtension->PendingRequestCount);
|
|
|
|
if (!Port)
|
|
{
|
|
ASSERT(HubExtension->WorkItemToQueue != NULL);
|
|
|
|
WorkItem = HubExtension->WorkItemToQueue;
|
|
HubExtension->WorkItemToQueue = NULL;
|
|
|
|
USBH_QueueWorkItem(HubExtension, WorkItem);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
Urb->Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
|
|
Urb->Hdr.UsbdDeviceHandle = NULL;
|
|
Urb->Hdr.Function = URB_FUNCTION_CLASS_OTHER;
|
|
|
|
Urb->TransferFlags = USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN;
|
|
Urb->TransferBuffer = &HubExtension->PortStatus;
|
|
Urb->TransferBufferLength = sizeof(HubExtension->PortStatus);
|
|
Urb->TransferBufferMDL = NULL;
|
|
Urb->UrbLink = NULL;
|
|
|
|
RequestType.B = 0;
|
|
RequestType.Recipient = BMREQUEST_TO_OTHER;
|
|
RequestType.Type = BMREQUEST_CLASS;
|
|
RequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
|
|
|
|
Urb->RequestTypeReservedBits = RequestType.B;
|
|
Urb->Request = USB_REQUEST_GET_STATUS;
|
|
Urb->Value = 0;
|
|
Urb->Index = Port;
|
|
|
|
HubExtension->Port = Port;
|
|
|
|
IoInitializeIrp(Irp,
|
|
IoSizeOfIrp(HubExtension->LowerDevice->StackSize),
|
|
HubExtension->LowerDevice->StackSize);
|
|
|
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
|
|
|
IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
IoStack->Parameters.Others.Argument1 = Urb;
|
|
IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
|
|
|
|
IoSetCompletionRoutine(Irp,
|
|
USBH_ChangeIndicationProcessChange,
|
|
HubExtension,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
Status = IoCallDriver(HubExtension->LowerDevice, Irp);
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_ProcessHubStateChange(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PUSB_HUB_STATUS_AND_CHANGE HubStatus)
|
|
{
|
|
USB_HUB_CHANGE HubStatusChange;
|
|
|
|
DPRINT_SCE("USBH_ProcessHubStateChange: HubStatus - %lx\n", HubStatus->AsUlong32);
|
|
|
|
HubStatusChange = HubStatus->HubChange;
|
|
|
|
if (HubStatusChange.LocalPowerChange)
|
|
{
|
|
DPRINT1("USBH_ProcessHubStateChange: LocalPowerChange\n");
|
|
USBH_SyncClearHubStatus(HubExtension,
|
|
USBHUB_FEATURE_C_HUB_LOCAL_POWER);
|
|
}
|
|
else if (HubStatusChange.OverCurrentChange)
|
|
{
|
|
USBH_SyncClearHubStatus(HubExtension,
|
|
USBHUB_FEATURE_C_HUB_OVER_CURRENT);
|
|
if (HubStatus->HubStatus.OverCurrent)
|
|
{
|
|
DPRINT1("USBH_ProcessHubStateChange: OverCurrent UNIMPLEMENTED. FIXME\n");
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_ProcessPortStateChange(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN USHORT Port,
|
|
IN PUSB_PORT_STATUS_AND_CHANGE PortStatus)
|
|
{
|
|
PUSBHUB_PORT_DATA PortData;
|
|
USB_20_PORT_CHANGE PortStatusChange;
|
|
PDEVICE_OBJECT PortDevice;
|
|
PUSBHUB_PORT_PDO_EXTENSION PortExtension;
|
|
PVOID SerialNumber;
|
|
PVOID DeviceHandle;
|
|
USHORT RequestValue;
|
|
KIRQL Irql;
|
|
|
|
DPRINT_SCE("USBH_ProcessPortStateChange ... \n");
|
|
|
|
ASSERT(Port > 0);
|
|
PortData = &HubExtension->PortData[Port - 1];
|
|
|
|
PortStatusChange = PortStatus->PortChange.Usb20PortChange;
|
|
|
|
if (PortStatusChange.ConnectStatusChange)
|
|
{
|
|
PortData->PortStatus = *PortStatus;
|
|
|
|
USBH_SyncClearPortStatus(HubExtension,
|
|
Port,
|
|
USBHUB_FEATURE_C_PORT_CONNECTION);
|
|
|
|
PortData = &HubExtension->PortData[Port - 1];
|
|
|
|
PortDevice = PortData->DeviceObject;
|
|
|
|
if (!PortDevice)
|
|
{
|
|
IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
|
|
return;
|
|
}
|
|
|
|
PortExtension = PortDevice->DeviceExtension;
|
|
|
|
if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_OVERCURRENT_PORT)
|
|
{
|
|
return;
|
|
}
|
|
|
|
KeAcquireSpinLock(&HubExtension->RelationsWorkerSpinLock, &Irql);
|
|
|
|
if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D3)
|
|
{
|
|
KeReleaseSpinLock(&HubExtension->RelationsWorkerSpinLock, Irql);
|
|
IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
|
|
return;
|
|
}
|
|
|
|
PortData->DeviceObject = NULL;
|
|
PortData->ConnectionStatus = NoDeviceConnected;
|
|
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_STATE_CHANGING;
|
|
|
|
InsertTailList(&HubExtension->PdoList, &PortExtension->PortLink);
|
|
|
|
KeReleaseSpinLock(&HubExtension->RelationsWorkerSpinLock, Irql);
|
|
|
|
SerialNumber = InterlockedExchangePointer((PVOID)&PortExtension->SerialNumber,
|
|
NULL);
|
|
|
|
if (SerialNumber)
|
|
{
|
|
ExFreePoolWithTag(SerialNumber, USB_HUB_TAG);
|
|
}
|
|
|
|
DeviceHandle = InterlockedExchangePointer(&PortExtension->DeviceHandle,
|
|
NULL);
|
|
|
|
if (DeviceHandle)
|
|
{
|
|
USBD_RemoveDeviceEx(HubExtension, DeviceHandle, 0);
|
|
USBH_SyncDisablePort(HubExtension, Port);
|
|
}
|
|
|
|
IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
|
|
}
|
|
else if (PortStatusChange.PortEnableDisableChange)
|
|
{
|
|
RequestValue = USBHUB_FEATURE_C_PORT_ENABLE;
|
|
PortData->PortStatus = *PortStatus;
|
|
USBH_SyncClearPortStatus(HubExtension, Port, RequestValue);
|
|
return;
|
|
}
|
|
else if (PortStatusChange.SuspendChange)
|
|
{
|
|
DPRINT1("USBH_ProcessPortStateChange: SuspendChange UNIMPLEMENTED. FIXME\n");
|
|
DbgBreakPoint();
|
|
}
|
|
else if (PortStatusChange.OverCurrentIndicatorChange)
|
|
{
|
|
DPRINT1("USBH_ProcessPortStateChange: OverCurrentIndicatorChange UNIMPLEMENTED. FIXME\n");
|
|
DbgBreakPoint();
|
|
}
|
|
else if (PortStatusChange.ResetChange)
|
|
{
|
|
RequestValue = USBHUB_FEATURE_C_PORT_RESET;
|
|
PortData->PortStatus = *PortStatus;
|
|
USBH_SyncClearPortStatus(HubExtension, Port, RequestValue);
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_GetPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PULONG PortStatus)
|
|
{
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION IoStack;
|
|
NTSTATUS Status;
|
|
KEVENT Event;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
DPRINT("USBH_GetPortStatus ... \n");
|
|
|
|
*PortStatus = 0;
|
|
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_PORT_STATUS,
|
|
HubExtension->LowerDevice,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
TRUE,
|
|
&Event,
|
|
&IoStatusBlock);
|
|
|
|
if (!Irp)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
|
IoStack->Parameters.Others.Argument1 = PortStatus;
|
|
|
|
Status = IoCallDriver(HubExtension->LowerDevice, Irp);
|
|
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
IoStatusBlock.Status = Status;
|
|
}
|
|
|
|
return IoStatusBlock.Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_EnableParentPort(IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
PIRP Irp;
|
|
NTSTATUS Status;
|
|
KEVENT Event;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
DPRINT("USBH_EnableParentPort ... \n");
|
|
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_ENABLE_PORT,
|
|
HubExtension->LowerDevice,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
TRUE,
|
|
&Event,
|
|
&IoStatusBlock);
|
|
|
|
if (!Irp)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Status = IoCallDriver(HubExtension->LowerDevice, Irp);
|
|
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
IoStatusBlock.Status = Status;
|
|
}
|
|
|
|
return IoStatusBlock.Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_ResetInterruptPipe(IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
struct _URB_PIPE_REQUEST * Urb;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBH_ResetInterruptPipe ... \n");
|
|
|
|
Urb = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(struct _URB_PIPE_REQUEST),
|
|
USB_HUB_TAG);
|
|
|
|
if (Urb)
|
|
{
|
|
RtlZeroMemory(Urb, sizeof(struct _URB_PIPE_REQUEST));
|
|
|
|
Urb->Hdr.Length = sizeof(struct _URB_PIPE_REQUEST);
|
|
Urb->Hdr.Function = URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL;
|
|
Urb->PipeHandle = HubExtension->PipeInfo.PipeHandle;
|
|
|
|
Status = USBH_FdoSyncSubmitUrb(HubExtension->Common.SelfDevice,
|
|
(PURB)Urb);
|
|
|
|
ExFreePoolWithTag(Urb, USB_HUB_TAG);
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
HubExtension->RequestErrors = 0;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_ResetHub(IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG PortStatusFlags = 0;
|
|
|
|
DPRINT("USBH_ResetHub: ... \n");
|
|
|
|
Status = USBH_GetPortStatus(HubExtension, &PortStatusFlags);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
if (!(PortStatusFlags & USBD_PORT_ENABLED))
|
|
{
|
|
if (PortStatusFlags & USBD_PORT_CONNECTED)
|
|
{
|
|
USBH_EnableParentPort(HubExtension);
|
|
}
|
|
}
|
|
|
|
Status = USBH_ResetInterruptPipe(HubExtension);
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_ChangeIndicationWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PVOID Context)
|
|
{
|
|
PUSBHUB_FDO_EXTENSION LowerHubExtension;
|
|
PUSBHUB_PORT_PDO_EXTENSION LowerPortExtension;
|
|
PUSBHUB_STATUS_CHANGE_CONTEXT WorkItem;
|
|
USB_PORT_STATUS_AND_CHANGE PortStatus;
|
|
USB_HUB_STATUS_AND_CHANGE HubStatus;
|
|
NTSTATUS Status;
|
|
USHORT Port = 0;
|
|
|
|
DPRINT_SCE("USBH_ChangeIndicationWorker ... \n");
|
|
|
|
WorkItem = Context;
|
|
|
|
KeWaitForSingleObject(&HubExtension->HubSemaphore,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING)
|
|
{
|
|
KeSetEvent(&HubExtension->StatusChangeEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if (!HubExtension->RequestErrors)
|
|
{
|
|
goto Enum;
|
|
}
|
|
|
|
DPRINT_SCE("USBH_ChangeIndicationWorker: RequestErrors - %x\n",
|
|
HubExtension->RequestErrors);
|
|
|
|
if (HubExtension->LowerPDO == HubExtension->RootHubPdo)
|
|
{
|
|
goto Enum;
|
|
}
|
|
|
|
LowerPortExtension = HubExtension->LowerPDO->DeviceExtension;
|
|
|
|
if (LowerPortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D1_OR_D2)
|
|
{
|
|
goto Enum;
|
|
}
|
|
|
|
LowerHubExtension = LowerPortExtension->HubExtension;
|
|
|
|
if (!LowerHubExtension)
|
|
{
|
|
goto Enum;
|
|
}
|
|
|
|
Status = USBH_SyncGetPortStatus(LowerHubExtension,
|
|
LowerPortExtension->PortNumber,
|
|
&PortStatus,
|
|
sizeof(USB_PORT_STATUS_AND_CHANGE));
|
|
|
|
if (!NT_SUCCESS(Status) ||
|
|
!PortStatus.PortStatus.Usb20PortStatus.CurrentConnectStatus)
|
|
{
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_REMOVED;
|
|
|
|
KeSetEvent(&HubExtension->StatusChangeEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_ESD_RECOVERING))
|
|
{
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_ESD_RECOVERING;
|
|
|
|
DPRINT1("USBH_ChangeIndicationWorker: USBHUB_FDO_FLAG_ESD_RECOVERING FIXME\n");
|
|
DbgBreakPoint();
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
Enum:
|
|
|
|
if (WorkItem->IsRequestErrors)
|
|
{
|
|
USBH_ResetHub(HubExtension);
|
|
}
|
|
else
|
|
{
|
|
for (Port = 0;
|
|
Port < HubExtension->HubDescriptor->bNumberOfPorts;
|
|
Port++)
|
|
{
|
|
if (IsBitSet((PUCHAR)(WorkItem + 1), Port))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Port)
|
|
{
|
|
Status = USBH_SyncGetPortStatus(HubExtension,
|
|
Port,
|
|
&PortStatus,
|
|
sizeof(PortStatus));
|
|
}
|
|
else
|
|
{
|
|
Status = USBH_SyncGetHubStatus(HubExtension,
|
|
&HubStatus,
|
|
sizeof(HubStatus));
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
if (Port)
|
|
{
|
|
USBH_ProcessPortStateChange(HubExtension,
|
|
Port,
|
|
&PortStatus);
|
|
}
|
|
else
|
|
{
|
|
USBH_ProcessHubStateChange(HubExtension,
|
|
&HubStatus);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HubExtension->RequestErrors++;
|
|
|
|
if (HubExtension->RequestErrors > USBHUB_MAX_REQUEST_ERRORS)
|
|
{
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
USBH_SubmitStatusChangeTransfer(HubExtension);
|
|
|
|
Exit:
|
|
|
|
KeReleaseSemaphore(&HubExtension->HubSemaphore,
|
|
LOW_REALTIME_PRIORITY,
|
|
1,
|
|
FALSE);
|
|
|
|
if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
|
|
{
|
|
KeSetEvent(&HubExtension->PendingRequestEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
}
|
|
|
|
if (!InterlockedDecrement((PLONG)&HubExtension->ResetRequestCount))
|
|
{
|
|
KeSetEvent(&HubExtension->ResetEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEFER_CHECK_IDLE)
|
|
{
|
|
USBH_CheckHubIdle(HubExtension);
|
|
}
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_ChangeIndication(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context)
|
|
{
|
|
PUSBHUB_FDO_EXTENSION HubExtension;
|
|
USBD_STATUS UrbStatus;
|
|
BOOLEAN IsErrors = FALSE;
|
|
PUSBHUB_IO_WORK_ITEM HubWorkItem;
|
|
PUSBHUB_STATUS_CHANGE_CONTEXT HubWorkItemBuffer;
|
|
USHORT NumPorts;
|
|
USHORT Port;
|
|
NTSTATUS Status;
|
|
PVOID Bitmap;
|
|
ULONG BufferLength;
|
|
|
|
HubExtension = Context;
|
|
UrbStatus = HubExtension->SCEWorkerUrb.Hdr.Status;
|
|
|
|
DPRINT_SCE("USBH_ChangeIndication: IrpStatus - %x, UrbStatus - %x, HubFlags - %lX\n",
|
|
Irp->IoStatus.Status,
|
|
UrbStatus,
|
|
HubExtension->HubFlags);
|
|
|
|
if (NT_ERROR(Irp->IoStatus.Status) || USBD_ERROR(UrbStatus) ||
|
|
(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED) ||
|
|
(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING))
|
|
{
|
|
HubExtension->RequestErrors++;
|
|
|
|
IsErrors = TRUE;
|
|
|
|
KeSetEvent(&HubExtension->StatusChangeEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING ||
|
|
HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED ||
|
|
HubExtension->RequestErrors > USBHUB_MAX_REQUEST_ERRORS ||
|
|
Irp->IoStatus.Status == STATUS_DELETE_PENDING)
|
|
{
|
|
DPRINT_SCE("USBH_ChangeIndication: HubExtension->RequestErrors - %x\n",
|
|
HubExtension->RequestErrors);
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
DPRINT_SCE("USBH_ChangeIndication: HubExtension->RequestErrors - %x\n",
|
|
HubExtension->RequestErrors);
|
|
}
|
|
else
|
|
{
|
|
HubExtension->RequestErrors = 0;
|
|
}
|
|
|
|
BufferLength = sizeof(USBHUB_STATUS_CHANGE_CONTEXT) +
|
|
HubExtension->SCEBitmapLength;
|
|
|
|
Status = USBH_AllocateWorkItem(HubExtension,
|
|
&HubWorkItem,
|
|
USBH_ChangeIndicationWorker,
|
|
BufferLength,
|
|
(PVOID *)&HubWorkItemBuffer,
|
|
DelayedWorkQueue);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
RtlZeroMemory(HubWorkItemBuffer, BufferLength);
|
|
|
|
HubWorkItemBuffer->IsRequestErrors = FALSE;
|
|
|
|
if (IsErrors)
|
|
{
|
|
HubWorkItemBuffer->IsRequestErrors = TRUE;
|
|
}
|
|
|
|
if (InterlockedIncrement(&HubExtension->ResetRequestCount) == 1)
|
|
{
|
|
KeClearEvent(&HubExtension->ResetEvent);
|
|
}
|
|
|
|
HubWorkItemBuffer->HubExtension = HubExtension;
|
|
|
|
HubExtension->WorkItemToQueue = HubWorkItem;
|
|
|
|
Bitmap = HubWorkItemBuffer + 1;
|
|
|
|
RtlCopyMemory(Bitmap,
|
|
HubExtension->SCEBitmap,
|
|
HubExtension->SCEBitmapLength);
|
|
|
|
NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
|
|
|
|
for (Port = 0; Port <= NumPorts; ++Port)
|
|
{
|
|
if (IsBitSet(Bitmap, Port))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Port > NumPorts)
|
|
{
|
|
Port = 0;
|
|
}
|
|
|
|
Status = USBH_ChangeIndicationQueryChange(HubExtension,
|
|
HubExtension->ResetPortIrp,
|
|
&HubExtension->SCEWorkerUrb,
|
|
Port);
|
|
|
|
if (NT_ERROR(Status))
|
|
{
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
|
|
}
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_SubmitStatusChangeTransfer(IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
PIRP Irp;
|
|
NTSTATUS Status;
|
|
struct _URB_BULK_OR_INTERRUPT_TRANSFER * Urb;
|
|
PIO_STACK_LOCATION IoStack;
|
|
|
|
DPRINT_SCE("USBH_SubmitStatusChangeTransfer: HubExtension - %p, SCEIrp - %p\n",
|
|
HubExtension,
|
|
HubExtension->SCEIrp);
|
|
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_NOT_D0_STATE)
|
|
{
|
|
DPRINT_SCE("USBH_SubmitStatusChangeTransfer: USBHUB_FDO_FLAG_NOT_D0_STATE\n");
|
|
DPRINT_SCE("USBH_SubmitStatusChangeTransfer: HubFlags - %lX\n",
|
|
HubExtension->HubFlags);
|
|
|
|
return STATUS_INVALID_DEVICE_STATE;
|
|
}
|
|
|
|
Irp = HubExtension->SCEIrp;
|
|
|
|
if (!Irp)
|
|
{
|
|
return STATUS_INVALID_DEVICE_STATE;
|
|
}
|
|
|
|
Urb = (struct _URB_BULK_OR_INTERRUPT_TRANSFER *)&HubExtension->SCEWorkerUrb;
|
|
|
|
Urb->Hdr.Length = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
|
|
Urb->Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
|
|
Urb->Hdr.UsbdDeviceHandle = NULL;
|
|
|
|
Urb->PipeHandle = HubExtension->PipeInfo.PipeHandle;
|
|
Urb->TransferFlags = USBD_SHORT_TRANSFER_OK;
|
|
Urb->TransferBuffer = HubExtension->SCEBitmap;
|
|
Urb->TransferBufferLength = HubExtension->SCEBitmapLength;
|
|
Urb->TransferBufferMDL = NULL;
|
|
Urb->UrbLink = NULL;
|
|
|
|
IoInitializeIrp(Irp,
|
|
IoSizeOfIrp(HubExtension->LowerDevice->StackSize),
|
|
HubExtension->LowerDevice->StackSize);
|
|
|
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
|
|
|
IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
IoStack->Parameters.Others.Argument1 = &HubExtension->SCEWorkerUrb;
|
|
IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
|
|
|
|
IoSetCompletionRoutine(Irp,
|
|
USBH_ChangeIndication,
|
|
HubExtension,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
KeClearEvent(&HubExtension->StatusChangeEvent);
|
|
|
|
Status = IoCallDriver(HubExtension->LowerDevice, Irp);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBD_CreateDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PUSB_DEVICE_HANDLE * OutDeviceHandle,
|
|
IN USB_PORT_STATUS UsbPortStatus,
|
|
IN USHORT Port)
|
|
{
|
|
PUSB_DEVICE_HANDLE HubDeviceHandle;
|
|
PUSB_BUSIFFN_CREATE_USB_DEVICE CreateUsbDevice;
|
|
|
|
DPRINT("USBD_CreateDeviceEx: Port - %x, UsbPortStatus - 0x%04X\n",
|
|
Port,
|
|
UsbPortStatus.AsUshort16);
|
|
|
|
CreateUsbDevice = HubExtension->BusInterface.CreateUsbDevice;
|
|
|
|
if (!CreateUsbDevice)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
HubDeviceHandle = USBH_SyncGetDeviceHandle(HubExtension->LowerDevice);
|
|
|
|
return CreateUsbDevice(HubExtension->BusInterface.BusContext,
|
|
OutDeviceHandle,
|
|
HubDeviceHandle,
|
|
UsbPortStatus.AsUshort16,
|
|
Port);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBD_RemoveDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PUSB_DEVICE_HANDLE DeviceHandle,
|
|
IN ULONG Flags)
|
|
{
|
|
PUSB_BUSIFFN_REMOVE_USB_DEVICE RemoveUsbDevice;
|
|
|
|
DPRINT("USBD_RemoveDeviceEx: DeviceHandle - %p, Flags - %X\n",
|
|
DeviceHandle,
|
|
Flags);
|
|
|
|
RemoveUsbDevice = HubExtension->BusInterface.RemoveUsbDevice;
|
|
|
|
if (!RemoveUsbDevice)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return RemoveUsbDevice(HubExtension->BusInterface.BusContext,
|
|
DeviceHandle,
|
|
Flags);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBD_InitializeDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PUSB_DEVICE_HANDLE DeviceHandle,
|
|
IN PUCHAR DeviceDescriptorBuffer,
|
|
IN ULONG DeviceDescriptorBufferLength,
|
|
IN PUCHAR ConfigDescriptorBuffer,
|
|
IN ULONG ConfigDescriptorBufferLength)
|
|
{
|
|
NTSTATUS Status;
|
|
PUSB_BUSIFFN_INITIALIZE_USB_DEVICE InitializeUsbDevice;
|
|
PUSB_BUSIFFN_GET_USB_DESCRIPTORS GetUsbDescriptors;
|
|
|
|
DPRINT("USBD_InitializeDeviceEx: ... \n");
|
|
|
|
InitializeUsbDevice = HubExtension->BusInterface.InitializeUsbDevice;
|
|
GetUsbDescriptors = HubExtension->BusInterface.GetUsbDescriptors;
|
|
|
|
if (!InitializeUsbDevice || !GetUsbDescriptors)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
Status = InitializeUsbDevice(HubExtension->BusInterface.BusContext,
|
|
DeviceHandle);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
return GetUsbDescriptors(HubExtension->BusInterface.BusContext,
|
|
DeviceHandle,
|
|
DeviceDescriptorBuffer,
|
|
&DeviceDescriptorBufferLength,
|
|
ConfigDescriptorBuffer,
|
|
&ConfigDescriptorBufferLength);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBHUB_SetDeviceHandleData(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PDEVICE_OBJECT UsbDevicePdo,
|
|
IN PVOID DeviceHandle)
|
|
{
|
|
PUSB_BUSIFFN_SET_DEVHANDLE_DATA SetDeviceHandleData;
|
|
|
|
DPRINT("USBHUB_SetDeviceHandleData ... \n");
|
|
|
|
SetDeviceHandleData = HubExtension->BusInterface.SetDeviceHandleData;
|
|
|
|
if (!SetDeviceHandleData)
|
|
{
|
|
return;
|
|
}
|
|
|
|
SetDeviceHandleData(HubExtension->BusInterface.BusContext,
|
|
DeviceHandle,
|
|
UsbDevicePdo);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBHUB_FlushAllTransfers(IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
PUSB_BUSIFFN_FLUSH_TRANSFERS FlushTransfers;
|
|
|
|
DPRINT("USBHUB_FlushAllTransfers ... \n");
|
|
|
|
FlushTransfers = HubExtension->BusInterface.FlushTransfers;
|
|
|
|
if (FlushTransfers)
|
|
{
|
|
FlushTransfers(HubExtension->BusInterface.BusContext, NULL);
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBD_GetDeviceInformationEx(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
|
|
IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PUSB_NODE_CONNECTION_INFORMATION_EX Info,
|
|
IN ULONG Length,
|
|
IN PUSB_DEVICE_HANDLE DeviceHandle)
|
|
{
|
|
PUSB_BUSIFFN_GET_DEVICE_INFORMATION QueryDeviceInformation;
|
|
PUSB_DEVICE_INFORMATION_0 DeviceInfo;
|
|
SIZE_T DeviceInfoLength;
|
|
PUSB_NODE_CONNECTION_INFORMATION_EX NodeInfo;
|
|
SIZE_T NodeInfoLength;
|
|
ULONG PipeNumber;
|
|
ULONG dummy;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBD_GetDeviceInformationEx ... \n");
|
|
|
|
QueryDeviceInformation = HubExtension->BusInterface.QueryDeviceInformation;
|
|
|
|
if (!QueryDeviceInformation)
|
|
{
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
return Status;
|
|
}
|
|
|
|
DeviceInfoLength = sizeof(USB_DEVICE_INFORMATION_0);
|
|
|
|
while (TRUE)
|
|
{
|
|
DeviceInfo = ExAllocatePoolWithTag(PagedPool,
|
|
DeviceInfoLength,
|
|
USB_HUB_TAG);
|
|
|
|
if (!DeviceInfo)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(DeviceInfo, DeviceInfoLength);
|
|
|
|
DeviceInfo->InformationLevel = 0;
|
|
|
|
Status = QueryDeviceInformation(HubExtension->BusInterface.BusContext,
|
|
DeviceHandle,
|
|
DeviceInfo,
|
|
DeviceInfoLength,
|
|
&dummy);
|
|
|
|
if (Status != STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
DeviceInfoLength = DeviceInfo->ActualLength;
|
|
|
|
ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
|
|
}
|
|
|
|
NodeInfo = NULL;
|
|
NodeInfoLength = 0;
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
NodeInfoLength = (sizeof(USB_NODE_CONNECTION_INFORMATION_EX) - sizeof(USB_PIPE_INFO)) +
|
|
DeviceInfo->NumberOfOpenPipes * sizeof(USB_PIPE_INFO);
|
|
|
|
NodeInfo = ExAllocatePoolWithTag(PagedPool, NodeInfoLength, USB_HUB_TAG);
|
|
|
|
if (!NodeInfo)
|
|
{
|
|
ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(NodeInfo, NodeInfoLength);
|
|
|
|
NodeInfo->ConnectionIndex = Info->ConnectionIndex;
|
|
|
|
RtlCopyMemory(&NodeInfo->DeviceDescriptor,
|
|
&DeviceInfo->DeviceDescriptor,
|
|
sizeof(USB_DEVICE_DESCRIPTOR));
|
|
|
|
NodeInfo->CurrentConfigurationValue = DeviceInfo->CurrentConfigurationValue;
|
|
NodeInfo->Speed = DeviceInfo->DeviceSpeed;
|
|
NodeInfo->DeviceIsHub = PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE;
|
|
NodeInfo->DeviceAddress = DeviceInfo->DeviceAddress;
|
|
NodeInfo->NumberOfOpenPipes = DeviceInfo->NumberOfOpenPipes;
|
|
NodeInfo->ConnectionStatus = Info->ConnectionStatus;
|
|
|
|
for (PipeNumber = 0;
|
|
PipeNumber < DeviceInfo->NumberOfOpenPipes;
|
|
PipeNumber++)
|
|
{
|
|
RtlCopyMemory(&NodeInfo->PipeList[PipeNumber],
|
|
&DeviceInfo->PipeList[PipeNumber],
|
|
sizeof(USB_PIPE_INFO));
|
|
}
|
|
}
|
|
|
|
ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
|
|
|
|
if (NodeInfo)
|
|
{
|
|
if (NodeInfoLength <= Length)
|
|
{
|
|
Length = NodeInfoLength;
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
RtlCopyMemory(Info, NodeInfo, Length);
|
|
|
|
ExFreePoolWithTag(NodeInfo, USB_HUB_TAG);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBD_RestoreDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN OUT PUSB_DEVICE_HANDLE OldDeviceHandle,
|
|
IN OUT PUSB_DEVICE_HANDLE NewDeviceHandle)
|
|
{
|
|
PUSB_BUSIFFN_RESTORE_DEVICE RestoreUsbDevice;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBD_RestoreDeviceEx: HubExtension - %p, OldDeviceHandle - %p, NewDeviceHandle - %p\n",
|
|
HubExtension,
|
|
OldDeviceHandle,
|
|
NewDeviceHandle);
|
|
|
|
RestoreUsbDevice = HubExtension->BusInterface.RestoreUsbDevice;
|
|
|
|
if (RestoreUsbDevice)
|
|
{
|
|
Status = RestoreUsbDevice(HubExtension->BusInterface.BusContext,
|
|
OldDeviceHandle,
|
|
NewDeviceHandle);
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_AllocateWorkItem(PUSBHUB_FDO_EXTENSION HubExtension,
|
|
PUSBHUB_IO_WORK_ITEM * OutHubIoWorkItem,
|
|
PUSBHUB_WORKER_ROUTINE WorkerRoutine,
|
|
SIZE_T BufferLength,
|
|
PVOID * OutHubWorkItemBuffer,
|
|
WORK_QUEUE_TYPE Type)
|
|
{
|
|
PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
|
|
PIO_WORKITEM WorkItem;
|
|
PVOID WorkItemBuffer;
|
|
|
|
DPRINT("USBH_AllocateWorkItem: ... \n");
|
|
|
|
if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_WITEM_INIT))
|
|
{
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
HubIoWorkItem = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(USBHUB_IO_WORK_ITEM),
|
|
USB_HUB_TAG);
|
|
|
|
if (!HubIoWorkItem)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(HubIoWorkItem, sizeof(USBHUB_IO_WORK_ITEM));
|
|
|
|
WorkItem = IoAllocateWorkItem(HubExtension->Common.SelfDevice);
|
|
|
|
HubIoWorkItem->HubWorkItem = WorkItem;
|
|
|
|
if (!WorkItem)
|
|
{
|
|
ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if (BufferLength && OutHubWorkItemBuffer)
|
|
{
|
|
WorkItemBuffer = ExAllocatePoolWithTag(NonPagedPool,
|
|
BufferLength,
|
|
USB_HUB_TAG);
|
|
|
|
HubIoWorkItem->HubWorkItemBuffer = WorkItemBuffer;
|
|
|
|
if (!WorkItemBuffer)
|
|
{
|
|
IoFreeWorkItem(HubIoWorkItem->HubWorkItem);
|
|
ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(WorkItemBuffer, BufferLength);
|
|
}
|
|
else
|
|
{
|
|
HubIoWorkItem->HubWorkItemBuffer = NULL;
|
|
}
|
|
|
|
HubIoWorkItem->HubWorkItemType = Type;
|
|
HubIoWorkItem->HubExtension = HubExtension;
|
|
HubIoWorkItem->HubWorkerRoutine = WorkerRoutine;
|
|
|
|
if (OutHubIoWorkItem)
|
|
{
|
|
*OutHubIoWorkItem = HubIoWorkItem;
|
|
}
|
|
|
|
if (OutHubWorkItemBuffer)
|
|
{
|
|
*OutHubWorkItemBuffer = HubIoWorkItem->HubWorkItemBuffer;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_Worker(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PVOID Context)
|
|
{
|
|
PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
|
|
PUSBHUB_FDO_EXTENSION HubExtension;
|
|
KIRQL OldIrql;
|
|
PIO_WORKITEM WorkItem;
|
|
|
|
DPRINT("USBH_Worker: HubIoWorkItem - %p\n", Context);
|
|
|
|
HubIoWorkItem = Context;
|
|
|
|
InterlockedDecrement(&HubIoWorkItem->HubWorkerQueued);
|
|
|
|
HubExtension = HubIoWorkItem->HubExtension;
|
|
WorkItem = HubIoWorkItem->HubWorkItem;
|
|
|
|
HubIoWorkItem->HubWorkerRoutine(HubIoWorkItem->HubExtension,
|
|
HubIoWorkItem->HubWorkItemBuffer);
|
|
|
|
KeAcquireSpinLock(&HubExtension->WorkItemSpinLock, &OldIrql);
|
|
RemoveEntryList(&HubIoWorkItem->HubWorkItemLink);
|
|
KeReleaseSpinLock(&HubExtension->WorkItemSpinLock, OldIrql);
|
|
|
|
if (HubIoWorkItem->HubWorkItemBuffer)
|
|
{
|
|
ExFreePoolWithTag(HubIoWorkItem->HubWorkItemBuffer, USB_HUB_TAG);
|
|
}
|
|
|
|
ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
|
|
|
|
if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
|
|
{
|
|
KeSetEvent(&HubExtension->PendingRequestEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
}
|
|
|
|
IoFreeWorkItem(WorkItem);
|
|
|
|
DPRINT("USBH_Worker: HubIoWorkItem %p complete\n", Context);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_QueueWorkItem(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PUSBHUB_IO_WORK_ITEM HubIoWorkItem)
|
|
{
|
|
DPRINT("USBH_QueueWorkItem: ... \n");
|
|
|
|
InterlockedIncrement(&HubExtension->PendingRequestCount);
|
|
InterlockedIncrement(&HubIoWorkItem->HubWorkerQueued);
|
|
|
|
ExInterlockedInsertTailList(&HubExtension->WorkItemList,
|
|
&HubIoWorkItem->HubWorkItemLink,
|
|
&HubExtension->WorkItemSpinLock);
|
|
|
|
IoQueueWorkItem(HubIoWorkItem->HubWorkItem,
|
|
USBH_Worker,
|
|
HubIoWorkItem->HubWorkItemType,
|
|
HubIoWorkItem);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_FreeWorkItem(IN PUSBHUB_IO_WORK_ITEM HubIoWorkItem)
|
|
{
|
|
PIO_WORKITEM WorkItem;
|
|
|
|
DPRINT("USBH_FreeWorkItem: ... \n");
|
|
|
|
WorkItem = HubIoWorkItem->HubWorkItem;
|
|
|
|
if (HubIoWorkItem->HubWorkItemBuffer)
|
|
{
|
|
ExFreePoolWithTag(HubIoWorkItem->HubWorkItemBuffer, USB_HUB_TAG);
|
|
}
|
|
|
|
ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
|
|
|
|
IoFreeWorkItem(WorkItem);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBHUB_RootHubCallBack(IN PVOID Context)
|
|
{
|
|
PUSBHUB_FDO_EXTENSION HubExtension;
|
|
|
|
DPRINT("USBHUB_RootHubCallBack: ... \n");
|
|
|
|
HubExtension = Context;
|
|
|
|
if (HubExtension->SCEIrp)
|
|
{
|
|
HubExtension->HubFlags |= (USBHUB_FDO_FLAG_DO_ENUMERATION |
|
|
USBHUB_FDO_FLAG_NOT_ENUMERATED);
|
|
|
|
USBH_SubmitStatusChangeTransfer(HubExtension);
|
|
|
|
IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
|
|
}
|
|
else
|
|
{
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_DO_ENUMERATION;
|
|
}
|
|
|
|
KeSetEvent(&HubExtension->RootHubNotificationEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBD_RegisterRootHubCallBack(IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
PUSB_BUSIFFN_ROOTHUB_INIT_NOTIFY RootHubInitNotification;
|
|
|
|
DPRINT("USBD_RegisterRootHubCallBack: ... \n");
|
|
|
|
RootHubInitNotification = HubExtension->BusInterface.RootHubInitNotification;
|
|
|
|
if (!RootHubInitNotification)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
KeClearEvent(&HubExtension->RootHubNotificationEvent);
|
|
|
|
return RootHubInitNotification(HubExtension->BusInterface.BusContext,
|
|
HubExtension,
|
|
USBHUB_RootHubCallBack);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBD_UnRegisterRootHubCallBack(IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
PUSB_BUSIFFN_ROOTHUB_INIT_NOTIFY RootHubInitNotification;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBD_UnRegisterRootHubCallBack ... \n");
|
|
|
|
RootHubInitNotification = HubExtension->BusInterface.RootHubInitNotification;
|
|
|
|
if (!RootHubInitNotification)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
Status = RootHubInitNotification(HubExtension->BusInterface.BusContext,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
KeWaitForSingleObject(&HubExtension->RootHubNotificationEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_HubSetDWakeCompletion(IN PDEVICE_OBJECT DeviceObject,
|
|
IN UCHAR MinorFunction,
|
|
IN POWER_STATE PowerState,
|
|
IN PVOID Context,
|
|
IN PIO_STATUS_BLOCK IoStatus)
|
|
{
|
|
DPRINT("USBH_HubSetDWakeCompletion: ... \n");
|
|
KeSetEvent((PRKEVENT)Context, IO_NO_INCREMENT, FALSE);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_HubQueuePortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PLIST_ENTRY IdleList)
|
|
{
|
|
PDEVICE_OBJECT PortDevice;
|
|
PUSBHUB_PORT_PDO_EXTENSION PortExtension;
|
|
PIRP IdleIrp;
|
|
PIRP HubIdleIrp;
|
|
ULONG NumPorts;
|
|
ULONG Port;
|
|
KIRQL Irql;
|
|
|
|
DPRINT("USBH_HubQueuePortIdleIrps ... \n");
|
|
|
|
InitializeListHead(IdleList);
|
|
|
|
IoAcquireCancelSpinLock(&Irql);
|
|
|
|
NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
|
|
|
|
for (Port = 0; Port < NumPorts; ++Port)
|
|
{
|
|
PortDevice = HubExtension->PortData[Port].DeviceObject;
|
|
|
|
if (PortDevice)
|
|
{
|
|
PortExtension = PortDevice->DeviceExtension;
|
|
|
|
IdleIrp = PortExtension->IdleNotificationIrp;
|
|
PortExtension->IdleNotificationIrp = NULL;
|
|
|
|
if (IdleIrp && IoSetCancelRoutine(IdleIrp, NULL))
|
|
{
|
|
DPRINT1("USBH_HubQueuePortIdleIrps: IdleIrp != NULL. FIXME\n");
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
|
|
{
|
|
HubIdleIrp = HubExtension->PendingIdleIrp;
|
|
HubExtension->PendingIdleIrp = NULL;
|
|
}
|
|
else
|
|
{
|
|
HubIdleIrp = NULL;
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(Irql);
|
|
|
|
if (HubIdleIrp)
|
|
{
|
|
USBH_HubCancelIdleIrp(HubExtension, HubIdleIrp);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_HubCompleteQueuedPortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PLIST_ENTRY IdleList,
|
|
IN NTSTATUS NtStatus)
|
|
{
|
|
DPRINT("USBH_HubCompleteQueuedPortIdleIrps ... \n");
|
|
|
|
while (!IsListEmpty(IdleList))
|
|
{
|
|
DPRINT1("USBH_HubCompleteQueuedPortIdleIrps: IdleList not Empty. FIXME\n");
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_FlushPortPwrList(IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
PDEVICE_OBJECT PortDevice;
|
|
PUSBHUB_PORT_PDO_EXTENSION PortExtension;
|
|
PLIST_ENTRY Entry;
|
|
ULONG Port;
|
|
|
|
DPRINT("USBH_FlushPortPwrList ... \n");
|
|
|
|
InterlockedIncrement((PLONG)&HubExtension->PendingRequestCount);
|
|
|
|
KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
for (Port = 0; Port < HubExtension->HubDescriptor->bNumberOfPorts; ++Port)
|
|
{
|
|
PortDevice = HubExtension->PortData[Port].DeviceObject;
|
|
|
|
if (!PortDevice)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
PortExtension = PortDevice->DeviceExtension;
|
|
|
|
InterlockedExchange((PLONG)&PortExtension->StateBehindD2, 0);
|
|
|
|
while (TRUE)
|
|
{
|
|
Entry = ExInterlockedRemoveHeadList(&PortExtension->PortPowerList,
|
|
&PortExtension->PortPowerListSpinLock);
|
|
|
|
if (!Entry)
|
|
{
|
|
break;
|
|
}
|
|
|
|
DPRINT1("USBH_FlushPortPwrList: PortPowerList FIXME\n");
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
|
|
KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
|
|
LOW_REALTIME_PRIORITY,
|
|
1,
|
|
FALSE);
|
|
|
|
if (!InterlockedDecrement((PLONG)&HubExtension->PendingRequestCount))
|
|
{
|
|
KeSetEvent(&HubExtension->PendingRequestEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_HubCompletePortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN NTSTATUS NtStatus)
|
|
{
|
|
LIST_ENTRY IdleList;
|
|
|
|
DPRINT("USBH_HubCompletePortIdleIrps ... \n");
|
|
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
|
|
{
|
|
USBH_HubQueuePortIdleIrps(HubExtension, &IdleList);
|
|
|
|
USBH_HubCompleteQueuedPortIdleIrps(HubExtension,
|
|
&IdleList,
|
|
NtStatus);
|
|
|
|
USBH_FlushPortPwrList(HubExtension);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_HubCancelIdleIrp(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PIRP IdleIrp)
|
|
{
|
|
DPRINT("USBH_HubCancelIdleIrp ... \n");
|
|
|
|
IoCancelIrp(IdleIrp);
|
|
|
|
if (InterlockedExchange(&HubExtension->IdleRequestLock, 1))
|
|
{
|
|
IoFreeIrp(IdleIrp);
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
USBH_CheckIdleAbort(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN BOOLEAN IsWait,
|
|
IN BOOLEAN IsExtCheck)
|
|
{
|
|
PDEVICE_OBJECT PdoDevice;
|
|
PUSBHUB_PORT_PDO_EXTENSION PortExtension;
|
|
PUSBHUB_PORT_DATA PortData;
|
|
ULONG Port;
|
|
BOOLEAN Result = FALSE;
|
|
|
|
DPRINT("USBH_CheckIdleAbort: ... \n");
|
|
|
|
InterlockedIncrement(&HubExtension->PendingRequestCount);
|
|
|
|
if (IsWait == TRUE)
|
|
{
|
|
KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
|
|
PortData = HubExtension->PortData;
|
|
|
|
for (Port = 0; Port < HubExtension->HubDescriptor->bNumberOfPorts; Port++)
|
|
{
|
|
PdoDevice = PortData[Port].DeviceObject;
|
|
|
|
if (PdoDevice)
|
|
{
|
|
PortExtension = PdoDevice->DeviceExtension;
|
|
|
|
if (PortExtension->PoRequestCounter)
|
|
{
|
|
Result = TRUE;
|
|
goto Wait;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (IsExtCheck == TRUE)
|
|
{
|
|
PortData = HubExtension->PortData;
|
|
|
|
for (Port = 0;
|
|
Port < HubExtension->HubDescriptor->bNumberOfPorts;
|
|
Port++)
|
|
{
|
|
PdoDevice = PortData[Port].DeviceObject;
|
|
|
|
if (PdoDevice)
|
|
{
|
|
PortExtension = PdoDevice->DeviceExtension;
|
|
InterlockedExchange(&PortExtension->StateBehindD2, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
Wait:
|
|
|
|
if (IsWait == TRUE)
|
|
{
|
|
KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
|
|
LOW_REALTIME_PRIORITY,
|
|
1,
|
|
FALSE);
|
|
}
|
|
|
|
if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
|
|
{
|
|
KeSetEvent(&HubExtension->PendingRequestEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_FdoWaitWakeIrpCompletion(IN PDEVICE_OBJECT DeviceObject,
|
|
IN UCHAR MinorFunction,
|
|
IN POWER_STATE PowerState,
|
|
IN PVOID Context,
|
|
IN PIO_STATUS_BLOCK IoStatus)
|
|
{
|
|
DPRINT("USBH_FdoWaitWakeIrpCompletion ... \n");
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_FdoSubmitWaitWakeIrp(IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
POWER_STATE PowerState;
|
|
NTSTATUS Status;
|
|
PIRP Irp = NULL;
|
|
KIRQL Irql;
|
|
|
|
DPRINT("USBH_FdoSubmitWaitWakeIrp: ... \n");
|
|
|
|
PowerState.SystemState = HubExtension->SystemWake;
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_PENDING_WAKE_IRP;
|
|
|
|
InterlockedIncrement(&HubExtension->PendingRequestCount);
|
|
InterlockedExchange(&HubExtension->FdoWaitWakeLock, 0);
|
|
|
|
Status = PoRequestPowerIrp(HubExtension->LowerPDO,
|
|
IRP_MN_WAIT_WAKE,
|
|
PowerState,
|
|
USBH_FdoWaitWakeIrpCompletion,
|
|
HubExtension,
|
|
&Irp);
|
|
|
|
IoAcquireCancelSpinLock(&Irql);
|
|
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_PENDING_WAKE_IRP)
|
|
{
|
|
HubExtension->PendingWakeIrp = Irp;
|
|
DPRINT("USBH_FdoSubmitWaitWakeIrp: PendingWakeIrp - %p\n",
|
|
HubExtension->PendingWakeIrp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_PENDING_WAKE_IRP;
|
|
|
|
if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
|
|
{
|
|
KeSetEvent(&HubExtension->PendingRequestEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
}
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(Irql);
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_FdoIdleNotificationCallback(IN PVOID Context)
|
|
{
|
|
PUSBHUB_FDO_EXTENSION HubExtension;
|
|
PUSBHUB_PORT_DATA PortData;
|
|
PDEVICE_OBJECT PortDevice;
|
|
PUSBHUB_PORT_PDO_EXTENSION PortExtension;
|
|
PIRP Irp = NULL;
|
|
PIRP IdleIrp;
|
|
POWER_STATE PowerState;
|
|
KEVENT Event;
|
|
ULONG Port;
|
|
PIO_STACK_LOCATION IoStack;
|
|
PUSB_IDLE_CALLBACK_INFO CallbackInfo;
|
|
BOOLEAN IsReady;
|
|
KIRQL OldIrql;
|
|
NTSTATUS Status;
|
|
|
|
HubExtension = Context;
|
|
|
|
DPRINT("USBH_FdoIdleNotificationCallback: HubExtension - %p, HubFlags - %lX\n",
|
|
HubExtension,
|
|
HubExtension->HubFlags);
|
|
|
|
if (HubExtension->HubFlags & (USBHUB_FDO_FLAG_ENUM_POST_RECOVER |
|
|
USBHUB_FDO_FLAG_WAKEUP_START |
|
|
USBHUB_FDO_FLAG_DEVICE_REMOVED |
|
|
USBHUB_FDO_FLAG_STATE_CHANGING |
|
|
USBHUB_FDO_FLAG_ESD_RECOVERING |
|
|
USBHUB_FDO_FLAG_DEVICE_FAILED |
|
|
USBHUB_FDO_FLAG_DEVICE_STOPPING))
|
|
{
|
|
DbgBreakPoint();
|
|
return;
|
|
}
|
|
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_GOING_IDLE;
|
|
|
|
if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_PENDING_WAKE_IRP))
|
|
{
|
|
Status = USBH_FdoSubmitWaitWakeIrp(HubExtension);
|
|
|
|
if (Status != STATUS_PENDING)
|
|
{
|
|
DPRINT("Status != STATUS_PENDING. DbgBreakPoint()\n");
|
|
DbgBreakPoint();
|
|
HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_GOING_IDLE;
|
|
return;
|
|
}
|
|
}
|
|
|
|
InterlockedIncrement(&HubExtension->PendingRequestCount);
|
|
|
|
KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
PortData = HubExtension->PortData;
|
|
IsReady = TRUE;
|
|
|
|
for (Port = 0;
|
|
Port < HubExtension->HubDescriptor->bNumberOfPorts;
|
|
Port++)
|
|
{
|
|
PortDevice = PortData[Port].DeviceObject;
|
|
|
|
if (PortDevice)
|
|
{
|
|
PortExtension = PortDevice->DeviceExtension;
|
|
|
|
IdleIrp = PortExtension->IdleNotificationIrp;
|
|
|
|
if (!IdleIrp)
|
|
{
|
|
IsReady = FALSE;
|
|
goto IdleHub;
|
|
}
|
|
|
|
IoStack = IoGetCurrentIrpStackLocation(IdleIrp);
|
|
|
|
CallbackInfo = IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
|
|
if (!CallbackInfo)
|
|
{
|
|
IsReady = FALSE;
|
|
goto IdleHub;
|
|
}
|
|
|
|
if (!CallbackInfo->IdleCallback)
|
|
{
|
|
IsReady = FALSE;
|
|
goto IdleHub;
|
|
}
|
|
|
|
if (PortExtension->PendingSystemPoRequest)
|
|
{
|
|
IsReady = FALSE;
|
|
goto IdleHub;
|
|
}
|
|
|
|
if (InterlockedCompareExchange(&PortExtension->StateBehindD2,
|
|
1,
|
|
0))
|
|
{
|
|
IsReady = FALSE;
|
|
goto IdleHub;
|
|
}
|
|
|
|
DPRINT("USBH_FdoIdleNotificationCallback: IdleContext - %p\n",
|
|
CallbackInfo->IdleContext);
|
|
|
|
CallbackInfo->IdleCallback(CallbackInfo->IdleContext);
|
|
|
|
if (PortExtension->CurrentPowerState.DeviceState == PowerDeviceD0)
|
|
{
|
|
IsReady = FALSE;
|
|
goto IdleHub;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING) &&
|
|
(USBH_CheckIdleAbort(HubExtension, FALSE, FALSE) == TRUE))
|
|
{
|
|
IsReady = FALSE;
|
|
}
|
|
|
|
IdleHub:
|
|
|
|
KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
|
|
LOW_REALTIME_PRIORITY,
|
|
1,
|
|
FALSE);
|
|
|
|
if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
|
|
{
|
|
KeSetEvent(&HubExtension->PendingRequestEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
}
|
|
|
|
if (!IsReady ||
|
|
(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_SUSPENDED))
|
|
{
|
|
DPRINT1("USBH_FdoIdleNotificationCallback: HubFlags - %lX\n",
|
|
HubExtension->HubFlags);
|
|
|
|
HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_DEVICE_SUSPENDED |
|
|
USBHUB_FDO_FLAG_GOING_IDLE);
|
|
|
|
/* Aborting Idle for Hub */
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
if (HubExtension->PendingIdleIrp)
|
|
{
|
|
Irp = HubExtension->PendingIdleIrp;
|
|
HubExtension->PendingIdleIrp = NULL;
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
if (Irp)
|
|
{
|
|
USBH_HubCancelIdleIrp(HubExtension, Irp);
|
|
}
|
|
|
|
DbgBreakPoint();
|
|
USBH_HubCompletePortIdleIrps(HubExtension, STATUS_CANCELLED);
|
|
}
|
|
else
|
|
{
|
|
PowerState.DeviceState = HubExtension->DeviceWake;
|
|
|
|
KeWaitForSingleObject(&HubExtension->IdleSemaphore,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_GOING_IDLE;
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_DO_SUSPENSE;
|
|
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
DPRINT("USBH_FdoIdleNotificationCallback: LowerPdo - %p\n",
|
|
HubExtension->LowerPDO);
|
|
|
|
DPRINT("USBH_FdoIdleNotificationCallback: PowerState.DeviceState - %x\n",
|
|
PowerState.DeviceState);
|
|
|
|
Status = PoRequestPowerIrp(HubExtension->LowerPDO,
|
|
IRP_MN_SET_POWER,
|
|
PowerState,
|
|
USBH_HubSetDWakeCompletion,
|
|
&Event,
|
|
NULL);
|
|
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_CompletePortIdleIrpsWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PVOID Context)
|
|
{
|
|
PUSBHUB_IDLE_PORT_CONTEXT IdlePortContext;
|
|
NTSTATUS NtStatus;
|
|
NTSTATUS Status;
|
|
BOOLEAN IsFlush = FALSE;
|
|
|
|
DPRINT("USBH_CompletePortIdleIrpsWorker ... \n");
|
|
|
|
IdlePortContext = Context;
|
|
NtStatus = IdlePortContext->Status;
|
|
|
|
USBH_HubCompleteQueuedPortIdleIrps(HubExtension,
|
|
&IdlePortContext->PwrList,
|
|
NtStatus);
|
|
|
|
DPRINT1("USBH_CompletePortIdleIrpsWorker: USBH_RegQueryFlushPortPowerIrpsFlag() UNIMPLEMENTED. FIXME\n");
|
|
Status = STATUS_NOT_IMPLEMENTED;// USBH_RegQueryFlushPortPowerIrpsFlag(&IsFlush);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
if (IsFlush)
|
|
{
|
|
USBH_FlushPortPwrList(HubExtension);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_IdleCompletePowerHubWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PVOID Context)
|
|
{
|
|
PUSBHUB_IDLE_HUB_CONTEXT HubWorkItemBuffer;
|
|
|
|
DPRINT("USBH_IdleCompletePowerHubWorker ... \n");
|
|
|
|
if (HubExtension &&
|
|
HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0 &&
|
|
HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
|
|
{
|
|
USBH_HubSetD0(HubExtension);
|
|
}
|
|
|
|
HubWorkItemBuffer = Context;
|
|
|
|
USBH_HubCompletePortIdleIrps(HubExtension, HubWorkItemBuffer->Status);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_FdoIdleNotificationRequestComplete(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context)
|
|
{
|
|
PUSBHUB_FDO_EXTENSION HubExtension;
|
|
NTSTATUS NtStatus;
|
|
PVOID IdleIrp;
|
|
KIRQL Irql;
|
|
NTSTATUS Status;
|
|
PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
|
|
|
|
IoAcquireCancelSpinLock(&Irql);
|
|
|
|
HubExtension = Context;
|
|
HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
|
|
|
|
IdleIrp = InterlockedExchangePointer((PVOID)&HubExtension->PendingIdleIrp,
|
|
NULL);
|
|
|
|
DPRINT("USBH_FdoIdleNotificationRequestComplete: IdleIrp - %p\n", IdleIrp);
|
|
|
|
if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
|
|
{
|
|
KeSetEvent(&HubExtension->PendingRequestEvent, EVENT_INCREMENT, FALSE);
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(Irql);
|
|
|
|
NtStatus = Irp->IoStatus.Status;
|
|
|
|
DPRINT("USBH_FdoIdleNotificationRequestComplete: NtStatus - %lX\n",
|
|
NtStatus);
|
|
|
|
if (!NT_SUCCESS(NtStatus) &&
|
|
NtStatus != STATUS_POWER_STATE_INVALID &&
|
|
!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_REMOVED) &&
|
|
!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
|
|
{
|
|
DPRINT("USBH_FdoIdleNotificationRequestComplete: DeviceState - %x\n",
|
|
HubExtension->CurrentPowerState.DeviceState);
|
|
|
|
if (HubExtension->CurrentPowerState.DeviceState == PowerDeviceD0)
|
|
{
|
|
PUSBHUB_IDLE_PORT_CONTEXT HubWorkItemBuffer;
|
|
|
|
Status = USBH_AllocateWorkItem(HubExtension,
|
|
&HubIoWorkItem,
|
|
USBH_CompletePortIdleIrpsWorker,
|
|
sizeof(USBHUB_IDLE_PORT_CONTEXT),
|
|
(PVOID *)&HubWorkItemBuffer,
|
|
DelayedWorkQueue);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
HubWorkItemBuffer->Status = NtStatus;
|
|
|
|
USBH_HubQueuePortIdleIrps(HubExtension,
|
|
&HubWorkItemBuffer->PwrList);
|
|
|
|
USBH_QueueWorkItem(HubExtension, HubIoWorkItem);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PUSBHUB_IDLE_HUB_CONTEXT HubWorkItemBuffer;
|
|
|
|
Status = USBH_AllocateWorkItem(HubExtension,
|
|
&HubIoWorkItem,
|
|
USBH_IdleCompletePowerHubWorker,
|
|
sizeof(USBHUB_IDLE_HUB_CONTEXT),
|
|
(PVOID *)&HubWorkItemBuffer,
|
|
DelayedWorkQueue);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
HubWorkItemBuffer->Status = NtStatus;
|
|
USBH_QueueWorkItem(HubExtension, HubIoWorkItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (IdleIrp ||
|
|
InterlockedExchange((PLONG)&HubExtension->IdleRequestLock, 1))
|
|
{
|
|
DPRINT("USBH_FdoIdleNotificationRequestComplete: Irp - %p\n", Irp);
|
|
IoFreeIrp(Irp);
|
|
}
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_FdoSubmitIdleRequestIrp(IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG HubFlags;
|
|
PDEVICE_OBJECT LowerPDO;
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION IoStack;
|
|
KIRQL Irql;
|
|
|
|
DPRINT("USBH_FdoSubmitIdleRequestIrp: HubExtension - %p, PendingIdleIrp - %p\n",
|
|
HubExtension,
|
|
HubExtension->PendingIdleIrp);
|
|
|
|
if (HubExtension->PendingIdleIrp)
|
|
{
|
|
Status = STATUS_DEVICE_BUSY;
|
|
KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
|
|
return Status;
|
|
}
|
|
|
|
HubFlags = HubExtension->HubFlags;
|
|
|
|
if (HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING ||
|
|
HubFlags & USBHUB_FDO_FLAG_DEVICE_REMOVED)
|
|
{
|
|
HubExtension->HubFlags = HubFlags & ~USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
|
|
KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
|
|
return STATUS_DEVICE_REMOVED;
|
|
}
|
|
|
|
LowerPDO = HubExtension->LowerPDO;
|
|
|
|
HubExtension->IdleCallbackInfo.IdleCallback = USBH_FdoIdleNotificationCallback;
|
|
HubExtension->IdleCallbackInfo.IdleContext = HubExtension;
|
|
|
|
Irp = IoAllocateIrp(LowerPDO->StackSize, FALSE);
|
|
|
|
if (!Irp)
|
|
{
|
|
HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
|
|
return Status;
|
|
}
|
|
|
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
|
|
|
IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
|
|
IoStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(USB_IDLE_CALLBACK_INFO);
|
|
IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;
|
|
IoStack->Parameters.DeviceIoControl.Type3InputBuffer = &HubExtension->IdleCallbackInfo;
|
|
|
|
IoSetCompletionRoutine(Irp,
|
|
USBH_FdoIdleNotificationRequestComplete,
|
|
HubExtension,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
InterlockedIncrement(&HubExtension->PendingRequestCount);
|
|
InterlockedExchange(&HubExtension->IdleRequestLock, 0);
|
|
|
|
HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_DEVICE_SUSPENDED |
|
|
USBHUB_FDO_FLAG_GOING_IDLE);
|
|
|
|
Status = IoCallDriver(HubExtension->LowerPDO, Irp);
|
|
|
|
IoAcquireCancelSpinLock(&Irql);
|
|
|
|
if (Status == STATUS_PENDING &&
|
|
HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
|
|
{
|
|
HubExtension->PendingIdleIrp = Irp;
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(Irql);
|
|
|
|
KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_CheckHubIdle(IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
PDEVICE_OBJECT PdoDevice;
|
|
PUSBHUB_PORT_PDO_EXTENSION PortExtension;
|
|
PUSBHUB_PORT_DATA PortData;
|
|
ULONG HubFlags;
|
|
ULONG Port;
|
|
KIRQL Irql;
|
|
BOOLEAN IsHubIdle = FALSE;
|
|
BOOLEAN IsAllPortsIdle;
|
|
BOOLEAN IsHubCheck = TRUE;
|
|
|
|
DPRINT("USBH_CheckHubIdle: FIXME !!! HubExtension - %p\n", HubExtension);
|
|
|
|
return; //HACK: delete it line after fixing Power Manager!!!
|
|
|
|
KeAcquireSpinLock(&HubExtension->CheckIdleSpinLock, &Irql);
|
|
|
|
if (HubExtension->HubFlags & USBHUB_FDO_FLAG_CHECK_IDLE_LOCK)
|
|
{
|
|
KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
|
|
return;
|
|
}
|
|
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_CHECK_IDLE_LOCK;
|
|
KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
|
|
|
|
if (USBH_GetRootHubExtension(HubExtension)->SystemPowerState.SystemState != PowerSystemWorking)
|
|
{
|
|
KeAcquireSpinLock(&HubExtension->CheckIdleSpinLock, &Irql);
|
|
HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_CHECK_IDLE_LOCK;
|
|
KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
|
|
return;
|
|
}
|
|
|
|
HubFlags = HubExtension->HubFlags;
|
|
DPRINT("USBH_CheckHubIdle: HubFlags - %lX\n", HubFlags);
|
|
|
|
if (!(HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED) ||
|
|
!(HubFlags & USBHUB_FDO_FLAG_DO_ENUMERATION))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (HubFlags & USBHUB_FDO_FLAG_NOT_ENUMERATED ||
|
|
HubFlags & USBHUB_FDO_FLAG_ENUM_POST_RECOVER ||
|
|
HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED ||
|
|
HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING ||
|
|
HubFlags & USBHUB_FDO_FLAG_DEVICE_REMOVED ||
|
|
HubFlags & USBHUB_FDO_FLAG_STATE_CHANGING ||
|
|
HubFlags & USBHUB_FDO_FLAG_WAKEUP_START ||
|
|
HubFlags & USBHUB_FDO_FLAG_ESD_RECOVERING)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (HubExtension->ResetRequestCount)
|
|
{
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEFER_CHECK_IDLE;
|
|
goto Exit;
|
|
}
|
|
|
|
HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DEFER_CHECK_IDLE;
|
|
|
|
InterlockedIncrement(&HubExtension->PendingRequestCount);
|
|
|
|
KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
IoAcquireCancelSpinLock(&Irql);
|
|
|
|
IsAllPortsIdle = TRUE;
|
|
|
|
PortData = HubExtension->PortData;
|
|
|
|
for (Port = 0;
|
|
Port < HubExtension->HubDescriptor->bNumberOfPorts;
|
|
Port++)
|
|
{
|
|
PdoDevice = PortData[Port].DeviceObject;
|
|
|
|
if (PdoDevice)
|
|
{
|
|
PortExtension = PdoDevice->DeviceExtension;
|
|
|
|
if (!PortExtension->IdleNotificationIrp)
|
|
{
|
|
DPRINT("USBH_CheckHubIdle: PortExtension - %p\n",
|
|
PortExtension);
|
|
|
|
IsAllPortsIdle = FALSE;
|
|
IsHubCheck = FALSE;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (IsHubCheck &&
|
|
!(HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST))
|
|
{
|
|
KeClearEvent(&HubExtension->IdleEvent);
|
|
HubExtension->HubFlags |= USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
|
|
IsHubIdle = TRUE;
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(Irql);
|
|
|
|
KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
|
|
LOW_REALTIME_PRIORITY,
|
|
1,
|
|
FALSE);
|
|
|
|
if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
|
|
{
|
|
KeSetEvent(&HubExtension->PendingRequestEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
}
|
|
|
|
DPRINT("USBH_CheckHubIdle: IsAllPortsIdle - %x, IsHubIdle - %x\n",
|
|
IsAllPortsIdle,
|
|
IsHubIdle);
|
|
|
|
if (IsAllPortsIdle && IsHubIdle)
|
|
{
|
|
USBH_FdoSubmitIdleRequestIrp(HubExtension);
|
|
}
|
|
|
|
Exit:
|
|
KeAcquireSpinLock(&HubExtension->CheckIdleSpinLock, &Irql);
|
|
HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_CHECK_IDLE_LOCK;
|
|
KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_CheckIdleWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PVOID Context)
|
|
{
|
|
DPRINT("USBH_CheckIdleWorker: ... \n");
|
|
USBH_CheckHubIdle(HubExtension);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_CheckIdleDeferred(IN PUSBHUB_FDO_EXTENSION HubExtension)
|
|
{
|
|
PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBH_CheckIdleDeferred: HubExtension - %p\n", HubExtension);
|
|
|
|
Status = USBH_AllocateWorkItem(HubExtension,
|
|
&HubIoWorkItem,
|
|
USBH_CheckIdleWorker,
|
|
0,
|
|
NULL,
|
|
DelayedWorkQueue);
|
|
|
|
DPRINT("USBH_CheckIdleDeferred: HubIoWorkItem - %p\n", HubIoWorkItem);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
USBH_QueueWorkItem(HubExtension, HubIoWorkItem);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_PdoSetCapabilities(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension)
|
|
{
|
|
PUSBHUB_FDO_EXTENSION HubExtension;
|
|
ULONG State;
|
|
SYSTEM_POWER_STATE SystemPowerState;
|
|
PDEVICE_POWER_STATE pDeviceState;
|
|
|
|
DPRINT("USBH_PdoSetCapabilities ... \n");
|
|
|
|
HubExtension = PortExtension->HubExtension;
|
|
|
|
PortExtension->Capabilities.Size = 64;
|
|
PortExtension->Capabilities.Version = 1;
|
|
|
|
PortExtension->Capabilities.Removable = 1;
|
|
PortExtension->Capabilities.Address = PortExtension->PortNumber;
|
|
|
|
if (PortExtension->SerialNumber)
|
|
{
|
|
PortExtension->Capabilities.UniqueID = 1;
|
|
}
|
|
else
|
|
{
|
|
PortExtension->Capabilities.UniqueID = 0;
|
|
}
|
|
|
|
PortExtension->Capabilities.RawDeviceOK = 0;
|
|
|
|
RtlCopyMemory(PortExtension->Capabilities.DeviceState,
|
|
HubExtension->DeviceState,
|
|
(PowerSystemMaximum + 2) * sizeof(POWER_STATE));
|
|
|
|
PortExtension->Capabilities.DeviceState[1] = PowerDeviceD0;
|
|
|
|
if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REMOTE_WAKEUP)
|
|
{
|
|
PortExtension->Capabilities.DeviceWake = PowerDeviceD2;
|
|
|
|
PortExtension->Capabilities.DeviceD1 = 1;
|
|
PortExtension->Capabilities.DeviceD2 = 1;
|
|
|
|
PortExtension->Capabilities.WakeFromD0 = 1;
|
|
PortExtension->Capabilities.WakeFromD1 = 1;
|
|
PortExtension->Capabilities.WakeFromD2 = 1;
|
|
|
|
pDeviceState = &PortExtension->Capabilities.DeviceState[2];
|
|
|
|
for (State = 2; State <= 5; State++)
|
|
{
|
|
SystemPowerState = State;
|
|
|
|
if (PortExtension->Capabilities.SystemWake < SystemPowerState)
|
|
{
|
|
*pDeviceState = PowerDeviceD3;
|
|
}
|
|
else
|
|
{
|
|
*pDeviceState = PowerDeviceD2;
|
|
}
|
|
|
|
++pDeviceState;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PortExtension->Capabilities.DeviceWake = PowerDeviceD0;
|
|
PortExtension->Capabilities.DeviceState[2] = PowerDeviceD3;
|
|
PortExtension->Capabilities.DeviceState[3] = PowerDeviceD3;
|
|
PortExtension->Capabilities.DeviceState[4] = PowerDeviceD3;
|
|
PortExtension->Capabilities.DeviceState[5] = PowerDeviceD3;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_ProcessDeviceInformation(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension)
|
|
{
|
|
PUSB_INTERFACE_DESCRIPTOR Pid;
|
|
PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBH_ProcessDeviceInformation ... \n");
|
|
|
|
ConfigDescriptor = NULL;
|
|
|
|
RtlZeroMemory(&PortExtension->InterfaceDescriptor,
|
|
sizeof(PortExtension->InterfaceDescriptor));
|
|
|
|
PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_HUB_DEVICE;
|
|
|
|
Status = USBH_GetConfigurationDescriptor(PortExtension->Common.SelfDevice,
|
|
&ConfigDescriptor);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
if (ConfigDescriptor)
|
|
{
|
|
ExFreePool(ConfigDescriptor);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_REMOTE_WAKEUP;
|
|
|
|
if (ConfigDescriptor->bmAttributes & 0x20)
|
|
{
|
|
/* device configuration supports remote wakeup */
|
|
PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_REMOTE_WAKEUP;
|
|
}
|
|
|
|
USBHUB_DumpingDeviceDescriptor(&PortExtension->DeviceDescriptor);
|
|
USBHUB_DumpingConfiguration(ConfigDescriptor);
|
|
|
|
DPRINT_PNP("USBH_ProcessDeviceInformation: Class - %x, SubClass - %x, Protocol - %x\n",
|
|
PortExtension->DeviceDescriptor.bDeviceClass,
|
|
PortExtension->DeviceDescriptor.bDeviceSubClass,
|
|
PortExtension->DeviceDescriptor.bDeviceProtocol);
|
|
|
|
DPRINT_PNP("USBH_ProcessDeviceInformation: bNumConfigurations - %x, bNumInterfaces - %x\n",
|
|
PortExtension->DeviceDescriptor.bNumConfigurations,
|
|
ConfigDescriptor->bNumInterfaces);
|
|
|
|
|
|
/* Enumeration of USB Composite Devices (msdn):
|
|
1) The device class field of the device descriptor (bDeviceClass) must contain a value of zero,
|
|
or the class (bDeviceClass), subclass (bDeviceSubClass), and protocol (bDeviceProtocol)
|
|
fields of the device descriptor must have the values 0xEF, 0x02 and 0x01 respectively,
|
|
as explained in USB Interface Association Descriptor.
|
|
2) The device must have multiple interfaces
|
|
3) The device must have a single configuration.
|
|
*/
|
|
|
|
if (((PortExtension->DeviceDescriptor.bDeviceClass == USB_DEVICE_CLASS_RESERVED) ||
|
|
(PortExtension->DeviceDescriptor.bDeviceClass == USB_DEVICE_CLASS_MISCELLANEOUS &&
|
|
PortExtension->DeviceDescriptor.bDeviceSubClass == 0x02 &&
|
|
PortExtension->DeviceDescriptor.bDeviceProtocol == 0x01)) &&
|
|
(ConfigDescriptor->bNumInterfaces > 1) &&
|
|
(PortExtension->DeviceDescriptor.bNumConfigurations < 2))
|
|
{
|
|
DPRINT("USBH_ProcessDeviceInformation: Multi-Interface configuration\n");
|
|
|
|
PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_MULTI_INTERFACE;
|
|
|
|
if (ConfigDescriptor)
|
|
{
|
|
ExFreePool(ConfigDescriptor);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
Pid = USBD_ParseConfigurationDescriptorEx(ConfigDescriptor,
|
|
ConfigDescriptor,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1);
|
|
if (Pid)
|
|
{
|
|
RtlCopyMemory(&PortExtension->InterfaceDescriptor,
|
|
Pid,
|
|
sizeof(PortExtension->InterfaceDescriptor));
|
|
|
|
if (Pid->bInterfaceClass == USB_DEVICE_CLASS_HUB)
|
|
{
|
|
PortExtension->PortPdoFlags |= (USBHUB_PDO_FLAG_HUB_DEVICE |
|
|
USBHUB_PDO_FLAG_REMOTE_WAKEUP);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if (ConfigDescriptor)
|
|
{
|
|
ExFreePool(ConfigDescriptor);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
USBH_CheckDeviceIDUnique(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN USHORT idVendor,
|
|
IN USHORT idProduct,
|
|
IN PVOID SerialNumber,
|
|
IN USHORT SN_DescriptorLength)
|
|
{
|
|
PDEVICE_OBJECT PortDevice;
|
|
PUSBHUB_PORT_PDO_EXTENSION PortExtension;
|
|
ULONG Port;
|
|
SIZE_T NumberBytes;
|
|
|
|
DPRINT("USBH_CheckDeviceIDUnique: idVendor - 0x%04X, idProduct - 0x%04X\n",
|
|
idVendor,
|
|
idProduct);
|
|
|
|
if (!HubExtension->HubDescriptor->bNumberOfPorts)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
for (Port = 0; Port < HubExtension->HubDescriptor->bNumberOfPorts; Port++)
|
|
{
|
|
PortDevice = HubExtension->PortData[Port].DeviceObject;
|
|
|
|
if (PortDevice)
|
|
{
|
|
PortExtension = PortDevice->DeviceExtension;
|
|
|
|
if (PortExtension->DeviceDescriptor.idVendor == idVendor &&
|
|
PortExtension->DeviceDescriptor.idProduct == idProduct &&
|
|
PortExtension->SN_DescriptorLength == SN_DescriptorLength)
|
|
{
|
|
if (PortExtension->SerialNumber)
|
|
{
|
|
NumberBytes = RtlCompareMemory(PortExtension->SerialNumber,
|
|
SerialNumber,
|
|
SN_DescriptorLength);
|
|
|
|
if (NumberBytes == SN_DescriptorLength)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
USBH_ValidateSerialNumberString(IN PUSHORT SerialNumberString)
|
|
{
|
|
USHORT ix;
|
|
USHORT Symbol;
|
|
|
|
DPRINT("USBH_ValidateSerialNumberString: ... \n");
|
|
|
|
for (ix = 0; SerialNumberString[ix] != UNICODE_NULL; ix++)
|
|
{
|
|
Symbol = SerialNumberString[ix];
|
|
|
|
if (Symbol < 0x20 || Symbol > 0x7F || Symbol == 0x2C) // ','
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_CheckDeviceLanguage(IN PDEVICE_OBJECT DeviceObject,
|
|
IN USHORT LanguageId)
|
|
{
|
|
PUSB_STRING_DESCRIPTOR Descriptor;
|
|
NTSTATUS Status;
|
|
ULONG NumSymbols;
|
|
ULONG ix;
|
|
PWCHAR pSymbol;
|
|
ULONG Length;
|
|
|
|
DPRINT("USBH_CheckDeviceLanguage: LanguageId - 0x%04X\n", LanguageId);
|
|
|
|
Descriptor = ExAllocatePoolWithTag(NonPagedPool,
|
|
MAXIMUM_USB_STRING_LENGTH,
|
|
USB_HUB_TAG);
|
|
|
|
if (!Descriptor)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(Descriptor, MAXIMUM_USB_STRING_LENGTH);
|
|
|
|
Status = USBH_SyncGetStringDescriptor(DeviceObject,
|
|
0,
|
|
0,
|
|
Descriptor,
|
|
MAXIMUM_USB_STRING_LENGTH,
|
|
&Length,
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(Status) ||
|
|
Length < sizeof(USB_COMMON_DESCRIPTOR))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
NumSymbols = (Length -
|
|
FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString)) / sizeof(WCHAR);
|
|
|
|
pSymbol = Descriptor->bString;
|
|
|
|
for (ix = 1; ix < NumSymbols; ix++)
|
|
{
|
|
if (*pSymbol == (WCHAR)LanguageId)
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
goto Exit;
|
|
}
|
|
|
|
pSymbol++;
|
|
}
|
|
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
|
|
Exit:
|
|
ExFreePoolWithTag(Descriptor, USB_HUB_TAG);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_GetSerialNumberString(IN PDEVICE_OBJECT DeviceObject,
|
|
IN LPWSTR * OutSerialNumber,
|
|
IN PUSHORT OutDescriptorLength,
|
|
IN USHORT LanguageId,
|
|
IN UCHAR Index)
|
|
{
|
|
PUSB_STRING_DESCRIPTOR Descriptor;
|
|
NTSTATUS Status;
|
|
LPWSTR SerialNumberBuffer = NULL;
|
|
UCHAR StringLength;
|
|
UCHAR Length;
|
|
|
|
DPRINT("USBH_GetSerialNumberString: ... \n");
|
|
|
|
*OutSerialNumber = NULL;
|
|
*OutDescriptorLength = 0;
|
|
|
|
Descriptor = ExAllocatePoolWithTag(NonPagedPool,
|
|
MAXIMUM_USB_STRING_LENGTH,
|
|
USB_HUB_TAG);
|
|
|
|
if (!Descriptor)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(Descriptor, MAXIMUM_USB_STRING_LENGTH);
|
|
|
|
Status = USBH_CheckDeviceLanguage(DeviceObject, LanguageId);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Status = USBH_SyncGetStringDescriptor(DeviceObject,
|
|
Index,
|
|
LanguageId,
|
|
Descriptor,
|
|
MAXIMUM_USB_STRING_LENGTH,
|
|
NULL,
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(Status) ||
|
|
Descriptor->bLength <= sizeof(USB_COMMON_DESCRIPTOR))
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
|
|
StringLength = Descriptor->bLength -
|
|
FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString);
|
|
|
|
Length = StringLength + sizeof(UNICODE_NULL);
|
|
|
|
SerialNumberBuffer = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG);
|
|
|
|
if (!SerialNumberBuffer)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
RtlZeroMemory(SerialNumberBuffer, Length);
|
|
RtlCopyMemory(SerialNumberBuffer, Descriptor->bString, StringLength);
|
|
|
|
*OutSerialNumber = SerialNumberBuffer;
|
|
*OutDescriptorLength = Length;
|
|
|
|
Exit:
|
|
ExFreePoolWithTag(Descriptor, USB_HUB_TAG);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_CreateDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN USHORT Port,
|
|
IN USB_PORT_STATUS UsbPortStatus,
|
|
IN ULONG IsWait)
|
|
{
|
|
ULONG PdoNumber = 0;
|
|
WCHAR CharDeviceName[64];
|
|
UNICODE_STRING DeviceName;
|
|
PDEVICE_OBJECT DeviceObject = NULL;
|
|
PUSBHUB_PORT_PDO_EXTENSION PortExtension;
|
|
PUSB_DEVICE_HANDLE DeviceHandle;
|
|
LPWSTR SerialNumberBuffer;
|
|
BOOLEAN IsHsDevice;
|
|
BOOLEAN IsLsDevice;
|
|
BOOLEAN IgnoringHwSerial = FALSE;
|
|
NTSTATUS Status;
|
|
UNICODE_STRING DestinationString;
|
|
|
|
DPRINT("USBH_CreateDevice: Port - %x, UsbPortStatus - %lX\n",
|
|
Port,
|
|
UsbPortStatus.AsUshort16);
|
|
|
|
do
|
|
{
|
|
RtlStringCbPrintfW(CharDeviceName,
|
|
sizeof(CharDeviceName),
|
|
L"\\Device\\USBPDO-%d",
|
|
PdoNumber);
|
|
|
|
RtlInitUnicodeString(&DeviceName, CharDeviceName);
|
|
|
|
Status = IoCreateDevice(HubExtension->Common.SelfDevice->DriverObject,
|
|
sizeof(USBHUB_PORT_PDO_EXTENSION),
|
|
&DeviceName,
|
|
FILE_DEVICE_USB,
|
|
0,
|
|
FALSE,
|
|
&DeviceObject);
|
|
|
|
++PdoNumber;
|
|
}
|
|
while (Status == STATUS_OBJECT_NAME_COLLISION);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ASSERT(Port > 0);
|
|
HubExtension->PortData[Port-1].DeviceObject = DeviceObject;
|
|
return Status;
|
|
}
|
|
|
|
DeviceObject->StackSize = HubExtension->RootHubPdo2->StackSize;
|
|
|
|
PortExtension = DeviceObject->DeviceExtension;
|
|
|
|
DPRINT("USBH_CreateDevice: PortDevice - %p, <%wZ>\n", DeviceObject, &DeviceName);
|
|
DPRINT("USBH_CreateDevice: PortExtension - %p\n", PortExtension);
|
|
|
|
RtlZeroMemory(PortExtension, sizeof(USBHUB_PORT_PDO_EXTENSION));
|
|
|
|
PortExtension->Common.ExtensionType = USBH_EXTENSION_TYPE_PORT;
|
|
PortExtension->Common.SelfDevice = DeviceObject;
|
|
|
|
PortExtension->HubExtension = HubExtension;
|
|
PortExtension->RootHubExtension = HubExtension;
|
|
|
|
PortExtension->PortNumber = Port;
|
|
PortExtension->CurrentPowerState.DeviceState = PowerDeviceD0;
|
|
PortExtension->IgnoringHwSerial = FALSE;
|
|
|
|
KeInitializeSpinLock(&PortExtension->PortTimeoutSpinLock);
|
|
|
|
InitializeListHead(&PortExtension->PortPowerList);
|
|
KeInitializeSpinLock(&PortExtension->PortPowerListSpinLock);
|
|
|
|
PortExtension->PoRequestCounter = 0;
|
|
PortExtension->PendingSystemPoRequest = 0;
|
|
PortExtension->PendingDevicePoRequest = 0;
|
|
PortExtension->StateBehindD2 = 0;
|
|
|
|
SerialNumberBuffer = NULL;
|
|
|
|
IsHsDevice = UsbPortStatus.Usb20PortStatus.HighSpeedDeviceAttached;
|
|
IsLsDevice = UsbPortStatus.Usb20PortStatus.LowSpeedDeviceAttached;
|
|
|
|
if (IsLsDevice == 0)
|
|
{
|
|
if (IsHsDevice)
|
|
{
|
|
PortExtension->PortPdoFlags = USBHUB_PDO_FLAG_PORT_HIGH_SPEED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PortExtension->PortPdoFlags = USBHUB_PDO_FLAG_PORT_LOW_SPEED;
|
|
}
|
|
|
|
/* Initialize PortExtension->InstanceID */
|
|
RtlInitUnicodeString(&DestinationString, (PCWSTR)&PortExtension->InstanceID);
|
|
DestinationString.MaximumLength = 4 * sizeof(WCHAR);
|
|
Status = RtlIntegerToUnicodeString(Port, 10, &DestinationString);
|
|
|
|
DeviceObject->Flags |= DO_POWER_PAGABLE;
|
|
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("USBH_CreateDevice: IoCreateDevice() failed - %lX\n", Status);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Status = USBD_CreateDeviceEx(HubExtension,
|
|
&PortExtension->DeviceHandle,
|
|
UsbPortStatus,
|
|
Port);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("USBH_CreateDevice: USBD_CreateDeviceEx() failed - %lX\n", Status);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Status = USBH_SyncResetPort(HubExtension, Port);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("USBH_CreateDevice: USBH_SyncResetPort() failed - %lX\n", Status);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (IsWait)
|
|
{
|
|
USBH_Wait(50);
|
|
}
|
|
|
|
Status = USBD_InitializeDeviceEx(HubExtension,
|
|
PortExtension->DeviceHandle,
|
|
(PUCHAR)&PortExtension->DeviceDescriptor,
|
|
sizeof(USB_DEVICE_DESCRIPTOR),
|
|
(PUCHAR)&PortExtension->ConfigDescriptor,
|
|
sizeof(USB_CONFIGURATION_DESCRIPTOR));
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("USBH_CreateDevice: USBD_InitializeDeviceEx() failed - %lX\n", Status);
|
|
PortExtension->DeviceHandle = NULL;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
DPRINT1("USBH_RegQueryDeviceIgnoreHWSerNumFlag UNIMPLEMENTED. FIXME\n");
|
|
//Status = USBH_RegQueryDeviceIgnoreHWSerNumFlag(PortExtension->DeviceDescriptor.idVendor,
|
|
// PortExtension->DeviceDescriptor.idProduct,
|
|
// &IgnoringHwSerial);
|
|
|
|
if (TRUE)//Status == STATUS_OBJECT_NAME_NOT_FOUND)
|
|
{
|
|
IgnoringHwSerial = FALSE;
|
|
}
|
|
|
|
if (IgnoringHwSerial)
|
|
{
|
|
PortExtension->IgnoringHwSerial = TRUE;
|
|
}
|
|
|
|
if (PortExtension->DeviceDescriptor.iSerialNumber &&
|
|
!PortExtension->IgnoringHwSerial)
|
|
{
|
|
InterlockedExchangePointer((PVOID)&PortExtension->SerialNumber, NULL);
|
|
|
|
USBH_GetSerialNumberString(PortExtension->Common.SelfDevice,
|
|
&SerialNumberBuffer,
|
|
&PortExtension->SN_DescriptorLength,
|
|
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
|
|
PortExtension->DeviceDescriptor.iSerialNumber);
|
|
|
|
if (SerialNumberBuffer)
|
|
{
|
|
if (!USBH_ValidateSerialNumberString((PUSHORT)SerialNumberBuffer))
|
|
{
|
|
ExFreePoolWithTag(SerialNumberBuffer, USB_HUB_TAG);
|
|
SerialNumberBuffer = NULL;
|
|
}
|
|
|
|
if (SerialNumberBuffer &&
|
|
!USBH_CheckDeviceIDUnique(HubExtension,
|
|
PortExtension->DeviceDescriptor.idVendor,
|
|
PortExtension->DeviceDescriptor.idProduct,
|
|
SerialNumberBuffer,
|
|
PortExtension->SN_DescriptorLength))
|
|
{
|
|
ExFreePoolWithTag(SerialNumberBuffer, USB_HUB_TAG);
|
|
SerialNumberBuffer = NULL;
|
|
}
|
|
}
|
|
|
|
InterlockedExchangePointer((PVOID)&PortExtension->SerialNumber,
|
|
SerialNumberBuffer);
|
|
}
|
|
|
|
Status = USBH_ProcessDeviceInformation(PortExtension);
|
|
|
|
USBH_PdoSetCapabilities(PortExtension);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
ErrorExit:
|
|
|
|
PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_INIT_PORT_FAILED;
|
|
|
|
DeviceHandle = InterlockedExchangePointer(&PortExtension->DeviceHandle,
|
|
NULL);
|
|
|
|
if (DeviceHandle)
|
|
{
|
|
USBD_RemoveDeviceEx(HubExtension, DeviceHandle, 0);
|
|
}
|
|
|
|
SerialNumberBuffer = InterlockedExchangePointer((PVOID)&PortExtension->SerialNumber,
|
|
NULL);
|
|
|
|
if (SerialNumberBuffer)
|
|
{
|
|
ExFreePoolWithTag(SerialNumberBuffer, USB_HUB_TAG);
|
|
}
|
|
|
|
Exit:
|
|
|
|
ASSERT(Port > 0);
|
|
HubExtension->PortData[Port-1].DeviceObject = DeviceObject;
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_ResetDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN USHORT Port,
|
|
IN BOOLEAN IsKeepDeviceData,
|
|
IN BOOLEAN IsWait)
|
|
{
|
|
NTSTATUS Status;
|
|
PUSBHUB_PORT_DATA PortData;
|
|
PDEVICE_OBJECT PortDevice;
|
|
PUSBHUB_PORT_PDO_EXTENSION PortExtension;
|
|
PVOID NewDeviceHandle;
|
|
PVOID Handle;
|
|
PVOID OldDeviceHandle;
|
|
PUSB_DEVICE_HANDLE * DeviceHandle;
|
|
USB_PORT_STATUS_AND_CHANGE PortStatus;
|
|
|
|
DPRINT("USBH_ResetDevice: HubExtension - %p, Port - %x, IsKeepDeviceData - %x, IsWait - %x\n",
|
|
HubExtension,
|
|
Port,
|
|
IsKeepDeviceData,
|
|
IsWait);
|
|
|
|
Status = USBH_SyncGetPortStatus(HubExtension,
|
|
Port,
|
|
&PortStatus,
|
|
sizeof(USB_PORT_STATUS_AND_CHANGE));
|
|
|
|
if (!NT_SUCCESS(Status) ||
|
|
!(PortStatus.PortStatus.Usb20PortStatus.CurrentConnectStatus))
|
|
{
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
InterlockedIncrement(&HubExtension->PendingRequestCount);
|
|
|
|
KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
ASSERT(Port > 0);
|
|
PortData = &HubExtension->PortData[Port-1];
|
|
|
|
PortDevice = PortData->DeviceObject;
|
|
|
|
if (!PortDevice)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
|
|
LOW_REALTIME_PRIORITY,
|
|
1,
|
|
FALSE);
|
|
|
|
if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
|
|
{
|
|
KeSetEvent(&HubExtension->PendingRequestEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
PortExtension = PortDevice->DeviceExtension;
|
|
DeviceHandle = &PortExtension->DeviceHandle;
|
|
|
|
OldDeviceHandle = InterlockedExchangePointer(&PortExtension->DeviceHandle,
|
|
NULL);
|
|
|
|
if (OldDeviceHandle)
|
|
{
|
|
if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REMOVING_PORT_PDO))
|
|
{
|
|
Status = USBD_RemoveDeviceEx(HubExtension,
|
|
OldDeviceHandle,
|
|
IsKeepDeviceData);
|
|
|
|
PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_REMOVING_PORT_PDO;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OldDeviceHandle = NULL;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Status = USBH_SyncResetPort(HubExtension, Port);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Status = USBH_SyncGetPortStatus(HubExtension,
|
|
Port,
|
|
&PortStatus,
|
|
sizeof(USB_PORT_STATUS_AND_CHANGE));
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Status = USBD_CreateDeviceEx(HubExtension,
|
|
DeviceHandle,
|
|
PortStatus.PortStatus,
|
|
Port);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Status = USBH_SyncResetPort(HubExtension, Port);
|
|
|
|
if (IsWait)
|
|
{
|
|
USBH_Wait(50);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Status = USBD_InitializeDeviceEx(HubExtension,
|
|
*DeviceHandle,
|
|
&PortExtension->DeviceDescriptor.bLength,
|
|
sizeof(PortExtension->DeviceDescriptor),
|
|
&PortExtension->ConfigDescriptor.bLength,
|
|
sizeof(PortExtension->ConfigDescriptor));
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
if (IsKeepDeviceData)
|
|
{
|
|
Status = USBD_RestoreDeviceEx(HubExtension,
|
|
OldDeviceHandle,
|
|
*DeviceHandle);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
Handle = InterlockedExchangePointer(DeviceHandle, NULL);
|
|
|
|
USBD_RemoveDeviceEx(HubExtension, Handle, 0);
|
|
USBH_SyncDisablePort(HubExtension, Port);
|
|
|
|
Status = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_REMOVING_PORT_PDO;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
*DeviceHandle = NULL;
|
|
|
|
ErrorExit:
|
|
|
|
NewDeviceHandle = InterlockedExchangePointer(DeviceHandle,
|
|
OldDeviceHandle);
|
|
|
|
if (NewDeviceHandle)
|
|
{
|
|
Status = USBD_RemoveDeviceEx(HubExtension, NewDeviceHandle, 0);
|
|
}
|
|
|
|
Exit:
|
|
|
|
KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
|
|
LOW_REALTIME_PRIORITY,
|
|
1,
|
|
FALSE);
|
|
|
|
if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
|
|
{
|
|
KeSetEvent(&HubExtension->PendingRequestEvent,
|
|
EVENT_INCREMENT,
|
|
FALSE);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_PdoDispatch(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
|
|
IN PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
UCHAR MajorFunction;
|
|
BOOLEAN ShouldCompleteIrp;
|
|
ULONG ControlCode;
|
|
NTSTATUS Status;
|
|
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
MajorFunction = IoStack->MajorFunction;
|
|
|
|
switch (MajorFunction)
|
|
{
|
|
case IRP_MJ_CREATE:
|
|
case IRP_MJ_CLOSE:
|
|
DPRINT("USBH_PdoDispatch: IRP_MJ_CREATE / IRP_MJ_CLOSE (%d)\n",
|
|
MajorFunction);
|
|
Status = STATUS_SUCCESS;
|
|
USBH_CompleteIrp(Irp, Status);
|
|
break;
|
|
|
|
case IRP_MJ_DEVICE_CONTROL:
|
|
ControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode;
|
|
DPRINT("USBH_PdoDispatch: IRP_MJ_DEVICE_CONTROL ControlCode - %x\n",
|
|
ControlCode);
|
|
|
|
if (ControlCode == IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER)
|
|
{
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
USBH_CompleteIrp(Irp, Status);
|
|
break;
|
|
}
|
|
|
|
if (ControlCode == IOCTL_KS_PROPERTY)
|
|
{
|
|
DPRINT1("USBH_PdoDispatch: IOCTL_KS_PROPERTY FIXME\n");
|
|
DbgBreakPoint();
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
USBH_CompleteIrp(Irp, Status);
|
|
break;
|
|
}
|
|
|
|
Status = Irp->IoStatus.Status;
|
|
USBH_CompleteIrp(Irp, Status);
|
|
break;
|
|
|
|
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
|
|
Status = USBH_PdoInternalControl(PortExtension, Irp);
|
|
break;
|
|
|
|
case IRP_MJ_PNP:
|
|
Status = USBH_PdoPnP(PortExtension,
|
|
Irp,
|
|
IoStack->MinorFunction,
|
|
&ShouldCompleteIrp);
|
|
|
|
if (ShouldCompleteIrp)
|
|
{
|
|
USBH_CompleteIrp(Irp, Status);
|
|
}
|
|
|
|
break;
|
|
|
|
case IRP_MJ_POWER:
|
|
Status = USBH_PdoPower(PortExtension, Irp, IoStack->MinorFunction);
|
|
break;
|
|
|
|
case IRP_MJ_SYSTEM_CONTROL:
|
|
DPRINT1("USBH_PdoDispatch: USBH_SystemControl() UNIMPLEMENTED. FIXME\n");
|
|
//USBH_PortSystemControl(PortExtension, Irp);
|
|
Status = Irp->IoStatus.Status;
|
|
USBH_CompleteIrp(Irp, Status);
|
|
break;
|
|
|
|
default:
|
|
DPRINT("USBH_PdoDispatch: Unhandled MajorFunction - %d\n", MajorFunction);
|
|
Status = Irp->IoStatus.Status;
|
|
USBH_CompleteIrp(Irp, Status);
|
|
break;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_FdoDispatch(IN PUSBHUB_FDO_EXTENSION HubExtension,
|
|
IN PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
UCHAR MajorFunction;
|
|
NTSTATUS Status;
|
|
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
DPRINT("USBH_FdoDispatch: HubExtension - %p, Irp - %p, MajorFunction - %X\n",
|
|
HubExtension,
|
|
Irp,
|
|
IoStack->MajorFunction);
|
|
|
|
MajorFunction = IoStack->MajorFunction;
|
|
|
|
switch (MajorFunction)
|
|
{
|
|
case IRP_MJ_CREATE:
|
|
case IRP_MJ_CLOSE:
|
|
Status = STATUS_SUCCESS;
|
|
USBH_CompleteIrp(Irp, Status);
|
|
break;
|
|
|
|
case IRP_MJ_DEVICE_CONTROL:
|
|
Status = USBH_DeviceControl(HubExtension, Irp);
|
|
break;
|
|
|
|
case IRP_MJ_PNP:
|
|
Status = USBH_FdoPnP(HubExtension, Irp, IoStack->MinorFunction);
|
|
break;
|
|
|
|
case IRP_MJ_POWER:
|
|
Status = USBH_FdoPower(HubExtension, Irp, IoStack->MinorFunction);
|
|
break;
|
|
|
|
case IRP_MJ_SYSTEM_CONTROL:
|
|
DPRINT1("USBH_FdoDispatch: USBH_SystemControl() UNIMPLEMENTED. FIXME\n");
|
|
/* fall through */
|
|
|
|
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
|
|
default:
|
|
Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
|
|
break;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_AddDevice(IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT LowerPDO)
|
|
{
|
|
PDEVICE_OBJECT DeviceObject;
|
|
NTSTATUS Status;
|
|
PUSBHUB_FDO_EXTENSION HubExtension;
|
|
PDEVICE_OBJECT LowerDevice;
|
|
|
|
DPRINT("USBH_AddDevice: DriverObject - %p, LowerPDO - %p\n",
|
|
DriverObject,
|
|
LowerPDO);
|
|
|
|
DeviceObject = NULL;
|
|
|
|
Status = IoCreateDevice(DriverObject,
|
|
sizeof(USBHUB_FDO_EXTENSION),
|
|
NULL,
|
|
0x8600,
|
|
FILE_AUTOGENERATED_DEVICE_NAME,
|
|
FALSE,
|
|
&DeviceObject);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("USBH_AddDevice: IoCreateDevice() fail\n");
|
|
|
|
if (DeviceObject)
|
|
{
|
|
IoDeleteDevice(DeviceObject);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
DPRINT("USBH_AddDevice: DeviceObject - %p\n", DeviceObject);
|
|
|
|
HubExtension = DeviceObject->DeviceExtension;
|
|
RtlZeroMemory(HubExtension, sizeof(USBHUB_FDO_EXTENSION));
|
|
|
|
HubExtension->Common.ExtensionType = USBH_EXTENSION_TYPE_HUB;
|
|
|
|
LowerDevice = IoAttachDeviceToDeviceStack(DeviceObject, LowerPDO);
|
|
|
|
if (!LowerDevice)
|
|
{
|
|
DPRINT1("USBH_AddDevice: IoAttachDeviceToDeviceStack() fail\n");
|
|
|
|
if (DeviceObject)
|
|
{
|
|
IoDeleteDevice(DeviceObject);
|
|
}
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
DPRINT("USBH_AddDevice: LowerDevice - %p\n", LowerDevice);
|
|
|
|
HubExtension->Common.SelfDevice = DeviceObject;
|
|
|
|
HubExtension->LowerPDO = LowerPDO;
|
|
HubExtension->LowerDevice = LowerDevice;
|
|
|
|
KeInitializeSemaphore(&HubExtension->IdleSemaphore, 1, 1);
|
|
|
|
DeviceObject->Flags |= DO_POWER_PAGABLE;
|
|
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
DPRINT("USBH_AddDevice: call IoWMIRegistrationControl() UNIMPLEMENTED. FIXME\n");
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBH_DriverUnload(IN PDRIVER_OBJECT DriverObject)
|
|
{
|
|
DPRINT("USBH_DriverUnload: UNIMPLEMENTED\n");
|
|
|
|
if (GenericUSBDeviceString)
|
|
{
|
|
ExFreePool(GenericUSBDeviceString);
|
|
GenericUSBDeviceString = NULL;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_HubDispatch(IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PCOMMON_DEVICE_EXTENSION DeviceExtension;
|
|
ULONG ExtensionType;
|
|
NTSTATUS Status;
|
|
|
|
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
|
ExtensionType = DeviceExtension->ExtensionType;
|
|
|
|
if (ExtensionType == USBH_EXTENSION_TYPE_HUB)
|
|
{
|
|
DPRINT("USBH_HubDispatch: DeviceObject - %p, Irp - %p\n",
|
|
DeviceObject,
|
|
Irp);
|
|
|
|
Status = USBH_FdoDispatch((PUSBHUB_FDO_EXTENSION)DeviceExtension, Irp);
|
|
}
|
|
else if (ExtensionType == USBH_EXTENSION_TYPE_PORT)
|
|
{
|
|
PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
UCHAR MajorFunction = IoStack->MajorFunction;
|
|
BOOLEAN IsDprint = TRUE;
|
|
|
|
if (MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)
|
|
{
|
|
ULONG ControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode;
|
|
|
|
if (ControlCode == IOCTL_INTERNAL_USB_SUBMIT_URB)
|
|
{
|
|
IsDprint = FALSE;
|
|
}
|
|
}
|
|
|
|
if (IsDprint)
|
|
{
|
|
DPRINT("USBH_HubDispatch: DeviceObject - %p, Irp - %p\n",
|
|
DeviceObject,
|
|
Irp);
|
|
}
|
|
|
|
Status = USBH_PdoDispatch((PUSBHUB_PORT_PDO_EXTENSION)DeviceExtension, Irp);
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("USBH_HubDispatch: Unknown ExtensionType - %x\n", ExtensionType);
|
|
DbgBreakPoint();
|
|
Status = STATUS_ASSERTION_FAILURE;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBH_RegQueryGenericUSBDeviceString(PVOID USBDeviceString)
|
|
{
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
|
|
|
|
DPRINT("USBH_RegQueryGenericUSBDeviceString ... \n");
|
|
|
|
RtlZeroMemory(QueryTable, sizeof(QueryTable));
|
|
|
|
QueryTable[0].QueryRoutine = USBH_GetConfigValue;
|
|
QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
|
|
QueryTable[0].Name = L"GenericUSBDeviceString";
|
|
QueryTable[0].EntryContext = USBDeviceString;
|
|
QueryTable[0].DefaultType = REG_NONE;
|
|
QueryTable[0].DefaultData = 0;
|
|
QueryTable[0].DefaultLength = 0;
|
|
|
|
return RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
|
|
L"usbflags",
|
|
QueryTable,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
DriverEntry(IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath)
|
|
{
|
|
DPRINT("USBHUB: DriverEntry - %wZ\n", RegistryPath);
|
|
|
|
DriverObject->DriverExtension->AddDevice = USBH_AddDevice;
|
|
DriverObject->DriverUnload = USBH_DriverUnload;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = USBH_HubDispatch;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = USBH_HubDispatch;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = USBH_HubDispatch;
|
|
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = USBH_HubDispatch;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_PNP] = USBH_HubDispatch;
|
|
DriverObject->MajorFunction[IRP_MJ_POWER] = USBH_HubDispatch;
|
|
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = USBH_HubDispatch;
|
|
|
|
USBH_RegQueryGenericUSBDeviceString(&GenericUSBDeviceString);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|