summaryrefslogtreecommitdiff
path: root/network/wwan/cxwmbclass/utils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'network/wwan/cxwmbclass/utils.cpp')
-rw-r--r--network/wwan/cxwmbclass/utils.cpp588
1 files changed, 588 insertions, 0 deletions
diff --git a/network/wwan/cxwmbclass/utils.cpp b/network/wwan/cxwmbclass/utils.cpp
new file mode 100644
index 00000000..ec791ab4
--- /dev/null
+++ b/network/wwan/cxwmbclass/utils.cpp
@@ -0,0 +1,588 @@
+//
+// Copyright (C) Microsoft. All rights reserved.
+//
+#include <precomp.h>
+#include "util.h"
+NTSTATUS
+SendSyncControlCommand(
+ __in WDFUSBDEVICE WdfUsbDevice,
+ __in WDF_USB_BMREQUEST_DIRECTION Direction,
+ __in WDF_USB_BMREQUEST_RECIPIENT Recipient,
+ __in BYTE Request,
+ __in USHORT Value,
+ __inout_bcount_opt(BufferLength) PUCHAR Buffer,
+ __in ULONG BufferLength,
+ __out_opt PULONG BytesTransfered)
+
+{
+
+ NTSTATUS Status;
+ WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket;
+ WDF_MEMORY_DESCRIPTOR memoryDescriptor;
+ WDF_REQUEST_SEND_OPTIONS SendOptions;
+ PUSB_DEVICE_CONTEXT usbDeviceContext = NULL;
+
+ usbDeviceContext = GetUsbDeviceContext(WdfUsbDevice);
+
+ if (Buffer != NULL)
+ {
+
+ WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memoryDescriptor, (PVOID)Buffer, BufferLength);
+ }
+
+ WDF_USB_CONTROL_SETUP_PACKET_INIT_CLASS(&controlSetupPacket, Direction, Recipient, Request, Value, usbDeviceContext->UsbCommunicationInterfaceIndex);
+
+ WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions, 0);
+
+ WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions, WDF_REL_TIMEOUT_IN_SEC(10));
+
+ Status = WdfUsbTargetDeviceSendControlTransferSynchronously(
+ WdfUsbDevice, WDF_NO_HANDLE, &SendOptions, &controlSetupPacket, (Buffer != NULL) ? &memoryDescriptor : NULL, BytesTransfered);
+
+ if (!NT_SUCCESS(Status))
+ {
+ BOOLEAN ToHost = Direction == BmRequestDeviceToHost;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+TransactControlChannel(
+ __in PBUS_OBJECT BusObject,
+ __in ULONG TimeOut,
+ __in_bcount_opt(InBufferLength) PUCHAR InBuffer,
+ __in ULONG InBufferLength,
+ __out_bcount_opt(OutBufferLength) PUCHAR OutBuffer,
+ __in ULONG OutBufferLength,
+ __out PULONG BytesRead)
+
+{
+ ULONG BytesTransfered = 0;
+ NTSTATUS Status;
+
+ *BytesRead = 0;
+
+ Status = SendSyncControlCommand(
+ BusObject->WdfUsbDevice, BmRequestHostToDevice, BmRequestToInterface, SEND_ENCAPSULATE_COMMAND, 0, InBuffer, InBufferLength, &BytesTransfered);
+
+ if (NT_SUCCESS(Status))
+ {
+ if (BytesTransfered < InBufferLength)
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
+ }
+
+ Status = WaitForResponseAvailible(BusObject, TimeOut);
+
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
+ }
+
+ Status = SendSyncControlCommand(
+ BusObject->WdfUsbDevice, BmRequestDeviceToHost, BmRequestToInterface, GET_ENCAPSULATE_RESPONSE, 0, OutBuffer, OutBufferLength, &BytesTransfered);
+
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
+ }
+
+ *BytesRead = BytesTransfered;
+
+Cleanup:
+
+ return Status;
+}
+
+NTSTATUS
+ReadInterrupt(_In_ PBUS_OBJECT BusObject, _Inout_updates_bytes_(BufferLength) PUCHAR Buffer, _In_ ULONG BufferLength, _In_ ULONG Timeout, _Out_ PULONG BytesRead)
+
+{
+
+ NTSTATUS status;
+ WDFMEMORY memHandle = NULL;
+
+ WDFREQUEST request = NULL;
+ BOOLEAN SentToDevice = FALSE;
+ WDF_REQUEST_SEND_OPTIONS SendOptions;
+ PUSB_DEVICE_CONTEXT usbDeviceContext = NULL;
+ WDF_MEMORY_DESCRIPTOR MemoryDescriptor;
+
+ usbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice);
+
+ WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&MemoryDescriptor, (PVOID)Buffer, BufferLength);
+
+ WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions, WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE);
+
+ WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions, WDF_REL_TIMEOUT_IN_SEC(Timeout));
+
+ status = WdfUsbTargetPipeReadSynchronously(usbDeviceContext->InterruptPipe, NULL, &SendOptions, &MemoryDescriptor, BytesRead);
+
+ return status;
+}
+
+NTSTATUS
+GetDeviceString(__in WDFUSBDEVICE UsbDevice, __in UCHAR Index, __out PWSTR* String)
+
+{
+ NTSTATUS Status;
+ WDF_REQUEST_SEND_OPTIONS SendOptions;
+ USHORT CharacterCount = 0;
+ ULONG AllocationSize = 0;
+ PWSTR AllocatedString = NULL;
+
+ WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions, 0);
+
+ WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions, WDF_REL_TIMEOUT_IN_SEC(DEFAULT_IO_TIMEOUT));
+
+ *String = NULL;
+
+ Status = WdfUsbTargetDeviceQueryString(UsbDevice, NULL, &SendOptions, NULL, &CharacterCount, Index, 0);
+
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
+ }
+
+ //
+ // allocate one more char to make sure sting is null terminated
+ //
+ AllocationSize = (CharacterCount + 1) * sizeof(WCHAR);
+
+ AllocatedString = (PWSTR)ALLOCATE_PAGED_POOL(AllocationSize);
+
+ if (AllocatedString == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Cleanup;
+ }
+
+ RtlZeroMemory(AllocatedString, AllocationSize);
+
+ Status = WdfUsbTargetDeviceQueryString(UsbDevice, NULL, &SendOptions, AllocatedString, &CharacterCount, Index, 0);
+
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
+ }
+
+ *String = AllocatedString;
+ AllocatedString = NULL;
+
+Cleanup:
+
+ if (AllocatedString != NULL)
+ {
+ FREE_POOL(AllocatedString);
+ AllocatedString = NULL;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+MbbBusSetPacketFilter(__in MBB_BUS_HANDLE BusHandle, __in ULONG PacketFilter)
+
+{
+
+ PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle;
+ NTSTATUS Status;
+ ULONG BytesTransfered = 0;
+ UCHAR ReadBuffer[256];
+
+ Status = SendSyncControlCommand(
+ BusObject->WdfUsbDevice, BmRequestHostToDevice, BmRequestToInterface, SET_PACKET_FILTER, 0, (PUCHAR)&PacketFilter, sizeof(PacketFilter), &BytesTransfered);
+
+ if (NT_SUCCESS(Status))
+ {
+ if (BytesTransfered < sizeof(PacketFilter))
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+ }
+
+ return Status;
+}
+
+NTSTATUS
+MbbBusSetNtbInSize(__in MBB_BUS_HANDLE BusHandle, __in ULONG InSize)
+
+{
+
+ PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle;
+ NTSTATUS Status;
+ ULONG BytesTransfered = 0;
+
+ Status = SendSyncControlCommand(
+ BusObject->WdfUsbDevice, BmRequestHostToDevice, BmRequestToInterface, SET_NTB_INPUT_SIZE, 0, (PUCHAR)&InSize, sizeof(InSize), &BytesTransfered);
+
+ if (NT_SUCCESS(Status))
+ {
+ if (BytesTransfered < sizeof(InSize))
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+ }
+
+ return Status;
+}
+
+NTSTATUS
+MbbBusGetStat(__in MBB_BUS_HANDLE BusHandle, __in USHORT StatIndex, __out ULONGLONG* Value)
+
+{
+ PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle;
+ NTSTATUS Status;
+ ULONG BytesTransfered = 0;
+
+#pragma warning(suppress : 6001)
+ Status = SendSyncControlCommand(
+ BusObject->WdfUsbDevice, BmRequestDeviceToHost, BmRequestToInterface, GET_STATISTIC, StatIndex, (PUCHAR)Value, sizeof(*Value), &BytesTransfered);
+
+ if (NT_SUCCESS(Status))
+ {
+ if (BytesTransfered < sizeof(Value))
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+ }
+
+ return Status;
+}
+
+NTSTATUS
+MbbBusSetNtbFormat(__in MBB_BUS_HANDLE BusHandle, __in USHORT Format)
+
+{
+
+ PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle;
+ NTSTATUS Status;
+ ULONG BytesTransfered = 0;
+
+ Status = SendSyncControlCommand(
+ BusObject->WdfUsbDevice, BmRequestHostToDevice, BmRequestToInterface, SET_NBT_FORMAT, Format, (PUCHAR)NULL, 0, &BytesTransfered);
+
+ if (NT_SUCCESS(Status))
+ {
+ }
+
+ return Status;
+}
+
+NTSTATUS
+MbbBusResetFunction(__in MBB_BUS_HANDLE BusHandle)
+
+{
+
+ PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle;
+ NTSTATUS Status;
+ ULONG BytesTransfered = 0;
+
+ Status = SendSyncControlCommand(
+ BusObject->WdfUsbDevice, BmRequestHostToDevice, BmRequestToInterface, RESET_FUNCTION, 0, (PUCHAR)NULL, 0, &BytesTransfered);
+
+ if (NT_SUCCESS(Status))
+ {
+ }
+
+ return Status;
+}
+
+NTSTATUS
+MbbBusResetDeviceAndSetParms(__in PBUS_OBJECT BusObject)
+
+{
+ NTSTATUS Status;
+ USHORT NtbFormat = NCM_SET_NTB_FORMAT_16_BIT;
+
+ //
+ // put the device back into a known state
+ //
+ Status = MbbBusResetFunction(BusObject);
+
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
+ }
+
+ Status = MbbBusSetNtbInSize(BusObject, BusObject->MaxBulkInTransfer);
+
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
+ }
+
+ if ((BusObject->NtbParam.bmNtbFormatSupported & NCM_NTB_FORMAT_32_BIT) == NCM_NTB_FORMAT_32_BIT)
+ {
+ //
+ // device supports 32 bit mode
+ //
+ if (BusObject->NtbFormat32Bit)
+ {
+ //
+ // the device can actually handle a transfer larger than 16bit, change to 32 bit
+ //
+ NtbFormat = NCM_SET_NTB_FORMAT_32_BIT;
+ }
+
+ //
+ // set the format
+ //
+ Status = MbbBusSetNtbFormat(BusObject, NtbFormat);
+
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
+ }
+ }
+
+Cleanup:
+
+ return Status;
+}
+
+ULONG
+ProcessInterruptPipeRead(
+ PBUS_OBJECT BusObject,
+ __in_ecount(NewFragmentLength) PCUCHAR NewFragment,
+ ULONG NewFragmentLength,
+ __out_ecount(MessageBufferSize) PUCHAR CompleteMessageBuffer,
+ ULONG MessageBufferSize)
+
+{
+
+ ULONG CompleteMessageLength = 0;
+ PUSB_CDC_NOTIFICATION CdcNotification = NULL;
+
+ ASSERT(MessageBufferSize == sizeof(BusObject->InterruptReassemnblyBuffer));
+
+ if (BusObject->CurrentOffset == 0)
+ {
+ //
+ // beggining of interrupt transfer
+ //
+ if ((NewFragmentLength >= sizeof(*CdcNotification)) && (NewFragmentLength <= sizeof(BusObject->InterruptReassemnblyBuffer)))
+ {
+ //
+ // big enough for a notification
+ //
+ CdcNotification = (PUSB_CDC_NOTIFICATION)NewFragment;
+
+ if ((CdcNotification->bmRequestType == 0xa1))
+ {
+ BusObject->ExpectLength = sizeof(*CdcNotification) + CdcNotification->wLength;
+
+ RtlCopyMemory(&BusObject->InterruptReassemnblyBuffer[BusObject->CurrentOffset], NewFragment, NewFragmentLength);
+
+ BusObject->CurrentOffset += NewFragmentLength;
+ }
+ else
+ {
+ //
+ // wrong request type, drop
+ //
+ }
+ }
+ else
+ {
+ //
+ // not big enough to be a cdc notification, drop
+ //
+ }
+ }
+ else
+ {
+ //
+ // we already have some of the data
+ //
+ if ((NewFragmentLength + BusObject->CurrentOffset) <= sizeof(BusObject->InterruptReassemnblyBuffer))
+ {
+ //
+ // still room in the NewFragment
+ //
+ RtlCopyMemory(&BusObject->InterruptReassemnblyBuffer[BusObject->CurrentOffset], NewFragment, NewFragmentLength);
+ }
+ else
+ {
+ //
+ // over flow, Keep procssing until we get the whole thing so we don't get out of sync
+ //
+ }
+ BusObject->CurrentOffset += NewFragmentLength;
+ }
+
+ if (BusObject->CurrentOffset < BusObject->ExpectLength)
+ {
+ //
+ // we don't have the whole thing yet, keep going
+ //
+ if (NewFragmentLength == 0)
+ {
+ //
+ // got a zero length transfer, reset the re-assembly state
+ BusObject->ExpectLength = 0;
+ BusObject->CurrentOffset = 0;
+ }
+ }
+ else
+ {
+ if (BusObject->CurrentOffset == BusObject->ExpectLength)
+ {
+ //
+ // got it all
+ //
+ if ((BusObject->CurrentOffset <= sizeof(BusObject->InterruptReassemnblyBuffer)) && (BusObject->CurrentOffset <= MessageBufferSize))
+ {
+ //
+ // the whole thing fit in the NewFragment
+ //
+ RtlCopyMemory(CompleteMessageBuffer, BusObject->InterruptReassemnblyBuffer, BusObject->CurrentOffset);
+
+ CompleteMessageLength = BusObject->CurrentOffset;
+ BusObject->CurrentOffset = 0;
+ }
+ else
+ {
+ //
+ // it is bigger than the re-assembly NewFragment,
+ // drop it
+ //
+ }
+
+ //
+ // done with the current re-assembled NewFragment
+ //
+ BusObject->ExpectLength = 0;
+ BusObject->CurrentOffset = 0;
+ }
+ else
+ {
+ //
+ // current offset is beyond the what we expected
+ //
+ ASSERT(0);
+ }
+ }
+
+ return CompleteMessageLength;
+}
+
+NTSTATUS
+WaitForResponseAvailible(PBUS_OBJECT BusObject, ULONG TimeOut)
+
+{
+ NTSTATUS Status;
+ UCHAR IndicateBuffer[INTERRUPT_REASSEMBLY_BUFFER_SIZE];
+ ULONG BufferLength = 0;
+ ULONG BytesTransfered = 0;
+ BOOLEAN ExitLoop = FALSE;
+ PUSB_DEVICE_CONTEXT usbDeviceContext = NULL;
+ PUSB_CDC_NOTIFICATION Notification = NULL;
+
+ usbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice);
+
+ BusObject->ExpectLength = 0;
+ BusObject->CurrentOffset = 0;
+
+ while (!ExitLoop)
+ {
+
+ Status = ReadInterrupt(BusObject, BusObject->SyncInterruptReadBuffer, usbDeviceContext->InterruptPipeMaxPacket, TimeOut, &BytesTransfered);
+
+ if (NT_SUCCESS(Status))
+ {
+
+ BufferLength = ProcessInterruptPipeRead(
+ BusObject, BusObject->SyncInterruptReadBuffer, BytesTransfered, IndicateBuffer, sizeof(IndicateBuffer));
+
+ if (BufferLength == 0)
+ {
+ //
+ //
+ // don't have a complete message yet
+ //
+ continue;
+ }
+ else
+ {
+ if (BufferLength < sizeof(*Notification))
+ {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ goto Cleanup;
+ }
+
+ Notification = (PUSB_CDC_NOTIFICATION)IndicateBuffer;
+
+ if (Notification->bNotificationCode != USB_CDC_NOTIFICATION_RESPONSE_AVAILABLE)
+ {
+ continue;
+ }
+ }
+ }
+ else
+ {
+ goto Cleanup;
+ }
+
+ ExitLoop = TRUE;
+ }
+
+ Status = STATUS_SUCCESS;
+
+Cleanup:
+
+ return Status;
+}
+
+BOOLEAN IsUsbCapDeviceInfoValid(_In_ USB_CAP_DEVICE_INFO UsbCapDeviceInfo, _In_ ULONG CapResultLength)
+{
+ if (CapResultLength < sizeof(USB_CAP_DEVICE_INFO_HEADER))
+ {
+ return FALSE;
+ }
+ switch (UsbCapDeviceInfo.DeviceInfoHeader.DeviceType)
+ {
+ case USB_CAP_DEVICE_TYPE_UDE_MBIM: __fallthrough;
+ case USB_CAP_DEVICE_TYPE_UDE_MBIM_FASTIO:
+ // Only support version 1.0 now
+ if (UsbCapDeviceInfo.DeviceInfoHeader.DeviceMajorVersion == 0x1 && UsbCapDeviceInfo.DeviceInfoHeader.DeviceMinorVersion == 0x0)
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ default: return FALSE;
+ }
+}
+
+/*++
+
+Routine Description:
+
+ Check if the bus type is Ude
+
+Arguments:
+
+ BusHandle - identifies the instance of the bus layer.
+
+Return Value:
+
+ TRUE - The bus type is Ude
+ FALSE - The bus type isn't Ude
+
+--*/
+BOOLEAN
+MbbBusIsUde(_In_ MBB_BUS_HANDLE BusHandle)
+{
+ USB_CAP_DEVICE_TYPE DeviceType = ((PBUS_OBJECT)BusHandle)->UsbCapDeviceInfo.DeviceInfoHeader.DeviceType;
+ return (DeviceType == USB_CAP_DEVICE_TYPE_UDE_MBIM || DeviceType == USB_CAP_DEVICE_TYPE_UDE_MBIM_FASTIO);
+}