/*++ Copyright (c) 1996 Microsoft Corporation Module Name: IOCTLI.C Abstract: This module implements usb IOCTL requests to usb hub. Author: jdunn Environment: kernel mode only Notes: Revision History: 1-2-97 : re-wriiten --*/ /* // // ** User mode IOCTLS ** // // // IOCTL_USB_GET_NODE_INFORMATION // input: None output: outputbufferlength = sizeof(USB_BUS_NODE_INFORMATION) outputbuffer = filled in with USB_BUS_NODE_INFORMATION structure. // // IOCTL_USB_GET_NODE_CONNECTION_INFORMATION // input: inputbufferlength = size of user supplied buffer inpubuffer = ptr to USB_NODE_CONNECTION_INFORMATION structure with connectionIndex set to the requested connection. output: outputbufferlength = size of user supplied buffer outputbuffer = filled in with USB_NODE_CONNECTION_INFORMATION structure. // // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION // input: inputbufferlength = size of user supplied buffer. inputbuffer = ptr to USB_DESCRIPTOR_REQUEST, includes setup packet and connection index. output: outputbufferlength = length of descriptor data plus sizeof sizeof(USB_DESCRIPTOR_REQUEST). outputbuffer = ptr to USB_DESCRIPTOR_REQUEST filled in with returned data. // // ** Internal IOCTLS ** // // // IOCTL_INTERNAL_USB_RESET_PORT // */ #include #ifdef WMI_SUPPORT #include #include #include #endif /* WMI_SUPPORT */ #include "usbhub.h" #ifdef PAGE_CODE #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, USBH_IoctlGetNodeInformation) #pragma alloc_text(PAGE, USBH_IoctlGetHubCapabilities) #pragma alloc_text(PAGE, USBH_IoctlGetNodeConnectionInformation) #pragma alloc_text(PAGE, USBH_IoctlGetNodeConnectionDriverKeyName) #pragma alloc_text(PAGE, USBH_IoctlGetNodeName) #pragma alloc_text(PAGE, USBH_PdoIoctlGetPortStatus) #pragma alloc_text(PAGE, USBH_PdoIoctlEnablePort) #pragma alloc_text(PAGE, USBH_IoctlGetDescriptorForPDO) #pragma alloc_text(PAGE, USBH_SystemControl) #pragma alloc_text(PAGE, USBH_PortSystemControl) #pragma alloc_text(PAGE, USBH_ExecuteWmiMethod) #pragma alloc_text(PAGE, USBH_QueryWmiRegInfo) #pragma alloc_text(PAGE, USBH_CheckLeafHubsIdle) #endif #endif NTSTATUS USBH_IoctlGetNodeInformation( IN PDEVICE_EXTENSION_HUB DeviceExtensionHub, IN PIRP Irp ) /* ++ * * Description: * * Arguments: * * Return: * * NTSTATUS * * -- */ { NTSTATUS ntStatus = STATUS_SUCCESS; PIO_STACK_LOCATION ioStack; PUSB_NODE_INFORMATION outputBuffer; ULONG outputBufferLength; PAGED_CODE(); USBH_KdPrint((2,"'USBH_IoctlGetNodeInformation\n")); // // Get a pointer to the current location in the Irp. This is where // the function codes and parameters are located. // ioStack = IoGetCurrentIrpStackLocation(Irp); // // Get the pointer to the input/output buffer and it's length // outputBuffer = (PUSB_NODE_INFORMATION) Irp->AssociatedIrp.SystemBuffer; outputBufferLength = ioStack->Parameters.DeviceIoControl.OutputBufferLength; RtlZeroMemory(outputBuffer, outputBufferLength); if (outputBufferLength >= sizeof(USB_NODE_INFORMATION)) { // // for now everything is a hub // outputBuffer->NodeType = UsbHub; RtlCopyMemory(&outputBuffer->u.HubInformation.HubDescriptor, DeviceExtensionHub->HubDescriptor, sizeof(*DeviceExtensionHub->HubDescriptor)); // 100 milliamps/port means bus powered outputBuffer->u.HubInformation.HubIsBusPowered = USBH_HubIsBusPowered(DeviceExtensionHub->FunctionalDeviceObject, DeviceExtensionHub->ConfigurationDescriptor); Irp->IoStatus.Information = sizeof(USB_NODE_INFORMATION); } else { ntStatus = STATUS_BUFFER_TOO_SMALL; } USBH_CompleteIrp(Irp, ntStatus); return ntStatus; } NTSTATUS USBH_IoctlCycleHubPort( IN PDEVICE_EXTENSION_HUB DeviceExtensionHub, IN PIRP Irp ) /* ++ * * Description: * * Arguments: * * Return: * * NTSTATUS * * -- */ { NTSTATUS ntStatus = STATUS_SUCCESS; PIO_STACK_LOCATION ioStack; PULONG buffer; ULONG bufferLength; ULONG port; PAGED_CODE(); USBH_KdPrint((2,"'USBH_IoctlCycleHubPort\n")); ioStack = IoGetCurrentIrpStackLocation(Irp); // // Get the pointer to the input/output buffer and its length. // buffer = (PULONG) Irp->AssociatedIrp.SystemBuffer; bufferLength = ioStack->Parameters.DeviceIoControl.InputBufferLength; if (bufferLength < sizeof(port)) { ntStatus = STATUS_BUFFER_TOO_SMALL; goto USBH_IoctlCycleHubPort_Done; } // port number is input only port = *buffer; Irp->IoStatus.Information = 0; USBH_KdPrint((1,"'Request Cycle Port %d\n", port)); if (port <= DeviceExtensionHub->HubDescriptor->bNumberOfPorts && port > 0) { PPORT_DATA portData; PDEVICE_EXTENSION_PORT deviceExtensionPort; portData = &DeviceExtensionHub->PortData[port-1]; if (portData->DeviceObject) { deviceExtensionPort = portData->DeviceObject->DeviceExtension; USBH_InternalCyclePort(DeviceExtensionHub, (USHORT) port, deviceExtensionPort); } else { ntStatus = STATUS_UNSUCCESSFUL; } USBH_KdPrint((1,"'Cycle Port %d %x\n", port, ntStatus)); } USBH_IoctlCycleHubPort_Done: USBH_CompleteIrp(Irp, ntStatus); return ntStatus; } NTSTATUS USBH_IoctlGetHubCapabilities( IN PDEVICE_EXTENSION_HUB DeviceExtensionHub, IN PIRP Irp ) /* ++ * * Description: * * Arguments: * * Return: * * NTSTATUS * * -- */ { NTSTATUS ntStatus = STATUS_SUCCESS; PIO_STACK_LOCATION ioStack; PUSB_HUB_CAPABILITIES outputBuffer; ULONG outputBufferLength, copyLen; USB_HUB_CAPABILITIES localBuffer; PAGED_CODE(); USBH_KdPrint((2,"'USBH_IoctlGetHubCapabilities\n")); RtlZeroMemory(&localBuffer, sizeof(USB_HUB_CAPABILITIES)); // Fill in the data in the local buffer first, then copy as much of // this data to the user's buffer as requested (as indicated by the // size of the request buffer). localBuffer.HubIs2xCapable = (DeviceExtensionHub->HubFlags & HUBFLAG_USB20_HUB) ? 1:0; // // Get a pointer to the current location in the Irp. This is where // the function codes and parameters are located. // ioStack = IoGetCurrentIrpStackLocation(Irp); // // Get the pointer to the input/output buffer and its length. // outputBuffer = (PUSB_HUB_CAPABILITIES) Irp->AssociatedIrp.SystemBuffer; outputBufferLength = ioStack->Parameters.DeviceIoControl.OutputBufferLength; if (outputBufferLength <= sizeof(localBuffer)) { copyLen = outputBufferLength; } else { copyLen = sizeof(localBuffer); } // zero buffer passed in RtlZeroMemory(outputBuffer, outputBufferLength); // Only give the user the amount of data that they ask for // this may only be part of our info strucure RtlCopyMemory(outputBuffer, &localBuffer, copyLen); Irp->IoStatus.Information = copyLen; USBH_CompleteIrp(Irp, ntStatus); return ntStatus; } NTSTATUS USBH_IoctlGetNodeConnectionDriverKeyName( IN PDEVICE_EXTENSION_HUB DeviceExtensionHub, IN PIRP Irp ) /* ++ * * Description: * * Arguments: * * ConnectionIndex - The one-based port index to which a device is attached. * The devnode name of the will be returned, if there is sufficient buffer space. * * ActualLength - The structure size in bytes necessary to hold the NULL * terminated name. This includes the entire structure, not * just the name. * * NodeName - The UNICODE NULL terminated name of the devnode for the device * attached to this port. * * Return: * * NTSTATUS * * -- */ { NTSTATUS ntStatus = STATUS_SUCCESS; PIO_STACK_LOCATION ioStack; PUSB_NODE_CONNECTION_DRIVERKEY_NAME outputBuffer; ULONG outputBufferLength, length, i; PPORT_DATA portData; PAGED_CODE(); USBH_KdPrint((2,"'USBH_IoctlGetNodeConnectionDriverKeyName\n")); portData = DeviceExtensionHub->PortData; // // Get a pointer to the current location in the Irp. This is where // the function codes and parameters are located. // ioStack = IoGetCurrentIrpStackLocation(Irp); // // Get the pointer to the input/output buffer and it's length // outputBufferLength = ioStack->Parameters.DeviceIoControl.OutputBufferLength; outputBuffer = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME) Irp->AssociatedIrp.SystemBuffer; // find the PDO if (outputBufferLength >= sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME)) { USBH_KdPrint((2,"'Connection = %d\n", outputBuffer->ConnectionIndex)); ntStatus = STATUS_INVALID_PARAMETER; for(i=1; i<=DeviceExtensionHub->HubDescriptor->bNumberOfPorts; i++) { PDEVICE_EXTENSION_PORT deviceExtensionPort; if (i == outputBuffer->ConnectionIndex) { portData = &DeviceExtensionHub->PortData[outputBuffer->ConnectionIndex - 1]; if (portData->DeviceObject) { deviceExtensionPort = portData->DeviceObject->DeviceExtension; // Validate the PDO for PnP purposes. (PnP will bugcheck // if passed a not-quite-initialized PDO.) if (deviceExtensionPort->PortPdoFlags & PORTPDO_VALID_FOR_PNP_FUNCTION) { // we have the PDO, now attempt to // get the devnode name and return it length = outputBufferLength - sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME); USBH_KdPrint((1,"'Get DKN length = %d\n", length)); ntStatus = IoGetDeviceProperty( portData->DeviceObject, DevicePropertyDriverKeyName, length, outputBuffer->DriverKeyName, &length); USBH_KdPrint((1,"'Get DKN prop length = %d %x\n", length, ntStatus)); if (ntStatus == STATUS_BUFFER_TOO_SMALL) { ntStatus = STATUS_SUCCESS; } outputBuffer->ActualLength = length + sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME); USBH_KdPrint((1,"'DKN actual length = %d \n", outputBuffer->ActualLength)); // see how much data we actully copied if (outputBufferLength >= outputBuffer->ActualLength) { // user buffer is bigger, just indicate how much we copied Irp->IoStatus.Information = outputBuffer->ActualLength; } else { // it is not clear that IoGetDeviceProperty // returns anything in the case of BUFFER_TOO_SMALL // so to avoid returning unitialized memory we will // just return the structure passed in outputBuffer->DriverKeyName[0] = 0; Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME); } } else { ntStatus = STATUS_INVALID_DEVICE_STATE; } } } } } else { ntStatus = STATUS_BUFFER_TOO_SMALL; } USBH_CompleteIrp(Irp, ntStatus); return ntStatus; } NTSTATUS USBH_IoctlGetNodeConnectionInformation( IN PDEVICE_EXTENSION_HUB DeviceExtensionHub, IN PIRP Irp, IN BOOLEAN ExApi ) /* ++ * * Description: * * Arguments: * * Return: * * NTSTATUS * * -- */ { NTSTATUS ntStatus = STATUS_SUCCESS; PIO_STACK_LOCATION ioStack; PUSB_NODE_CONNECTION_INFORMATION_EX outputBuffer; ULONG outputBufferLength, length, i; PPORT_DATA portData; PAGED_CODE(); USBH_KdPrint((2,"'USBH_IoctlGetNodeConnectionInformation\n")); portData = DeviceExtensionHub->PortData; // // Get a pointer to the current location in the Irp. This is where // the function codes and parameters are located. // ioStack = IoGetCurrentIrpStackLocation(Irp); // // Get the pointer to the input/output buffer and it's length // outputBufferLength = ioStack->Parameters.DeviceIoControl.OutputBufferLength; outputBuffer = (PUSB_NODE_CONNECTION_INFORMATION_EX) Irp->AssociatedIrp.SystemBuffer; if (outputBufferLength >= sizeof(USB_NODE_CONNECTION_INFORMATION)) { ULONG index; USBH_KdPrint((2,"'Connection = %d\n", outputBuffer->ConnectionIndex)); // Clear the buffer in case we don't call USBD_GetDeviceInformation // below, but make sure to keep the ConnectionIndex! index = outputBuffer->ConnectionIndex; RtlZeroMemory(outputBuffer, outputBufferLength); outputBuffer->ConnectionIndex = index; ntStatus = STATUS_INVALID_PARAMETER; for(i=1; i<=DeviceExtensionHub->HubDescriptor->bNumberOfPorts; i++) { PDEVICE_EXTENSION_PORT deviceExtensionPort; if (i == outputBuffer->ConnectionIndex) { length = sizeof(USB_NODE_CONNECTION_INFORMATION); if (portData->DeviceObject) { deviceExtensionPort = portData->DeviceObject->DeviceExtension; outputBuffer->ConnectionStatus = portData->ConnectionStatus; outputBuffer->DeviceIsHub = (deviceExtensionPort->PortPdoFlags & PORTPDO_DEVICE_IS_HUB) ? TRUE : FALSE; USBH_KdPrint((2,"'outputbuffer = %x\n", outputBuffer)); RtlCopyMemory(&outputBuffer->DeviceDescriptor, &deviceExtensionPort->DeviceDescriptor, sizeof(outputBuffer->DeviceDescriptor)); if (deviceExtensionPort->DeviceData) { #ifdef USB2 USBH_KdPrint((2,"'devicedata = %x\n", deviceExtensionPort->DeviceData)); ntStatus = USBD_GetDeviceInformationEx( deviceExtensionPort, DeviceExtensionHub, outputBuffer, outputBufferLength, deviceExtensionPort->DeviceData); #else ntStatus = USBD_GetDeviceInformation(outputBuffer, outputBufferLength, deviceExtensionPort->DeviceData); #endif } else { // // We have a device connected, but it failed to start. // Since it hasn't started, there are no open pipes, so // we don't need to get pipe information. We are going // to return some relevant information, however, so // return STATUS_SUCCESS. // ntStatus = STATUS_SUCCESS; } USBH_KdPrint((2,"'status from USBD_GetDeviceInformation %x\n", ntStatus)); if (NT_SUCCESS(ntStatus)) { ULONG j; USBH_KdPrint((2,"'status %x \n", outputBuffer->ConnectionStatus)); // USBH_KdPrint((2,"'NodeName %s\n", outputBuffer->NodeName)); USBH_KdPrint((2,"'PID 0x%x\n", outputBuffer->DeviceDescriptor.idProduct)); USBH_KdPrint((2,"'VID 0x%x\n", outputBuffer->DeviceDescriptor.idVendor)); USBH_KdPrint((2,"'Current Configuration Value 0x%x\n", outputBuffer->CurrentConfigurationValue)); // map the speed field for the old API which returned // a BOOLEAN if (!ExApi) { PUSB_NODE_CONNECTION_INFORMATION tmp = (PUSB_NODE_CONNECTION_INFORMATION) outputBuffer; tmp->LowSpeed = (outputBuffer->Speed == UsbLowSpeed) ? TRUE : FALSE; } USBH_KdPrint((2,"'Speed = %x\n", outputBuffer->Speed)); USBH_KdPrint((2,"'Address = %x\n", outputBuffer->DeviceAddress)); USBH_KdPrint((2,"'NumberOfOpenPipes = %d\n", outputBuffer->NumberOfOpenPipes)); for(j=0; j< outputBuffer->NumberOfOpenPipes; j++) { USBH_KdPrint((2,"'Max Packet %x\n", outputBuffer->PipeList[j].EndpointDescriptor.wMaxPacketSize)); USBH_KdPrint((2,"'Interval %x \n", outputBuffer->PipeList[j].EndpointDescriptor.bInterval)); } Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_INFORMATION) + sizeof(USB_PIPE_INFO) * outputBuffer->NumberOfOpenPipes; } else if (ntStatus == STATUS_BUFFER_TOO_SMALL) { Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_INFORMATION); ntStatus = STATUS_SUCCESS; } } else { //no device object // This assert is no longer valid because we now support // displaying the UI on device enumeration failure. // // USBH_ASSERT(portData->ConnectionStatus == NoDeviceConnected || // portData->ConnectionStatus == DeviceCausedOvercurrent); outputBuffer->ConnectionStatus = portData->ConnectionStatus; Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_INFORMATION); ntStatus = STATUS_SUCCESS; } break; } portData++; } /* for */ } else { ntStatus = STATUS_BUFFER_TOO_SMALL; } USBH_CompleteIrp(Irp, ntStatus); return ntStatus; } NTSTATUS USBH_IoctlGetNodeConnectionAttributes( IN PDEVICE_EXTENSION_HUB DeviceExtensionHub, IN PIRP Irp ) /* ++ * * Description: * * Arguments: * * Return: * * NTSTATUS * * -- */ { NTSTATUS ntStatus = STATUS_SUCCESS; PIO_STACK_LOCATION ioStack; PUSB_NODE_CONNECTION_ATTRIBUTES outputBuffer; ULONG outputBufferLength, length, i; PPORT_DATA portData; PAGED_CODE(); USBH_KdPrint((2,"'USBH_IoctlGetNodeConnectionInformation\n")); portData = DeviceExtensionHub->PortData; // // Get a pointer to the current location in the Irp. This is where // the function codes and parameters are located. // ioStack = IoGetCurrentIrpStackLocation(Irp); // // Get the pointer to the input/output buffer and it's length // outputBufferLength = ioStack->Parameters.DeviceIoControl.OutputBufferLength; outputBuffer = (PUSB_NODE_CONNECTION_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer; if (outputBufferLength >= sizeof(USB_NODE_CONNECTION_ATTRIBUTES)) { ULONG index; USBH_KdPrint((2,"'Connection = %d\n", outputBuffer->ConnectionIndex)); // Clear the buffer in case we don't call USBD_GetDeviceInformation // below, but make sure to keep the ConnectionIndex! index = outputBuffer->ConnectionIndex; RtlZeroMemory(outputBuffer, outputBufferLength); outputBuffer->ConnectionIndex = index; ntStatus = STATUS_INVALID_PARAMETER; for(i=1; i<=DeviceExtensionHub->HubDescriptor->bNumberOfPorts; i++) { if (i == outputBuffer->ConnectionIndex) { length = sizeof(USB_NODE_CONNECTION_ATTRIBUTES); outputBuffer->ConnectionStatus = portData->ConnectionStatus; USBH_KdPrint((2,"'outputbuffer = %x\n", outputBuffer)); // map extended hub info here outputBuffer->PortAttributes = portData->PortAttributes; Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_ATTRIBUTES); ntStatus = STATUS_SUCCESS; break; } portData++; } /* for */ } else { ntStatus = STATUS_BUFFER_TOO_SMALL; } USBH_CompleteIrp(Irp, ntStatus); return ntStatus; } NTSTATUS USBH_IoctlHubSymbolicName( IN PDEVICE_EXTENSION_PORT DeviceExtensionPort, IN PIRP Irp ) /* ++ * * Description: * * Takes as input and output a pointer to the following structure: * * typedef struct _USB_HUB_NAME { * ULONG ActualLength; // OUTPUT * WCHAR HubName[1]; // OUTPUT * } USB_HUB_NAME; * * Arguments: * * ActualLength - The structure size in bytes necessary to hold the NULL * terminated symbolic link name. This includes the entire structure, not * just the name. * * NodeName - The UNICODE NULL terminated symbolic link name of the external * hub attached to the port. If there is no external hub attached to the port * a single NULL is returned. * * Return: * * NTSTATUS * * -- */ { NTSTATUS ntStatus = STATUS_SUCCESS; PIO_STACK_LOCATION ioStack; PUSB_HUB_NAME outputBuffer; ULONG outputBufferLength; PAGED_CODE(); // Get a pointer to the current location in the Irp. This is where // the function codes and parameters are located. // ioStack = IoGetCurrentIrpStackLocation(Irp); // Get the pointer to the input/output buffer and it's length // outputBufferLength = ioStack->Parameters.DeviceIoControl.OutputBufferLength; outputBuffer = (PUSB_HUB_NAME) Irp->AssociatedIrp.SystemBuffer; // Make sure that the output buffer is large enough for the base // structure that will be returned. // if (outputBufferLength < sizeof(USB_HUB_NAME)) { ntStatus = STATUS_BUFFER_TOO_SMALL; goto GetHubDone; } if ((DeviceExtensionPort->PortPdoFlags & PORTPDO_DEVICE_IS_HUB) && (DeviceExtensionPort->PortPdoFlags & PORTPDO_STARTED) && (DeviceExtensionPort->PortPdoFlags & PORTPDO_SYM_LINK)) { PUNICODE_STRING hubNameUnicodeString; ULONG length, offset=0; WCHAR *pwch; // Device is a hub, get the name of the hub // hubNameUnicodeString = &DeviceExtensionPort->SymbolicLinkName; // assuming the string is \n\name strip of '\n\' where // n is zero or more chars pwch = &hubNameUnicodeString->Buffer[0]; USBH_ASSERT(*pwch == '\\'); if (*pwch == '\\') { pwch++; while (*pwch != '\\' && *pwch) { pwch++; } USBH_ASSERT(*pwch == '\\'); if (*pwch == '\\') { pwch++; } offset = (ULONG)((PUCHAR)pwch - (PUCHAR)&hubNameUnicodeString->Buffer[0]); } // Strip off the '\DosDevices\' prefix. // Length does not include a terminating NULL. // length = hubNameUnicodeString->Length - offset; RtlZeroMemory(outputBuffer, outputBufferLength); if (outputBufferLength >= length + sizeof(USB_HUB_NAME)) { RtlCopyMemory(&outputBuffer->HubName[0], &hubNameUnicodeString->Buffer[offset/2], length); Irp->IoStatus.Information = length+ sizeof(USB_HUB_NAME); outputBuffer->ActualLength = (ULONG)Irp->IoStatus.Information; ntStatus = STATUS_SUCCESS; } else { // Output buffer is too small to hold the entire // string. Return just the length needed to hold // the entire string. // outputBuffer->ActualLength = length + sizeof(USB_HUB_NAME); outputBuffer->HubName[0] = (WCHAR)0; Irp->IoStatus.Information = sizeof(USB_HUB_NAME); } } else { // Device is not a hub or does not currently have a symbolic link // allocated, just return a NULL terminated string. // outputBuffer->ActualLength = sizeof(USB_HUB_NAME); outputBuffer->HubName[0] = 0; Irp->IoStatus.Information = sizeof(USB_HUB_NAME); } GetHubDone: USBH_CompleteIrp(Irp, ntStatus); return ntStatus; } NTSTATUS USBH_IoctlGetNodeName( IN PDEVICE_EXTENSION_HUB DeviceExtensionHub, IN PIRP Irp ) /* ++ * * Description: * * Takes as input and output a pointer to the following structure: * * typedef struct _USB_NODE_CONNECTION_NAME { * ULONG ConnectionIndex; // INPUT * ULONG ActualLength; // OUTPUT * WCHAR NodeName[1]; // OUTPUT * } USB_NODE_CONNECTION_NAME; * * Arguments: * * ConnectionIndex - The one-based port index to which a device is attached. * If an external hub is attached to this port, the symbolic link name of the * hub will be returned, if there is sufficient buffer space. * * ActualLength - The structure size in bytes necessary to hold the NULL * terminated symbolic link name. This includes the entire structure, not * just the name. * * NodeName - The UNICODE NULL terminated symbolic link name of the external * hub attached to the port. If there is no external hub attached to the port * a single NULL is returned. * * Return: * * NTSTATUS * * -- */ { NTSTATUS ntStatus = STATUS_SUCCESS; PIO_STACK_LOCATION ioStack; PUSB_NODE_CONNECTION_NAME outputBuffer; ULONG outputBufferLength; PPORT_DATA portData; PDEVICE_EXTENSION_PORT deviceExtensionPort; PAGED_CODE(); USBH_KdPrint((2,"'USBH_IoctlGetNodeName\n")); // Get a pointer to the current location in the Irp. This is where // the function codes and parameters are located. // ioStack = IoGetCurrentIrpStackLocation(Irp); // Get the pointer to the input/output buffer and it's length // outputBufferLength = ioStack->Parameters.DeviceIoControl.OutputBufferLength; outputBuffer = (PUSB_NODE_CONNECTION_NAME) Irp->AssociatedIrp.SystemBuffer; // Make sure that the output buffer is large enough for the base // structure that will be returned. // if (outputBufferLength < sizeof(USB_NODE_CONNECTION_NAME)) { ntStatus = STATUS_BUFFER_TOO_SMALL; goto GetNodeNameDone; } USBH_KdPrint((2,"'Connection = %d\n", outputBuffer->ConnectionIndex)); // Make sure that the (one-based) port index is valid. // if ((outputBuffer->ConnectionIndex == 0) || (outputBuffer->ConnectionIndex > DeviceExtensionHub->HubDescriptor->bNumberOfPorts)) { ntStatus = STATUS_INVALID_PARAMETER; goto GetNodeNameDone; } // Get a pointer to the data associated with the specified (one-based) port // portData = &DeviceExtensionHub->PortData[outputBuffer->ConnectionIndex - 1]; if (portData->DeviceObject) { deviceExtensionPort = portData->DeviceObject->DeviceExtension; if ((deviceExtensionPort->PortPdoFlags & PORTPDO_DEVICE_IS_HUB) && (deviceExtensionPort->PortPdoFlags & PORTPDO_STARTED) && (deviceExtensionPort->PortPdoFlags & PORTPDO_SYM_LINK)) { PUNICODE_STRING nodeNameUnicodeString; ULONG length, offset=0; WCHAR *pwch; // Device is a hub, get the name of the hub // nodeNameUnicodeString = &deviceExtensionPort->SymbolicLinkName; // assuming the string is \n\name strip of '\n\' where // n is zero or more chars pwch = &nodeNameUnicodeString->Buffer[0]; USBH_ASSERT(*pwch == '\\'); if (*pwch == '\\') { pwch++; while (*pwch != '\\' && *pwch) { pwch++; } USBH_ASSERT(*pwch == '\\'); if (*pwch == '\\') { pwch++; } offset = (ULONG)((PUCHAR)pwch - (PUCHAR)&nodeNameUnicodeString->Buffer[0]); } // Strip off the '\DosDevices\' prefix. // Length does not include a terminating NULL. // length = nodeNameUnicodeString->Length - offset; RtlZeroMemory(&outputBuffer->ActualLength, outputBufferLength - sizeof(outputBuffer->ConnectionIndex)); if (outputBufferLength >= length + sizeof(USB_NODE_CONNECTION_NAME)) { RtlCopyMemory(&outputBuffer->NodeName[0], &nodeNameUnicodeString->Buffer[offset/2], length); Irp->IoStatus.Information = length+ sizeof(USB_NODE_CONNECTION_NAME); outputBuffer->ActualLength = (ULONG)Irp->IoStatus.Information; ntStatus = STATUS_SUCCESS; } else { // Output buffer is too small to hold the entire // string. Return just the length needed to hold // the entire string. // outputBuffer->ActualLength = length + sizeof(USB_NODE_CONNECTION_NAME); outputBuffer->NodeName[0] = (WCHAR)0; Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_NAME); } } else { // Device is not a hub or does not currently have a symbolic link // allocated, just return a NULL terminated string. // outputBuffer->ActualLength = sizeof(USB_NODE_CONNECTION_NAME); outputBuffer->NodeName[0] = 0; Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_NAME); } } else { // No device attached, just return a NULL terminated string. Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_NAME); outputBuffer->ActualLength = sizeof(USB_NODE_CONNECTION_NAME); outputBuffer->NodeName[0] = 0; } GetNodeNameDone: USBH_CompleteIrp(Irp, ntStatus); return ntStatus; } NTSTATUS USBH_PdoIoctlGetPortStatus( IN PDEVICE_EXTENSION_PORT DeviceExtensionPort, IN PIRP Irp ) /* * Description: * * Arguments: * * Return: * * NTSTATUS * * -- */ { NTSTATUS ntStatus = STATUS_SUCCESS; PIO_STACK_LOCATION ioStackLocation; // our stack location PDEVICE_EXTENSION_HUB deviceExtensionHub; PDEVICE_OBJECT deviceObject; PPORT_DATA portData; PULONG portStatus; PAGED_CODE(); USBH_KdPrint((2,"'USBH_PdoIoctlGetPortStatus DeviceExtension %x Irp %x\n", DeviceExtensionPort, Irp)); deviceExtensionHub = DeviceExtensionPort->DeviceExtensionHub; USBH_KdPrint((2,"'***WAIT hub mutex %x\n", deviceExtensionHub)); USBH_INC_PENDING_IO_COUNT(deviceExtensionHub); KeWaitForSingleObject(&deviceExtensionHub->HubMutex, Executive, KernelMode, FALSE, NULL); USBH_KdPrint((2,"'***WAIT hub mutex done %x\n", deviceExtensionHub)); portData = &deviceExtensionHub->PortData[DeviceExtensionPort->PortNumber - 1]; deviceObject = DeviceExtensionPort->PortPhysicalDeviceObject; ioStackLocation = IoGetCurrentIrpStackLocation(Irp); portStatus = ioStackLocation->Parameters.Others.Argument1; USBH_ASSERT(portStatus != NULL); *portStatus = 0; // Refresh our notion of what the port status actually is. ntStatus = USBH_SyncGetPortStatus(deviceExtensionHub, DeviceExtensionPort->PortNumber, (PUCHAR) &portData->PortState, sizeof(portData->PortState)); if (DeviceExtensionPort->PortPhysicalDeviceObject == portData->DeviceObject) { // translate hup port status bits if (portData->PortState.PortStatus & PORT_STATUS_ENABLE) { *portStatus |= USBD_PORT_ENABLED; } if (portData->PortState.PortStatus & PORT_STATUS_CONNECT ) { *portStatus |= USBD_PORT_CONNECTED; } } USBH_KdPrint((2,"'***RELEASE hub mutex %x\n", deviceExtensionHub)); KeReleaseSemaphore(&deviceExtensionHub->HubMutex, LOW_REALTIME_PRIORITY, 1, FALSE); USBH_DEC_PENDING_IO_COUNT(deviceExtensionHub); USBH_CompleteIrp(Irp, ntStatus); return ntStatus; } NTSTATUS USBH_PdoIoctlEnablePort( IN PDEVICE_EXTENSION_PORT DeviceExtensionPort, IN PIRP Irp ) /* * Description: * * Arguments: * * Return: * * NTSTATUS * * -- */ { NTSTATUS ntStatus = STATUS_SUCCESS; PIO_STACK_LOCATION ioStackLocation; // our stack location PDEVICE_EXTENSION_HUB deviceExtensionHub; PDEVICE_OBJECT deviceObject; PPORT_DATA portData; PORT_STATE portState; USBH_KdPrint((2,"'USBH_PdoIoctlEnablePort DeviceExtension %x Irp %x\n", DeviceExtensionPort, Irp)); deviceExtensionHub = DeviceExtensionPort->DeviceExtensionHub; USBH_KdPrint((2,"'***WAIT hub mutex %x\n", deviceExtensionHub)); USBH_INC_PENDING_IO_COUNT(deviceExtensionHub); KeWaitForSingleObject(&deviceExtensionHub->HubMutex, Executive, KernelMode, FALSE, NULL); USBH_KdPrint((2,"'***WAIT hub mutex done %x\n", deviceExtensionHub)); portData = &deviceExtensionHub->PortData[DeviceExtensionPort->PortNumber - 1]; deviceObject = DeviceExtensionPort->PortPhysicalDeviceObject; ioStackLocation = IoGetCurrentIrpStackLocation(Irp); // validate that there is actually a device still conected ntStatus = USBH_SyncGetPortStatus(deviceExtensionHub, DeviceExtensionPort->PortNumber, (PUCHAR) &portState, sizeof(portState)); if ((NT_SUCCESS(ntStatus) && (portState.PortStatus & PORT_STATUS_CONNECT))) { LOGENTRY(LOG_PNP, "estE", deviceExtensionHub, DeviceExtensionPort->PortNumber, 0); ntStatus = USBH_SyncEnablePort(deviceExtensionHub, DeviceExtensionPort->PortNumber); } else { // error or no device connected or // can't be sure, fail the request LOGENTRY(LOG_PNP, "estx", deviceExtensionHub, DeviceExtensionPort->PortNumber, 0); ntStatus = STATUS_UNSUCCESSFUL; } USBH_KdPrint((2,"'***RELEASE hub mutex %x\n", deviceExtensionHub)); KeReleaseSemaphore(&deviceExtensionHub->HubMutex, LOW_REALTIME_PRIORITY, 1, FALSE); USBH_DEC_PENDING_IO_COUNT(deviceExtensionHub); USBH_CompleteIrp(Irp, ntStatus); return ntStatus; } NTSTATUS USBH_IoctlGetDescriptorForPDO( IN PDEVICE_EXTENSION_HUB DeviceExtensionHub, IN PIRP Irp ) /* ++ * * Description: * * Arguments: * * Return: * * NTSTATUS * * -- */ { NTSTATUS ntStatus = STATUS_SUCCESS; PIO_STACK_LOCATION ioStack; ULONG outputBufferLength; PUCHAR outputBuffer; PUSB_DESCRIPTOR_REQUEST request; PPORT_DATA portData; ULONG i; PAGED_CODE(); USBH_KdPrint((2,"'USBH_IoctlDescriptorRequest\n")); portData = DeviceExtensionHub->PortData; // // Get a pointer to the current location in the Irp. This is where // the function codes and parameters are located. // ioStack = IoGetCurrentIrpStackLocation(Irp); // // Get the pointer to the input/output buffer and it's length // outputBufferLength = ioStack->Parameters.DeviceIoControl.OutputBufferLength; if (outputBufferLength < sizeof(USB_DESCRIPTOR_REQUEST)) { ntStatus = STATUS_BUFFER_TOO_SMALL; goto USBH_IoctlGetDescriptorForPDO_Complete; } request = (PUSB_DESCRIPTOR_REQUEST) Irp->AssociatedIrp.SystemBuffer; outputBuffer = &request->Data[0]; // // do some parameter checking // // the wLength in the setup packet better be the size of the // outputbuffer minus header // if (request->SetupPacket.wLength > outputBufferLength - sizeof(USB_DESCRIPTOR_REQUEST)) { ntStatus = STATUS_BUFFER_TOO_SMALL; goto USBH_IoctlGetDescriptorForPDO_Complete; } else { // request won't return more than wLength outputBufferLength = request->SetupPacket.wLength; } // return invalid parameter if conn index is out // of bounds ntStatus = STATUS_INVALID_PARAMETER; for(i=1; i<=DeviceExtensionHub->HubDescriptor->bNumberOfPorts; i++) { if (i == request->ConnectionIndex) { PDEVICE_EXTENSION_PORT deviceExtensionPort; // make sure we have a valid devobj for this index if (portData->DeviceObject == NULL) { goto USBH_IoctlGetDescriptorForPDO_Complete; } deviceExtensionPort = portData->DeviceObject->DeviceExtension; if (request->SetupPacket.wValue == ((USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | 0) && outputBufferLength == sizeof(USB_CONFIGURATION_DESCRIPTOR)) { // // Only wants the basic configuration descriptor without the // rest of them tacked on (ie. interface, endpoint descriptors). // USBH_ASSERT(deviceExtensionPort->ExtensionType == EXTENSION_TYPE_PORT); RtlCopyMemory(outputBuffer, &deviceExtensionPort->ConfigDescriptor, outputBufferLength); Irp->IoStatus.Information = outputBufferLength + sizeof(USB_DESCRIPTOR_REQUEST); ntStatus = STATUS_SUCCESS; } else { PURB urb; // // OK send the request // USBH_KdPrint((2,"'sending descriptor request for ioclt\n")); // // Allocate an Urb and descriptor buffer. // urb = UsbhExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST)); if (urb) { UsbBuildGetDescriptorRequest(urb, (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST), request->SetupPacket.wValue >> 8, request->SetupPacket.wValue & 0xff, 0, outputBuffer, NULL, outputBufferLength, NULL); RtlCopyMemory(&urb->UrbControlDescriptorRequest.Reserved1, &request->SetupPacket.bmRequest, 8); ntStatus = USBH_SyncSubmitUrb(deviceExtensionPort->PortPhysicalDeviceObject, urb); Irp->IoStatus.Information = urb->UrbControlDescriptorRequest.TransferBufferLength + sizeof(USB_DESCRIPTOR_REQUEST); UsbhExFreePool(urb); } else { USBH_KdBreak(("SyncGetDeviceConfigurationDescriptor fail alloc Urb\n")); ntStatus = STATUS_INSUFFICIENT_RESOURCES; } } break; } portData++; } USBH_IoctlGetDescriptorForPDO_Complete: USBH_CompleteIrp(Irp, ntStatus); return ntStatus; } NTSTATUS USBH_PdoIoctlResetPort( IN PDEVICE_EXTENSION_PORT DeviceExtensionPort, IN PIRP Irp ) /* * Description: * * driver is requesting us to reset the port to which the device * is attached. * * Arguments: * * Return: * * NTSTATUS * * -- */ { NTSTATUS ntStatus = STATUS_SUCCESS; PDEVICE_EXTENSION_HUB deviceExtensionHub; PPORT_DATA portData; PAGED_CODE(); USBH_KdPrint((2,"'USBH_PdoIoctlResetPort DeviceExtension %x Irp %x\n", DeviceExtensionPort, Irp)); deviceExtensionHub = DeviceExtensionPort->DeviceExtensionHub; if (!deviceExtensionHub) { ntStatus = STATUS_UNSUCCESSFUL; goto USBH_PdoIoctlResetPortExit; } USBH_KdPrint((2,"'***WAIT hub mutex %x\n", deviceExtensionHub)); USBH_INC_PENDING_IO_COUNT(deviceExtensionHub); KeWaitForSingleObject(&deviceExtensionHub->HubMutex, Executive, KernelMode, FALSE, NULL); USBH_KdPrint((2,"'***WAIT hub mutex done %x\n", deviceExtensionHub)); portData = &deviceExtensionHub->PortData[DeviceExtensionPort->PortNumber - 1]; LOGENTRY(LOG_PNP, "Drst", deviceExtensionHub, DeviceExtensionPort->PortPhysicalDeviceObject, portData->DeviceObject); if (DeviceExtensionPort->PortPhysicalDeviceObject == portData->DeviceObject && DeviceExtensionPort->DeviceData != NULL) { #ifdef USB2 USBD_RemoveDeviceEx(deviceExtensionHub, DeviceExtensionPort->DeviceData, deviceExtensionHub->RootHubPdo, USBD_MARK_DEVICE_BUSY); #else USBD_RemoveDevice(DeviceExtensionPort->DeviceData, deviceExtensionHub->RootHubPdo, USBD_MARK_DEVICE_BUSY); #endif ntStatus = USBH_ResetDevice(deviceExtensionHub, DeviceExtensionPort->PortNumber, TRUE, 0); // RetryIteration } else { ntStatus = STATUS_INVALID_PARAMETER; } USBH_KdPrint((1,"'Warning: driver has reset the port (%x)\n", ntStatus)); USBH_KdPrint((2,"'***RELEASE hub mutex %x\n", deviceExtensionHub)); KeReleaseSemaphore(&deviceExtensionHub->HubMutex, LOW_REALTIME_PRIORITY, 1, FALSE); USBH_DEC_PENDING_IO_COUNT(deviceExtensionHub); USBH_PdoIoctlResetPortExit: // Must do this before completing the IRP because client driver may want // to post URB transfers in the completion routine. These transfers will // fail if this flag is still set. DeviceExtensionPort->PortPdoFlags &= ~PORTPDO_RESET_PENDING; USBH_CompleteIrp(Irp, ntStatus); return ntStatus; } VOID USBH_InternalCyclePort( IN PDEVICE_EXTENSION_HUB DeviceExtensionHub, IN USHORT PortNumber, IN PDEVICE_EXTENSION_PORT DeviceExtensionPort ) /* * Description: * * "Cycles" the requested port, i.e. causes PnP REMOVE and reenumeration * of the device. * * Arguments: * * Return: * * NTSTATUS * * -- */ { PPORT_DATA portData; PWCHAR sernumbuf = NULL; portData = &DeviceExtensionHub->PortData[PortNumber-1]; LOGENTRY(LOG_PNP, "WMIo", DeviceExtensionHub, PortNumber, DeviceExtensionPort); // synchronize with QBR USBH_KdPrint((2,"'***WAIT reset device mutex %x\n", DeviceExtensionHub)); USBH_INC_PENDING_IO_COUNT(DeviceExtensionHub); KeWaitForSingleObject(&DeviceExtensionHub->ResetDeviceMutex, Executive, KernelMode, FALSE, NULL); USBH_KdPrint((2,"'***WAIT reset device mutex done %x\n", DeviceExtensionHub)); { PDEVICE_OBJECT pdo; pdo = portData->DeviceObject; portData->DeviceObject = NULL; portData->ConnectionStatus = NoDeviceConnected; if (pdo) { // device should be present if we do this USBH_ASSERT(PDO_EXT(pdo)->PnPFlags & PDO_PNPFLAG_DEVICE_PRESENT); InsertTailList(&DeviceExtensionHub->DeletePdoList, &PDO_EXT(pdo)->DeletePdoLink); } } // in some overcurrent scenarios we may not have a PDO. // this function is synchronous, so the device should have // no tranfsers on completion if (DeviceExtensionPort) { USBD_RemoveDeviceEx(DeviceExtensionHub, DeviceExtensionPort->DeviceData, DeviceExtensionHub->RootHubPdo, 0); DeviceExtensionPort->DeviceData = NULL; // this prevents resets by the client DeviceExtensionPort->PortPdoFlags |= PORTPDO_CYCLED; // keep ref until removeal of hub OR child //DeviceExtensionPort->DeviceExtensionHub = NULL; // disable the port so no traffic passes to the device until reset USBH_SyncDisablePort(DeviceExtensionHub, DeviceExtensionPort->PortNumber); sernumbuf = InterlockedExchangePointer( &DeviceExtensionPort->SerialNumberBuffer, NULL); } if (sernumbuf) { UsbhExFreePool(sernumbuf); } USBH_KdPrint((2,"'***RELEASE reset device mutex %x\n", DeviceExtensionHub)); KeReleaseSemaphore(&DeviceExtensionHub->ResetDeviceMutex, LOW_REALTIME_PRIORITY, 1, FALSE); USBH_DEC_PENDING_IO_COUNT(DeviceExtensionHub); USBH_IoInvalidateDeviceRelations(DeviceExtensionHub->PhysicalDeviceObject, BusRelations); } NTSTATUS USBH_PdoIoctlCyclePort( IN PDEVICE_EXTENSION_PORT DeviceExtensionPort, IN PIRP Irp ) /* * Description: * * driver is requesting us to reset the port to which the device * is attached. * * Arguments: * * Return: * * NTSTATUS * * -- */ { NTSTATUS ntStatus = STATUS_SUCCESS; PDEVICE_EXTENSION_HUB deviceExtensionHub; USHORT portNumber; PAGED_CODE(); USBH_KdPrint((2,"'USBH_PdoIoctlResetPort DeviceExtension %x Irp %x\n", DeviceExtensionPort, Irp)); deviceExtensionHub = DeviceExtensionPort->DeviceExtensionHub; portNumber = DeviceExtensionPort->PortNumber; USBH_InternalCyclePort(deviceExtensionHub, portNumber, DeviceExtensionPort); USBH_CompleteIrp(Irp, ntStatus); return ntStatus; } #ifdef WMI_SUPPORT NTSTATUS USBH_BuildConnectionNotification( IN PDEVICE_EXTENSION_HUB DeviceExtensionHub, IN USHORT PortNumber, IN PUSB_CONNECTION_NOTIFICATION Notification ) /* * Description: * * driver is requesting us to reset the port to which the device * is attached. * * Arguments: * * Return: * * NTSTATUS * * -- */ { NTSTATUS ntStatus = STATUS_SUCCESS, status; USB_CONNECTION_STATUS connectStatus; USB_HUB_NAME hubName; PPORT_DATA portData; PDEVICE_EXTENSION_PORT deviceExtensionPort; portData = &DeviceExtensionHub->PortData[PortNumber-1]; if (portData->DeviceObject && portData->ConnectionStatus != DeviceHubNestedTooDeeply) { deviceExtensionPort = portData->DeviceObject->DeviceExtension; connectStatus = UsbhGetConnectionStatus(deviceExtensionPort); } else { deviceExtensionPort = NULL; connectStatus = portData->ConnectionStatus; } RtlZeroMemory(Notification, sizeof(*Notification)); Notification->ConnectionNumber = PortNumber; if (IS_ROOT_HUB(DeviceExtensionHub)) { hubName.ActualLength = sizeof(hubName) - sizeof(hubName.ActualLength); status = USBHUB_GetRootHubName(DeviceExtensionHub, &hubName.HubName, &hubName.ActualLength); } else { status = USBH_SyncGetHubName(DeviceExtensionHub->TopOfStackDeviceObject, &hubName, sizeof(hubName)); } USBH_KdPrint((1,"'Notification, hub name length = %d\n", hubName.ActualLength)); if (NT_SUCCESS(status)) { Notification->HubNameLength = hubName.ActualLength; } else { Notification->HubNameLength = 0; } switch(connectStatus) { case DeviceFailedEnumeration: // need to track some some reasons if (deviceExtensionPort) { Notification->EnumerationFailReason = deviceExtensionPort->FailReasonId; } else { Notification->EnumerationFailReason = 0; } Notification->NotificationType = EnumerationFailure; break; case DeviceCausedOvercurrent: Notification->NotificationType = OverCurrent; break; case DeviceNotEnoughPower: Notification->NotificationType = InsufficentPower; if (deviceExtensionPort) { Notification->PowerRequested = deviceExtensionPort->PowerRequested; } break; case DeviceNotEnoughBandwidth: Notification->NotificationType = InsufficentBandwidth; if (deviceExtensionPort) { Notification->RequestedBandwidth = deviceExtensionPort->RequestedBandwidth; } break; case DeviceHubNestedTooDeeply: Notification->NotificationType = HubNestedTooDeeply; break; case DeviceInLegacyHub: Notification->NotificationType = ModernDeviceInLegacyHub; break; case DeviceGeneralFailure: default: // nothing wrong? ntStatus = STATUS_UNSUCCESSFUL; } return ntStatus; } #endif NTSTATUS USBH_PdoEvent( IN PDEVICE_EXTENSION_HUB DeviceExtensionHub, IN USHORT PortNumber ) /* * Description: * * Triggers a WMI event based on the current connection status of the port * * Arguments: * * Return: * * NTSTATUS * * -- */ { NTSTATUS ntStatus = STATUS_SUCCESS; #ifdef WMI_SUPPORT PDEVICE_EXTENSION_PORT deviceExtensionPort; PPORT_DATA portData; PUSB_CONNECTION_NOTIFICATION notification; portData = &DeviceExtensionHub->PortData[PortNumber-1]; if (portData->DeviceObject) { deviceExtensionPort = portData->DeviceObject->DeviceExtension; } USBH_KdPrint((1,"'Fire WMI Event for Port Ext %x on hub ext %x\n", deviceExtensionPort, DeviceExtensionHub)); LOGENTRY(LOG_PNP, "WMIe", DeviceExtensionHub, deviceExtensionPort, 0); notification = ExAllocatePoolWithTag(PagedPool, sizeof(USB_CONNECTION_NOTIFICATION), USBHUB_HEAP_TAG); if (notification) { ntStatus = USBH_BuildConnectionNotification( DeviceExtensionHub, PortNumber, notification); if (NT_SUCCESS(ntStatus)) { ntStatus = WmiFireEvent( DeviceExtensionHub->FunctionalDeviceObject, (LPGUID)&GUID_USB_WMI_STD_NOTIFICATION, 0, sizeof(*notification), notification); } else { // Since we did not call WmiFireEvent then we must free the buffer // ourselves. ExFreePool(notification); } } else { ntStatus = STATUS_INSUFFICIENT_RESOURCES; } #endif /* WMI_SUPPORT */ return ntStatus; } #ifdef WMI_SUPPORT NTSTATUS USBH_SystemControl ( IN PDEVICE_EXTENSION_FDO DeviceExtensionFdo, IN PIRP Irp ) /*++ Routine Description We have just received a System Control IRP. Assume that this is a WMI IRP and call into the WMI system library and let it handle this IRP for us. --*/ { SYSCTL_IRP_DISPOSITION IrpDisposition; NTSTATUS ntStatus = STATUS_SUCCESS; ntStatus = WmiSystemControl( &DeviceExtensionFdo->WmiLibInfo, DeviceExtensionFdo->FunctionalDeviceObject, Irp, &IrpDisposition); switch (IrpDisposition) { case IrpProcessed: { // // This irp has been processed and may be completed or pending. break; } case IrpNotCompleted: { // // This irp has not been completed, but has been fully processed. // we will complete it now IoCompleteRequest(Irp, IO_NO_INCREMENT); break; } case IrpForward: case IrpNotWmi: { // // This irp is either not a WMI irp or is a WMI irp targetted // at a device lower in the stack. ntStatus = USBH_PassIrp(Irp, DeviceExtensionFdo->TopOfStackDeviceObject); break; } default: { // // We really should never get here, but if we do just forward.... ASSERT(FALSE); ntStatus = USBH_PassIrp(Irp, DeviceExtensionFdo->TopOfStackDeviceObject); break; } } return(ntStatus); } NTSTATUS USBH_PortSystemControl ( IN PDEVICE_EXTENSION_PORT DeviceExtensionPort, IN PIRP Irp ) /*++ Routine Description We have just received a System Control IRP. Assume that this is a WMI IRP and call into the WMI system library and let it handle this IRP for us. --*/ { SYSCTL_IRP_DISPOSITION IrpDisposition; NTSTATUS ntStatus = STATUS_SUCCESS; ntStatus = WmiSystemControl( &DeviceExtensionPort->WmiLibInfo, DeviceExtensionPort->PortPhysicalDeviceObject, Irp, &IrpDisposition); switch (IrpDisposition) { case IrpNotWmi: // Don't change status of IRP we don't know about. ntStatus = Irp->IoStatus.Status; // fall through case IrpNotCompleted: case IrpForward: default: USBH_CompleteIrp(Irp, ntStatus); break; case IrpProcessed: // Don't complete the IRP in this case. break; } return(ntStatus); } PDEVICE_EXTENSION_PORT USBH_GetPortPdoExtension( IN PDEVICE_EXTENSION_HUB DeviceExtensionHub, IN ULONG PortNumber ) /* * Description: * * Arguments: * * Return: * * NTSTATUS * * -- */ { PPORT_DATA portData; USHORT nextPortNumber; USHORT numberOfPorts; portData = DeviceExtensionHub->PortData; // // hub descriptor will be null if the hub is already stopped // if (portData && DeviceExtensionHub->HubDescriptor) { numberOfPorts = DeviceExtensionHub->HubDescriptor->bNumberOfPorts; for (nextPortNumber = 1; nextPortNumber <= numberOfPorts; nextPortNumber++, portData++) { USBH_KdPrint((1,"'portdata %x, do %x\n", portData, portData->DeviceObject)); if (PortNumber == nextPortNumber) { if (portData->DeviceObject) return portData->DeviceObject->DeviceExtension; else return NULL; } } } return NULL; } VOID USBH_CheckLeafHubsIdle( IN PDEVICE_EXTENSION_HUB DeviceExtensionHub ) /* ++ * * Description: * * This function walks the chain of hubs downstream from the specified hub, * and idles the leaf hubs if ready. * * Arguments: * * DeviceExtensionHub * * Return: * * NTSTATUS * * -- */ { PDEVICE_EXTENSION_PORT childDeviceExtensionPort; PDEVICE_EXTENSION_HUB childDeviceExtensionHub; BOOLEAN bHaveChildrenHubs = FALSE; ULONG i; PAGED_CODE(); // Ensure that child port configuration does not change while in this // function, i.e. don't allow QBR. // USBH_KdPrint((2,"'***WAIT reset device mutex %x\n", DeviceExtensionHub)); // USBH_INC_PENDING_IO_COUNT(DeviceExtensionHub); // KeWaitForSingleObject(&DeviceExtensionHub->ResetDeviceMutex, // Executive, // KernelMode, // FALSE, // NULL); // USBH_KdPrint((2,"'***WAIT reset device mutex done %x\n", DeviceExtensionHub)); for (i = 0; i < DeviceExtensionHub->HubDescriptor->bNumberOfPorts; i++) { if (DeviceExtensionHub->PortData[i].DeviceObject) { childDeviceExtensionPort = DeviceExtensionHub->PortData[i].DeviceObject->DeviceExtension; if (childDeviceExtensionPort->PortPdoFlags & PORTPDO_DEVICE_IS_HUB) { PDRIVER_OBJECT hubDriver; PDEVICE_OBJECT childHubPdo, childHubFdo; // We have a child hub. This means that we are not a leaf hub. // Indicate this and recurse down to the child hub. bHaveChildrenHubs = TRUE; hubDriver = DeviceExtensionHub->FunctionalDeviceObject->DriverObject; childHubPdo = childDeviceExtensionPort->PortPhysicalDeviceObject; do { childHubFdo = childHubPdo->AttachedDevice; childHubPdo = childHubFdo; } while (childHubFdo->DriverObject != hubDriver); childDeviceExtensionHub = childHubFdo->DeviceExtension; USBH_CheckLeafHubsIdle(childDeviceExtensionHub); } } } // USBH_KdPrint((2,"'***RELEASE reset device mutex %x\n", DeviceExtensionHub)); // KeReleaseSemaphore(&DeviceExtensionHub->ResetDeviceMutex, // LOW_REALTIME_PRIORITY, // 1, // FALSE); // // USBH_DEC_PENDING_IO_COUNT(DeviceExtensionHub); if (!bHaveChildrenHubs) { // If this hub has no children then it is a leaf hub. See if // it is ready to be idled out. USBH_CheckHubIdle(DeviceExtensionHub); } } // // WMI System Call back functions // NTSTATUS USBH_SetWmiDataBlock( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN ULONG GuidIndex, IN ULONG InstanceIndex, IN ULONG BufferSize, IN PUCHAR Buffer ) /*++ Routine Description: This routine is a callback into the driver to set the contents of a data block. When the driver has finished filling the data block it must call ClassWmiCompleteRequest to complete the irp. The driver can return STATUS_PENDING if the irp cannot be completed immediately. Arguments: DeviceObject is the device whose data block is being queried Irp is the Irp that makes this request GuidIndex is the index into the list of guids provided when the device registered InstanceIndex is the index that denotes which instance of the data block is being queried. BufferSize has the size of the data block passed Buffer has the new values for the data block Return Value: status --*/ { PDEVICE_EXTENSION_FDO deviceExtensionFdo; PDEVICE_EXTENSION_HUB deviceExtensionHub; NTSTATUS status; ULONG size = 0; BOOLEAN bEnableSS, bSelectiveSuspendEnabled = FALSE, globaDisableSS; deviceExtensionFdo = (PDEVICE_EXTENSION_FDO) DeviceObject->DeviceExtension; deviceExtensionHub = (PDEVICE_EXTENSION_HUB) DeviceObject->DeviceExtension; switch(GuidIndex) { case WMI_USB_DRIVER_INFORMATION: status = /*STATUS_WMI_READ_ONLY*/STATUS_INVALID_DEVICE_REQUEST; break; case WMI_USB_POWER_DEVICE_ENABLE: // We only support this for the Root Hub but this WMI request should // only occur for the Root Hub because we only register this GUID // for the Root Hub. We perform a sanity check anyway. USBH_ASSERT(deviceExtensionFdo->ExtensionType == EXTENSION_TYPE_HUB); USBH_ASSERT(IS_ROOT_HUB(deviceExtensionHub)); USBH_RegQueryUSBGlobalSelectiveSuspend(&globaDisableSS); if (deviceExtensionFdo->ExtensionType == EXTENSION_TYPE_HUB && IS_ROOT_HUB(deviceExtensionHub) && !globaDisableSS) { size = sizeof(BOOLEAN); if (BufferSize < size) { status = STATUS_BUFFER_TOO_SMALL; } else if (0 != InstanceIndex) { status = STATUS_INVALID_DEVICE_REQUEST; } else { bEnableSS = *(PBOOLEAN)Buffer; status = USBD_QuerySelectiveSuspendEnabled(deviceExtensionHub, &bSelectiveSuspendEnabled); if (NT_SUCCESS(status) && bEnableSS != bSelectiveSuspendEnabled) { // Update global flag and registry with new setting. status = USBD_SetSelectiveSuspendEnabled(deviceExtensionHub, bEnableSS); if (NT_SUCCESS(status)) { if (bEnableSS) { // We are being asked to enable Selective Suspend // when it was previously disabled. // Find the end hubs in the chain and idle them // out if ready. This will trickle down to // the parent hubs if all hubs are idle. USBH_CheckLeafHubsIdle(deviceExtensionHub); status = STATUS_SUCCESS; } else { // We are being asked to disable Selective Suspend // when it was previously enabled. if (deviceExtensionHub->CurrentPowerState != PowerDeviceD0 && (deviceExtensionHub->HubFlags & HUBFLAG_NEED_CLEANUP)) { USBH_HubSetD0(deviceExtensionHub); } else { USBH_HubCompletePortIdleIrps(deviceExtensionHub, STATUS_CANCELLED); } status = STATUS_SUCCESS; } } } } } else { status = STATUS_INVALID_DEVICE_REQUEST; } break; default: status = STATUS_WMI_GUID_NOT_FOUND; } status = WmiCompleteRequest(DeviceObject, Irp, status, 0, IO_NO_INCREMENT); return(status); } NTSTATUS USBH_QueryWmiDataBlock( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN ULONG GuidIndex, IN ULONG InstanceIndex, IN ULONG InstanceCount, IN OUT PULONG InstanceLengthArray, IN ULONG OutBufferSize, OUT PUCHAR Buffer ) /*++ Routine Description: This routine is a callback into the driver to query for the contents of a data block. When the driver has finished filling the data block it must call ClassWmiCompleteRequest to complete the irp. The driver can return STATUS_PENDING if the irp cannot be completed immediately. Arguments: DeviceObject is the device whose data block is being queried Irp is the Irp that makes this request GuidIndex is the index into the list of guids provided when the device registered InstanceIndex is the index that denotes which instance of the data block is being queried. InstanceCount is the number of instnaces expected to be returned for the data block. InstanceLengthArray is a pointer to an array of ULONG that returns the lengths of each instance of the data block. If this is NULL then there was not enough space in the output buffer to fufill the request so the irp should be completed with the buffer needed. BufferAvail on has the maximum size available to write the data block. Buffer on return is filled with the returned data block Return Value: status --*/ { PDEVICE_EXTENSION_FDO deviceExtensionFdo; PUSB_NOTIFICATION notification; NTSTATUS status; ULONG size = 0; PDEVICE_EXTENSION_HUB deviceExtensionHub; BOOLEAN bSelectiveSuspendEnabled = FALSE,globaDisableSS; deviceExtensionFdo = (PDEVICE_EXTENSION_FDO) DeviceObject->DeviceExtension; deviceExtensionHub = (PDEVICE_EXTENSION_HUB) DeviceObject->DeviceExtension; notification = (PUSB_NOTIFICATION) Buffer; USBH_KdPrint((1,"'WMI Query Data Block on hub ext %x\n", deviceExtensionHub)); switch (GuidIndex) { case WMI_USB_DRIVER_INFORMATION: if (InstanceLengthArray != NULL) { *InstanceLengthArray = 0; status = STATUS_SUCCESS; } else { status = STATUS_BUFFER_TOO_SMALL; } break; case WMI_USB_POWER_DEVICE_ENABLE: // We only support this for the Root Hub but this WMI request should // only occur for the Root Hub because we only register this GUID // for the Root Hub. We perform a sanity check anyway. USBH_ASSERT(deviceExtensionFdo->ExtensionType == EXTENSION_TYPE_HUB); USBH_ASSERT(IS_ROOT_HUB(deviceExtensionHub)); USBH_RegQueryUSBGlobalSelectiveSuspend(&globaDisableSS); if (deviceExtensionFdo->ExtensionType == EXTENSION_TYPE_HUB && IS_ROOT_HUB(deviceExtensionHub) && !globaDisableSS) { // // Only registers 1 instance for this GUID. // if ((0 != InstanceIndex) || (1 != InstanceCount)) { status = STATUS_INVALID_DEVICE_REQUEST; break; } size = sizeof(BOOLEAN); if (OutBufferSize < size) { status = STATUS_BUFFER_TOO_SMALL; break; } status = USBD_QuerySelectiveSuspendEnabled(deviceExtensionHub, &bSelectiveSuspendEnabled); if (!NT_SUCCESS(status)) { break; } *(PBOOLEAN)Buffer = bSelectiveSuspendEnabled; *InstanceLengthArray = size; status = STATUS_SUCCESS; } else { status = STATUS_INVALID_DEVICE_REQUEST; } break; default: status = STATUS_WMI_GUID_NOT_FOUND; } status = WmiCompleteRequest(DeviceObject, Irp, status, size, IO_NO_INCREMENT); return status; } NTSTATUS USBH_PortQueryWmiDataBlock( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN ULONG GuidIndex, IN ULONG InstanceIndex, IN ULONG InstanceCount, IN OUT PULONG InstanceLengthArray, IN ULONG OutBufferSize, OUT PUCHAR Buffer ) /*++ Routine Description: This routine is a callback into the driver to query for the contents of a data block. When the driver has finished filling the data block it must call ClassWmiCompleteRequest to complete the irp. The driver can return STATUS_PENDING if the irp cannot be completed immediately. Arguments: DeviceObject is the device whose data block is being queried Irp is the Irp that makes this request GuidIndex is the index into the list of guids provided when the device registered InstanceIndex is the index that denotes which instance of the data block is being queried. InstanceCount is the number of instnaces expected to be returned for the data block. InstanceLengthArray is a pointer to an array of ULONG that returns the lengths of each instance of the data block. If this is NULL then there was not enough space in the output buffer to fufill the request so the irp should be completed with the buffer needed. BufferAvail on has the maximum size available to write the data block. Buffer on return is filled with the returned data block Return Value: status --*/ { PDEVICE_EXTENSION_PORT deviceExtensionPort; PUSB_DEVICE_UI_FIRMWARE_REVISION fwRevBuf; NTSTATUS status; ULONG size = 0; PWCHAR revstr; USHORT bcdDevice; USHORT stringsize; deviceExtensionPort = (PDEVICE_EXTENSION_PORT) DeviceObject->DeviceExtension; USBH_KdPrint((1,"'WMI Query Data Block on PORT PDO ext %x\n", deviceExtensionPort)); switch (GuidIndex) { case 0: // Return USB device FW revision # in the following format "xx.xx". // Need buffer large enough for this string plus NULL terminator. stringsize = 6 * sizeof(WCHAR); size = sizeof(USB_DEVICE_UI_FIRMWARE_REVISION) + (ULONG)stringsize; if (OutBufferSize < size) { status = STATUS_BUFFER_TOO_SMALL; break; } bcdDevice = deviceExtensionPort->DeviceDescriptor.bcdDevice; fwRevBuf = (PUSB_DEVICE_UI_FIRMWARE_REVISION)Buffer; revstr = &fwRevBuf->FirmwareRevisionString[0]; *revstr = BcdNibbleToAscii(bcdDevice >> 12); *(revstr+1) = BcdNibbleToAscii((bcdDevice >> 8) & 0x000f); *(revstr+2) = '.'; *(revstr+3) = BcdNibbleToAscii((bcdDevice >> 4) & 0x000f); *(revstr+4) = BcdNibbleToAscii(bcdDevice & 0x000f); *(revstr+5) = 0; fwRevBuf->Length = stringsize; *InstanceLengthArray = size; status = STATUS_SUCCESS; USBH_KdPrint((1,"'WMI Query Data Block, returning FW rev # '%ws'\n", revstr)); break; default: status = STATUS_WMI_GUID_NOT_FOUND; } status = WmiCompleteRequest(DeviceObject, Irp, status, size, IO_NO_INCREMENT); return status; } NTSTATUS USBH_ExecuteWmiMethod( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN ULONG GuidIndex, IN ULONG InstanceIndex, IN ULONG MethodId, IN ULONG InBufferSize, IN ULONG OutBufferSize, IN OUT PUCHAR Buffer ) /*++ Routine Description: This routine is a callback into the driver to execute a method. When the driver has finished filling the data block it must call WmiCompleteRequest to complete the irp. The driver can return STATUS_PENDING if the irp cannot be completed immediately. Arguments: DeviceObject is the device whose data block is being queried Irp is the Irp that makes this request GuidIndex is the index into the list of guids provided when the device registered InstanceIndex is the index that denotes which instance of the data block is being called. MethodId has the id of the method being called InBufferSize has the size of the data block passed in as the input to the method. OutBufferSize on entry has the maximum size available to write the returned data block. Buffer on entry has the input data block and on return has the output output data block. Return Value: status --*/ { PDEVICE_EXTENSION_FDO deviceExtensionFdo; PUSB_NOTIFICATION notification; NTSTATUS ntStatus = STATUS_WMI_GUID_NOT_FOUND; ULONG size = 0; PDEVICE_EXTENSION_HUB deviceExtensionHub; PDEVICE_EXTENSION_PORT portPdoExt; BOOLEAN bDoCheckHubIdle = FALSE; deviceExtensionFdo = (PDEVICE_EXTENSION_FDO) DeviceObject->DeviceExtension; if (deviceExtensionFdo->ExtensionType == EXTENSION_TYPE_PARENT) { // Looks like a child PDO of a composite device is causing the problem. // Let's be sure to get the correct device extension for the hub. portPdoExt = deviceExtensionFdo->PhysicalDeviceObject->DeviceExtension; deviceExtensionHub = portPdoExt->DeviceExtensionHub; } else { deviceExtensionHub = (PDEVICE_EXTENSION_HUB) DeviceObject->DeviceExtension; } USBH_ASSERT(EXTENSION_TYPE_HUB == deviceExtensionHub->ExtensionType); // If this hub is currently Selective Suspended, then we need to // power up the hub first before sending any requests along to it. // Make sure hub has been started, though. if (deviceExtensionHub->CurrentPowerState != PowerDeviceD0 && (deviceExtensionHub->HubFlags & HUBFLAG_NEED_CLEANUP)) { bDoCheckHubIdle = TRUE; USBH_HubSetD0(deviceExtensionHub); } notification = (PUSB_NOTIFICATION) Buffer; USBH_KdPrint((1,"'WMI Execute Method on hub ext %x\n", deviceExtensionHub)); switch (GuidIndex) { case WMI_USB_DRIVER_INFORMATION: size = sizeof(*notification); if (OutBufferSize < size) { ntStatus = STATUS_BUFFER_TOO_SMALL; break; } // switch(MethodId) { switch (notification->NotificationType) { case EnumerationFailure: { PUSB_CONNECTION_NOTIFICATION connectionNotification; USBH_KdPrint((1,"'Method EnumerationFailure %x\n")); connectionNotification = (PUSB_CONNECTION_NOTIFICATION) Buffer; size = sizeof(*connectionNotification); if (OutBufferSize < size) { USBH_KdPrint((1,"'pwr - buff too small\n")); ntStatus = STATUS_BUFFER_TOO_SMALL; } else { portPdoExt = USBH_GetPortPdoExtension(deviceExtensionHub, connectionNotification->ConnectionNumber); if (portPdoExt) { connectionNotification->EnumerationFailReason = portPdoExt->FailReasonId; ntStatus = STATUS_SUCCESS; } else { USBH_KdPrint((1,"'ef - bad connection index\n")); ntStatus = STATUS_INVALID_PARAMETER; } } } break; case InsufficentBandwidth: { PUSB_CONNECTION_NOTIFICATION connectionNotification; USBH_KdPrint((1,"'Method InsufficentBandwidth\n")); connectionNotification = (PUSB_CONNECTION_NOTIFICATION) Buffer; size = sizeof(*connectionNotification); if (OutBufferSize < size) { USBH_KdPrint((1,"'pwr - buff too small\n")); ntStatus = STATUS_BUFFER_TOO_SMALL; } else { portPdoExt = USBH_GetPortPdoExtension(deviceExtensionHub, connectionNotification->ConnectionNumber); if (portPdoExt) { connectionNotification->RequestedBandwidth = portPdoExt->RequestedBandwidth; ntStatus = STATUS_SUCCESS; } else { USBH_KdPrint((1,"'bw - bad connection index\n")); ntStatus = STATUS_INVALID_PARAMETER; } } } break; case OverCurrent: // nothing to do here USBH_KdPrint((1,"'Method OverCurrent\n")); ntStatus = STATUS_SUCCESS; size = 0; break; case InsufficentPower: { PUSB_CONNECTION_NOTIFICATION connectionNotification; USBH_KdPrint((1,"'Method InsufficentPower\n")); size = sizeof(*connectionNotification); if (OutBufferSize < size) { USBH_KdPrint((1,"'pwr - buff too small\n")); ntStatus = STATUS_BUFFER_TOO_SMALL; } else { connectionNotification = (PUSB_CONNECTION_NOTIFICATION) Buffer; USBH_KdPrint((1,"'pwr - connection %d\n", connectionNotification->ConnectionNumber)); if (connectionNotification->ConnectionNumber) { if (portPdoExt = USBH_GetPortPdoExtension(deviceExtensionHub, connectionNotification->ConnectionNumber)) { connectionNotification->PowerRequested = portPdoExt->PowerRequested; ntStatus = STATUS_SUCCESS; } } else { USBH_KdPrint((1,"'pwr - bad connection index\n")); ntStatus = STATUS_INVALID_PARAMETER; } } } break; case ResetOvercurrent: { PUSB_CONNECTION_NOTIFICATION connectionNotification; USBH_KdPrint((1,"'Method ResetOvercurrent\n")); size = sizeof(*connectionNotification); if (OutBufferSize < size) { USBH_KdPrint((1,"'reset - buff too small\n")); ntStatus = STATUS_BUFFER_TOO_SMALL; } else { connectionNotification = (PUSB_CONNECTION_NOTIFICATION) Buffer; if (connectionNotification->ConnectionNumber) { USBH_KdPrint((1,"'reset - port %d\n", connectionNotification->ConnectionNumber)); portPdoExt = USBH_GetPortPdoExtension(deviceExtensionHub, connectionNotification->ConnectionNumber); ntStatus = USBH_ResetPortOvercurrent(deviceExtensionHub, (USHORT)connectionNotification->ConnectionNumber, portPdoExt); // } else { // // bad connection index // USBH_KdPrint((1,"'reset - bad connection index\n")); // ntStatus = STATUS_INVALID_PARAMETER; // } } else { // this is a reset for the whole hub USBH_KdPrint((1,"'not implemented yet\n")); TEST_TRAP(); ntStatus = STATUS_NOT_IMPLEMENTED; } } } break; case AcquireBusInfo: { PUSB_BUS_NOTIFICATION busNotification; USBH_KdPrint((1,"'Method AcquireBusInfo\n")); size = sizeof(*busNotification); if (OutBufferSize < size) { USBH_KdPrint((1,"'AcquireBusInfo - buff too small\n")); ntStatus = STATUS_BUFFER_TOO_SMALL; } else { busNotification = (PUSB_BUS_NOTIFICATION) Buffer; // ntStatus = USBH_SyncGetControllerInfo( // deviceExtensionHub->TopOfStackDeviceObject, // busNotification, // sizeof(*busNotification), // IOCTL_INTERNAL_USB_GET_BUS_INFO); ntStatus = USBHUB_GetBusInfo(deviceExtensionHub, busNotification, NULL); USBH_KdPrint((1,"'Notification, controller name length = %d\n", busNotification->ControllerNameLength)); } } break; case AcquireHubName: /*+ we utilize the fact that these structures have some elements in common USB_HUB_NAME USB_ACQUIRE_INFO ------------ ---------------- USB_NOTIFICATION_TYPE NotificationType; ULONG ActualLength; ULONG TotalSize; WCHAR HubName[1]; WCHAR Buffer[1]; USB_NOTIFICATION_TYPE NotificationType; +*/ { PUSB_HUB_NAME hubName; PUSB_ACQUIRE_INFO acquireInfo; USBH_KdPrint((1,"'Method AcquireHubName\n")); size = sizeof(USB_ACQUIRE_INFO); acquireInfo = (PUSB_ACQUIRE_INFO) Buffer; if (OutBufferSize < size || acquireInfo->TotalSize < size) { ntStatus = STATUS_BUFFER_TOO_SMALL; break; } // return the samller of the two as the output length so we don't // copy more than necessary size = acquireInfo->TotalSize > OutBufferSize ? OutBufferSize : acquireInfo->TotalSize; hubName = (PUSB_HUB_NAME) &acquireInfo->TotalSize; // TotalSize contains the size of the notification type as well // comsume notification type field hubName->ActualLength -= sizeof(USB_NOTIFICATION_TYPE); OutBufferSize -= sizeof(USB_NOTIFICATION_TYPE); // As long as ActualLength is less than the true output buffer // length we are safe if (hubName->ActualLength > OutBufferSize) { ntStatus = STATUS_BUFFER_TOO_SMALL; break; } if (IS_ROOT_HUB(deviceExtensionHub)) { // consume the length field hubName->ActualLength -= sizeof(hubName->ActualLength); // this will set HubName to the name plus set the // actual length field to the true length of the name // the API needs to return the length of the entire hubname // structure ntStatus = USBHUB_GetRootHubName(deviceExtensionHub, hubName->HubName, &hubName->ActualLength); // ActualLength is the length of the entire structure hubName->ActualLength += sizeof(hubName->ActualLength); } else { // passes the hubname strucutre down, ActualLength is the // length of the entire structure ntStatus = USBH_SyncGetHubName( deviceExtensionHub->TopOfStackDeviceObject, hubName, hubName->ActualLength); } // readjust to previous value hubName->ActualLength += sizeof(USB_NOTIFICATION_TYPE); OutBufferSize += sizeof(USB_NOTIFICATION_TYPE); } break; case AcquireControllerName: /*+ we utilize the fact that these structures have some elements in common USB_HUB_NAME USB_ACQUIRE_INFO ------------ ---------------- USB_NOTIFICATION_TYPE NotificationType; ULONG ActualLength; ULONG TotalSize; WCHAR HubName[1]; WCHAR Buffer[1]; USB_NOTIFICATION_TYPE NotificationType; +*/ { PUSB_HUB_NAME controllerName; PUSB_ACQUIRE_INFO acquireInfo; USBH_KdPrint((1,"'Method AcquireControllerName\n")); size = sizeof(USB_ACQUIRE_INFO); acquireInfo = (PUSB_ACQUIRE_INFO) Buffer; if (OutBufferSize < size || acquireInfo->TotalSize < size) { ntStatus = STATUS_BUFFER_TOO_SMALL; break; } USBH_KdPrint((1,"'TotalSize %d\n", acquireInfo->TotalSize)); USBH_KdPrint((1,"'NotificationType %x\n", acquireInfo->NotificationType)); // use the smaller of the two specified values for the copy // back to user mode size = acquireInfo->TotalSize > OutBufferSize ? OutBufferSize : acquireInfo->TotalSize; controllerName = (PUSB_HUB_NAME) &acquireInfo->TotalSize; // TotalSize contains the size of the notification type as well // consume USB_NOTIFICATION_TYPE controllerName->ActualLength -= sizeof(USB_NOTIFICATION_TYPE); OutBufferSize -= sizeof(USB_NOTIFICATION_TYPE); if (controllerName->ActualLength > OutBufferSize) { ntStatus = STATUS_BUFFER_TOO_SMALL; break; } ntStatus = USBHUB_GetControllerName(deviceExtensionHub, controllerName, controllerName->ActualLength); // readjust to previous value controllerName->ActualLength += sizeof(USB_NOTIFICATION_TYPE); OutBufferSize += sizeof(USB_NOTIFICATION_TYPE); USBH_KdPrint((1,"'Method AcquireControllerName %x - %d\n", acquireInfo, controllerName->ActualLength)); } break; case HubOvercurrent: USBH_KdPrint((1,"'Method HubOvercurrent\n")); USBH_KdPrint((1,"'not implemented yet\n")); ntStatus = STATUS_SUCCESS; size = 0; break; case HubPowerChange: USBH_KdPrint((1,"'Method HubPowerChange\n")); USBH_KdPrint((1,"'not implemented yet\n")); ntStatus = STATUS_SUCCESS; size = 0; break; case HubNestedTooDeeply: // nothing to do here USBH_KdPrint((1,"'Method HubNestedTooDeeply\n")); ntStatus = STATUS_SUCCESS; size = 0; break; case ModernDeviceInLegacyHub: // nothing to do here USBH_KdPrint((1,"'Method ModernDeviceInLegacyHub\n")); ntStatus = STATUS_SUCCESS; size = 0; break; } break; default: ntStatus = STATUS_WMI_GUID_NOT_FOUND; } ntStatus = WmiCompleteRequest(DeviceObject, Irp, ntStatus, size, IO_NO_INCREMENT); if (bDoCheckHubIdle) { USBH_CheckHubIdle(deviceExtensionHub); } return ntStatus; } NTSTATUS USBH_QueryWmiRegInfo( IN PDEVICE_OBJECT DeviceObject, OUT PULONG RegFlags, OUT PUNICODE_STRING InstanceName, OUT PUNICODE_STRING *RegistryPath, OUT PUNICODE_STRING MofResourceName, OUT PDEVICE_OBJECT *Pdo ) /*++ Routine Description: This routine is a callback into the driver to retrieve information about the guids being registered. Implementations of this routine may be in paged memory Arguments: DeviceObject is the device whose registration information is needed *RegFlags returns with a set of flags that describe all of the guids being registered for this device. If the device wants enable and disable collection callbacks before receiving queries for the registered guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case the instance name is determined from the PDO associated with the device object. Note that the PDO must have an associated devnode. If WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique name for the device. These flags are ORed into the flags specified by the GUIDREGINFO for each guid. InstanceName returns with the instance name for the guids if WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The caller will call ExFreePool with the buffer returned. *RegistryPath returns with the registry path of the driver. This is required MofResourceName returns with the name of the MOF resource attached to the binary file. If the driver does not have a mof resource attached then this can be returned unmodified. If a value is returned then it is NOT freed. *Pdo returns with the device object for the PDO associated with this device if the WMIREG_FLAG_INSTANCE_PDO flag is returned in *RegFlags. Return Value: status --*/ { PDEVICE_EXTENSION_HUB deviceExtensionHub; // pointer to our device // extension deviceExtensionHub = (PDEVICE_EXTENSION_HUB) DeviceObject->DeviceExtension; *RegFlags = WMIREG_FLAG_INSTANCE_PDO; *RegistryPath = &UsbhRegistryPath; *Pdo = deviceExtensionHub->PhysicalDeviceObject; return STATUS_SUCCESS; } NTSTATUS USBH_PortQueryWmiRegInfo( IN PDEVICE_OBJECT DeviceObject, OUT PULONG RegFlags, OUT PUNICODE_STRING InstanceName, OUT PUNICODE_STRING *RegistryPath, OUT PUNICODE_STRING MofResourceName, OUT PDEVICE_OBJECT *Pdo ) /*++ Routine Description: This routine is a callback into the driver to retrieve information about the guids being registered. Implementations of this routine may be in paged memory Arguments: DeviceObject is the device whose registration information is needed *RegFlags returns with a set of flags that describe all of the guids being registered for this device. If the device wants enable and disable collection callbacks before receiving queries for the registered guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case the instance name is determined from the PDO associated with the device object. Note that the PDO must have an associated devnode. If WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique name for the device. These flags are ORed into the flags specified by the GUIDREGINFO for each guid. InstanceName returns with the instance name for the guids if WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The caller will call ExFreePool with the buffer returned. *RegistryPath returns with the registry path of the driver. This is required MofResourceName returns with the name of the MOF resource attached to the binary file. If the driver does not have a mof resource attached then this can be returned unmodified. If a value is returned then it is NOT freed. *Pdo returns with the device object for the PDO associated with this device if the WMIREG_FLAG_INSTANCE_PDO flag is returned in *RegFlags. Return Value: status --*/ { PDEVICE_EXTENSION_PORT deviceExtensionPort; deviceExtensionPort = (PDEVICE_EXTENSION_PORT) DeviceObject->DeviceExtension; *RegFlags = WMIREG_FLAG_INSTANCE_PDO; *RegistryPath = &UsbhRegistryPath; *Pdo = deviceExtensionPort->PortPhysicalDeviceObject; return STATUS_SUCCESS; } #endif /* WMI_SUPPORT */ NTSTATUS USBH_ResetPortOvercurrent( IN PDEVICE_EXTENSION_HUB DeviceExtensionHub, IN USHORT PortNumber, IN PDEVICE_EXTENSION_PORT DeviceExtensionPort ) /* * Description: * * Reset the overcurrent condition for a port * * Arguments: * * Return: * * NTSTATUS * * -- */ { NTSTATUS ntStatus = STATUS_SUCCESS, status; PORT_STATE portState; USBH_KdPrint((0,"'Reset Overcurrent for port %d\n", PortNumber)); // we will need to re-enable and re-power the port ntStatus = USBH_SyncGetPortStatus(DeviceExtensionHub, PortNumber, (PUCHAR) &portState, sizeof(portState)); // // port should be powered off at this point // LOGENTRY(LOG_PNP, "RPOv", DeviceExtensionHub, portState.PortStatus, portState.PortChange); if (NT_SUCCESS(ntStatus)) { if (portState.PortStatus & PORT_STATUS_POWER) { ntStatus = STATUS_INVALID_PARAMETER; } else { if (DeviceExtensionPort) { // clear overcurrent Flags DeviceExtensionPort->PortPdoFlags &= ~PORTPDO_OVERCURRENT; } // power up the port ntStatus = USBH_SyncPowerOnPort(DeviceExtensionHub, PortNumber, TRUE); USBH_InternalCyclePort(DeviceExtensionHub, PortNumber, DeviceExtensionPort); } } return ntStatus; } NTSTATUS USBH_CalculateInterfaceBandwidth( IN PDEVICE_EXTENSION_PORT DeviceExtensionPort, IN PUSBD_INTERFACE_INFORMATION Interface, IN OUT PULONG Bandwidth // in kenr units? ) /* * Description: * * Arguments: * * Return: * * NTSTATUS * * -- */ { NTSTATUS ntStatus = STATUS_SUCCESS; ULONG i, bw; // we'll need to walk through the interface // and figure out how much BW it requires for (i=0; iNumberOfPipes; i++) { //#ifdef USB2 // bw = USBD_CalculateUsbBandwidthEx( // (ULONG) Interface->Pipes[i].MaximumPacketSize, // (UCHAR) Interface->Pipes[i].PipeType, // (BOOLEAN) (DeviceExtensionPort->PortPdoFlags & // PORTPDO_LOW_SPEED_DEVICE)); //#else bw = USBD_CalculateUsbBandwidth( (ULONG) Interface->Pipes[i].MaximumPacketSize, (UCHAR) Interface->Pipes[i].PipeType, (BOOLEAN) (DeviceExtensionPort->PortPdoFlags & PORTPDO_LOW_SPEED_DEVICE)); //#endif USBH_KdPrint((1,"'ept = %d packetsize = %d bw = %d\n", Interface->Pipes[i].PipeType, Interface->Pipes[i].MaximumPacketSize, bw)); *Bandwidth += bw; } return ntStatus; }