2020-09-24 20:51:15 +00:00
|
|
|
/*++
|
|
|
|
|
|
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
|
|
|
|
Module Name:
|
|
|
|
|
|
|
|
FxUsbDeviceKm.cpp
|
|
|
|
|
|
|
|
Abstract:
|
|
|
|
|
|
|
|
Author:
|
|
|
|
|
|
|
|
Environment:
|
|
|
|
|
|
|
|
kernel mode only
|
|
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
#include <initguid.h>
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "fxusbpch.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
#include "FxUsbDeviceKm.tmh"
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define UCHAR_MAX (0xff)
|
|
|
|
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
FxUsbDevice::InitDevice(
|
|
|
|
__in ULONG USBDClientContractVersionForWdfClient
|
|
|
|
)
|
|
|
|
{
|
|
|
|
URB urb;
|
|
|
|
FxSyncRequest request(GetDriverGlobals(), NULL);
|
|
|
|
WDF_REQUEST_SEND_OPTIONS options;
|
|
|
|
NTSTATUS status;
|
|
|
|
ULONG size;
|
|
|
|
|
|
|
|
RtlZeroMemory(&urb, sizeof(urb));
|
|
|
|
|
|
|
|
if (USBDClientContractVersionForWdfClient != USBD_CLIENT_CONTRACT_VERSION_INVALID) {
|
|
|
|
|
|
|
|
//
|
|
|
|
// Register with USBDEX.lib
|
|
|
|
//
|
|
|
|
status = USBD_CreateHandle(m_InStackDevice,
|
|
|
|
m_TargetDevice,
|
|
|
|
USBDClientContractVersionForWdfClient,
|
|
|
|
GetDriverGlobals()->Tag,
|
|
|
|
&m_USBDHandle);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DoTraceLevelMessage(
|
|
|
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"USBD_CreateHandle failed, %!STATUS!", status);
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_UrbType = FxUrbTypeUsbdAllocated;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = request.m_TrueRequest->ValidateTarget(this);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
|
|
|
|
UsbBuildGetDescriptorRequest(&urb,
|
|
|
|
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
|
|
|
|
USB_DEVICE_DESCRIPTOR_TYPE,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
&m_DeviceDescriptor,
|
|
|
|
NULL,
|
|
|
|
sizeof(m_DeviceDescriptor),
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
FxFormatUsbRequest(request.m_TrueRequest, &urb, FxUrbTypeLegacy, NULL);
|
|
|
|
|
|
|
|
WDF_REQUEST_SEND_OPTIONS_INIT(&options, 0);
|
|
|
|
WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options, WDF_REL_TIMEOUT_IN_SEC(5));
|
|
|
|
|
|
|
|
status = SubmitSync(request.m_TrueRequest, &options);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DoTraceLevelMessage(
|
|
|
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"Could not retrieve device descriptor, %!STATUS!", status);
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// After successfully completing any default control URB, USBD/usbport fills
|
|
|
|
// in the PipeHandle field of the URB (it is the same offset in every URB,
|
|
|
|
// which this CASSERT verifies. Since USBD_DEFAULT_PIPE_TRANSFER is not
|
|
|
|
// supported by USBD (it is by USBPORT), this is the prescribed way of getting
|
|
|
|
// the default control pipe so that you can set the PipeHandle field in
|
|
|
|
// _URB_CONTROL_TRANSFER.
|
|
|
|
//
|
|
|
|
WDFCASSERT(FIELD_OFFSET(_URB_CONTROL_TRANSFER, PipeHandle) ==
|
|
|
|
FIELD_OFFSET(_URB_CONTROL_DESCRIPTOR_REQUEST, Reserved));
|
|
|
|
|
|
|
|
m_ControlPipe = urb.UrbControlDescriptorRequest.Reserved;
|
|
|
|
|
|
|
|
USB_CONFIGURATION_DESCRIPTOR config;
|
|
|
|
|
|
|
|
RtlZeroMemory(&config, sizeof(config));
|
|
|
|
size = sizeof(config);
|
|
|
|
|
|
|
|
UsbBuildGetDescriptorRequest(&urb,
|
|
|
|
sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST),
|
|
|
|
USB_CONFIGURATION_DESCRIPTOR_TYPE,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
&config,
|
|
|
|
NULL,
|
|
|
|
size,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_SUCCESS);
|
|
|
|
request.m_TrueRequest->ClearFieldsForReuse();
|
|
|
|
FxFormatUsbRequest(request.m_TrueRequest, &urb, FxUrbTypeLegacy, NULL);
|
|
|
|
|
|
|
|
status = SubmitSync(request.m_TrueRequest, &options);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DoTraceLevelMessage(
|
|
|
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"Could not retrieve config descriptor size, %!STATUS!", status);
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
else if (urb.UrbControlDescriptorRequest.TransferBufferLength == 0) {
|
|
|
|
//
|
|
|
|
// Not enough info returned
|
|
|
|
//
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
|
|
|
|
|
|
DoTraceLevelMessage(
|
|
|
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"Could not retrieve config descriptor size, zero bytes transferred, "
|
|
|
|
" %!STATUS!", status);
|
|
|
|
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
else if (config.wTotalLength < size) {
|
|
|
|
//
|
|
|
|
// Not enough info returned
|
|
|
|
//
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
|
|
|
|
|
|
DoTraceLevelMessage(
|
|
|
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"Could not retrieve config descriptor size, config.wTotalLength %d < "
|
|
|
|
"sizeof(config descriptor) (%d), %!STATUS!",
|
|
|
|
config.wTotalLength, size, status);
|
|
|
|
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Allocate an additional memory at the end of the buffer so if we
|
|
|
|
// accidentily access fields beyond the end of the buffer we don't crash
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
size = config.wTotalLength;
|
|
|
|
ULONG paddedSize = size + sizeof(USB_DEVICE_DESCRIPTOR);
|
|
|
|
|
|
|
|
m_ConfigDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)
|
|
|
|
FxPoolAllocate(GetDriverGlobals(),
|
|
|
|
NonPagedPool,
|
|
|
|
paddedSize);
|
|
|
|
|
|
|
|
if (m_ConfigDescriptor == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
|
|
|
DoTraceLevelMessage(
|
|
|
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"Could not allocate %d bytes for config descriptor, %!STATUS!",
|
|
|
|
paddedSize, status);
|
|
|
|
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
|
|
|
|
RtlZeroMemory(m_ConfigDescriptor, paddedSize);
|
|
|
|
|
|
|
|
UsbBuildGetDescriptorRequest(&urb,
|
|
|
|
sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST),
|
|
|
|
USB_CONFIGURATION_DESCRIPTOR_TYPE,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
m_ConfigDescriptor,
|
|
|
|
NULL,
|
|
|
|
size,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_SUCCESS);
|
|
|
|
request.m_TrueRequest->ClearFieldsForReuse();
|
|
|
|
FxFormatUsbRequest(request.m_TrueRequest, &urb, FxUrbTypeLegacy, NULL);
|
|
|
|
|
|
|
|
status = SubmitSync(request.m_TrueRequest, &options);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DoTraceLevelMessage(
|
|
|
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"Could not retrieve config descriptor, %!STATUS!", status);
|
|
|
|
goto Done;
|
|
|
|
} else if(m_ConfigDescriptor->wTotalLength != size) {
|
|
|
|
//
|
|
|
|
// Invalid wTotalLength
|
|
|
|
//
|
|
|
|
status = STATUS_DEVICE_DATA_ERROR;
|
|
|
|
DoTraceLevelMessage(
|
|
|
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"Defective USB device reported two different config descriptor "
|
|
|
|
"wTotalLength values: %d and %d, %!STATUS!",
|
|
|
|
size, m_ConfigDescriptor->wTotalLength, status);
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Check to see if we are wait wake capable
|
|
|
|
//
|
|
|
|
if (m_ConfigDescriptor->bmAttributes & USB_CONFIG_REMOTE_WAKEUP) {
|
|
|
|
m_Traits |= WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Check to see if we are self or bus powered
|
|
|
|
//
|
|
|
|
USHORT deviceStatus;
|
|
|
|
|
|
|
|
UsbBuildGetStatusRequest(&urb,
|
|
|
|
URB_FUNCTION_GET_STATUS_FROM_DEVICE,
|
|
|
|
0,
|
|
|
|
&deviceStatus,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_SUCCESS);
|
|
|
|
request.m_TrueRequest->ClearFieldsForReuse();
|
|
|
|
FxFormatUsbRequest(request.m_TrueRequest, &urb, FxUrbTypeLegacy, NULL);
|
|
|
|
|
|
|
|
status = SubmitSync(request.m_TrueRequest, &options);
|
|
|
|
if (NT_SUCCESS(status) && (deviceStatus & USB_GETSTATUS_SELF_POWERED)) {
|
|
|
|
m_Traits |= WDF_USB_DEVICE_TRAIT_SELF_POWERED;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Revert back to success b/c we don't care if the usb device get status
|
|
|
|
// fails
|
|
|
|
//
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
|
|
|
|
USB_BUS_INTERFACE_USBDI_V1 busIf;
|
|
|
|
|
|
|
|
RtlZeroMemory(&busIf, sizeof(busIf));
|
|
|
|
|
|
|
|
//
|
|
|
|
// All PNP irps must have this initial status
|
|
|
|
//
|
|
|
|
request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_NOT_SUPPORTED);
|
|
|
|
request.m_TrueRequest->ClearFieldsForReuse();
|
|
|
|
|
|
|
|
FxQueryInterface::_FormatIrp(
|
|
|
|
request.m_TrueRequest->GetSubmitFxIrp()->GetIrp(),
|
|
|
|
&USB_BUS_INTERFACE_USBDI_GUID,
|
|
|
|
(PINTERFACE) &busIf,
|
|
|
|
sizeof(busIf),
|
|
|
|
USB_BUSIF_USBDI_VERSION_1);
|
|
|
|
|
|
|
|
request.m_TrueRequest->VerifierSetFormatted();
|
|
|
|
|
|
|
|
status = SubmitSync(request.m_TrueRequest);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
//
|
|
|
|
// Retry with the older interface
|
|
|
|
//
|
|
|
|
RtlZeroMemory(&busIf, sizeof(busIf));
|
|
|
|
|
|
|
|
//
|
|
|
|
// All PNP irps must have this initial status
|
|
|
|
//
|
|
|
|
|
|
|
|
request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_NOT_SUPPORTED);
|
|
|
|
request.m_TrueRequest->ClearFieldsForReuse();
|
|
|
|
|
|
|
|
FxQueryInterface::_FormatIrp(
|
|
|
|
request.m_TrueRequest->GetSubmitFxIrp()->GetIrp(),
|
|
|
|
&USB_BUS_INTERFACE_USBDI_GUID,
|
|
|
|
(PINTERFACE) &busIf,
|
|
|
|
sizeof(USB_BUS_INTERFACE_USBDI_V0),
|
|
|
|
USB_BUSIF_USBDI_VERSION_0);
|
|
|
|
|
|
|
|
request.m_TrueRequest->VerifierSetFormatted();
|
|
|
|
|
|
|
|
status = SubmitSync(request.m_TrueRequest);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
|
|
// Need to check for NULL b/c we may have only retrieved the V0 interface
|
|
|
|
//
|
|
|
|
if (busIf.IsDeviceHighSpeed != NULL &&
|
|
|
|
busIf.IsDeviceHighSpeed(busIf.BusContext)) {
|
|
|
|
m_Traits |= WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Stash these off for later
|
|
|
|
//
|
|
|
|
m_QueryBusTime = busIf.QueryBusTime;
|
|
|
|
m_BusInterfaceContext = busIf.BusContext;
|
|
|
|
m_BusInterfaceDereference = busIf.InterfaceDereference;
|
|
|
|
|
|
|
|
ASSERT(busIf.GetUSBDIVersion != NULL);
|
|
|
|
busIf.GetUSBDIVersion(busIf.BusContext,
|
|
|
|
&m_UsbdVersionInformation,
|
|
|
|
&m_HcdPortCapabilities);
|
|
|
|
}
|
|
|
|
else if (status == STATUS_NOT_SUPPORTED) {
|
|
|
|
//
|
|
|
|
// We will only use m_ControlPipe on stacks which do not support
|
|
|
|
// USBD_DEFAULT_PIPE_TRANSFER. If all the QIs failed, then we know
|
|
|
|
// definitively that we are running on USBD and we need m_ControlPipe
|
|
|
|
// to be != NULL for later control transfers
|
|
|
|
//
|
|
|
|
ASSERT(m_ControlPipe != NULL);
|
|
|
|
|
|
|
|
m_OnUSBD = TRUE;
|
|
|
|
|
|
|
|
//
|
|
|
|
// The QI failed with not supported, do not return error
|
|
|
|
//
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
DoTraceLevelMessage(
|
|
|
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"Query Interface for bus returned error, %!STATUS!", status);
|
|
|
|
}
|
|
|
|
|
|
|
|
Done:
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
FxUsbDevice::GetString(
|
|
|
|
__in_ecount(*NumCharacters) PUSHORT String,
|
|
|
|
__in PUSHORT NumCharacters,
|
|
|
|
__in UCHAR StringIndex,
|
|
|
|
__in_opt USHORT LangID,
|
|
|
|
__in_opt WDFREQUEST Request,
|
|
|
|
__in_opt PWDF_REQUEST_SEND_OPTIONS Options
|
|
|
|
)
|
|
|
|
{
|
|
|
|
PUSB_STRING_DESCRIPTOR pDescriptor;
|
|
|
|
PVOID buffer;
|
|
|
|
_URB_CONTROL_DESCRIPTOR_REQUEST urb;
|
|
|
|
WDF_REQUEST_SEND_OPTIONS options, *pOptions;
|
|
|
|
USB_COMMON_DESCRIPTOR common;
|
|
|
|
ULONG length;
|
|
|
|
NTSTATUS status;
|
|
|
|
|
|
|
|
FxSyncRequest request(GetDriverGlobals(), NULL, Request);
|
|
|
|
|
|
|
|
//
|
|
|
|
// FxSyncRequest always succeesds for KM.
|
|
|
|
//
|
|
|
|
status = request.Initialize();
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"Failed to initialize FxSyncRequest");
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer = NULL;
|
|
|
|
|
|
|
|
status = request.m_TrueRequest->ValidateTarget(this);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
|
|
|
|
RtlZeroMemory(&urb, sizeof(urb));
|
|
|
|
|
|
|
|
if (String != NULL) {
|
|
|
|
length = sizeof(USB_STRING_DESCRIPTOR) + (*NumCharacters - 1) * sizeof(WCHAR);
|
|
|
|
|
|
|
|
buffer = FxPoolAllocate(GetDriverGlobals(),
|
|
|
|
NonPagedPool,
|
|
|
|
length);
|
|
|
|
|
|
|
|
if (buffer == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
|
|
|
|
RtlZeroMemory(buffer, length);
|
|
|
|
pDescriptor = (PUSB_STRING_DESCRIPTOR) buffer;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
RtlZeroMemory(&common, sizeof(common));
|
|
|
|
|
|
|
|
length = sizeof(USB_COMMON_DESCRIPTOR);
|
|
|
|
pDescriptor = (PUSB_STRING_DESCRIPTOR) &common;
|
|
|
|
}
|
|
|
|
|
|
|
|
UsbBuildGetDescriptorRequest((PURB) &urb,
|
|
|
|
sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST),
|
|
|
|
USB_STRING_DESCRIPTOR_TYPE,
|
|
|
|
StringIndex,
|
|
|
|
LangID,
|
|
|
|
pDescriptor,
|
|
|
|
NULL,
|
|
|
|
length,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (Options != NULL) {
|
|
|
|
pOptions = Options;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
WDF_REQUEST_SEND_OPTIONS_INIT(&options, 0);
|
|
|
|
WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options,
|
|
|
|
WDF_REL_TIMEOUT_IN_SEC(2));
|
|
|
|
|
|
|
|
pOptions = &options;
|
|
|
|
}
|
|
|
|
#pragma prefast(suppress: __WARNING_BUFFER_OVERFLOW, "this annotation change in usb.h is communicated to usb team")
|
|
|
|
FxFormatUsbRequest(request.m_TrueRequest, (PURB) &urb, FxUrbTypeLegacy, NULL);
|
|
|
|
status = SubmitSync(request.m_TrueRequest, pOptions);
|
|
|
|
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
USHORT numChars;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Make sure we got an even number of bytes and that we got a header
|
|
|
|
//
|
|
|
|
if ((pDescriptor->bLength & 0x1) ||
|
|
|
|
pDescriptor->bLength < sizeof(USB_COMMON_DESCRIPTOR)) {
|
|
|
|
status = STATUS_DEVICE_DATA_ERROR;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
//
|
|
|
|
// bLength is the length of the entire descriptor. Subtract off
|
|
|
|
// the descriptor header and then divide by the size of a WCHAR.
|
|
|
|
//
|
|
|
|
numChars =
|
|
|
|
(pDescriptor->bLength - sizeof(USB_COMMON_DESCRIPTOR)) / sizeof(WCHAR);
|
|
|
|
|
|
|
|
if (String != NULL) {
|
|
|
|
if (*NumCharacters >= numChars) {
|
|
|
|
length = numChars * sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
length = *NumCharacters * sizeof(WCHAR);
|
|
|
|
status = STATUS_BUFFER_OVERFLOW;
|
|
|
|
}
|
|
|
|
|
|
|
|
*NumCharacters = numChars;
|
|
|
|
RtlCopyMemory(String, pDescriptor->bString, length);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*NumCharacters = numChars;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buffer != NULL) {
|
|
|
|
FxPoolFree(buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
Done:
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
FxUsbDevice::FormatStringRequest(
|
|
|
|
__in FxRequestBase* Request,
|
|
|
|
__in FxRequestBuffer *RequestBuffer,
|
|
|
|
__in UCHAR StringIndex,
|
|
|
|
__in USHORT LangID
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
Formats a request to retrieve a string from a string descriptor
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
Request - request to format
|
|
|
|
|
|
|
|
RequestBuffer - Buffer to be filled in when the request has completed
|
|
|
|
|
|
|
|
StringIndex - index of the string
|
|
|
|
|
|
|
|
LandID - language ID of the string to be retrieved
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
FxUsbDeviceStringContext* pContext;
|
|
|
|
NTSTATUS status;
|
|
|
|
FX_URB_TYPE urbType;
|
|
|
|
|
|
|
|
status = Request->ValidateTarget(this);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"WDFUSBDEVICE %p, Request %p, setting target failed, "
|
|
|
|
"%!STATUS!", GetHandle(), Request, status);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Request->HasContextType(FX_RCT_USB_STRING_REQUEST)) {
|
|
|
|
pContext = (FxUsbDeviceStringContext*) Request->GetContext();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
urbType = GetFxUrbTypeForRequest(Request);
|
|
|
|
pContext = new(GetDriverGlobals()) FxUsbDeviceStringContext(urbType);
|
|
|
|
if (pContext == NULL) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (urbType == FxUrbTypeUsbdAllocated) {
|
|
|
|
status = pContext->AllocateUrb(m_USBDHandle);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"FxUsbDeviceStringContext::AllocateUrb failed, %!STATUS!", status);
|
|
|
|
delete pContext;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Since the AllocateUrb routine calls USBD_xxxUrbAllocate APIs to allocate an Urb, it is
|
|
|
|
// important to release those resorces before the devnode is removed. Those
|
|
|
|
// resoruces are removed at the time Request is disposed.
|
|
|
|
//
|
|
|
|
Request->EnableContextDisposeNotification();
|
|
|
|
}
|
|
|
|
|
|
|
|
Request->SetContext(pContext);
|
|
|
|
}
|
|
|
|
|
|
|
|
status = pContext->AllocateDescriptor(GetDriverGlobals(),
|
|
|
|
RequestBuffer->GetBufferLength());
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
pContext->StoreAndReferenceMemory(RequestBuffer);
|
|
|
|
pContext->SetUrbInfo(StringIndex, LangID);
|
|
|
|
|
|
|
|
if (pContext->m_Urb == &pContext->m_UrbLegacy) {
|
|
|
|
urbType = FxUrbTypeLegacy;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
urbType = FxUrbTypeUsbdAllocated;
|
|
|
|
}
|
|
|
|
|
|
|
|
FxFormatUsbRequest(Request, (PURB)pContext->m_Urb, urbType, m_USBDHandle);
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
FxUsbDevice::FormatControlRequest(
|
|
|
|
__in FxRequestBase* Request,
|
|
|
|
__in PWDF_USB_CONTROL_SETUP_PACKET SetupPacket,
|
|
|
|
__in FxRequestBuffer *RequestBuffer
|
|
|
|
)
|
|
|
|
{
|
|
|
|
FxUsbDeviceControlContext* pContext;
|
|
|
|
NTSTATUS status;
|
|
|
|
size_t bufferSize;
|
|
|
|
FX_URB_TYPE urbType;
|
|
|
|
|
|
|
|
bufferSize = RequestBuffer->GetBufferLength();
|
|
|
|
|
|
|
|
//
|
|
|
|
// We can only transfer 2 bytes worth of data, so if the buffer is larger,
|
|
|
|
// fail here.
|
|
|
|
//
|
|
|
|
if (bufferSize > 0xFFFF) {
|
|
|
|
DoTraceLevelMessage(
|
|
|
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"Control transfer buffer is limited to 0xFFFF bytes in size, "
|
|
|
|
"%I64d requested ", bufferSize);
|
|
|
|
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = Request->ValidateTarget(this);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"WDFUSBDEVICE %p, Request %p, setting target failed, "
|
|
|
|
"%!STATUS!", GetHandle(), Request, status);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Request->HasContextType(FX_RCT_USB_CONTROL_REQUEST)) {
|
|
|
|
pContext = (FxUsbDeviceControlContext*) Request->GetContext();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
urbType = GetFxUrbTypeForRequest(Request);
|
|
|
|
pContext = new(GetDriverGlobals()) FxUsbDeviceControlContext(urbType);
|
|
|
|
if (pContext == NULL) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (urbType == FxUrbTypeUsbdAllocated) {
|
|
|
|
status = pContext->AllocateUrb(m_USBDHandle);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"FxUsbDeviceControlContext::AllocateUrb Failed, %!STATUS!", status);
|
|
|
|
|
|
|
|
delete pContext;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// Since the AllocateUrb routine calls USBD_xxxUrbAllocate APIs to allocate an Urb, it is
|
|
|
|
// important to release those resorces before the devnode is removed. Those
|
|
|
|
// resoruces are removed at the time Request is disposed.
|
|
|
|
//
|
|
|
|
Request->EnableContextDisposeNotification();
|
|
|
|
}
|
|
|
|
|
|
|
|
Request->SetContext(pContext);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (RequestBuffer->HasMdl()) {
|
|
|
|
PMDL pMdl;
|
|
|
|
|
|
|
|
pMdl = NULL;
|
|
|
|
ASSERT(pContext->m_PartialMdl == NULL);
|
|
|
|
|
|
|
|
status = RequestBuffer->GetOrAllocateMdl(GetDriverGlobals(),
|
|
|
|
&pMdl,
|
|
|
|
&pContext->m_PartialMdl,
|
|
|
|
&pContext->m_UnlockPages,
|
|
|
|
IoModifyAccess);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT(pMdl != NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
pContext->StoreAndReferenceMemory(this, RequestBuffer, SetupPacket);
|
|
|
|
|
|
|
|
if (pContext->m_Urb == &pContext->m_UrbLegacy) {
|
|
|
|
urbType = FxUrbTypeLegacy;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
urbType = FxUrbTypeUsbdAllocated;
|
|
|
|
}
|
|
|
|
|
|
|
|
FxFormatUsbRequest(Request, (PURB)pContext->m_Urb, urbType, m_USBDHandle);
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
FxUsbDeviceControlContext::StoreAndReferenceMemory(
|
|
|
|
__in FxUsbDevice* Device,
|
|
|
|
__in FxRequestBuffer* Buffer,
|
|
|
|
__in PWDF_USB_CONTROL_SETUP_PACKET SetupPacket
|
|
|
|
)
|
|
|
|
{
|
|
|
|
SetUsbType(WdfUsbRequestTypeDeviceControlTransfer);
|
|
|
|
|
|
|
|
RtlZeroMemory(m_Urb, sizeof(*m_Urb));
|
|
|
|
|
|
|
|
m_Urb->Hdr.Function = URB_FUNCTION_CONTROL_TRANSFER;
|
|
|
|
m_Urb->Hdr.Length = sizeof(*m_Urb);
|
|
|
|
|
2020-10-16 03:30:51 +00:00
|
|
|
FxUsbRequestContext::StoreAndReferenceMemory(Buffer); // __super call
|
2020-09-24 20:51:15 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Set the values using what is stored in the buffer
|
|
|
|
//
|
|
|
|
Buffer->AssignValues(&m_Urb->TransferBuffer,
|
|
|
|
&m_Urb->TransferBufferMDL,
|
|
|
|
&m_Urb->TransferBufferLength);
|
|
|
|
|
|
|
|
RtlCopyMemory(&m_Urb->SetupPacket[0],
|
|
|
|
&SetupPacket->Generic.Bytes[0],
|
|
|
|
sizeof(m_Urb->SetupPacket));
|
|
|
|
|
|
|
|
//
|
|
|
|
// also indicate the length of the buffer in the header
|
|
|
|
//
|
|
|
|
((PWDF_USB_CONTROL_SETUP_PACKET) &m_Urb->SetupPacket[0])->Packet.wLength =
|
|
|
|
(USHORT) m_Urb->TransferBufferLength;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Control transfers are always short OK. USBD_TRANSFER_DIRECTION_IN may
|
|
|
|
// be OR'ed in later.
|
|
|
|
//
|
|
|
|
m_Urb->TransferFlags = USBD_SHORT_TRANSFER_OK;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Get the direction out of the setup packet
|
|
|
|
//
|
|
|
|
if (SetupPacket->Packet.bm.Request.Dir == BMREQUEST_DEVICE_TO_HOST) {
|
|
|
|
m_Urb->TransferFlags |= USBD_TRANSFER_DIRECTION_IN;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Device->OnUSBD()) {
|
|
|
|
m_Urb->PipeHandle = Device->GetControlPipeHandle();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
//
|
|
|
|
// USBPORT supports this flag
|
|
|
|
//
|
|
|
|
m_Urb->TransferFlags |= USBD_DEFAULT_PIPE_TRANSFER;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// If we have built a partial MDL, use that instead. TransferBufferLength
|
|
|
|
// is still valid because the Offsets or length in Buffer will have been
|
|
|
|
// used to create this PartialMdl by the caller.
|
|
|
|
//
|
|
|
|
if (m_PartialMdl != NULL) {
|
|
|
|
m_Urb->TransferBufferMDL = m_PartialMdl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
FxUsbDevice::QueryUsbCapability(
|
|
|
|
__in
|
|
|
|
CONST GUID* CapabilityType,
|
|
|
|
__in
|
|
|
|
ULONG CapabilityBufferLength,
|
|
|
|
__drv_when(CapabilityBufferLength == 0, __out_opt)
|
|
|
|
__drv_when(CapabilityBufferLength != 0 && ResultLength == NULL, __out_bcount(CapabilityBufferLength))
|
|
|
|
__drv_when(CapabilityBufferLength != 0 && ResultLength != NULL, __out_bcount_part_opt(CapabilityBufferLength, *ResultLength))
|
|
|
|
PVOID CapabilityBuffer,
|
|
|
|
__out_opt
|
|
|
|
__drv_when(ResultLength != NULL,__deref_out_range(<=,CapabilityBufferLength))
|
|
|
|
PULONG ResultLength
|
|
|
|
)
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
|
|
|
|
|
|
if (ResultLength != NULL) {
|
|
|
|
*ResultLength = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (GetUSBDHandle() == NULL) {
|
|
|
|
status = STATUS_INVALID_DEVICE_STATE;
|
|
|
|
|
|
|
|
DoTraceLevelMessage(
|
|
|
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"WDFUSBDEVICE must have been created using WdfUsbTargetDeviceCreateWithParameters, %!STATUS!",
|
|
|
|
status);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = USBD_QueryUsbCapability(m_USBDHandle,
|
|
|
|
CapabilityType,
|
|
|
|
CapabilityBufferLength,
|
|
|
|
(PUCHAR) CapabilityBuffer,
|
|
|
|
ResultLength);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DoTraceLevelMessage(
|
|
|
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"Could not retrieve capability %!GUID!, %!STATUS!",
|
|
|
|
CapabilityType, status);
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
exit:
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
FxUsbDevice::SelectConfigSingle(
|
|
|
|
__in PWDF_OBJECT_ATTRIBUTES PipeAttributes,
|
|
|
|
__in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
This will configure the single inteface case and pick up the first available
|
|
|
|
setting. If there are multiple settings on a single interface device
|
|
|
|
and the driver wants to pick one then the driver should use the multinterface
|
|
|
|
option to initialize.
|
|
|
|
|
|
|
|
This takes care of the simplest case only. Configuring a multi interface
|
|
|
|
device as a single interface device would be treated as an error. There is
|
|
|
|
duplication of code with the multi case but it is better to keep these two
|
|
|
|
separate especially if more gets added.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// The array needs an extra element which is zero'd out to mark the end
|
|
|
|
//
|
|
|
|
USBD_INTERFACE_LIST_ENTRY listEntry[2];
|
|
|
|
PURB urb;
|
|
|
|
NTSTATUS status;
|
|
|
|
|
|
|
|
RtlZeroMemory(&Params->Types.SingleInterface,
|
|
|
|
sizeof(Params->Types.SingleInterface));
|
|
|
|
|
|
|
|
if (m_NumInterfaces > 1) {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
DoTraceLevelMessage(
|
|
|
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"WDFUSBDEVICE %p cannot be auto configured for a single interface "
|
|
|
|
"since there are %d interfaces on the device, %!STATUS!",
|
|
|
|
GetHandle(), m_NumInterfaces, status);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
RtlZeroMemory(&listEntry[0], sizeof(listEntry));
|
|
|
|
|
|
|
|
//
|
|
|
|
// Use AlternateSetting 0 by default
|
|
|
|
//
|
|
|
|
listEntry[0].InterfaceDescriptor = m_Interfaces[0]->GetSettingDescriptor(0);
|
|
|
|
|
|
|
|
if (listEntry[0].InterfaceDescriptor == NULL) {
|
|
|
|
DoTraceLevelMessage(
|
|
|
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"WDFUSBDEVICE %p could not retrieve AlternateSetting 0 for "
|
|
|
|
"bInterfaceNumber %d", GetHandle(),
|
|
|
|
m_Interfaces[0]->m_InterfaceNumber);
|
|
|
|
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
urb = FxUsbCreateConfigRequest(GetDriverGlobals(),
|
|
|
|
m_ConfigDescriptor,
|
|
|
|
&listEntry[0],
|
|
|
|
GetDefaultMaxTransferSize());
|
|
|
|
|
|
|
|
if (urb == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
status = SelectConfig(PipeAttributes, urb, FxUrbTypeLegacy, NULL);
|
|
|
|
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
Params->Types.SingleInterface.NumberConfiguredPipes =
|
|
|
|
m_Interfaces[0]->GetNumConfiguredPipes();
|
|
|
|
|
|
|
|
Params->Types.SingleInterface.ConfiguredUsbInterface =
|
|
|
|
m_Interfaces[0]->GetHandle();
|
|
|
|
}
|
|
|
|
|
|
|
|
FxPoolFree(urb);
|
|
|
|
urb = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
FxUsbDevice::SelectConfigMulti(
|
|
|
|
__in PWDF_OBJECT_ATTRIBUTES PipesAttributes,
|
|
|
|
__in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
Selects the configuration as described by the parameter Params. If there is a
|
|
|
|
previous active configuration, the WDFUSBPIPEs for it are stopped and
|
|
|
|
destroyed before the new configuration is selected
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
PipesAttributes - object attributes to apply to each created WDFUSBPIPE
|
|
|
|
|
|
|
|
Params -
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PUSBD_INTERFACE_LIST_ENTRY pList;
|
|
|
|
PURB urb;
|
|
|
|
NTSTATUS status;
|
|
|
|
ULONG size;
|
|
|
|
UCHAR i;
|
|
|
|
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
|
|
|
|
|
|
|
pFxDriverGlobals = GetDriverGlobals();
|
|
|
|
|
|
|
|
Params->Types.MultiInterface.NumberOfConfiguredInterfaces = 0;
|
|
|
|
|
|
|
|
//
|
|
|
|
// The array needs an extra element which is zero'd out to mark the end
|
|
|
|
//
|
|
|
|
size = sizeof(USBD_INTERFACE_LIST_ENTRY) * (m_NumInterfaces + 1);
|
|
|
|
pList = (PUSBD_INTERFACE_LIST_ENTRY) FxPoolAllocate(
|
|
|
|
pFxDriverGlobals,
|
|
|
|
NonPagedPool,
|
|
|
|
size
|
|
|
|
);
|
|
|
|
|
|
|
|
if (pList == NULL) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
RtlZeroMemory(pList, size);
|
|
|
|
|
|
|
|
if (Params->Type == WdfUsbTargetDeviceSelectConfigTypeMultiInterface) {
|
|
|
|
for (i = 0; i < m_NumInterfaces; i++) {
|
|
|
|
pList[i].InterfaceDescriptor =
|
|
|
|
m_Interfaces[i]->GetSettingDescriptor(0);
|
|
|
|
|
|
|
|
if (pList[i].InterfaceDescriptor == NULL) {
|
|
|
|
DoTraceLevelMessage(
|
|
|
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"WDFUSBDEVICE %p could not retrieve AlternateSetting 0 for "
|
|
|
|
"bInterfaceNumber %d", GetHandle(),
|
|
|
|
m_Interfaces[i]->m_InterfaceNumber);
|
|
|
|
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
//
|
|
|
|
// Type is WdfUsbTargetDeviceSelectConfigTypeInterfacesPairs
|
|
|
|
//
|
|
|
|
UCHAR interfacePairsNum = 0;
|
|
|
|
UCHAR bitArray[UCHAR_MAX/sizeof(UCHAR)];
|
|
|
|
|
|
|
|
//
|
|
|
|
// initialize the bit array
|
|
|
|
//
|
|
|
|
RtlZeroMemory(bitArray, sizeof(bitArray));
|
|
|
|
//
|
|
|
|
// Build a list of descriptors from the Setting pairs
|
|
|
|
// passed in by the user. There could be interfaces not
|
|
|
|
// covered in the setting/interface pairs array passed.
|
|
|
|
// If that is the case return STATUS_INVALID_PARAMETER
|
|
|
|
//
|
|
|
|
for (i = 0; i < Params->Types.MultiInterface.NumberInterfaces ; i++) {
|
|
|
|
PWDF_USB_INTERFACE_SETTING_PAIR settingPair;
|
|
|
|
UCHAR interfaceNumber;
|
|
|
|
UCHAR altSettingIndex;
|
|
|
|
|
|
|
|
settingPair = &Params->Types.MultiInterface.Pairs[i];
|
|
|
|
|
|
|
|
status = GetInterfaceNumberFromInterface(
|
|
|
|
settingPair->UsbInterface,
|
|
|
|
&interfaceNumber
|
|
|
|
);
|
|
|
|
|
|
|
|
//
|
|
|
|
//convert the interface handle to interface number
|
|
|
|
//
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
altSettingIndex = settingPair->SettingIndex;
|
|
|
|
|
|
|
|
//
|
|
|
|
// do the following only if the bit is not already set
|
|
|
|
//
|
|
|
|
if (FxBitArraySet(&bitArray[0], interfaceNumber) == FALSE) {
|
|
|
|
pList[interfacePairsNum].InterfaceDescriptor =
|
|
|
|
FxUsbParseConfigurationDescriptor(
|
|
|
|
m_ConfigDescriptor,
|
|
|
|
interfaceNumber,
|
|
|
|
altSettingIndex
|
|
|
|
);
|
|
|
|
|
|
|
|
if (pList[interfacePairsNum].InterfaceDescriptor == NULL) {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
DoTraceLevelMessage(
|
|
|
|
GetDriverGlobals(), TRACE_LEVEL_ERROR,
|
|
|
|
TRACINGIOTARGET,
|
|
|
|
"WDFUSBDEVICE %p could not retrieve "
|
|
|
|
"AlternateSetting %d for "
|
|
|
|
"bInterfaceNumber %d, returning %!STATUS!",
|
|
|
|
GetHandle(),
|
|
|
|
altSettingIndex, interfaceNumber, status);
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
|
|
|
|
interfacePairsNum++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Check if there are any interfaces not specified by the array. If
|
|
|
|
// there are, then select setting 0 for them.
|
|
|
|
//
|
|
|
|
if (m_NumInterfaces > interfacePairsNum) {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
DoTraceLevelMessage(
|
|
|
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"WDFUSBDEVICE %p interface pairs set (%d) is not equal to actual "
|
|
|
|
"# of interfaces (%d) reported by the device, %!STATUS!",
|
|
|
|
GetObjectHandle(), interfacePairsNum, m_NumInterfaces, status);
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
} //WdfUsbTargetDeviceSelectConfigTypeInterfacesPairs
|
|
|
|
|
|
|
|
urb = FxUsbCreateConfigRequest(
|
|
|
|
GetDriverGlobals(),
|
|
|
|
m_ConfigDescriptor,
|
|
|
|
pList,
|
|
|
|
GetDefaultMaxTransferSize()
|
|
|
|
);
|
|
|
|
|
|
|
|
if (urb == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
status = SelectConfig(
|
|
|
|
PipesAttributes,
|
|
|
|
urb,
|
|
|
|
FxUrbTypeLegacy,
|
|
|
|
&Params->Types.MultiInterface.NumberOfConfiguredInterfaces);
|
|
|
|
|
|
|
|
FxPoolFree(urb);
|
|
|
|
urb = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Done:
|
|
|
|
FxPoolFree(pList);
|
|
|
|
pList = NULL;
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSTATUS
|
|
|
|
FxUsbDevice::Reset(
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
FxIoContext context;
|
|
|
|
FxSyncRequest request(GetDriverGlobals(), &context);
|
|
|
|
FxRequestBuffer emptyBuffer;
|
|
|
|
NTSTATUS status;
|
|
|
|
|
|
|
|
//
|
|
|
|
// FxSyncRequest always succeesds for KM.
|
|
|
|
//
|
|
|
|
status = request.Initialize();
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
|
|
|
"Failed to initialize FxSyncRequest");
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = FormatIoctlRequest(request.m_TrueRequest,
|
|
|
|
IOCTL_INTERNAL_USB_RESET_PORT,
|
|
|
|
TRUE,
|
|
|
|
&emptyBuffer,
|
|
|
|
&emptyBuffer);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
CancelSentIo();
|
|
|
|
status = SubmitSyncRequestIgnoreTargetState(request.m_TrueRequest, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|