windows-nt/Source/XPSP1/NT/drivers/wdm/usb/driver/hub.pnp/busif.c
2020-09-26 16:20:57 +08:00

1416 lines
34 KiB
C

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
busif.c
Abstract:
Links to new usb 2.0 stack
The effect is that when running on the USB2 stack the hub
is no longer depenent on the port driver archetecture or
USBD for the PnP services:
CreateDevice
InitailiazeDevice
RemoveDevice
Environment:
kernel mode only
Notes:
Revision History:
10-29-95 : created
--*/
#include <wdm.h>
#ifdef WMI_SUPPORT
#include <wmilib.h>
#endif /* WMI_SUPPORT */
#include "usbhub.h"
#ifdef USB2
NTSTATUS
USBD_DeferIrpCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This routine is called when the port driver completes an IRP.
Arguments:
DeviceObject - Pointer to the device object for the class device.
Irp - Irp completed.
Context - Driver defined context.
Return Value:
The function value is the final status from the operation.
--*/
{
PKEVENT event = Context;
KeSetEvent(event,
1,
FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
USBHUB_GetBusInterface(
IN PDEVICE_OBJECT RootHubPdo,
IN PUSB_HUB_BUS_INTERFACE BusInterface
)
/*++
Routine Description:
Arguments:
Return Value:
returns success if USB2 stack
--*/
{
PIO_STACK_LOCATION nextStack;
PIRP irp;
NTSTATUS ntStatus;
KEVENT event;
irp = IoAllocateIrp(RootHubPdo->StackSize, FALSE);
if (!irp) {
return STATUS_UNSUCCESSFUL;
}
// All PnP IRP's need the Status field initialized to STATUS_NOT_SUPPORTED.
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoSetCompletionRoutine(irp,
USBD_DeferIrpCompletion,
&event,
TRUE,
TRUE,
TRUE);
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
nextStack->MajorFunction= IRP_MJ_PNP;
nextStack->MinorFunction= IRP_MN_QUERY_INTERFACE;
// init busif
//busIf->
nextStack->Parameters.QueryInterface.Interface = (PINTERFACE) BusInterface;
nextStack->Parameters.QueryInterface.InterfaceSpecificData =
RootHubPdo;
nextStack->Parameters.QueryInterface.InterfaceType =
&USB_BUS_INTERFACE_HUB_GUID;
nextStack->Parameters.QueryInterface.Size =
sizeof(*BusInterface);
nextStack->Parameters.QueryInterface.Version =
HUB_BUSIF_VERSION;
ntStatus = IoCallDriver(RootHubPdo,
irp);
if (ntStatus == STATUS_PENDING) {
KeWaitForSingleObject(
&event,
Suspended,
KernelMode,
FALSE,
NULL);
ntStatus = irp->IoStatus.Status;
}
if (NT_SUCCESS(ntStatus)) {
// we have a bus interface
ASSERT(BusInterface->Version == HUB_BUSIF_VERSION);
ASSERT(BusInterface->Size == sizeof(*BusInterface));
}
IoFreeIrp(irp);
// get the bus interface
return ntStatus;
}
NTSTATUS
USBD_CreateDeviceEx(
IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
IN OUT PUSB_DEVICE_HANDLE *DeviceData,
IN PDEVICE_OBJECT RootHubPdo,
IN ULONG MaxPacketSize_Endpoint0,
IN OUT PULONG DeviceHackFlags,
IN USHORT PortStatus,
IN USHORT PortNumber
)
/*++
Routine Description:
Arguments:
Return Value:
NT status code.
--*/
{
NTSTATUS ntStatus;
PUSB_DEVICE_HANDLE hubDeviceHandle;
PUSB_HUB_BUS_INTERFACE busIf;
// note no device extension for USBD if running on
// usb 2 stack
// If the HUB was ever reset through USBH_ResetDevice, the HUB PDO
// DeviceExtensionPort->DeviceData could have changed. Instead of trying
// to propagate a change in the HUB PDO DeviceExtensionPort->DeviceData
// through to the HUB FDO DeviceExtensionHub when a change happens, let's
// just retrieve the HubDeviceHandle every time we use it (which is only
// in this routine) instead of keeping a cached copy.
//
hubDeviceHandle =
USBH_SyncGetDeviceHandle(DeviceExtensionHub->TopOfStackDeviceObject);
busIf = &DeviceExtensionHub->BusIf;
if (!busIf->CreateUsbDevice) {
ntStatus = STATUS_NOT_IMPLEMENTED;
USBH_ASSERT(FALSE);
} else {
ntStatus = busIf->CreateUsbDevice(busIf->BusContext,
DeviceData,
hubDeviceHandle,
PortStatus,
// ttnumber
PortNumber);
}
// get the hack flags
return ntStatus;
}
NTSTATUS
USBD_InitUsb2Hub(
IN PDEVICE_EXTENSION_HUB DeviceExtensionHub
)
/*++
Routine Description:
Arguments:
Return Value:
NT status code.
--*/
{
NTSTATUS ntStatus;
PUSB_DEVICE_HANDLE hubDeviceHandle;
PUSB_HUB_BUS_INTERFACE busIf;
ULONG ttCount = 1;
// note no device extension for USBD if running on
// usb 2 stack
// should only call this on a usb 2.0 hub
USBH_ASSERT(DeviceExtensionHub->HubFlags & HUBFLAG_USB20_HUB);
if (DeviceExtensionHub->HubFlags & HUBFLAG_USB20_MULTI_TT) {
PUSB_HUB_DESCRIPTOR hubDescriptor;
hubDescriptor = DeviceExtensionHub->HubDescriptor;
USBH_ASSERT(NULL != hubDescriptor);
ttCount = hubDescriptor->bNumberOfPorts;
}
// If the HUB was ever reset through USBH_ResetDevice, the HUB PDO
// DeviceExtensionPort->DeviceData could have changed. Instead of trying
// to propagate a change in the HUB PDO DeviceExtensionPort->DeviceData
// through to the HUB FDO DeviceExtensionHub when a change happens, let's
// just retrieve the HubDeviceHandle every time we use it (which is only
// in this routine) instead of keeping a cached copy.
//
hubDeviceHandle =
USBH_SyncGetDeviceHandle(DeviceExtensionHub->TopOfStackDeviceObject);
busIf = &DeviceExtensionHub->BusIf;
if (!busIf->Initialize20Hub) {
ntStatus = STATUS_NOT_IMPLEMENTED;
USBH_ASSERT(FALSE);
} else {
ntStatus = busIf->Initialize20Hub(busIf->BusContext,
hubDeviceHandle,
ttCount);
}
return ntStatus;
}
NTSTATUS
USBD_InitializeDeviceEx(
IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
IN PUSB_DEVICE_HANDLE DeviceData,
IN PDEVICE_OBJECT RootHubPdo,
IN OUT PUSB_DEVICE_DESCRIPTOR DeviceDescriptor,
IN ULONG DeviceDescriptorLength,
IN OUT PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor,
IN ULONG ConfigDescriptorLength
)
/*++
Routine Description:
Arguments:
Return Value:
NT status code.
--*/
{
NTSTATUS ntStatus;
PUSB_HUB_BUS_INTERFACE busIf;
busIf = &DeviceExtensionHub->BusIf;
if (!busIf->InitializeUsbDevice || !busIf->GetUsbDescriptors) {
ntStatus = STATUS_NOT_IMPLEMENTED;
USBH_ASSERT(FALSE);
} else {
ntStatus = busIf->InitializeUsbDevice(busIf->BusContext,
DeviceData);
}
// if successful fetch the descriptors
if (NT_SUCCESS(ntStatus)) {
ntStatus = busIf->GetUsbDescriptors(busIf->BusContext,
DeviceData,
(PUCHAR) DeviceDescriptor,
&DeviceDescriptorLength,
(PUCHAR) ConfigDescriptor,
&ConfigDescriptorLength);
}
return ntStatus;
}
NTSTATUS
USBD_RemoveDeviceEx(
IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
IN PUSB_DEVICE_HANDLE DeviceData,
IN PDEVICE_OBJECT RootHubPdo,
IN ULONG Flags
)
/*++
Routine Description:
Arguments:
Return Value:
NT status code.
--*/
{
NTSTATUS ntStatus;
PUSB_HUB_BUS_INTERFACE busIf;
busIf = &DeviceExtensionHub->BusIf;
// flags are currently not used by usb2 stack
if (!busIf->RemoveUsbDevice) {
ntStatus = STATUS_NOT_IMPLEMENTED;
USBH_ASSERT(FALSE);
} else {
ntStatus = busIf->RemoveUsbDevice(busIf->BusContext,
DeviceData,
Flags);
}
return ntStatus;
}
NTSTATUS
USBD_GetDeviceInformationEx(
IN PDEVICE_EXTENSION_PORT DeviceExtensionPort,
IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
IN PUSB_NODE_CONNECTION_INFORMATION_EX DeviceInformation,
IN ULONG DeviceInformationLength,
IN PUSB_DEVICE_HANDLE DeviceData
)
/*
This function maps the new port service on to the
old hub api.
*/
{
NTSTATUS ntStatus;
PUSB_HUB_BUS_INTERFACE busIf;
ULONG length, lengthCopied;
ULONG i, need;
PUSB_DEVICE_INFORMATION_0 level_0 = NULL;
PUSB_NODE_CONNECTION_INFORMATION_EX localDeviceInfo;
busIf = &DeviceExtensionHub->BusIf;
if (!busIf->QueryDeviceInformation) {
ntStatus = STATUS_NOT_IMPLEMENTED;
USBH_ASSERT(FALSE);
return ntStatus;
}
// call the new API and map the data to the old format
// USBH_KdPrint((0, "'Warning: Caller is using old style IOCTL.\n"));
// USBH_KdPrint((0, "'If this is a WinOS component or Test Application please fix it.\n"));
// TEST_TRAP();
length = sizeof(*level_0);
do {
ntStatus = STATUS_SUCCESS;
level_0 = UsbhExAllocatePool(PagedPool, length);
if (level_0 == NULL) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(ntStatus)) {
level_0->InformationLevel = 0;
ntStatus = busIf->QueryDeviceInformation(busIf->BusContext,
DeviceData,
level_0,
length,
&lengthCopied);
if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
length = level_0->ActualLength;
UsbhExFreePool(level_0);
}
}
} while (ntStatus == STATUS_BUFFER_TOO_SMALL);
// do we have enough to satisfiy the API?
need = level_0->NumberOfOpenPipes * sizeof(USB_PIPE_INFO) +
sizeof(USB_NODE_CONNECTION_INFORMATION);
localDeviceInfo = UsbhExAllocatePool(PagedPool, need);
if (localDeviceInfo == NULL) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(ntStatus)) {
USBH_KdPrint((2, "'level_0 %x\n", level_0 ));
// BUGBUG
// DeviceInformation has some preset fields, save them
// in the loacl info buffer
localDeviceInfo->DeviceIsHub =
DeviceInformation->DeviceIsHub;
localDeviceInfo->ConnectionIndex =
DeviceInformation->ConnectionIndex;
localDeviceInfo->ConnectionStatus =
DeviceInformation->ConnectionStatus;
localDeviceInfo->DeviceIsHub =
DeviceInformation->DeviceIsHub;
// map to the old format
localDeviceInfo->DeviceDescriptor =
level_0->DeviceDescriptor;
localDeviceInfo->CurrentConfigurationValue =
level_0->CurrentConfigurationValue;
localDeviceInfo->Speed = (UCHAR) level_0->DeviceSpeed;
// draw this from our extension
localDeviceInfo->DeviceIsHub =
(DeviceExtensionPort->PortPdoFlags & PORTPDO_DEVICE_IS_HUB)
? TRUE : FALSE;
localDeviceInfo->DeviceAddress =
level_0->DeviceAddress;
localDeviceInfo->NumberOfOpenPipes =
level_0->NumberOfOpenPipes;
// BUGBUG - hardcode to 'connected' ?
// is this used by callers?
// DeviceInformation->ConnectionStatus =
// DeviceConnected;
for (i=0; i< level_0->NumberOfOpenPipes; i++) {
localDeviceInfo->PipeList[i].EndpointDescriptor =
level_0->PipeList[i].EndpointDescriptor;
localDeviceInfo->PipeList[i].ScheduleOffset =
level_0->PipeList[i].ScheduleOffset;
}
}
if (level_0 != NULL) {
UsbhExFreePool(level_0);
level_0 = NULL;
}
if (localDeviceInfo != NULL) {
if (need > DeviceInformationLength) {
// return what we can
RtlCopyMemory(DeviceInformation,
localDeviceInfo,
DeviceInformationLength);
ntStatus = STATUS_BUFFER_TOO_SMALL;
} else {
// return what is appropriate
RtlCopyMemory(DeviceInformation,
localDeviceInfo ,
need);
}
UsbhExFreePool(localDeviceInfo);
localDeviceInfo = NULL;
}
return ntStatus;
}
//ULONG
//USBD_GetHackFlags(
// IN PDEVICE_EXTENSION_HUB DeviceExtensionHub
// )
//{
// NTSTATUS ntStatus;
// ULONG flags;
// PUSB_HUB_BUS_INTERFACE busIf;
//
// busIf = &DeviceExtensionHub->BusIf;
//
// // flags are currently not used by usb2 stack
//
// ntStatus = busIf->GetPortHackFlags(busIf->BusContext, &flags);
//
// return flags;
//}
NTSTATUS
USBD_MakePdoNameEx(
IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
IN OUT PUNICODE_STRING PdoNameUnicodeString,
IN ULONG Index
)
/*++
Routine Description:
This service Creates a name for a PDO created by the HUB
Arguments:
Return Value:
--*/
{
PWCHAR nameBuffer = NULL;
WCHAR rootName[] = L"\\Device\\USBPDO-";
UNICODE_STRING idUnicodeString;
WCHAR buffer[32];
NTSTATUS ntStatus = STATUS_SUCCESS;
USHORT length;
length = sizeof(buffer)+sizeof(rootName);
//
// use ExAllocate because client will free it
//
nameBuffer = UsbhExAllocatePool(PagedPool, length);
if (nameBuffer) {
RtlCopyMemory(nameBuffer, rootName, sizeof(rootName));
RtlInitUnicodeString(PdoNameUnicodeString,
nameBuffer);
PdoNameUnicodeString->MaximumLength =
length;
RtlInitUnicodeString(&idUnicodeString,
&buffer[0]);
idUnicodeString.MaximumLength =
sizeof(buffer);
ntStatus = RtlIntegerToUnicodeString(
Index,
10,
&idUnicodeString);
if (NT_SUCCESS(ntStatus)) {
ntStatus = RtlAppendUnicodeStringToString(PdoNameUnicodeString,
&idUnicodeString);
}
USBH_KdPrint((2, "'USBD_MakeNodeName string = %x\n",
PdoNameUnicodeString));
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
if (!NT_SUCCESS(ntStatus) && nameBuffer) {
UsbhExFreePool(nameBuffer);
}
return ntStatus;
}
NTSTATUS
USBD_RestoreDeviceEx(
IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
IN OUT PUSB_DEVICE_HANDLE OldDeviceData,
IN OUT PUSB_DEVICE_HANDLE NewDeviceData,
IN PDEVICE_OBJECT RootHubPdo
)
{
NTSTATUS ntStatus;
PUSB_HUB_BUS_INTERFACE busIf;
busIf = &DeviceExtensionHub->BusIf;
if (!busIf->RestoreUsbDevice) {
ntStatus = STATUS_NOT_IMPLEMENTED;
USBH_ASSERT(FALSE);
} else {
ntStatus = busIf->RestoreUsbDevice(busIf->BusContext,
OldDeviceData,
NewDeviceData);
}
return ntStatus;
}
NTSTATUS
USBD_QuerySelectiveSuspendEnabled(
IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
IN OUT PBOOLEAN SelectiveSuspendEnabled
)
{
NTSTATUS ntStatus;
PUSB_HUB_BUS_INTERFACE busIf;
USB_CONTROLLER_INFORMATION_0 controllerInfo;
ULONG dataLen = 0;
controllerInfo.InformationLevel = 0;
busIf = &DeviceExtensionHub->BusIf;
if (!busIf->GetControllerInformation) {
ntStatus = STATUS_NOT_IMPLEMENTED;
USBH_ASSERT(FALSE);
} else {
ntStatus = busIf->GetControllerInformation(busIf->BusContext,
&controllerInfo,
sizeof(controllerInfo),
&dataLen);
}
USBH_ASSERT(dataLen);
if (dataLen) {
*SelectiveSuspendEnabled = controllerInfo.SelectiveSuspendEnabled;
}
return ntStatus;
}
VOID
USBHUB_RhHubCallBack(
PDEVICE_EXTENSION_HUB DeviceExtensionHub
)
{
DeviceExtensionHub->HubFlags |= HUBFLAG_OK_TO_ENUMERATE;
// if irp is null'ed out then it must have been stopped or removed before
// our callback we just check for NULL here instead of the dozen or so
// flags the hub has.
if (DeviceExtensionHub->Irp != NULL) {
USBH_SubmitInterruptTransfer(DeviceExtensionHub);
USBH_IoInvalidateDeviceRelations(DeviceExtensionHub->PhysicalDeviceObject,
BusRelations);
}
}
NTSTATUS
USBD_RegisterRhHubCallBack(
IN PDEVICE_EXTENSION_HUB DeviceExtensionHub
)
{
NTSTATUS ntStatus;
PUSB_HUB_BUS_INTERFACE busIf;
busIf = &DeviceExtensionHub->BusIf;
if (!busIf->RootHubInitNotification) {
ntStatus = STATUS_NOT_IMPLEMENTED;
USBH_ASSERT(FALSE);
} else {
ntStatus = busIf->RootHubInitNotification(busIf->BusContext,
DeviceExtensionHub,
USBHUB_RhHubCallBack);
}
return ntStatus;
}
NTSTATUS
USBD_UnRegisterRhHubCallBack(
IN PDEVICE_EXTENSION_HUB DeviceExtensionHub
)
{
NTSTATUS ntStatus;
PUSB_HUB_BUS_INTERFACE busIf;
busIf = &DeviceExtensionHub->BusIf;
if (!busIf->RootHubInitNotification) {
ntStatus = STATUS_NOT_IMPLEMENTED;
USBH_ASSERT(FALSE);
} else {
ntStatus = busIf->RootHubInitNotification(busIf->BusContext,
NULL,
NULL);
}
return ntStatus;
}
NTSTATUS
USBD_SetSelectiveSuspendEnabled(
IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
IN BOOLEAN SelectiveSuspendEnabled
)
{
NTSTATUS ntStatus;
PUSB_HUB_BUS_INTERFACE busIf;
busIf = &DeviceExtensionHub->BusIf;
if (!busIf->ControllerSelectiveSuspend) {
ntStatus = STATUS_NOT_IMPLEMENTED;
USBH_ASSERT(FALSE);
} else {
ntStatus = busIf->ControllerSelectiveSuspend(busIf->BusContext,
SelectiveSuspendEnabled);
}
return ntStatus;
}
BOOLEAN
USBH_ValidateConfigurationDescriptor(
PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
USBD_STATUS *UsbdStatus
)
/*++
Routine Description:
Validate a configuration descriptor
Arguments:
ConfigurationDescriptor -
Urb -
Return Value:
TRUE if it looks valid
--*/
{
BOOLEAN valid = TRUE;
if (ConfigurationDescriptor->bDescriptorType !=
USB_CONFIGURATION_DESCRIPTOR_TYPE) {
valid = FALSE;
*UsbdStatus = USBD_STATUS_INAVLID_CONFIGURATION_DESCRIPTOR;
}
// USB 1.1, Section 9.5 Descriptors:
//
// If a descriptor returns with a value in its length field that is
// less than defined by this specification, the descriptor is invalid and
// should be rejected by the host. If the descriptor returns with a
// value in its length field that is greater than defined by this
// specification, the extra bytes are ignored by the host, but the next
// descriptor is located using the length returned rather than the length
// expected.
if (ConfigurationDescriptor->bLength <
sizeof(USB_CONFIGURATION_DESCRIPTOR)) {
valid = FALSE;
*UsbdStatus = USBD_STATUS_INAVLID_CONFIGURATION_DESCRIPTOR;
}
return valid;
}
NTSTATUS
USBHUB_GetBusInterfaceUSBDI(
IN PDEVICE_OBJECT HubPdo,
IN PUSB_BUS_INTERFACE_USBDI_V2 BusInterface
)
/*++
Routine Description:
Arguments:
Return Value:
returns success if USB2 stack
--*/
{
PIO_STACK_LOCATION nextStack;
PIRP irp;
NTSTATUS ntStatus;
KEVENT event;
irp = IoAllocateIrp(HubPdo->StackSize, FALSE);
if (!irp) {
return STATUS_UNSUCCESSFUL;
}
// All PnP IRP's need the Status field initialized to STATUS_NOT_SUPPORTED.
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoSetCompletionRoutine(irp,
USBD_DeferIrpCompletion,
&event,
TRUE,
TRUE,
TRUE);
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
nextStack->MajorFunction= IRP_MJ_PNP;
nextStack->MinorFunction= IRP_MN_QUERY_INTERFACE;
// init busif
//busIf->
nextStack->Parameters.QueryInterface.Interface = (PINTERFACE) BusInterface;
// this is the device handle, filled in as we pass down the
// stack
nextStack->Parameters.QueryInterface.InterfaceSpecificData =
NULL;
nextStack->Parameters.QueryInterface.InterfaceType =
&USB_BUS_INTERFACE_USBDI_GUID;
nextStack->Parameters.QueryInterface.Size =
sizeof(*BusInterface);
nextStack->Parameters.QueryInterface.Version =
USB_BUSIF_USBDI_VERSION_2;
ntStatus = IoCallDriver(HubPdo,
irp);
if (ntStatus == STATUS_PENDING) {
KeWaitForSingleObject(
&event,
Suspended,
KernelMode,
FALSE,
NULL);
ntStatus = irp->IoStatus.Status;
}
if (NT_SUCCESS(ntStatus)) {
// we have a bus interface
ASSERT(BusInterface->Version == USB_BUSIF_USBDI_VERSION_2);
ASSERT(BusInterface->Size == sizeof(*BusInterface));
}
IoFreeIrp(irp);
// get the bus interface
return ntStatus;
}
NTSTATUS
USBHUB_GetBusInfoDevice(
IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
IN PDEVICE_EXTENSION_PORT DeviceExtensionPort,
IN PUSB_BUS_NOTIFICATION BusInfo
)
/*++
Routine Description:
Return the bus information relative to a specific device
Arguments:
Return Value:
--*/
{
NTSTATUS ntStatus;
PUSB_HUB_BUS_INTERFACE busIf;
PVOID busContext;
busIf = &DeviceExtensionHub->BusIf;
busContext = busIf->GetDeviceBusContext(busIf->BusContext,
DeviceExtensionPort->DeviceData);
// get the TT handle for this device and query the
// bus information relative to it
ntStatus = USBHUB_GetBusInfo(DeviceExtensionHub,
BusInfo,
busContext);
return ntStatus;
}
NTSTATUS
USBHUB_GetBusInfo(
IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
IN PUSB_BUS_NOTIFICATION BusInfo,
IN PVOID BusContext
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PUSB_BUS_INFORMATION_LEVEL_1 level_1;
PUSB_BUS_INTERFACE_USBDI_V2 busIf;
ULONG length, actualLength;
NTSTATUS ntStatus;
busIf = &DeviceExtensionHub->UsbdiBusIf;
if (!busIf->QueryBusInformation) {
ntStatus = STATUS_NOT_IMPLEMENTED;
USBH_ASSERT(FALSE);
return ntStatus;
}
length = sizeof(USB_BUS_INFORMATION_LEVEL_1);
do {
level_1 = UsbhExAllocatePool(PagedPool, length);
if (level_1 != NULL) {
if (BusContext == NULL) {
BusContext = busIf->BusContext;
}
ntStatus = busIf->QueryBusInformation(BusContext,
1,
level_1,
&length,
&actualLength);
if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
length = actualLength;
UsbhExFreePool(level_1);
level_1 = NULL;
}
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
} while (ntStatus == STATUS_BUFFER_TOO_SMALL);
if (NT_SUCCESS(ntStatus)) {
LOGENTRY(LOG_PNP, "lev1", level_1, 0, 0);
BusInfo->TotalBandwidth = level_1->TotalBandwidth;
BusInfo->ConsumedBandwidth = level_1->ConsumedBandwidth;
/* length of the UNICODE symbolic name (in bytes) for the controller
that this device is attached to.
not including NULL */
BusInfo->ControllerNameLength = level_1->ControllerNameLength;
UsbhExFreePool(level_1);
}
return ntStatus;
}
NTSTATUS
USBHUB_GetExtendedHubInfo(
IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
IN PUSB_EXTHUB_INFORMATION_0 ExtendedHubInfo
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS ntStatus;
PUSB_HUB_BUS_INTERFACE busIf;
PVOID busContext;
ULONG length;
busIf = &DeviceExtensionHub->BusIf;
ntStatus = busIf->GetExtendedHubInformation(busIf->BusContext,
DeviceExtensionHub->PhysicalDeviceObject,
ExtendedHubInfo,
sizeof(*ExtendedHubInfo),
&length);
return ntStatus;
}
PUSB_DEVICE_HANDLE
USBH_SyncGetDeviceHandle(
IN PDEVICE_OBJECT DeviceObject
)
/* ++
*
* Routine Description:
*
* Arguments:
*
* Return Value:
*
* NTSTATUS
*
* -- */
{
NTSTATUS ntStatus, status;
PIRP irp;
KEVENT event;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
PUSB_DEVICE_HANDLE handle = NULL;
PAGED_CODE();
USBH_KdPrint((2,"'enter USBH_SyncGetDeviceHandle\n"));
//
// issue a synchronous request to the RootHubBdo
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE,
DeviceObject,
NULL,
0,
NULL,
0,
TRUE, // INTERNAL
&event,
&ioStatus);
if (NULL == irp) {
goto USBH_SyncGetDeviceHandle_Done;
}
//
// Call the class driver to perform the operation. If the returned
// status
// is PENDING, wait for the request to complete.
//
nextStack = IoGetNextIrpStackLocation(irp);
//
// pass the URB to the USBD 'class driver'
//
nextStack->Parameters.Others.Argument1 = &handle;
ntStatus = IoCallDriver(DeviceObject, irp);
USBH_KdPrint((2,"'return from IoCallDriver USBD %x\n", ntStatus));
if (ntStatus == STATUS_PENDING) {
USBH_KdPrint((2,"'Wait for single object\n"));
status = KeWaitForSingleObject(&event,
Suspended,
KernelMode,
FALSE,
NULL);
USBH_KdPrint((2,"'Wait for single object, returned %x\n", status));
} else {
ioStatus.Status = ntStatus;
}
ntStatus = ioStatus.Status;
USBH_KdPrint((2,"'exit USBH_SyncGetDeviceHandle (%x)\n", ntStatus));
USBH_SyncGetDeviceHandle_Done:
return handle;
}
USB_DEVICE_TYPE
USBH_GetDeviceType(
IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
IN PUSB_DEVICE_HANDLE DeviceData
)
/*
This function maps the new port service on to the
old hub api.
*/
{
NTSTATUS ntStatus;
PUSB_HUB_BUS_INTERFACE busIf;
ULONG length, lengthCopied;
ULONG i, need;
PUSB_DEVICE_INFORMATION_0 level_0 = NULL;
// if all else fails assum it is 11
USB_DEVICE_TYPE deviceType = Usb11Device;
busIf = &DeviceExtensionHub->BusIf;
if (!busIf->QueryDeviceInformation) {
ntStatus = STATUS_NOT_IMPLEMENTED;
USBH_ASSERT(FALSE);
return ntStatus;
}
length = sizeof(*level_0);
do {
ntStatus = STATUS_SUCCESS;
level_0 = UsbhExAllocatePool(PagedPool, length);
if (level_0 == NULL) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(ntStatus)) {
level_0->InformationLevel = 0;
ntStatus = busIf->QueryDeviceInformation(busIf->BusContext,
DeviceData,
level_0,
length,
&lengthCopied);
if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
length = level_0->ActualLength;
UsbhExFreePool(level_0);
}
}
} while (ntStatus == STATUS_BUFFER_TOO_SMALL);
// do we have enough to satisfiy the API?
need = level_0->NumberOfOpenPipes * sizeof(USB_PIPE_INFO) +
sizeof(USB_NODE_CONNECTION_INFORMATION);
if (NT_SUCCESS(ntStatus)) {
deviceType = level_0->DeviceType;
}
if (level_0 != NULL) {
UsbhExFreePool(level_0);
level_0 = NULL;
}
USBH_KdPrint((2,"'exit USBH_GetDeviceType (%x)\n", deviceType));
return deviceType;
}
VOID
USBH_InitializeUSB2Hub(
PDEVICE_EXTENSION_HUB DeviceExtensionHub
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS ntStatus;
PUSB_DEVICE_HANDLE hubDeviceHandle;
// NOTE: if we are running on the old 1.1 stack a NULL
// is returned
hubDeviceHandle =
USBH_SyncGetDeviceHandle(DeviceExtensionHub->TopOfStackDeviceObject);
// if we are a USB 2 hub then set the hub flag so we ignore
// failed resets
if (hubDeviceHandle != NULL &&
USBH_GetDeviceType(DeviceExtensionHub,
hubDeviceHandle) == Usb20Device) {
DeviceExtensionHub->HubFlags |= HUBFLAG_USB20_HUB;
}
#ifdef TEST_2X_UI
if (IS_ROOT_HUB(DeviceExtensionHub)) {
// To test the UI, mark the root hub as 2.x capable.
DeviceExtensionHub->HubFlags |= HUBFLAG_USB20_HUB;
}
#endif
}
NTSTATUS
USBHUB_GetControllerName(
IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
IN PUSB_HUB_NAME Buffer,
IN ULONG BufferLength
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PUSB_BUS_INFORMATION_LEVEL_1 level_1;
PUSB_BUS_INTERFACE_USBDI_V2 busIf;
ULONG lenToCopy, length, actualLength;
NTSTATUS ntStatus;
busIf = &DeviceExtensionHub->UsbdiBusIf;
if (!busIf->QueryBusInformation) {
ntStatus = STATUS_NOT_IMPLEMENTED;
USBH_ASSERT(FALSE);
return ntStatus;
}
length = sizeof(USB_BUS_INFORMATION_LEVEL_1);
do {
level_1 = UsbhExAllocatePool(PagedPool, length);
if (level_1 != NULL) {
ntStatus = busIf->QueryBusInformation(busIf->BusContext,
1,
level_1,
&length,
&actualLength);
if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
length = actualLength;
UsbhExFreePool(level_1);
level_1 = NULL;
}
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
} while (ntStatus == STATUS_BUFFER_TOO_SMALL);
if (NT_SUCCESS(ntStatus)) {
LOGENTRY(LOG_PNP, "lev1", level_1, 0, 0);
// not sure if BufferLength includes size of the
// ActualLength field, we will assume it does
Buffer->ActualLength = level_1->ControllerNameLength;
if ((BufferLength - sizeof(Buffer->ActualLength))
>= level_1->ControllerNameLength) {
lenToCopy = level_1->ControllerNameLength;
} else {
lenToCopy = BufferLength - sizeof(Buffer->ActualLength);
}
// copy what we can
RtlCopyMemory(&Buffer->HubName[0],
&level_1->ControllerNameUnicodeString[0],
lenToCopy);
UsbhExFreePool(level_1);
}
return ntStatus;
}
NTSTATUS
USBHUB_GetRootHubName(
IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
IN PVOID Buffer,
IN PULONG BufferLength
)
{
NTSTATUS ntStatus;
PUSB_HUB_BUS_INTERFACE busIf;
busIf = &DeviceExtensionHub->BusIf;
if (!busIf->GetRootHubSymbolicName) {
ntStatus = STATUS_NOT_IMPLEMENTED;
USBH_ASSERT(FALSE);
} else {
ntStatus = busIf->GetRootHubSymbolicName(
busIf->BusContext,
Buffer,
*BufferLength,
BufferLength);
}
return ntStatus;
}
VOID
USBHUB_FlushAllTransfers(
PDEVICE_EXTENSION_HUB DeviceExtensionHub
)
{
NTSTATUS ntStatus;
PUSB_HUB_BUS_INTERFACE busIf;
busIf = &DeviceExtensionHub->BusIf;
if (!busIf->FlushTransfers) {
ntStatus = STATUS_NOT_IMPLEMENTED;
USBH_ASSERT(FALSE);
} else {
busIf->FlushTransfers(busIf->BusContext,
NULL);
}
return;
}
VOID
USBHUB_SetDeviceHandleData(
PDEVICE_EXTENSION_HUB DeviceExtensionHub,
PDEVICE_OBJECT PdoDeviceObject,
PVOID DeviceData
)
{
PUSB_HUB_BUS_INTERFACE busIf;
busIf = &DeviceExtensionHub->BusIf;
// associate this PDO with the device handle
// (if we can)
if (!busIf->SetDeviceHandleData) {
USBH_ASSERT(FALSE);
} else {
busIf->SetDeviceHandleData(busIf->BusContext,
DeviceData,
PdoDeviceObject);
}
return;
}
#endif