reactos/sdk/lib/drivers/wdf/shared/targets/usb/um/fxusbdeviceum.cpp

924 lines
28 KiB
C++
Raw Normal View History

/*++
Copyright (c) Microsoft Corporation
Module Name:
FxUsbDeviceUm.cpp
Abstract:
Author:
Environment:
User mode only
Revision History:
--*/
extern "C" {
#include <initguid.h>
}
#include "fxusbpch.hpp"
extern "C" {
#include "FxUsbDeviceUm.tmh"
}
_Must_inspect_result_
NTSTATUS
FxUsbDevice::SendSyncRequest(
__in FxSyncRequest* Request,
__in ULONGLONG Time
)
{
NTSTATUS status;
WDF_REQUEST_SEND_OPTIONS options;
WDF_REQUEST_SEND_OPTIONS_INIT(&options, 0);
WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options, WDF_REL_TIMEOUT_IN_SEC(Time));
status = SubmitSync(Request->m_TrueRequest, &options);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"FxUsbDevice SubmitSync failed");
goto Done;
}
Done:
return status;
}
_Must_inspect_result_
NTSTATUS
FxUsbDevice::SendSyncUmUrb(
__inout PUMURB Urb,
__in ULONGLONG Time,
__in_opt WDFREQUEST Request,
__in_opt PWDF_REQUEST_SEND_OPTIONS Options
)
{
NTSTATUS status;
WDF_REQUEST_SEND_OPTIONS options;
FxSyncRequest request(GetDriverGlobals(), NULL, Request);
status = request.Initialize();
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Failed to initialize FxSyncRequest");
return status;
}
if (NULL == Options) {
Options = &options;
}
WDF_REQUEST_SEND_OPTIONS_INIT(Options, 0);
WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(Options, WDF_REL_TIMEOUT_IN_SEC(Time));
status = request.m_TrueRequest->ValidateTarget(this);
if (NT_SUCCESS(status)) {
FxUsbUmFormatRequest(request.m_TrueRequest, &Urb->UmUrbHeader, m_pHostTargetFile);
status = SubmitSync(request.m_TrueRequest, Options);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"FxUsbDevice SubmitSync failed");
return status;
}
}
return status;
}
_Must_inspect_result_
NTSTATUS
FxUsbDevice::InitDevice(
__in ULONG USBDClientContractVersionForWdfClient
)
{
HRESULT hr = S_OK;
NTSTATUS status = STATUS_SUCCESS;
IWudfDevice* device = NULL;
IWudfDeviceStack2* devstack2 = NULL;
UMURB urb;
USB_CONFIGURATION_DESCRIPTOR config;
USHORT wTotalLength = 0;
FxRequestBuffer buf;
FxUsbDeviceControlContext context(FxUrbTypeLegacy);
WDF_USB_CONTROL_SETUP_PACKET setupPacket;
USHORT deviceStatus = 0;
UCHAR deviceSpeed = 0;
FxSyncRequest request(GetDriverGlobals(), NULL);
FxSyncRequest request2(GetDriverGlobals(), &context);
UNREFERENCED_PARAMETER(USBDClientContractVersionForWdfClient);
status = request.Initialize();
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Failed to initialize FxSyncRequest");
goto Done;
}
status = request2.Initialize();
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Failed to initialize second FxSyncRequest");
goto Done;
}
status = request.m_TrueRequest->ValidateTarget(this);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Failed to validate FxSyncRequest target");
goto Done;
}
status = request2.m_TrueRequest->ValidateTarget(this);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Failed to validate second FxSyncRequest target");
goto Done;
}
RtlZeroMemory(&urb, sizeof(urb));
device = m_DeviceBase->GetDeviceObject();
devstack2 = m_Device->GetDeviceStack2();
if (m_pHostTargetFile == NULL) {
//
// Opens a handle on the reflector for USB side-band communication
// based on the currently selected dispatcher type.
//
hr = devstack2->OpenUSBCommunicationChannel(device,
device->GetAttachedDevice(),
&m_pHostTargetFile);
if (SUCCEEDED(hr)) {
m_WinUsbHandle = (WINUSB_INTERFACE_HANDLE)m_pHostTargetFile->GetCreateContext();
}
}
//
// Get USB device descriptor
//
FxUsbUmInitDescriptorUrb(&urb,
m_WinUsbHandle,
USB_DEVICE_DESCRIPTOR_TYPE,
sizeof(m_DeviceDescriptor),
&m_DeviceDescriptor);
FxUsbUmFormatRequest(request.m_TrueRequest,
&urb.UmUrbHeader,
m_pHostTargetFile,
TRUE);
status = SendSyncRequest(&request, 5);
if (!NT_SUCCESS(status)) {
goto Done;
}
//
// Get USB configuration descriptor
//
FxUsbUmInitDescriptorUrb(&urb,
m_WinUsbHandle,
USB_CONFIGURATION_DESCRIPTOR_TYPE,
sizeof(config),
&config);
FxUsbUmFormatRequest(request.m_TrueRequest,
&urb.UmUrbHeader,
m_pHostTargetFile,
TRUE);
status = SendSyncRequest(&request, 5);
if (!NT_SUCCESS(status)) {
goto Done;
}
if (config.wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR)) {
//
// 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, sizeof(USB_CONFIGURATION_DESCRIPTOR), status);
goto Done;
}
wTotalLength = config.wTotalLength;
m_ConfigDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)
FxPoolAllocate(GetDriverGlobals(),
NonPagedPool,
wTotalLength);
if (NULL == m_ConfigDescriptor) {
status = STATUS_INSUFFICIENT_RESOURCES;
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"Could not allocate %d bytes for config descriptor, %!STATUS!",
sizeof(USB_CONFIGURATION_DESCRIPTOR), status);
goto Done;
}
//
// Get USB configuration descriptor and subsequent interface descriptors, etc.
//
FxUsbUmInitDescriptorUrb(&urb,
m_WinUsbHandle,
USB_CONFIGURATION_DESCRIPTOR_TYPE,
wTotalLength,
m_ConfigDescriptor);
FxUsbUmFormatRequest(request.m_TrueRequest,
&urb.UmUrbHeader,
m_pHostTargetFile,
TRUE);
status = SendSyncRequest(&request, 5);
if (!NT_SUCCESS(status)) {
goto Done;
} else if (m_ConfigDescriptor->wTotalLength != wTotalLength) {
//
// 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!",
wTotalLength, m_ConfigDescriptor->wTotalLength, status);
goto Done;
}
m_NumInterfaces = m_ConfigDescriptor->bNumInterfaces;
//
// 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;
}
//
// Get the device status to check if device is self-powered.
//
WDF_USB_CONTROL_SETUP_PACKET_INIT_GET_STATUS(&setupPacket,
BmRequestToDevice,
0); // Device status
buf.SetBuffer(&deviceStatus, sizeof(USHORT));
status = FormatControlRequest(request2.m_TrueRequest,
&setupPacket,
&buf);
if (!NT_SUCCESS(status)) {
goto Done;
}
status = SendSyncRequest(&request2, 5);
if (!NT_SUCCESS(status)) {
goto Done;
}
if (deviceStatus & USB_GETSTATUS_SELF_POWERED) {
m_Traits |= WDF_USB_DEVICE_TRAIT_SELF_POWERED;
}
//
// Get device speed information.
//
FxUsbUmInitInformationUrb(&urb,
m_WinUsbHandle,
sizeof(UCHAR),
&deviceSpeed);
FxUsbUmFormatRequest(request.m_TrueRequest,
&urb.UmUrbHeader,
m_pHostTargetFile,
TRUE);
status = SendSyncRequest(&request, 5);
if (!NT_SUCCESS(status)) {
goto Done;
}
if (deviceSpeed == 3) {
m_Traits |= WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED;
}
//
// User-mode events must be initialized manually.
//
status = m_InterfaceIterationLock.Initialize();
if (!NT_SUCCESS(status)) {
goto Done;
}
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
)
{
UMURB urb;
PUSB_STRING_DESCRIPTOR pDescriptor;
PVOID buffer = NULL;
USB_COMMON_DESCRIPTOR common;
ULONG length;
NTSTATUS status;
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;
}
FxUsbUmInitDescriptorUrb(&urb,
m_WinUsbHandle,
USB_STRING_DESCRIPTOR_TYPE,
length,
pDescriptor);
urb.UmUrbDescriptorRequest.Index = StringIndex;
urb.UmUrbDescriptorRequest.LanguageID = LangID;
status = SendSyncUmUrb(&urb, 2, Request, Options);
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
--*/
{
NTSTATUS status;
FxUsbDeviceStringContext* pContext;
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 {
pContext = new(GetDriverGlobals()) FxUsbDeviceStringContext(FxUrbTypeLegacy);
if (pContext == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
Request->SetContext(pContext);
}
FxUsbUmInitDescriptorUrb(&pContext->m_UmUrb,
m_WinUsbHandle,
USB_STRING_DESCRIPTOR_TYPE,
0,
NULL);
status = pContext->AllocateDescriptor(GetDriverGlobals(),
RequestBuffer->GetBufferLength());
if (!NT_SUCCESS(status)) {
return status;
}
pContext->StoreAndReferenceMemory(RequestBuffer);
pContext->SetUrbInfo(StringIndex, LangID);
FxUsbUmFormatRequest(Request, &pContext->m_UmUrb.UmUrbHeader, m_pHostTargetFile);
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;
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 {
pContext = new(GetDriverGlobals()) FxUsbDeviceControlContext(FxUrbTypeLegacy);
if (pContext == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
Request->SetContext(pContext);
}
FxUsbUmInitControlTransferUrb(&pContext->m_UmUrb,
m_WinUsbHandle,
0,
NULL);
pContext->StoreAndReferenceMemory(this, RequestBuffer, SetupPacket);
FxUsbUmFormatRequest(Request, &pContext->m_UmUrb.UmUrbHeader, m_pHostTargetFile);
return STATUS_SUCCESS;
}
VOID
FxUsbDeviceControlContext::StoreAndReferenceMemory(
__in FxUsbDevice* Device,
__in FxRequestBuffer* Buffer,
__in PWDF_USB_CONTROL_SETUP_PACKET SetupPacket
)
{
SetUsbType(WdfUsbRequestTypeDeviceControlTransfer);
__super::StoreAndReferenceMemory(Buffer);
//
// Convert WDF_USB_CONTROL_SETUP_PACKET to WINUSB_SETUP_PACKET
//
m_UmUrb.UmUrbControlTransfer.SetupPacket.RequestType = SetupPacket->Packet.bm.Byte;
m_UmUrb.UmUrbControlTransfer.SetupPacket.Request = SetupPacket->Packet.bRequest;
m_UmUrb.UmUrbControlTransfer.SetupPacket.Value = SetupPacket->Packet.wValue.Value;
m_UmUrb.UmUrbControlTransfer.SetupPacket.Index = SetupPacket->Packet.wIndex.Value;
//
// Set the TransferBuffer values using what is stored in the Buffer
//
Buffer->AssignValues(&m_UmUrb.UmUrbControlTransfer.TransferBuffer,
NULL,
&m_UmUrb.UmUrbControlTransfer.TransferBufferLength);
m_UmUrb.UmUrbControlTransfer.SetupPacket.Length =
(USHORT)m_UmUrb.UmUrbControlTransfer.TransferBufferLength;
}
_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;
}
//
// We cannot send an actual query to the USB stack through winusb.
// However, we have the information to handle this query. It is not
// ideal to implement this API in this manner because we are making
// assumptions about the behavior of USB stack that can change in future.
// However, it is too late in the OS cycle to implement a correct solution.
// The ideal way is for winusb to expose this information. We should
// revisit this API in blue+1
//
if (RtlCompareMemory(CapabilityType,
&GUID_USB_CAPABILITY_DEVICE_CONNECTION_HIGH_SPEED_COMPATIBLE,
sizeof(GUID)) == sizeof(GUID)) {
if (m_Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) {
status = STATUS_SUCCESS;
} else {
status = STATUS_NOT_SUPPORTED;
}
}
else if (RtlCompareMemory(CapabilityType,
&GUID_USB_CAPABILITY_DEVICE_CONNECTION_SUPER_SPEED_COMPATIBLE,
sizeof(GUID)) == sizeof(GUID)) {
if (m_DeviceDescriptor.bcdUSB >= 0x300) {
status = STATUS_SUCCESS;
} else {
status = STATUS_NOT_SUPPORTED;
}
}
else if (RtlCompareMemory(CapabilityType,
&GUID_USB_CAPABILITY_SELECTIVE_SUSPEND,
sizeof(GUID)) == sizeof(GUID)) {
//
// Both EHCI as well as XHCI stack support selective suspend.
// Since XHCI UCX interface is not open, there aren't any
// third party controller drivers to worry about. This can
// of course change in future
//
status = STATUS_SUCCESS;
}
else if (RtlCompareMemory(CapabilityType,
&GUID_USB_CAPABILITY_FUNCTION_SUSPEND,
sizeof(GUID)) == sizeof(GUID)) {
//
// Note that a SuperSpeed device will report a bcdUSB of 2.1
// when working on a 2.0 port. Therefore a bcdUSB of 3.0 also
// indicates that the device is actually working on 3.0, in
// which case we always support function suspend
//
if (m_DeviceDescriptor.bcdUSB >= 0x300) {
status = STATUS_SUCCESS;
} else {
status = STATUS_NOT_SUPPORTED;
}
}
else {
//
// We do not support chained MDLs or streams for a UMDF driver
// GUID_USB_CAPABILITY_CHAINED_MDLS
// GUID_USB_CAPABILITY_STATIC_STREAMS
//
status = STATUS_NOT_SUPPORTED;
}
return status;
}
_Must_inspect_result_
NTSTATUS
FxUsbDevice::SelectConfigSingle(
__in PWDF_OBJECT_ATTRIBUTES PipeAttributes,
__in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params
)
/*++
Routine Description:
Since the device is already configured, all this routine
does is to make sure the alternate setting 0 is selected,
in case the client driver selected some other alternate
setting after the initial configuration
Arguments:
Return Value:
NTSTATUS
--*/
{
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;
}
//
// Use AlternateSetting 0 by default
//
if (m_Interfaces[0]->GetSettingDescriptor(0) == 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;
}
status = m_Interfaces[0]->CheckAndSelectSettingByIndex(0);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"WDFUSBDEVICE %p set AlternateSetting 0 for interface 0"
"failed, %!STATUS!", GetHandle(), status);
return status;
}
if (PipeAttributes) {
status = m_Interfaces[0]->UpdatePipeAttributes(PipeAttributes);
}
Params->Types.SingleInterface.ConfiguredUsbInterface =
m_Interfaces[0]->GetHandle();
Params->Types.SingleInterface.NumberConfiguredPipes =
m_Interfaces[0]->GetNumConfiguredPipes();
return status;
}
_Must_inspect_result_
NTSTATUS
FxUsbDevice::SelectConfigMulti(
__in PWDF_OBJECT_ATTRIBUTES PipeAttributes,
__in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params
)
/*++
Routine Description:
Since the device is already configured, all this routine
does is to make sure the alternate setting 0 is selected
for all interfaces, in case the client driver selected some
other alternate setting after the initial configuration
Arguments:
PipeAttributes - Should be NULL
Params -
Return Value:
NTSTATUS
--*/
{
FxUsbInterface * pUsbInterface;
NTSTATUS status;
UCHAR i;
PFX_DRIVER_GLOBALS pFxDriverGlobals;
pFxDriverGlobals = GetDriverGlobals();
Params->Types.MultiInterface.NumberOfConfiguredInterfaces = 0;
if (Params->Type == WdfUsbTargetDeviceSelectConfigTypeMultiInterface) {
for (i = 0; i < m_NumInterfaces; i++) {
if (m_Interfaces[i]->GetSettingDescriptor(0) == 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;
}
status = m_Interfaces[i]->CheckAndSelectSettingByIndex(0);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"WDFUSBDEVICE %p set AlternateSetting 0 for bInterfaceNumber %d"
"failed, %!STATUS!",
GetHandle(), m_Interfaces[i]->m_InterfaceNumber, status);
goto Done;
}
if (PipeAttributes) {
status = m_Interfaces[i]->UpdatePipeAttributes(PipeAttributes);
}
}
}
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];
FxObjectHandleGetPtr(GetDriverGlobals(),
settingPair->UsbInterface,
FX_TYPE_USB_INTERFACE ,
(PVOID*) &pUsbInterface);
interfaceNumber = pUsbInterface->GetInterfaceNumber();
altSettingIndex = settingPair->SettingIndex;
//
// do the following only if the bit is not already set
//
if (FxBitArraySet(&bitArray[0], interfaceNumber) == FALSE) {
if (pUsbInterface->GetSettingDescriptor(altSettingIndex) == 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++;
//
// Ensure alternate setting 0 is selected
//
status = pUsbInterface->CheckAndSelectSettingByIndex(
settingPair->SettingIndex);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
"WDFUSBDEVICE %p set AlternateSetting %d for bInterfaceNumber %d"
"failed, %!STATUS!",
GetHandle(), altSettingIndex, m_Interfaces[i]->m_InterfaceNumber,
status);
goto Done;
}
if (PipeAttributes) {
status = pUsbInterface->UpdatePipeAttributes(PipeAttributes);
}
}
}
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
status = STATUS_SUCCESS;
Params->Types.MultiInterface.NumberOfConfiguredInterfaces = m_NumInterfaces;
Done:
return status;
}
_Must_inspect_result_
NTSTATUS
FxUsbDevice::Reset(
VOID
)
{
UMURB urb;
NTSTATUS status;
RtlZeroMemory(&urb, sizeof(UMURB));
urb.UmUrbSelectInterface.Hdr.Function = UMURB_FUNCTION_RESET_PORT;
urb.UmUrbSelectInterface.Hdr.Length = sizeof(_UMURB_HEADER);
status = SendSyncUmUrb(&urb, 2);
return status;
}