reactos/sdk/lib/drivers/wdf/shared/targets/usb/um/fxusbdeviceum.cpp
Victor Perevertkin 1f377076d7
[WDF] Fix KMDF so it can compile with ReactOS SDK
Not all files are included, but these are necessary to compile cdrom driver.
So far it can only be statically linked with drivers, a proper
implementation requires wdfldr helper driver
2020-11-03 00:06:27 +03:00

924 lines
28 KiB
C++

/*++
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);
FxUsbRequestContext::StoreAndReferenceMemory(Buffer); // __super call
//
// 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;
}