mirror of
https://github.com/reactos/reactos.git
synced 2024-08-20 10:23:22 +00:00
1045 lines
35 KiB
C
1045 lines
35 KiB
C
/*
|
|
* PROJECT: ReactOS USB Port Driver
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
|
* PURPOSE: USBPort root hub implementation
|
|
* COPYRIGHT: Copyright 2017 Vadim Galyant <vgal@rambler.ru>
|
|
*/
|
|
|
|
#include "usbport.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
#define NDEBUG_USBPORT_CORE
|
|
#include "usbdebug.h"
|
|
|
|
RHSTATUS
|
|
NTAPI
|
|
USBPORT_MPStatusToRHStatus(IN MPSTATUS MPStatus)
|
|
{
|
|
RHSTATUS RHStatus = RH_STATUS_SUCCESS;
|
|
|
|
//DPRINT("USBPORT_MPStatusToRHStatus: MPStatus - %x\n", MPStatus);
|
|
|
|
if (MPStatus)
|
|
{
|
|
RHStatus = (MPStatus != MP_STATUS_FAILURE);
|
|
++RHStatus;
|
|
}
|
|
|
|
return RHStatus;
|
|
}
|
|
|
|
MPSTATUS
|
|
NTAPI
|
|
USBPORT_RH_SetFeatureUSB2PortPower(IN PDEVICE_OBJECT FdoDevice,
|
|
IN USHORT Port)
|
|
{
|
|
PUSBPORT_DEVICE_EXTENSION FdoExtension;
|
|
PUSBPORT_REGISTRATION_PACKET Packet;
|
|
PDEVICE_RELATIONS CompanionControllersList;
|
|
PUSBPORT_REGISTRATION_PACKET CompanionPacket;
|
|
PDEVICE_OBJECT CompanionFdoDevice;
|
|
PUSBPORT_DEVICE_EXTENSION CompanionFdoExtension;
|
|
PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
|
|
USHORT ix;
|
|
PDEVICE_OBJECT * Entry;
|
|
ULONG NumController = 0;
|
|
|
|
DPRINT("USBPORT_RootHub_PowerUsb2Port: FdoDevice - %p, Port - %p\n",
|
|
FdoDevice,
|
|
Port);
|
|
|
|
FdoExtension = FdoDevice->DeviceExtension;
|
|
Packet = &FdoExtension->MiniPortInterface->Packet;
|
|
|
|
CompanionControllersList = USBPORT_FindCompanionControllers(FdoDevice,
|
|
FALSE,
|
|
TRUE);
|
|
|
|
if (!CompanionControllersList)
|
|
{
|
|
Packet->RH_SetFeaturePortPower(FdoExtension->MiniPortExt, Port);
|
|
return MP_STATUS_SUCCESS;
|
|
}
|
|
|
|
Entry = &CompanionControllersList->Objects[0];
|
|
|
|
while (NumController < CompanionControllersList->Count)
|
|
{
|
|
CompanionFdoDevice = *Entry;
|
|
|
|
CompanionFdoExtension = CompanionFdoDevice->DeviceExtension;
|
|
CompanionPacket = &CompanionFdoExtension->MiniPortInterface->Packet;
|
|
|
|
PdoExtension = CompanionFdoExtension->RootHubPdo->DeviceExtension;
|
|
|
|
for (ix = 0;
|
|
(PdoExtension->CommonExtension.PnpStateFlags & USBPORT_PNP_STATE_STARTED) &&
|
|
ix < PdoExtension->RootHubDescriptors->Descriptor.bNumberOfPorts;
|
|
++ix)
|
|
{
|
|
CompanionPacket->RH_SetFeaturePortPower(CompanionFdoExtension->MiniPortExt,
|
|
ix + 1);
|
|
}
|
|
|
|
++NumController;
|
|
++Entry;
|
|
}
|
|
|
|
Packet->RH_SetFeaturePortPower(FdoExtension->MiniPortExt, Port);
|
|
|
|
if (CompanionControllersList)
|
|
{
|
|
ExFreePoolWithTag(CompanionControllersList, USB_PORT_TAG);
|
|
}
|
|
|
|
return MP_STATUS_SUCCESS;
|
|
}
|
|
|
|
RHSTATUS
|
|
NTAPI
|
|
USBPORT_RootHubClassCommand(IN PDEVICE_OBJECT FdoDevice,
|
|
IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
|
|
IN PVOID Buffer,
|
|
IN PULONG BufferLength)
|
|
{
|
|
PUSBPORT_DEVICE_EXTENSION FdoExtension;
|
|
PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
|
|
PUSBPORT_REGISTRATION_PACKET Packet;
|
|
USHORT Port;
|
|
USHORT Feature;
|
|
MPSTATUS MPStatus;
|
|
RHSTATUS RHStatus = RH_STATUS_UNSUCCESSFUL;
|
|
KIRQL OldIrql;
|
|
|
|
DPRINT("USBPORT_RootHubClassCommand: USB command - %x, *BufferLength - %x\n",
|
|
SetupPacket->bRequest,
|
|
*BufferLength);
|
|
|
|
FdoExtension = FdoDevice->DeviceExtension;
|
|
PdoExtension = FdoExtension->RootHubPdo->DeviceExtension;
|
|
Packet = &FdoExtension->MiniPortInterface->Packet;
|
|
|
|
Port = SetupPacket->wIndex.W;
|
|
|
|
switch (SetupPacket->bRequest)
|
|
{
|
|
case USB_REQUEST_GET_STATUS:
|
|
{
|
|
if (!Buffer)
|
|
{
|
|
return RHStatus;
|
|
}
|
|
|
|
*(PULONG)Buffer = 0;
|
|
|
|
if (SetupPacket->bmRequestType.Recipient == BMREQUEST_TO_OTHER)
|
|
{
|
|
ASSERT(*BufferLength >= 4);
|
|
|
|
if (Port > PdoExtension->RootHubDescriptors->Descriptor.bNumberOfPorts ||
|
|
Port <= 0 ||
|
|
SetupPacket->wLength < 4)
|
|
{
|
|
return RHStatus;
|
|
}
|
|
|
|
KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
|
|
|
|
MPStatus = Packet->RH_GetPortStatus(FdoExtension->MiniPortExt,
|
|
SetupPacket->wIndex.W,
|
|
Buffer);
|
|
|
|
KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
|
|
}
|
|
else
|
|
{
|
|
KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
|
|
|
|
MPStatus = Packet->RH_GetHubStatus(FdoExtension->MiniPortExt,
|
|
Buffer);
|
|
|
|
KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
|
|
}
|
|
|
|
RHStatus = USBPORT_MPStatusToRHStatus(MPStatus);
|
|
break;
|
|
}
|
|
|
|
case USB_REQUEST_CLEAR_FEATURE:
|
|
Feature = SetupPacket->wValue.W;
|
|
|
|
if ((SetupPacket->bmRequestType.Recipient) != USBPORT_RECIPIENT_PORT)
|
|
{
|
|
if (Feature == FEATURE_C_HUB_LOCAL_POWER)
|
|
{
|
|
RHStatus = RH_STATUS_SUCCESS;
|
|
return RHStatus;
|
|
}
|
|
|
|
if (Feature == FEATURE_C_HUB_OVER_CURRENT)
|
|
{
|
|
MPStatus = Packet->RH_ClearFeaturePortOvercurrentChange(FdoExtension->MiniPortExt,
|
|
0);
|
|
RHStatus = USBPORT_MPStatusToRHStatus(MPStatus);
|
|
return RHStatus;
|
|
}
|
|
|
|
DbgBreakPoint();
|
|
return RHStatus;
|
|
}
|
|
|
|
switch (Feature)
|
|
{
|
|
case FEATURE_PORT_ENABLE:
|
|
MPStatus = Packet->RH_ClearFeaturePortEnable(FdoExtension->MiniPortExt,
|
|
Port);
|
|
break;
|
|
|
|
case FEATURE_PORT_SUSPEND:
|
|
MPStatus = Packet->RH_ClearFeaturePortSuspend(FdoExtension->MiniPortExt,
|
|
Port);
|
|
break;
|
|
|
|
case FEATURE_PORT_POWER:
|
|
MPStatus = Packet->RH_ClearFeaturePortPower(FdoExtension->MiniPortExt,
|
|
Port);
|
|
break;
|
|
|
|
case FEATURE_C_PORT_CONNECTION:
|
|
MPStatus = Packet->RH_ClearFeaturePortConnectChange(FdoExtension->MiniPortExt,
|
|
Port);
|
|
break;
|
|
|
|
case FEATURE_C_PORT_ENABLE:
|
|
MPStatus = Packet->RH_ClearFeaturePortEnableChange(FdoExtension->MiniPortExt,
|
|
Port);
|
|
break;
|
|
|
|
case FEATURE_C_PORT_SUSPEND:
|
|
MPStatus = Packet->RH_ClearFeaturePortSuspendChange(FdoExtension->MiniPortExt,
|
|
Port);
|
|
break;
|
|
|
|
case FEATURE_C_PORT_OVER_CURRENT:
|
|
MPStatus = Packet->RH_ClearFeaturePortOvercurrentChange(FdoExtension->MiniPortExt,
|
|
Port);
|
|
break;
|
|
|
|
case FEATURE_C_PORT_RESET:
|
|
MPStatus = Packet->RH_ClearFeaturePortResetChange(FdoExtension->MiniPortExt,
|
|
Port);
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("USBPORT_RootHubClassCommand: Not supported feature - %x\n",
|
|
Feature);
|
|
return RHStatus;
|
|
}
|
|
|
|
RHStatus = USBPORT_MPStatusToRHStatus(MPStatus);
|
|
break;
|
|
|
|
case USB_REQUEST_SET_FEATURE:
|
|
if (SetupPacket->bmRequestType.Recipient != USBPORT_RECIPIENT_PORT)
|
|
{
|
|
return RHStatus;
|
|
}
|
|
|
|
Feature = SetupPacket->wValue.W;
|
|
|
|
switch (Feature)
|
|
{
|
|
case FEATURE_PORT_ENABLE:
|
|
MPStatus = Packet->RH_SetFeaturePortEnable(FdoExtension->MiniPortExt,
|
|
Port);
|
|
break;
|
|
|
|
case FEATURE_PORT_SUSPEND:
|
|
MPStatus = Packet->RH_SetFeaturePortSuspend(FdoExtension->MiniPortExt,
|
|
Port);
|
|
break;
|
|
|
|
case FEATURE_PORT_RESET:
|
|
MPStatus = Packet->RH_SetFeaturePortReset(FdoExtension->MiniPortExt,
|
|
Port);
|
|
break;
|
|
|
|
case FEATURE_PORT_POWER:
|
|
if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2)
|
|
{
|
|
MPStatus = USBPORT_RH_SetFeatureUSB2PortPower(FdoDevice, Port);
|
|
}
|
|
else
|
|
{
|
|
MPStatus = Packet->RH_SetFeaturePortPower(FdoExtension->MiniPortExt,
|
|
Port);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("USBPORT_RootHubClassCommand: Not supported feature - %x\n",
|
|
Feature);
|
|
return RHStatus;
|
|
}
|
|
|
|
RHStatus = USBPORT_MPStatusToRHStatus(MPStatus);
|
|
break;
|
|
|
|
case USB_REQUEST_GET_DESCRIPTOR:
|
|
if (Buffer &&
|
|
SetupPacket->wValue.W == 0 &&
|
|
SetupPacket->bmRequestType.Dir == BMREQUEST_DEVICE_TO_HOST)
|
|
{
|
|
SIZE_T DescriptorLength;
|
|
|
|
DescriptorLength = PdoExtension->RootHubDescriptors->Descriptor.bDescriptorLength;
|
|
|
|
if (*BufferLength < DescriptorLength)
|
|
DescriptorLength = *BufferLength;
|
|
|
|
RtlCopyMemory(Buffer,
|
|
&PdoExtension->RootHubDescriptors->Descriptor,
|
|
DescriptorLength);
|
|
|
|
*BufferLength = DescriptorLength;
|
|
RHStatus = RH_STATUS_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("USBPORT_RootHubClassCommand: Not supported USB request - %x\n",
|
|
SetupPacket->bRequest);
|
|
//USB_REQUEST_SET_ADDRESS 0x05
|
|
//USB_REQUEST_SET_DESCRIPTOR 0x07
|
|
//USB_REQUEST_GET_CONFIGURATION 0x08
|
|
//USB_REQUEST_SET_CONFIGURATION 0x09
|
|
//USB_REQUEST_GET_INTERFACE 0x0A
|
|
//USB_REQUEST_SET_INTERFACE 0x0B
|
|
//USB_REQUEST_SYNC_FRAME 0x0C
|
|
break;
|
|
}
|
|
|
|
return RHStatus;
|
|
}
|
|
|
|
RHSTATUS
|
|
NTAPI
|
|
USBPORT_RootHubStandardCommand(IN PDEVICE_OBJECT FdoDevice,
|
|
IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
|
|
IN PVOID Buffer,
|
|
IN OUT PULONG TransferLength)
|
|
{
|
|
PUSBPORT_DEVICE_EXTENSION FdoExtension;
|
|
PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
|
|
PUSBPORT_REGISTRATION_PACKET Packet;
|
|
SIZE_T Length;
|
|
PVOID Descriptor;
|
|
SIZE_T DescriptorLength;
|
|
MPSTATUS MPStatus;
|
|
RHSTATUS RHStatus = RH_STATUS_UNSUCCESSFUL;
|
|
KIRQL OldIrql;
|
|
|
|
DPRINT("USBPORT_RootHubStandardCommand: USB command - %x, TransferLength - %p\n",
|
|
SetupPacket->bRequest,
|
|
TransferLength);
|
|
|
|
FdoExtension = FdoDevice->DeviceExtension;
|
|
PdoExtension = FdoExtension->RootHubPdo->DeviceExtension;
|
|
Packet = &FdoExtension->MiniPortInterface->Packet;
|
|
|
|
switch (SetupPacket->bRequest)
|
|
{
|
|
case USB_REQUEST_GET_DESCRIPTOR:
|
|
if (SetupPacket->wValue.LowByte ||
|
|
!(SetupPacket->bmRequestType.Dir))
|
|
{
|
|
return RHStatus;
|
|
}
|
|
|
|
switch (SetupPacket->wValue.HiByte)
|
|
{
|
|
case USB_DEVICE_DESCRIPTOR_TYPE:
|
|
Descriptor = &PdoExtension->RootHubDescriptors->DeviceDescriptor;
|
|
DescriptorLength = sizeof(USB_DEVICE_DESCRIPTOR);
|
|
break;
|
|
|
|
case USB_CONFIGURATION_DESCRIPTOR_TYPE:
|
|
Descriptor = &PdoExtension->RootHubDescriptors->ConfigDescriptor;
|
|
DescriptorLength = sizeof(USB_CONFIGURATION_DESCRIPTOR) +
|
|
sizeof(USB_INTERFACE_DESCRIPTOR) +
|
|
sizeof(USB_ENDPOINT_DESCRIPTOR);
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("USBPORT_RootHubStandardCommand: Not supported Descriptor Type - %x\n",
|
|
SetupPacket->wValue.HiByte);
|
|
return RHStatus;
|
|
}
|
|
|
|
if (!Descriptor)
|
|
{
|
|
return RHStatus;
|
|
}
|
|
|
|
if (*TransferLength >= DescriptorLength)
|
|
Length = DescriptorLength;
|
|
else
|
|
Length = *TransferLength;
|
|
|
|
RtlCopyMemory(Buffer, Descriptor, Length);
|
|
*TransferLength = Length;
|
|
|
|
RHStatus = RH_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case USB_REQUEST_GET_STATUS:
|
|
if (!SetupPacket->wValue.W &&
|
|
SetupPacket->wLength == sizeof(USHORT) &&
|
|
!SetupPacket->wIndex.W &&
|
|
SetupPacket->bmRequestType.Dir == BMREQUEST_DEVICE_TO_HOST)
|
|
{
|
|
KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
|
|
|
|
MPStatus = Packet->RH_GetStatus(FdoExtension->MiniPortExt,
|
|
Buffer);
|
|
|
|
KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
|
|
|
|
*TransferLength = sizeof(USHORT);
|
|
RHStatus = USBPORT_MPStatusToRHStatus(MPStatus);
|
|
}
|
|
|
|
break;
|
|
|
|
case USB_REQUEST_GET_CONFIGURATION:
|
|
if (SetupPacket->wValue.W ||
|
|
SetupPacket->wIndex.W ||
|
|
SetupPacket->wLength != 1 ||
|
|
SetupPacket->bmRequestType.Dir == BMREQUEST_HOST_TO_DEVICE)
|
|
{
|
|
return RHStatus;
|
|
}
|
|
|
|
Length = 0;
|
|
|
|
if (*TransferLength >= 1)
|
|
{
|
|
Length = 1;
|
|
RtlCopyMemory(Buffer, &PdoExtension->ConfigurationValue, Length);
|
|
}
|
|
|
|
*TransferLength = Length;
|
|
|
|
RHStatus = RH_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case USB_REQUEST_SET_CONFIGURATION:
|
|
if (!SetupPacket->wIndex.W &&
|
|
!SetupPacket->wLength &&
|
|
!(SetupPacket->bmRequestType.Dir == BMREQUEST_DEVICE_TO_HOST))
|
|
{
|
|
if (SetupPacket->wValue.W == 0 ||
|
|
SetupPacket->wValue.W ==
|
|
PdoExtension->RootHubDescriptors->ConfigDescriptor.bConfigurationValue)
|
|
{
|
|
PdoExtension->ConfigurationValue = SetupPacket->wValue.LowByte;
|
|
RHStatus = RH_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case USB_REQUEST_SET_ADDRESS:
|
|
if (!SetupPacket->wIndex.W &&
|
|
!SetupPacket->wLength &&
|
|
!(SetupPacket->bmRequestType.Dir))
|
|
{
|
|
PdoExtension->DeviceHandle.DeviceAddress = SetupPacket->wValue.LowByte;
|
|
RHStatus = RH_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("USBPORT_RootHubStandardCommand: Not supported USB request - %x\n",
|
|
SetupPacket->bRequest);
|
|
//USB_REQUEST_CLEAR_FEATURE 0x01
|
|
//USB_REQUEST_SET_FEATURE 0x03
|
|
//USB_REQUEST_SET_DESCRIPTOR 0x07
|
|
//USB_REQUEST_GET_INTERFACE 0x0A
|
|
//USB_REQUEST_SET_INTERFACE 0x0B
|
|
//USB_REQUEST_SYNC_FRAME 0x0C
|
|
break;
|
|
}
|
|
|
|
return RHStatus;
|
|
}
|
|
|
|
RHSTATUS
|
|
NTAPI
|
|
USBPORT_RootHubEndpoint0(IN PUSBPORT_TRANSFER Transfer)
|
|
{
|
|
PDEVICE_OBJECT FdoDevice;
|
|
ULONG TransferLength;
|
|
PVOID Buffer;
|
|
PURB Urb;
|
|
PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket;
|
|
UCHAR Type;
|
|
RHSTATUS RHStatus;
|
|
|
|
DPRINT("USBPORT_RootHubEndpoint0: Transfer - %p\n", Transfer);
|
|
|
|
TransferLength = Transfer->TransferParameters.TransferBufferLength;
|
|
Urb = Transfer->Urb;
|
|
FdoDevice = Transfer->Endpoint->FdoDevice;
|
|
|
|
if (TransferLength > 0)
|
|
Buffer = Urb->UrbControlTransfer.TransferBufferMDL->MappedSystemVa;
|
|
else
|
|
Buffer = NULL;
|
|
|
|
SetupPacket = (PUSB_DEFAULT_PIPE_SETUP_PACKET)Urb->UrbControlTransfer.SetupPacket;
|
|
|
|
Type = SetupPacket->bmRequestType.Type;
|
|
|
|
if (Type == BMREQUEST_STANDARD)
|
|
{
|
|
RHStatus = USBPORT_RootHubStandardCommand(FdoDevice,
|
|
SetupPacket,
|
|
Buffer,
|
|
&TransferLength);
|
|
}
|
|
else if (Type == BMREQUEST_CLASS)
|
|
{
|
|
RHStatus = USBPORT_RootHubClassCommand(FdoDevice,
|
|
SetupPacket,
|
|
Buffer,
|
|
&TransferLength);
|
|
}
|
|
else
|
|
{
|
|
return RH_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if (RHStatus == RH_STATUS_SUCCESS)
|
|
Transfer->CompletedTransferLen = TransferLength;
|
|
|
|
return RHStatus;
|
|
}
|
|
|
|
RHSTATUS
|
|
NTAPI
|
|
USBPORT_RootHubSCE(IN PUSBPORT_TRANSFER Transfer)
|
|
{
|
|
PUSBPORT_ENDPOINT Endpoint;
|
|
PUSBPORT_DEVICE_EXTENSION FdoExtension;
|
|
PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
|
|
PUSBPORT_REGISTRATION_PACKET Packet;
|
|
ULONG TransferLength;
|
|
USB_PORT_STATUS_AND_CHANGE PortStatus;
|
|
USB_HUB_STATUS_AND_CHANGE HubStatus;
|
|
PVOID Buffer;
|
|
PULONG AddressBitMap;
|
|
ULONG Port;
|
|
PURB Urb;
|
|
RHSTATUS RHStatus = RH_STATUS_NO_CHANGES;
|
|
PUSB_HUB_DESCRIPTOR HubDescriptor;
|
|
UCHAR NumberOfPorts;
|
|
|
|
DPRINT("USBPORT_RootHubSCE: Transfer - %p\n", Transfer);
|
|
|
|
Endpoint = Transfer->Endpoint;
|
|
|
|
FdoExtension = Endpoint->FdoDevice->DeviceExtension;
|
|
PdoExtension = FdoExtension->RootHubPdo->DeviceExtension;
|
|
Packet = &FdoExtension->MiniPortInterface->Packet;
|
|
|
|
HubDescriptor = &PdoExtension->RootHubDescriptors->Descriptor;
|
|
NumberOfPorts = HubDescriptor->bNumberOfPorts;
|
|
|
|
PortStatus.AsUlong32 = 0;
|
|
HubStatus.AsUlong32 = 0;
|
|
|
|
Urb = Transfer->Urb;
|
|
TransferLength = Transfer->TransferParameters.TransferBufferLength;
|
|
|
|
if (TransferLength)
|
|
{
|
|
Buffer = Urb->UrbControlTransfer.TransferBufferMDL->MappedSystemVa;
|
|
}
|
|
else
|
|
{
|
|
Buffer = NULL;
|
|
}
|
|
|
|
/* Check parameters */
|
|
|
|
if (!Buffer)
|
|
{
|
|
/* Not valid parameter */
|
|
DPRINT1("USBPORT_RootHubSCE: Error! Buffer is NULL\n");
|
|
return RH_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if ((TransferLength < (NumberOfPorts / 8 + 1)))
|
|
{
|
|
/* Not valid parameters */
|
|
DPRINT1("USBPORT_RootHubSCE: Error! TransferLength - %x, NumberOfPorts - %x\n",
|
|
TransferLength,
|
|
NumberOfPorts);
|
|
|
|
return RH_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
RtlZeroMemory(Buffer, TransferLength);
|
|
|
|
AddressBitMap = Buffer;
|
|
|
|
/* Scan all the ports for changes */
|
|
for (Port = 1; Port <= NumberOfPorts; Port++)
|
|
{
|
|
DPRINT_CORE("USBPORT_RootHubSCE: Port - %p\n", Port);
|
|
|
|
/* Request the port status from miniport */
|
|
if (Packet->RH_GetPortStatus(FdoExtension->MiniPortExt,
|
|
Port,
|
|
&PortStatus))
|
|
{
|
|
/* Miniport returned an error */
|
|
DPRINT1("USBPORT_RootHubSCE: RH_GetPortStatus failed\n");
|
|
return RH_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if (PortStatus.PortChange.Usb20PortChange.ConnectStatusChange ||
|
|
PortStatus.PortChange.Usb20PortChange.PortEnableDisableChange ||
|
|
PortStatus.PortChange.Usb20PortChange.SuspendChange ||
|
|
PortStatus.PortChange.Usb20PortChange.OverCurrentIndicatorChange ||
|
|
PortStatus.PortChange.Usb20PortChange.ResetChange)
|
|
{
|
|
/* At the port status there is a change */
|
|
AddressBitMap[Port >> 5] |= 1 << (Port & 0x1F);
|
|
RHStatus = RH_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* Request the hub status from miniport */
|
|
if (!Packet->RH_GetHubStatus(FdoExtension->MiniPortExt, &HubStatus))
|
|
{
|
|
if (HubStatus.HubChange.LocalPowerChange == 1 ||
|
|
HubStatus.HubChange.OverCurrentChange == 1)
|
|
{
|
|
/* At the hub status there is a change */
|
|
AddressBitMap[0] |= 1;
|
|
RHStatus = RH_STATUS_SUCCESS;
|
|
}
|
|
|
|
if (RHStatus == RH_STATUS_SUCCESS)
|
|
{
|
|
/* Done */
|
|
Urb->UrbControlTransfer.TransferBufferLength = TransferLength;
|
|
return RH_STATUS_SUCCESS;
|
|
}
|
|
|
|
if (RHStatus == RH_STATUS_NO_CHANGES)
|
|
{
|
|
/* No changes. Enable IRQs for miniport root hub */
|
|
Packet->RH_EnableIrq(FdoExtension->MiniPortExt);
|
|
}
|
|
|
|
return RHStatus;
|
|
}
|
|
|
|
/* Miniport returned an error */
|
|
DPRINT1("USBPORT_RootHubSCE: RH_GetHubStatus failed\n");
|
|
return RH_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBPORT_RootHubEndpointWorker(IN PUSBPORT_ENDPOINT Endpoint)
|
|
{
|
|
PDEVICE_OBJECT FdoDevice;
|
|
PUSBPORT_DEVICE_EXTENSION FdoExtension;
|
|
PUSBPORT_REGISTRATION_PACKET Packet;
|
|
PUSBPORT_TRANSFER Transfer;
|
|
RHSTATUS RHStatus;
|
|
USBD_STATUS USBDStatus;
|
|
KIRQL OldIrql;
|
|
|
|
DPRINT_CORE("USBPORT_RootHubEndpointWorker: Endpoint - %p\n", Endpoint);
|
|
|
|
FdoDevice = Endpoint->FdoDevice;
|
|
FdoExtension = FdoDevice->DeviceExtension;
|
|
Packet = &FdoExtension->MiniPortInterface->Packet;
|
|
|
|
KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
|
|
if (!(FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND))
|
|
{
|
|
Packet->CheckController(FdoExtension->MiniPortExt);
|
|
}
|
|
KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
|
|
|
|
KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql);
|
|
|
|
Transfer = CONTAINING_RECORD(Endpoint->TransferList.Flink,
|
|
USBPORT_TRANSFER,
|
|
TransferLink);
|
|
|
|
if (IsListEmpty(&Endpoint->TransferList) ||
|
|
Endpoint->TransferList.Flink == NULL ||
|
|
!Transfer)
|
|
{
|
|
if (Endpoint->StateLast == USBPORT_ENDPOINT_REMOVE)
|
|
{
|
|
ExInterlockedInsertTailList(&FdoExtension->EndpointClosedList,
|
|
&Endpoint->CloseLink,
|
|
&FdoExtension->EndpointClosedSpinLock);
|
|
}
|
|
|
|
KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
|
|
|
|
USBPORT_FlushCancelList(Endpoint);
|
|
return;
|
|
}
|
|
|
|
if (Transfer->Flags & (TRANSFER_FLAG_ABORTED | TRANSFER_FLAG_CANCELED))
|
|
{
|
|
RemoveEntryList(&Transfer->TransferLink);
|
|
InsertTailList(&Endpoint->CancelList, &Transfer->TransferLink);
|
|
|
|
KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
|
|
USBPORT_FlushCancelList(Endpoint);
|
|
return;
|
|
}
|
|
|
|
KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
|
|
|
|
if (Endpoint->EndpointProperties.TransferType == USBPORT_TRANSFER_TYPE_CONTROL)
|
|
RHStatus = USBPORT_RootHubEndpoint0(Transfer);
|
|
else
|
|
RHStatus = USBPORT_RootHubSCE(Transfer);
|
|
|
|
if (RHStatus != RH_STATUS_NO_CHANGES)
|
|
{
|
|
if (RHStatus == RH_STATUS_SUCCESS)
|
|
USBDStatus = USBD_STATUS_SUCCESS;
|
|
else
|
|
USBDStatus = USBD_STATUS_STALL_PID;
|
|
|
|
KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql);
|
|
USBPORT_QueueDoneTransfer(Transfer, USBDStatus);
|
|
KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
|
|
|
|
USBPORT_FlushCancelList(Endpoint);
|
|
return;
|
|
}
|
|
|
|
USBPORT_FlushCancelList(Endpoint);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
USBPORT_RootHubCreateDevice(IN PDEVICE_OBJECT FdoDevice,
|
|
IN PDEVICE_OBJECT PdoDevice)
|
|
{
|
|
PUSBPORT_DEVICE_EXTENSION FdoExtension;
|
|
PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
|
|
PUSBPORT_REGISTRATION_PACKET Packet;
|
|
PUSBPORT_DEVICE_HANDLE DeviceHandle;
|
|
USBPORT_ROOT_HUB_DATA RootHubData;
|
|
ULONG NumMaskByte;
|
|
ULONG DescriptorsLength;
|
|
PUSBPORT_RH_DESCRIPTORS Descriptors;
|
|
PUSB_DEVICE_DESCRIPTOR RH_DeviceDescriptor;
|
|
PUSB_CONFIGURATION_DESCRIPTOR RH_ConfigurationDescriptor;
|
|
PUSB_INTERFACE_DESCRIPTOR RH_InterfaceDescriptor;
|
|
PUSB_ENDPOINT_DESCRIPTOR RH_EndPointDescriptor;
|
|
PUSB_HUB_DESCRIPTOR RH_HubDescriptor;
|
|
ULONG ix;
|
|
PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("USBPORT_RootHubCreateDevice: FdoDevice - %p, PdoDevice - %p\n",
|
|
FdoDevice,
|
|
PdoDevice);
|
|
|
|
FdoExtension = FdoDevice->DeviceExtension;
|
|
PdoExtension = PdoDevice->DeviceExtension;
|
|
Packet = &FdoExtension->MiniPortInterface->Packet;
|
|
|
|
DeviceHandle = &PdoExtension->DeviceHandle;
|
|
USBPORT_AddDeviceHandle(FdoDevice, DeviceHandle);
|
|
|
|
InitializeListHead(&DeviceHandle->PipeHandleList);
|
|
|
|
DeviceHandle->IsRootHub = TRUE;
|
|
DeviceHandle->DeviceSpeed = UsbFullSpeed;
|
|
DeviceHandle->Flags = DEVICE_HANDLE_FLAG_ROOTHUB;
|
|
|
|
RtlZeroMemory(&RootHubData, sizeof(RootHubData));
|
|
|
|
Packet->RH_GetRootHubData(FdoExtension->MiniPortExt, &RootHubData);
|
|
|
|
ASSERT(RootHubData.NumberOfPorts != 0);
|
|
NumMaskByte = (RootHubData.NumberOfPorts - 1) / 8 + 1;
|
|
|
|
DescriptorsLength = sizeof(USB_DEVICE_DESCRIPTOR) +
|
|
sizeof(USB_CONFIGURATION_DESCRIPTOR) +
|
|
sizeof(USB_INTERFACE_DESCRIPTOR) +
|
|
sizeof(USB_ENDPOINT_DESCRIPTOR) +
|
|
(sizeof(USB_HUB_DESCRIPTOR) + 2 * NumMaskByte);
|
|
|
|
Descriptors = ExAllocatePoolWithTag(NonPagedPool,
|
|
DescriptorsLength,
|
|
USB_PORT_TAG);
|
|
|
|
if (Descriptors)
|
|
{
|
|
RtlZeroMemory(Descriptors, DescriptorsLength);
|
|
|
|
PdoExtension->RootHubDescriptors = Descriptors;
|
|
|
|
RH_DeviceDescriptor = &PdoExtension->RootHubDescriptors->DeviceDescriptor;
|
|
|
|
RH_DeviceDescriptor->bLength = sizeof(USB_DEVICE_DESCRIPTOR);
|
|
RH_DeviceDescriptor->bDescriptorType = USB_DEVICE_DESCRIPTOR_TYPE;
|
|
RH_DeviceDescriptor->bcdUSB = 0x100;
|
|
RH_DeviceDescriptor->bDeviceClass = USB_DEVICE_CLASS_HUB;
|
|
RH_DeviceDescriptor->bDeviceSubClass = 0x01;
|
|
RH_DeviceDescriptor->bDeviceProtocol = 0x00;
|
|
RH_DeviceDescriptor->bMaxPacketSize0 = 0x08;
|
|
RH_DeviceDescriptor->idVendor = FdoExtension->VendorID;
|
|
RH_DeviceDescriptor->idProduct = FdoExtension->DeviceID;
|
|
RH_DeviceDescriptor->bcdDevice = FdoExtension->RevisionID;
|
|
RH_DeviceDescriptor->iManufacturer = 0x00;
|
|
RH_DeviceDescriptor->iProduct = 0x00;
|
|
RH_DeviceDescriptor->iSerialNumber = 0x00;
|
|
RH_DeviceDescriptor->bNumConfigurations = 0x01;
|
|
|
|
RH_ConfigurationDescriptor = &PdoExtension->RootHubDescriptors->ConfigDescriptor;
|
|
|
|
RH_ConfigurationDescriptor->bLength = sizeof(USB_CONFIGURATION_DESCRIPTOR);
|
|
RH_ConfigurationDescriptor->bDescriptorType = USB_CONFIGURATION_DESCRIPTOR_TYPE;
|
|
|
|
RH_ConfigurationDescriptor->wTotalLength = sizeof(USB_CONFIGURATION_DESCRIPTOR) +
|
|
sizeof(USB_INTERFACE_DESCRIPTOR) +
|
|
sizeof(USB_ENDPOINT_DESCRIPTOR);
|
|
|
|
RH_ConfigurationDescriptor->bNumInterfaces = 0x01;
|
|
RH_ConfigurationDescriptor->bConfigurationValue = 0x01;
|
|
RH_ConfigurationDescriptor->iConfiguration = 0x00;
|
|
RH_ConfigurationDescriptor->bmAttributes = USB_CONFIG_SELF_POWERED;
|
|
RH_ConfigurationDescriptor->MaxPower = 0x00;
|
|
|
|
RH_InterfaceDescriptor = &PdoExtension->RootHubDescriptors->InterfaceDescriptor;
|
|
|
|
RH_InterfaceDescriptor->bLength = sizeof(USB_INTERFACE_DESCRIPTOR);
|
|
RH_InterfaceDescriptor->bDescriptorType = USB_INTERFACE_DESCRIPTOR_TYPE;
|
|
RH_InterfaceDescriptor->bInterfaceNumber = 0x00;
|
|
RH_InterfaceDescriptor->bAlternateSetting = 0x00;
|
|
RH_InterfaceDescriptor->bNumEndpoints = 0x01;
|
|
RH_InterfaceDescriptor->bInterfaceClass = USB_DEVICE_CLASS_HUB;
|
|
RH_InterfaceDescriptor->bInterfaceSubClass = 0x01;
|
|
RH_InterfaceDescriptor->bInterfaceProtocol = 0x00;
|
|
RH_InterfaceDescriptor->iInterface = 0x00;
|
|
|
|
RH_EndPointDescriptor = &PdoExtension->RootHubDescriptors->EndPointDescriptor;
|
|
|
|
RH_EndPointDescriptor->bLength = sizeof(USB_ENDPOINT_DESCRIPTOR);
|
|
RH_EndPointDescriptor->bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE;
|
|
RH_EndPointDescriptor->bEndpointAddress = 0x81;
|
|
RH_EndPointDescriptor->bmAttributes = USB_ENDPOINT_TYPE_INTERRUPT; // SCE endpoint
|
|
RH_EndPointDescriptor->wMaxPacketSize = 0x0008;
|
|
RH_EndPointDescriptor->bInterval = 0x0C; // 12 msec
|
|
|
|
RH_HubDescriptor = &PdoExtension->RootHubDescriptors->Descriptor;
|
|
|
|
RH_HubDescriptor->bDescriptorLength = FIELD_OFFSET(USB_HUB_DESCRIPTOR, bRemoveAndPowerMask) + 2 * NumMaskByte;
|
|
|
|
if (Packet->MiniPortVersion == USB_MINIPORT_VERSION_OHCI ||
|
|
Packet->MiniPortVersion == USB_MINIPORT_VERSION_UHCI ||
|
|
Packet->MiniPortVersion == USB_MINIPORT_VERSION_EHCI)
|
|
{
|
|
RH_HubDescriptor->bDescriptorType = USB_20_HUB_DESCRIPTOR_TYPE;
|
|
}
|
|
else if (Packet->MiniPortVersion == USB_MINIPORT_VERSION_XHCI)
|
|
{
|
|
RH_HubDescriptor->bDescriptorType = USB_30_HUB_DESCRIPTOR_TYPE;
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("USBPORT_RootHubCreateDevice: Unknown MiniPortVersion - %x\n",
|
|
Packet->MiniPortVersion);
|
|
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
RH_HubDescriptor->bNumberOfPorts = RootHubData.NumberOfPorts;
|
|
RH_HubDescriptor->wHubCharacteristics = RootHubData.HubCharacteristics.AsUSHORT;
|
|
RH_HubDescriptor->bPowerOnToPowerGood = RootHubData.PowerOnToPowerGood;
|
|
RH_HubDescriptor->bHubControlCurrent = RootHubData.HubControlCurrent;
|
|
|
|
for (ix = 0; ix < NumMaskByte; ix += 2)
|
|
{
|
|
RH_HubDescriptor->bRemoveAndPowerMask[ix] = 0;
|
|
RH_HubDescriptor->bRemoveAndPowerMask[ix + 1] = -1;
|
|
}
|
|
|
|
EndpointDescriptor = &DeviceHandle->PipeHandle.EndpointDescriptor;
|
|
|
|
EndpointDescriptor->bLength = sizeof(USB_ENDPOINT_DESCRIPTOR);
|
|
EndpointDescriptor->bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE;
|
|
EndpointDescriptor->bEndpointAddress = 0x00;
|
|
EndpointDescriptor->bmAttributes = USB_ENDPOINT_TYPE_CONTROL;
|
|
EndpointDescriptor->wMaxPacketSize = 0x0040;
|
|
EndpointDescriptor->bInterval = 0x00;
|
|
|
|
Status = USBPORT_OpenPipe(FdoDevice,
|
|
DeviceHandle,
|
|
&DeviceHandle->PipeHandle,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
USBPORT_InvalidateRootHub(PVOID MiniPortExtension)
|
|
{
|
|
PUSBPORT_DEVICE_EXTENSION FdoExtension;
|
|
PDEVICE_OBJECT FdoDevice;
|
|
PDEVICE_OBJECT PdoDevice;
|
|
PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
|
|
PUSBPORT_ENDPOINT Endpoint = NULL;
|
|
|
|
DPRINT("USBPORT_InvalidateRootHub ... \n");
|
|
|
|
FdoExtension = (PUSBPORT_DEVICE_EXTENSION)((ULONG_PTR)MiniPortExtension -
|
|
sizeof(USBPORT_DEVICE_EXTENSION));
|
|
|
|
FdoDevice = FdoExtension->CommonExtension.SelfDevice;
|
|
|
|
if (FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND &&
|
|
FdoExtension->Flags & USBPORT_FLAG_HC_WAKE_SUPPORT &&
|
|
FdoExtension->MiniPortFlags & USBPORT_MPFLAG_SUSPENDED &&
|
|
FdoExtension->TimerFlags & USBPORT_TMFLAG_WAKE)
|
|
{
|
|
USBPORT_HcQueueWakeDpc(FdoDevice);
|
|
return 0;
|
|
}
|
|
|
|
FdoExtension->MiniPortInterface->Packet.RH_DisableIrq(FdoExtension->MiniPortExt);
|
|
|
|
PdoDevice = FdoExtension->RootHubPdo;
|
|
|
|
if (PdoDevice)
|
|
{
|
|
PdoExtension = PdoDevice->DeviceExtension;
|
|
Endpoint = PdoExtension->Endpoint;
|
|
|
|
if (Endpoint)
|
|
{
|
|
USBPORT_InvalidateEndpointHandler(FdoDevice,
|
|
PdoExtension->Endpoint,
|
|
INVALIDATE_ENDPOINT_WORKER_THREAD);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBPORT_RootHubPowerAndChirpAllCcPorts(IN PDEVICE_OBJECT FdoDevice)
|
|
{
|
|
PUSBPORT_DEVICE_EXTENSION FdoExtension;
|
|
PUSBPORT_REGISTRATION_PACKET Packet;
|
|
USBPORT_ROOT_HUB_DATA RootHubData;
|
|
ULONG Port;
|
|
PDEVICE_RELATIONS CompanionControllersList;
|
|
PUSBPORT_DEVICE_EXTENSION CompanionFdoExtension;
|
|
PUSBPORT_REGISTRATION_PACKET CompanionPacket;
|
|
ULONG CompanionPorts;
|
|
ULONG NumController;
|
|
PDEVICE_OBJECT * Entry;
|
|
ULONG NumPorts;
|
|
|
|
DPRINT("USBPORT_RootHub_PowerAndChirpAllCcPorts: FdoDevice - %p\n",
|
|
FdoDevice);
|
|
|
|
FdoExtension = FdoDevice->DeviceExtension;
|
|
|
|
Packet = &FdoExtension->MiniPortInterface->Packet;
|
|
|
|
RtlZeroMemory(&RootHubData, sizeof(RootHubData));
|
|
|
|
Packet->RH_GetRootHubData(FdoExtension->MiniPortExt,
|
|
&RootHubData);
|
|
|
|
NumPorts = RootHubData.NumberOfPorts;
|
|
|
|
for (Port = 1; Port <= NumPorts; ++Port)
|
|
{
|
|
Packet->RH_SetFeaturePortPower(FdoExtension->MiniPortExt, Port);
|
|
}
|
|
|
|
USBPORT_Wait(FdoDevice, 10);
|
|
|
|
CompanionControllersList = USBPORT_FindCompanionControllers(FdoDevice,
|
|
FALSE,
|
|
TRUE);
|
|
|
|
if (CompanionControllersList)
|
|
{
|
|
Entry = &CompanionControllersList->Objects[0];
|
|
|
|
for (NumController = 0;
|
|
NumController < CompanionControllersList->Count;
|
|
NumController++)
|
|
{
|
|
CompanionPacket = &FdoExtension->MiniPortInterface->Packet;
|
|
|
|
CompanionFdoExtension = (*Entry)->DeviceExtension;
|
|
|
|
CompanionPacket->RH_GetRootHubData(CompanionFdoExtension->MiniPortExt,
|
|
&RootHubData);
|
|
|
|
CompanionPorts = RootHubData.NumberOfPorts;
|
|
|
|
for (Port = 1; Port <= CompanionPorts; ++Port)
|
|
{
|
|
CompanionPacket->RH_SetFeaturePortPower(CompanionFdoExtension->MiniPortExt,
|
|
Port);
|
|
}
|
|
|
|
++Entry;
|
|
}
|
|
|
|
ExFreePoolWithTag(CompanionControllersList, USB_PORT_TAG);
|
|
}
|
|
|
|
USBPORT_Wait(FdoDevice, 100);
|
|
|
|
for (Port = 1; Port <= NumPorts; ++Port)
|
|
{
|
|
if (FdoExtension->MiniPortInterface->Version < 200)
|
|
{
|
|
break;
|
|
}
|
|
|
|
InterlockedIncrement((PLONG)&FdoExtension->ChirpRootPortLock);
|
|
Packet->RH_ChirpRootPort(FdoExtension->MiniPortExt, Port);
|
|
InterlockedDecrement((PLONG)&FdoExtension->ChirpRootPortLock);
|
|
}
|
|
}
|