mirror of
https://github.com/reactos/reactos.git
synced 2024-11-10 00:34:39 +00:00
235 lines
7 KiB
C++
235 lines
7 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
FxUsbInterfaceUm.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
user mode only
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "fxusbpch.hpp"
|
||
|
|
||
|
extern "C" {
|
||
|
#include "FxUsbInterfaceUm.tmh"
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
FxUsbInterface::SetWinUsbHandle(
|
||
|
_In_ UCHAR FrameworkInterfaceIndex
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS status = STATUS_SUCCESS;
|
||
|
UMURB urb;
|
||
|
|
||
|
if (m_InterfaceNumber != FrameworkInterfaceIndex) {
|
||
|
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET,
|
||
|
"Composite device detected: Converting absolute interface "
|
||
|
"index %d to relative interface index %d", m_InterfaceNumber,
|
||
|
FrameworkInterfaceIndex);
|
||
|
}
|
||
|
|
||
|
if (FrameworkInterfaceIndex == 0) {
|
||
|
m_WinUsbHandle = m_UsbDevice->m_WinUsbHandle;
|
||
|
}
|
||
|
else {
|
||
|
RtlZeroMemory(&urb, sizeof(UMURB));
|
||
|
|
||
|
urb.UmUrbGetAssociatedInterface.Hdr.InterfaceHandle = m_UsbDevice->m_WinUsbHandle;
|
||
|
urb.UmUrbGetAssociatedInterface.Hdr.Function = UMURB_FUNCTION_GET_ASSOCIATED_INTERFACE;
|
||
|
urb.UmUrbGetAssociatedInterface.Hdr.Length = sizeof(_UMURB_GET_ASSOCIATED_INTERFACE);
|
||
|
|
||
|
//
|
||
|
// If this is using the WinUSB dispatcher, this will ultimately call
|
||
|
// WinUsb_GetAssociatedInterface which expects a 0-based index but starts
|
||
|
// counting from index 1. To get the handle for interface n, we pass n-1
|
||
|
// and WinUSB will return the handle for (n-1)+1.
|
||
|
//
|
||
|
// The NativeUSB dispatcher ultimately calls WdfUsbTargetDeviceGetInterface.
|
||
|
// Unlike WinUSB.sys, this starts counting from index zero. The NativeUSB
|
||
|
// dispatcher expects this framework quirk and adjusts accordingly. See
|
||
|
// WudfNativeUsbDispatcher.cpp for more information.
|
||
|
//
|
||
|
// The actual interface number may differ from the interface index in
|
||
|
// composite devices. In all cases, the interface index (starting from zero)
|
||
|
// must be used.
|
||
|
//
|
||
|
urb.UmUrbGetAssociatedInterface.InterfaceIndex = FrameworkInterfaceIndex - 1;
|
||
|
|
||
|
status = m_UsbDevice->SendSyncUmUrb(&urb, 5);
|
||
|
|
||
|
if (NT_SUCCESS(status)) {
|
||
|
m_WinUsbHandle = urb.UmUrbGetAssociatedInterface.InterfaceHandle;
|
||
|
}
|
||
|
else {
|
||
|
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
||
|
"Failed to retrieve WinUsb interface handle");
|
||
|
m_WinUsbHandle = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
FxUsbInterface::MakeAndConfigurePipes(
|
||
|
__in PWDF_OBJECT_ATTRIBUTES PipesAttributes,
|
||
|
__in UCHAR NumPipes
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS status = STATUS_SUCCESS;
|
||
|
UCHAR iPipe;
|
||
|
FxUsbPipe* pPipe;
|
||
|
FxUsbPipe** ppPipes;
|
||
|
//
|
||
|
// Zero pipes are a valid configuration, this simplifies the code below.
|
||
|
//
|
||
|
ULONG size = (NumPipes == 0 ? 1 : NumPipes) * sizeof(FxUsbPipe*);
|
||
|
UMURB urb;
|
||
|
|
||
|
ppPipes = (FxUsbPipe**)FxPoolAllocate(GetDriverGlobals(), NonPagedPool, size);
|
||
|
if (ppPipes == NULL) {
|
||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
DoTraceLevelMessage(
|
||
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
||
|
"Unable to allocate memory %!STATUS!", status);
|
||
|
goto Done;
|
||
|
}
|
||
|
|
||
|
RtlZeroMemory(ppPipes, size);
|
||
|
|
||
|
for (iPipe = 0; iPipe < NumPipes; iPipe++) {
|
||
|
ppPipes[iPipe] = new (GetDriverGlobals(), PipesAttributes)
|
||
|
FxUsbPipe(GetDriverGlobals(), m_UsbDevice);
|
||
|
|
||
|
if (ppPipes[iPipe] == NULL) {
|
||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
DoTraceLevelMessage(
|
||
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
||
|
"Unable to allocate memory for the pipes %!STATUS!", status);
|
||
|
goto Done;
|
||
|
}
|
||
|
|
||
|
pPipe = ppPipes[iPipe];
|
||
|
|
||
|
status = pPipe->Init(m_UsbDevice->m_Device);
|
||
|
if (!NT_SUCCESS(status)) {
|
||
|
DoTraceLevelMessage(
|
||
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
||
|
"Init pipe failed %!STATUS!", status);
|
||
|
goto Done;
|
||
|
}
|
||
|
|
||
|
status = pPipe->Commit(PipesAttributes, NULL, this);
|
||
|
if (!NT_SUCCESS(status)) {
|
||
|
DoTraceLevelMessage(
|
||
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
||
|
"Commit pipe failed %!STATUS!", status);
|
||
|
goto Done;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (IsInterfaceConfigured()) {
|
||
|
//
|
||
|
// Delete the old pipes
|
||
|
//
|
||
|
m_UsbDevice->CleanupInterfacePipesAndDelete(this);
|
||
|
}
|
||
|
|
||
|
SetNumConfiguredPipes(NumPipes);
|
||
|
SetConfiguredPipes(ppPipes);
|
||
|
|
||
|
for (iPipe = 0; iPipe < m_NumberOfConfiguredPipes ; iPipe++) {
|
||
|
RtlZeroMemory(&urb, sizeof(UMURB));
|
||
|
|
||
|
urb.UmUrbQueryPipe.Hdr.InterfaceHandle = m_WinUsbHandle;
|
||
|
urb.UmUrbQueryPipe.Hdr.Function = UMURB_FUNCTION_QUERY_PIPE;
|
||
|
urb.UmUrbQueryPipe.Hdr.Length = sizeof(_UMURB_QUERY_PIPE);
|
||
|
|
||
|
urb.UmUrbQueryPipe.AlternateSetting = m_CurAlternateSetting;
|
||
|
urb.UmUrbQueryPipe.PipeID = iPipe;
|
||
|
|
||
|
status = m_UsbDevice->SendSyncUmUrb(&urb, 2);
|
||
|
|
||
|
if (!NT_SUCCESS(status)) {
|
||
|
DoTraceLevelMessage(
|
||
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
||
|
"Send UMURB_FUNCTION_QUERY_PIPE failed %!STATUS!", status);
|
||
|
goto Done;
|
||
|
}
|
||
|
|
||
|
m_ConfiguredPipes[iPipe]->InitPipe(&urb.UmUrbQueryPipe.PipeInformation,
|
||
|
m_InterfaceNumber,
|
||
|
this);
|
||
|
}
|
||
|
|
||
|
Done:
|
||
|
if (!NT_SUCCESS(status)) {
|
||
|
if (ppPipes != NULL) {
|
||
|
ASSERT(ppPipes != m_ConfiguredPipes);
|
||
|
|
||
|
for (iPipe = 0; iPipe < NumPipes; iPipe++) {
|
||
|
if (ppPipes[iPipe] != NULL) {
|
||
|
ppPipes[iPipe]->DeleteFromFailedCreate();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FxPoolFree(ppPipes);
|
||
|
ppPipes = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
FxUsbInterface::UpdatePipeAttributes(
|
||
|
__in PWDF_OBJECT_ATTRIBUTES PipesAttributes
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS status = STATUS_SUCCESS;
|
||
|
UCHAR iPipe;
|
||
|
FxUsbPipe** ppPipes;
|
||
|
UCHAR numberOfPipes;
|
||
|
|
||
|
numberOfPipes = m_NumberOfConfiguredPipes;
|
||
|
ppPipes = m_ConfiguredPipes;
|
||
|
|
||
|
for (iPipe = 0; iPipe < numberOfPipes; iPipe++) {
|
||
|
status = FxObjectAllocateContext(ppPipes[iPipe],
|
||
|
PipesAttributes,
|
||
|
TRUE,
|
||
|
NULL);
|
||
|
if (!NT_SUCCESS(status)) {
|
||
|
DoTraceLevelMessage(
|
||
|
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
|
||
|
"UpdatePipeAttributes failed %!STATUS!", status);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Pipe attributes are updated as part of select
|
||
|
// config and it is ok for the client driver to configure
|
||
|
// twice with the same attributes. In a similar scenario,
|
||
|
// KMDF will return STATUS_SUCCESS, so we should do the
|
||
|
// same for UMDF for consistency
|
||
|
//
|
||
|
if (status == STATUS_OBJECT_NAME_EXISTS) {
|
||
|
status = STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|