From 28a39aede5ef6afe63667c4a58b511fd1d28b41c Mon Sep 17 00:00:00 2001 From: Michael Loh <90074657+AmeNote-Michael@users.noreply.github.com> Date: Wed, 3 Apr 2024 11:52:38 -0600 Subject: [PATCH 1/8] Sysex Handling WIP Design 2 for Sysex Handling WIP. --- src/api/Drivers/USBMIDI2/Driver/Device.cpp | 46 ++++++++++++++++++---- src/api/Drivers/USBMIDI2/Driver/Device.h | 32 ++++++++------- 2 files changed, 56 insertions(+), 22 deletions(-) diff --git a/src/api/Drivers/USBMIDI2/Driver/Device.cpp b/src/api/Drivers/USBMIDI2/Driver/Device.cpp index 325344d8b..d1e9cb468 100644 --- a/src/api/Drivers/USBMIDI2/Driver/Device.cpp +++ b/src/api/Drivers/USBMIDI2/Driver/Device.cpp @@ -185,6 +185,14 @@ Return Value: devCtx->Midi = nullptr; devCtx->ExcludeD3Cold = WdfFalse; + for (int count = 0; count < MAX_NUM_GROUPS_CABLES; count++) + { + devCtx->midi1IsInSysex[count] = false; + devCtx->midi1OutSysex[count].head = 0; + devCtx->midi1OutSysex[count].tail = 0; + devCtx->midi1OutSysex[count].inSysex = false; + } + // // Allow ACX to add any post-requirement it needs on this device. // @@ -1091,7 +1099,6 @@ Return Value: // // Configure continuous reader // -#if 1 if (pDeviceContext->MidiInPipe) // only if there is an In endpoint { WDF_USB_CONTINUOUS_READER_CONFIG_INIT( @@ -1114,7 +1121,6 @@ Return Value: return status; } } -#endif TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit"); return STATUS_SUCCESS; @@ -1539,8 +1545,6 @@ Return Value: // Check the subtype and process accordingly midi_desc_header_common_t* pCommonHdr = (midi_desc_header_common_t*)pNextDescriptor; - //PUINT8 pThisIndex = NULL; - //PUSHORT pThisGTBStringSize = NULL; midi_desc_in_jack_t* pInJack = NULL; midi_desc_out_jack_t* pOutJack = NULL; @@ -2111,28 +2115,56 @@ Return Value:Amy case UMP_MT_DATA_64: { + bool bEnterSysex = false; bool bEndSysex = false; // Determine if sysex will end after this message switch (umpPacket.umpData.umpBytes[1] & UMP_SYSEX7_STATUS_MASK) { case UMP_SYSEX7_COMPLETE: - pDeviceContext->midi1OutSysex[cbl_num].index = 1; + bEnterSysex = true; case UMP_SYSEX7_END: bEndSysex = true; break; case UMP_SYSEX7_START: - pDeviceContext->midi1OutSysex[cbl_num].index = 1; + bEnterSysex = true; + default: bEndSysex = false; break; } - // determine the size + // If starting sysex and not already started + if (bEnterSysex && !pDeviceContext->midi1OutSysex[cbl_num].inSysex) + { + // We are responsible to start the Sysex flag for USB MIDI 1.0 + pDeviceContext->midi1OutSysex[cbl_num].buffer[pDeviceContext->midi1OutSysex[cbl_num].head++] = 0xf0; + pDeviceContext->midi1OutSysex[cbl_num].head %= MIDI_STREAM_BUF_SIZE; + pDeviceContext->midi1OutSysex[cbl_num].inSysex = true; + } + + // determine the size and move the data in UINT8 sysexSize = umpPacket.umpData.umpBytes[1] & UMP_SYSEX7_SIZE_MASK; + UINT8 umpDataByteCount = 0; + while (sysexSize--) + { + pDeviceContext->midi1OutSysex[cbl_num].buffer[pDeviceContext->midi1OutSysex[cbl_num].head++] + = umpPacket.umpData.umpBytes[umpDataByteCount++]; + pDeviceContext->midi1OutSysex[cbl_num].head %= MIDI_STREAM_BUF_SIZE; // it should not be possible to overflow buffer + } + + // If ending + if (bEndSysex && pDeviceContext->midi1OutSysex[cbl_num].inSysex) + { + // We are responsible to start the Sysex flag for USB MIDI 1.0 + pDeviceContext->midi1OutSysex[cbl_num].buffer[pDeviceContext->midi1OutSysex[cbl_num].head++] = 0xf7; + pDeviceContext->midi1OutSysex[cbl_num].head %= MIDI_STREAM_BUF_SIZE; + pDeviceContext->midi1OutSysex[cbl_num].inSysex = false; + } // determine the number of USB MIDI 1 packets to be created + sysexSize = UINT8 numWordsNeeded = (sysexSize + pDeviceContext->midi1OutSysex[cbl_num].index - 1) / 3; UINT8 numBytesRemain = (sysexSize + pDeviceContext->midi1OutSysex[cbl_num].index - 1) % 3; if (bEndSysex && numBytesRemain) diff --git a/src/api/Drivers/USBMIDI2/Driver/Device.h b/src/api/Drivers/USBMIDI2/Driver/Device.h index add5b5ac6..c386f69eb 100644 --- a/src/api/Drivers/USBMIDI2/Driver/Device.h +++ b/src/api/Drivers/USBMIDI2/Driver/Device.h @@ -61,22 +61,24 @@ extern "C" { // // Structures to aid in conversion between USB MIDI 1.0 and UMP // - typedef struct MIDI_STREAM_t +#define MIDI_STREAM_BUF_SIZE 14 // size of two UMP Sysex 7 plus start and end +typedef struct MIDI_STREAM_t +{ + UINT8 buffer[MIDI_STREAM_BUF_SIZE]; + UINT8 head; + UINT8 tail; + bool inSysex; +} MIDI_STREAM_TYPE; + +typedef struct +{ + UINT8 wordCount; + union ump_device { - UINT8 buffer[4]; - UINT8 index; - UINT8 total; - } MIDI_STREAM_TYPE; - - typedef struct - { - UINT8 wordCount; - union ump_device - { - UINT32 umpWords[4]; - UINT8 umpBytes[sizeof(UINT32) * 4]; - } umpData; - } UMP_PACKET, *PUMP_PACKET; + UINT32 umpWords[4]; + UINT8 umpBytes[sizeof(UINT32) * 4]; + } umpData; +} UMP_PACKET, *PUMP_PACKET; // // Define device context. From 0beeeb8e8be402ee0be5c09842e6930277486c12 Mon Sep 17 00:00:00 2001 From: Michael Loh <90074657+AmeNote-Michael@users.noreply.github.com> Date: Wed, 22 May 2024 11:29:56 -0600 Subject: [PATCH 2/8] Issues 236, 226 (WIP), 165 Issues indicated plus need to test against issues 312, 309, 307. 226 is WIP as code compilation issue prevents some validation testing and completion of integration. --- .gitignore | 1 + src/api/Drivers/USBMIDI2/Driver/Device.cpp | 61 +++++++++++++++---- src/api/Drivers/USBMIDI2/Driver/Device.h | 21 ++++--- .../Drivers/USBMIDI2/Driver/StreamEngine.cpp | 3 +- .../Drivers/USBMIDI2/Driver/USBMidi2.vcxproj | 7 +++ src/api/Drivers/USBMIDI2/Driver/ump.h | 3 + .../Drivers/USBMIDI2/vcpkg-configuration.json | 14 +++++ src/api/Drivers/USBMIDI2/vcpkg.json | 5 ++ 8 files changed, 91 insertions(+), 24 deletions(-) create mode 100644 src/api/Drivers/USBMIDI2/vcpkg-configuration.json create mode 100644 src/api/Drivers/USBMIDI2/vcpkg.json diff --git a/.gitignore b/.gitignore index 6f106fd2b..4c4b78ce4 100644 --- a/.gitignore +++ b/.gitignore @@ -356,3 +356,4 @@ build/dependencies/winui/WindowsAppRuntimeInstall-x64.exe build/dependencies/winui/WindowsAppRuntimeInstall-arm64.exe *.zip *.debugtarget +/src/api/Drivers/USBMIDI2/vcpkg_installed diff --git a/src/api/Drivers/USBMIDI2/Driver/Device.cpp b/src/api/Drivers/USBMIDI2/Driver/Device.cpp index d1e9cb468..1009f410f 100644 --- a/src/api/Drivers/USBMIDI2/Driver/Device.cpp +++ b/src/api/Drivers/USBMIDI2/Driver/Device.cpp @@ -188,8 +188,6 @@ Return Value: for (int count = 0; count < MAX_NUM_GROUPS_CABLES; count++) { devCtx->midi1IsInSysex[count] = false; - devCtx->midi1OutSysex[count].head = 0; - devCtx->midi1OutSysex[count].tail = 0; devCtx->midi1OutSysex[count].inSysex = false; } @@ -1942,7 +1940,8 @@ VOID USBMIDI2DriverIoWrite( WDFDEVICE Device, PVOID BufferStart, - size_t numBytes + size_t numBytes, + BOOLEAN isMoreData ) /*++ @@ -2080,6 +2079,9 @@ Return Value:Amy case UMP_SYSTEM_STOP: case UMP_SYSTEM_ACTIVE_SENSE: case UMP_SYSTEM_RESET: + case UMP_SYSTEM_UNDEFINED_F4: + case UMP_SYSTEM_UNDEFINED_F5: + case UMP_SYSTEM_UNDEFINED_F9: umpWritePacket.umpData.umpBytes[0] = (cbl_num << 4) | MIDI_CIN_SYSEX_END_1BYTE; break; @@ -2129,21 +2131,42 @@ Return Value:Amy case UMP_SYSEX7_START: bEnterSysex = true; - default: bEndSysex = false; break; } - // If starting sysex and not already started + if (bEnterSysex) + { + // Determine if believed already in Sysex and if so, reset converter + if (pDeviceContext->midi1OutSysex[cbl_num].inSysex) + { + // Need to flush any available bytes from converter + while (pDeviceContext->midi1OutSysex[cbl_num].umpToBS.availableBS()) + { + pDeviceContext->midi1OutSysex[cbl_num].umpToBS.readBS(); + } + pDeviceContext->midi1OutSysex[cbl_num].inSysex = false; + } + } if (bEnterSysex && !pDeviceContext->midi1OutSysex[cbl_num].inSysex) { - // We are responsible to start the Sysex flag for USB MIDI 1.0 - pDeviceContext->midi1OutSysex[cbl_num].buffer[pDeviceContext->midi1OutSysex[cbl_num].head++] = 0xf0; - pDeviceContext->midi1OutSysex[cbl_num].head %= MIDI_STREAM_BUF_SIZE; + pDeviceContext->midi1OutSysex[cbl_num].usbMIDI1Pos = 1; // first byte position to stream into pDeviceContext->midi1OutSysex[cbl_num].inSysex = true; } + // Use AM Lib to convert current UMP SYSEX7 into MIDIByte Stream + for (int count = 0; count < umpPacket.wordCount; count++) + { + pDeviceContext->midi1OutSysex[cbl_num].umpToBS.UMPStreamParse(umpPacket.umpData.umpWords[count]); + } + + // Capture byte stream into outgoing data + umpWritePacket.wordCount = 0; // For now we have no data to transfer to USB MIDI 1.0 + // move BS to umpWritePacket + + +#if 0 // determine the size and move the data in UINT8 sysexSize = umpPacket.umpData.umpBytes[1] & UMP_SYSEX7_SIZE_MASK; UINT8 umpDataByteCount = 0; @@ -2164,9 +2187,11 @@ Return Value:Amy } // determine the number of USB MIDI 1 packets to be created - sysexSize = - UINT8 numWordsNeeded = (sysexSize + pDeviceContext->midi1OutSysex[cbl_num].index - 1) / 3; - UINT8 numBytesRemain = (sysexSize + pDeviceContext->midi1OutSysex[cbl_num].index - 1) % 3; + sysexSize = (pDeviceContext->midi1OutSysex[cbl_num].head >= pDeviceContext->midi1OutSysex[cbl_num].tail) + ? (pDeviceContext->midi1OutSysex[cbl_num].head - pDeviceContect->midiOutSystex[cbl_num].tail) + : ((MIDI_STREAM_BUF_SIZE - pDeviceContext->midi1OutSysex[cbl_num].tail) + pDeviceContext->midi1OutSysex[cbl_num].head); + UINT8 numWordsNeeded = sysexSize / 3; + UINT8 numBytesRemain = sysexSize % 3; if (bEndSysex && numBytesRemain) { numWordsNeeded++; // add word for any remaining sysex data @@ -2177,7 +2202,13 @@ Return Value:Amy UINT8 sysexWordCount = 0; while (sysexCount < sysexSize && sysexWordCount < numWordsNeeded) { - pDeviceContext->midi1OutSysex[cbl_num].buffer[pDeviceContext->midi1OutSysex[cbl_num].index++] = umpPacket.umpData.umpBytes[2 + sysexCount++]; + UINT8 currentWord; + while (sysexCount < sysexSize) + { + + } + pDeviceContext->midi1OutSysex[cbl_num].buffer[pDeviceContext->midi1OutSysex[cbl_num].index++] + = umpPacket.umpData.umpBytes[2 + sysexCount++]; // is current packet build full if (pDeviceContext->midi1OutSysex[cbl_num].index == 4) @@ -2232,6 +2263,7 @@ Return Value:Amy umpWritePacket.umpData.umpWords[sysexWordCount++] = *(PUINT32)&pDeviceContext->midi1OutSysex[cbl_num].buffer; pDeviceContext->midi1OutSysex[cbl_num].index = 1; } +#endif break; } @@ -2312,7 +2344,7 @@ Return Value:Amy } // Check if anything leftover to write to USB - if (writeBufferIndex) + if (writeBufferIndex && !isMoreData) // and there is not more data coming { // NEED TO FILL REST OF BUFFER WITH NULL // @@ -2684,6 +2716,9 @@ Return Value: case UMP_SYSTEM_STOP: case UMP_SYSTEM_ACTIVE_SENSE: case UMP_SYSTEM_RESET: + case UMP_SYSTEM_UNDEFINED_F4: + case UMP_SYSTEM_UNDEFINED_F5: + case UMP_SYSTEM_UNDEFINED_F9: code_index = MIDI_CIN_SYSEX_END_1BYTE; break; diff --git a/src/api/Drivers/USBMIDI2/Driver/Device.h b/src/api/Drivers/USBMIDI2/Driver/Device.h index c386f69eb..21c009520 100644 --- a/src/api/Drivers/USBMIDI2/Driver/Device.h +++ b/src/api/Drivers/USBMIDI2/Driver/Device.h @@ -49,6 +49,7 @@ Module Name: #include "Public.h" #include "Common.h" #include "StreamEngine.h" +#include /* make prototypes usable from C++ */ #ifdef __cplusplus @@ -59,16 +60,15 @@ extern "C" { #define MAX_NUM_GROUPS_CABLES 16 // -// Structures to aid in conversion between USB MIDI 1.0 and UMP +// Structure to aid in UMP SYSEX to USB MIDI 1.0 // -#define MIDI_STREAM_BUF_SIZE 14 // size of two UMP Sysex 7 plus start and end -typedef struct MIDI_STREAM_t +typedef struct UMP_TO_MIDI1_SYSEX_t { - UINT8 buffer[MIDI_STREAM_BUF_SIZE]; - UINT8 head; - UINT8 tail; - bool inSysex; -} MIDI_STREAM_TYPE; + bool inSysex; + umpToBytestream umpToBS; + UINT8 usbMIDI1Pkt[4]; + UINT8 usbMIDI1Pos; +} UMP_TO_MIDI1_SYSEX; typedef struct { @@ -98,7 +98,7 @@ typedef struct _DEVICE_CONTEXT { // Buffers and information for USB MIDI 1.0 and UMP translations bool midi1IsInSysex[MAX_NUM_GROUPS_CABLES]; - MIDI_STREAM_TYPE midi1OutSysex[MAX_NUM_GROUPS_CABLES]; + UMP_TO_MIDI1_SYSEX midi1OutSysex[MAX_NUM_GROUPS_CABLES]; // Pipes // Currently setup for single endpoint pair - need to consider for multiple endpoint pairs @@ -244,7 +244,8 @@ VOID USBMIDI2DriverIoWrite( _In_ WDFDEVICE Device, _In_ PVOID BufferStart, - _In_ size_t numBytes + _In_ size_t numBytes, + _In_ BOOLEAN isMoreData ); _Must_inspect_result_ diff --git a/src/api/Drivers/USBMIDI2/Driver/StreamEngine.cpp b/src/api/Drivers/USBMIDI2/Driver/StreamEngine.cpp index f4078a5a6..2d01ec2b2 100644 --- a/src/api/Drivers/USBMIDI2/Driver/StreamEngine.cpp +++ b/src/api/Drivers/USBMIDI2/Driver/StreamEngine.cpp @@ -238,7 +238,8 @@ StreamEngine::HandleIo() USBMIDI2DriverIoWrite( AcxCircuitGetWdfDevice(AcxPinGetCircuit(m_Pin)), (PUCHAR)startingReadAddress + sizeof(UMPDATAFORMAT), - thisData->ByteCount + thisData->ByteCount, + (finalReadPosition != midiOutWritePosition) ? TRUE : FALSE // indicates there is more data in this pass or not ); } diff --git a/src/api/Drivers/USBMIDI2/Driver/USBMidi2.vcxproj b/src/api/Drivers/USBMIDI2/Driver/USBMidi2.vcxproj index 6923ae24b..4eae225a0 100644 --- a/src/api/Drivers/USBMIDI2/Driver/USBMidi2.vcxproj +++ b/src/api/Drivers/USBMIDI2/Driver/USBMidi2.vcxproj @@ -79,6 +79,7 @@ USBMidi2 $(SolutionDir)VSFiles\$(Platform)\$(Configuration)\ $(SolutionDir)VSFiles\intermediate\usbmidi2\$(Platform)\$(Configuration)\ + $(IncludePath) DbgengKernelDebugger @@ -91,6 +92,7 @@ USBMidi2 $(SolutionDir)VSFiles\$(Platform)\$(Configuration)\ $(SolutionDir)VSFiles\intermediate\usbmidi2\$(Platform)\$(Configuration)\ + $(IncludePath) DbgengKernelDebugger @@ -98,6 +100,9 @@ $(SolutionDir)VSFiles\$(Platform)\$(Configuration)\ $(SolutionDir)VSFiles\intermediate\usbmidi2\$(Platform)\$(Configuration)\ + + true + true @@ -111,6 +116,7 @@ %(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib;acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR)\acxstub.lib;$(DDK_LIB_PATH)\libcntpr.lib;$(DDK_LIB_PATH)\wpprecorder.lib;$(DDK_LIB_PATH)\Usbd.lib + false %(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR);. @@ -176,6 +182,7 @@ %(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib;acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR)\acxstub.lib;$(DDK_LIB_PATH)\libcntpr.lib;$(DDK_LIB_PATH)\wpprecorder.lib;$(DDK_LIB_PATH)\Usbd.lib + false stdcpp17 diff --git a/src/api/Drivers/USBMIDI2/Driver/ump.h b/src/api/Drivers/USBMIDI2/Driver/ump.h index 1a5e1373c..7db84c3b2 100644 --- a/src/api/Drivers/USBMIDI2/Driver/ump.h +++ b/src/api/Drivers/USBMIDI2/Driver/ump.h @@ -108,8 +108,11 @@ Module Name: #define UMP_SYSTEM_MTC 0xf1 // 2 bytes incl status #define UMP_SYSTEM_SONG_POS_PTR 0xf2 // 3 bytes incl status #define UMP_SYSTEM_SONG_SELECT 0xf3 // 2 bytes incl status +#define UMP_SYSTEM_UNDEFINED_F4 0xf4 // undefined +#define UMP_SYSTEM_UNDEFINED_F5 0xf5 // undefined #define UMP_SYSTEM_TUNE_REQ 0xf6 // status byte only #define UMP_SYSTEM_TIMING_CLK 0xf8 // status byte only +#define UMP_SYSTEM_UNDEFINED_F9 0xf9 // undefined #define UMP_SYSTEM_START 0xfa // status byte only #define UMP_SYSTEM_CONTINUE 0xfb // status byte only #define UMP_SYSTEM_STOP 0xfc // status byte only diff --git a/src/api/Drivers/USBMIDI2/vcpkg-configuration.json b/src/api/Drivers/USBMIDI2/vcpkg-configuration.json new file mode 100644 index 000000000..ae49e1bdf --- /dev/null +++ b/src/api/Drivers/USBMIDI2/vcpkg-configuration.json @@ -0,0 +1,14 @@ +{ + "default-registry": { + "kind": "git", + "baseline": "2fd62b5d878104f4092af80533923bfe2bba2ee0", + "repository": "https://github.com/microsoft/vcpkg" + }, + "registries": [ + { + "kind": "artifact", + "location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip", + "name": "microsoft" + } + ] +} diff --git a/src/api/Drivers/USBMIDI2/vcpkg.json b/src/api/Drivers/USBMIDI2/vcpkg.json new file mode 100644 index 000000000..4939478d2 --- /dev/null +++ b/src/api/Drivers/USBMIDI2/vcpkg.json @@ -0,0 +1,5 @@ +{ + "dependencies": [ + "libmidi2" + ] +} From f4f1ee22927873acd1ae05503c9627e9902d1986 Mon Sep 17 00:00:00 2001 From: Michael Loh <90074657+AmeNote-Michael@users.noreply.github.com> Date: Mon, 24 Jun 2024 17:14:01 -0600 Subject: [PATCH 3/8] Delete src/api/Drivers/USBMIDI2/vcpkg-configuration.json No longer to use library. --- src/api/Drivers/USBMIDI2/vcpkg-configuration.json | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 src/api/Drivers/USBMIDI2/vcpkg-configuration.json diff --git a/src/api/Drivers/USBMIDI2/vcpkg-configuration.json b/src/api/Drivers/USBMIDI2/vcpkg-configuration.json deleted file mode 100644 index ae49e1bdf..000000000 --- a/src/api/Drivers/USBMIDI2/vcpkg-configuration.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "default-registry": { - "kind": "git", - "baseline": "2fd62b5d878104f4092af80533923bfe2bba2ee0", - "repository": "https://github.com/microsoft/vcpkg" - }, - "registries": [ - { - "kind": "artifact", - "location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip", - "name": "microsoft" - } - ] -} From 4defb1875efa26f13702e5ea9d97a9fea8ccc278 Mon Sep 17 00:00:00 2001 From: Michael Loh <90074657+AmeNote-Michael@users.noreply.github.com> Date: Mon, 24 Jun 2024 17:14:25 -0600 Subject: [PATCH 4/8] Delete src/api/Drivers/USBMIDI2/vcpkg.json No longer to use library. --- src/api/Drivers/USBMIDI2/vcpkg.json | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 src/api/Drivers/USBMIDI2/vcpkg.json diff --git a/src/api/Drivers/USBMIDI2/vcpkg.json b/src/api/Drivers/USBMIDI2/vcpkg.json deleted file mode 100644 index 4939478d2..000000000 --- a/src/api/Drivers/USBMIDI2/vcpkg.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "dependencies": [ - "libmidi2" - ] -} From dac2c03a9e38ebfdea29f352221d02ec95b79116 Mon Sep 17 00:00:00 2001 From: Michael Loh Date: Mon, 8 Jul 2024 21:27:14 -0600 Subject: [PATCH 5/8] Updates for final Release Power Management Handling Initialize memory in device context Correcting routines to non-paged memory Presenting only GTBs listed in endpoints Sysex conversion from USB MIDI 1.0 to UMP UMP across multiple USB Packets Removing MUTEX use --- src/api/Drivers/USBMIDI2/Driver/Device.cpp | 942 +++++++++++++++------ src/api/Drivers/USBMIDI2/Driver/Device.h | 35 +- 2 files changed, 696 insertions(+), 281 deletions(-) diff --git a/src/api/Drivers/USBMIDI2/Driver/Device.cpp b/src/api/Drivers/USBMIDI2/Driver/Device.cpp index 1009f410f..1b2b55320 100644 --- a/src/api/Drivers/USBMIDI2/Driver/Device.cpp +++ b/src/api/Drivers/USBMIDI2/Driver/Device.cpp @@ -157,6 +157,8 @@ Return Value: WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); pnpPowerCallbacks.EvtDevicePrepareHardware = EvtDevicePrepareHardware; pnpPowerCallbacks.EvtDeviceReleaseHardware = EvtDeviceReleaseHardware; + pnpPowerCallbacks.EvtDeviceD0Entry = EvtDeviceD0Entry; + pnpPowerCallbacks.EvtDeviceD0Exit = EvtDeviceD0Exit; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); // @@ -184,7 +186,13 @@ Return Value: devCtx->Midi = nullptr; devCtx->ExcludeD3Cold = WdfFalse; - + devCtx->DeviceInGTBIDs = NULL; + devCtx->DeviceGTBMemory = NULL; + devCtx->DeviceOutGTBIDs = NULL; + devCtx->DeviceWriteMemory = NULL; + devCtx->DeviceWriteBuffer = NULL; + devCtx->DeviceWriteBufferIndex = NULL; + for (int count = 0; count < MAX_NUM_GROUPS_CABLES; count++) { devCtx->midi1IsInSysex[count] = false; @@ -420,7 +428,8 @@ SetPowerPolicy( // WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings; WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleCannotWakeFromS0); - idleSettings.IdleTimeout = IDLE_POWER_TIMEOUT; + //idleSettings.IdleTimeout = IDLE_POWER_TIMEOUT; + idleSettings.IdleTimeout = 15*60*1000; idleSettings.IdleTimeoutType = SystemManagedIdleTimeoutWithHint; idleSettings.ExcludeD3Cold = devCtx->ExcludeD3Cold; @@ -437,6 +446,85 @@ SetPowerPolicy( return status; } +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +EvtDeviceD0Entry( + _In_ WDFDEVICE Device, + _In_ WDF_POWER_DEVICE_STATE PreviousState +) +{ + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(PreviousState); + + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry"); + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit"); + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +EvtDeviceD0Exit( + _In_ WDFDEVICE Device, + _In_ WDF_POWER_DEVICE_STATE TargetState +) +{ + NTSTATUS status = STATUS_SUCCESS; + POWER_ACTION powerAction; + + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry"); + + PAGED_CODE(); + + powerAction = WdfDeviceGetSystemPowerAction(Device); + + // + // Update the power policy D3-cold info for Connected Standby. + // + if (TargetState == WdfPowerDeviceD3 && powerAction == PowerActionNone) + { + PDEVICE_CONTEXT devCtx; + WDF_TRI_STATE excludeD3Cold = WdfTrue; + ACX_DX_EXIT_LATENCY latency; + + devCtx = GetDeviceContext(Device); + ASSERT(devCtx != nullptr); + + // + // Get the current exit latency. + // + latency = AcxDeviceGetCurrentDxExitLatency(Device, + WdfDeviceGetSystemPowerAction(Device), + TargetState); + + if (latency == AcxDxExitLatencyResponsive) + { + excludeD3Cold = WdfFalse; + } + + if (devCtx->ExcludeD3Cold != excludeD3Cold) + { + devCtx->ExcludeD3Cold = excludeD3Cold; + + status = SetPowerPolicy(Device); + if (!NT_SUCCESS(status)) + { + ASSERT(FALSE); + status = STATUS_SUCCESS; + } + } + } + + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit"); + + return status; +} + _Use_decl_annotations_ PAGED_CODE_SEG VOID @@ -661,7 +749,7 @@ Return Value: deviceConfigAttrib.ParentObject = pDeviceContext->UsbDevice; status = WdfMemoryCreate( &deviceConfigAttrib, - PagedPool, + NonPagedPoolNx, USBMIDI_POOLTAG, (size_t)((numChars + 1) * sizeof(WCHAR)), &pDeviceContext->DeviceSNMemory, @@ -719,7 +807,7 @@ Return Value: deviceConfigAttrib.ParentObject = pDeviceContext->UsbDevice; status = WdfMemoryCreate( &deviceConfigAttrib, - PagedPool, + NonPagedPoolNx, USBMIDI_POOLTAG, (size_t)((numChars + 1) * sizeof(WCHAR)), &pDeviceContext->DeviceManfMemory, @@ -772,7 +860,7 @@ Return Value: deviceConfigAttrib.ParentObject = pDeviceContext->UsbDevice; status = WdfMemoryCreate( &deviceConfigAttrib, - PagedPool, + NonPagedPoolNx, USBMIDI_POOLTAG, (size_t)((numChars + 1) * sizeof(WCHAR)), &pDeviceContext->DeviceProductNameMemory, @@ -1181,6 +1269,15 @@ Return Value: } goto exit; } + else + { + status = USBMIDI2DriverGetGTBIndexes(Device); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "Error determining GTB indexes for USB MIDI 2.0 device. %!STATUS!", status); + status = STATUS_SUCCESS; + } + } // First get the GTB Header to determine overall size needed // @@ -1227,7 +1324,7 @@ Return Value: goto exit; } - // First take a guess at size and declare memory + // Get size of full GTB memory from header gtbMemorySize = gtbHeader.wTotalLength; // Create temporary memory for holding the GTB data from device @@ -1292,12 +1389,51 @@ Return Value: midi2_cs_interface_desc_group_terminal_blocks* pUSBGTBs = (midi2_cs_interface_desc_group_terminal_blocks *)gtbMemoryPtr; + // Get GTB ID Indexes + size_t numInIDs = 0; + size_t numOutIDs = 0; + PUCHAR inIDs = NULL; + PUCHAR outIDs = NULL; + + if (devCtx->DeviceInGTBIDs) + { + inIDs = (PUCHAR)WdfMemoryGetBuffer(devCtx->DeviceInGTBIDs, &numInIDs); + } + if (devCtx->DeviceOutGTBIDs) + { + outIDs = (PUCHAR)WdfMemoryGetBuffer(devCtx->DeviceOutGTBIDs, &numOutIDs); + } + // Determine the size of GTB Structure UINT grpTermBlockStructureSize = sizeof(KSMULTIPLE_ITEM); USHORT grpTermBlockStringSizes[255]; + bool isInIndex; + UINT numCapturedGTBs = 0; for (UINT termBlockCount = 0; termBlockCount < numTerminalBlocks; termBlockCount++) { + isInIndex = false; + for (size_t count = 0; count < numInIDs; count++) + { + if (pUSBGTBs->aBlock[termBlockCount].bGrpTrmBlkID == inIDs[count]) + { + isInIndex = true; + break; + } + } + for (size_t count = 0; count < numOutIDs; count++) + { + if (pUSBGTBs->aBlock[termBlockCount].bGrpTrmBlkID == outIDs[count]) + { + isInIndex = true; + break; + } + } + + // If not in index then cycle to next GTB + if (!isInIndex) continue; + + numCapturedGTBs++; grpTermBlockStructureSize += sizeof(UMP_GROUP_TERMINAL_BLOCK_HEADER); // See if there is a string defined @@ -1345,7 +1481,7 @@ Return Value: gtbMemoryAttributes.ParentObject = devCtx->UsbDevice; status = WdfMemoryCreate( >bMemoryAttributes, - PagedPool, + NonPagedPoolNx, USBMIDI_POOLTAG, (size_t)grpTermBlockStructureSize, &devCtx->DeviceGTBMemory, @@ -1360,11 +1496,32 @@ Return Value: // Place KSMULTIPLE_ITEM Strucutre PKSMULTIPLE_ITEM pMultiHeader = (PKSMULTIPLE_ITEM)pGTBPropertyBuffer; pMultiHeader->Size = grpTermBlockStructureSize; - pMultiHeader->Count = numTerminalBlocks; + pMultiHeader->Count = numCapturedGTBs; pGTBPropertyBuffer += sizeof(KSMULTIPLE_ITEM); for (UINT termBlockCount = 0; termBlockCount < numTerminalBlocks; termBlockCount++) { + isInIndex = false; + for (size_t count = 0; count < numInIDs; count++) + { + if (pUSBGTBs->aBlock[termBlockCount].bGrpTrmBlkID == inIDs[count]) + { + isInIndex = true; + break; + } + } + for (size_t count = 0; count < numOutIDs; count++) + { + if (pUSBGTBs->aBlock[termBlockCount].bGrpTrmBlkID == outIDs[count]) + { + isInIndex = true; + break; + } + } + + // If not in index then cycle to next GTB + if (!isInIndex) continue; + PUMP_GROUP_TERMINAL_BLOCK_DEFINITION pThisGrpTrmBlk = (PUMP_GROUP_TERMINAL_BLOCK_DEFINITION)pGTBPropertyBuffer; // Populate data from GTB read from USB Device @@ -1656,7 +1813,7 @@ Return Value: gtbMemoryAttributes.ParentObject = pDevCtx->UsbDevice; status = WdfMemoryCreate( >bMemoryAttributes, - PagedPool, + NonPagedPoolNx, USBMIDI_POOLTAG, (size_t)grpTermBlockStructureSize, &pDevCtx->DeviceGTBMemory, @@ -1724,6 +1881,163 @@ Return Value: return status; } +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +USBMIDI2DriverGetGTBIndexes( + _In_ WDFDEVICE Device +) +/*++ +Routine Description: + + This is a helper routine to fetch the GTB IDs indexed by Endpoints for this + device interface. + +Arguments: + Device - the device context from USB Driver + Indexes - pointer to array of indexes to be populated with indexes found. + +Return Value: + + NONE + +--*/ +{ + PDEVICE_CONTEXT pDevCtx = NULL; + PUSB_CONFIGURATION_DESCRIPTOR pConfigurationDescriptor = NULL; + PUCHAR pCurrent = NULL; + PUCHAR pEnd = NULL; + size_t configDescSize; + NTSTATUS status = 0; + WDF_OBJECT_ATTRIBUTES deviceConfigAttrib; + bool isInEndpoint = false; + PUSB_ENDPOINT_DESCRIPTOR pEndpointDescriptor = NULL; + + ASSERT(Device); + pDevCtx = GetDeviceContext(Device); + ASSERT(pDevCtx); + + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry"); + + if (pDevCtx->DeviceGTBMemory) + { + TraceEvents(TRACE_LEVEL_WARNING, TRACE_DEVICE, "GTB response memory already created."); + goto exit; + } + + pConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)WdfMemoryGetBuffer(pDevCtx->DeviceConfigDescriptorMemory, &configDescSize); + // Confirm this is a USB MIDI 2.0 device interface + if (pDevCtx->UsbMIDIbcdMSC != 0x200) + { + status = STATUS_INSUFFICIENT_RESOURCES; + TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "Unexpected bcdMSC version."); + goto exit; + } + + // Find the relevant interface + PUSB_INTERFACE_DESCRIPTOR pInterfaceDescriptor = USBD_ParseConfigurationDescriptor( + pConfigurationDescriptor, // Descriptor Buffer + pDevCtx->UsbMIDIInterfaceNumber, // Interface Number + pDevCtx->UsbMIDIStreamingAlt // Alternate Setting + ); + if (!pInterfaceDescriptor) + { + status = STATUS_INSUFFICIENT_RESOURCES; + TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "Could not find interface descriptor for selected device."); + goto exit; + } + // Set current search possition + pCurrent = (PUCHAR)pInterfaceDescriptor + sizeof(USB_INTERFACE_DESCRIPTOR); + + // Find the end of this interface by looking for end or next interface + PUSB_INTERFACE_DESCRIPTOR pInterfaceDescriptorNext = USBD_ParseConfigurationDescriptorEx( + pConfigurationDescriptor, + (PVOID)pCurrent, + -1, // looking for the next interface whatever it is + -1, + -1, + -1, + -1 + ); + if (!pInterfaceDescriptorNext) + { + // means likely last interface descriptor, thus we search to end + pEnd = (PUCHAR)pConfigurationDescriptor + configDescSize; + } + else + { + // Next interface marks end of interface descriptor of interest + pEnd = (PUCHAR)pInterfaceDescriptorNext; + } + + // Now we know the bounds of the descriptor, look for endpoints to determine GTB ID Indexes. + // Walk through finding Class-Specific MIDI Streaming Data Endpoint Descriptors + // Walk through looking for Jack Descriptors + PUSB_COMMON_DESCRIPTOR pNextDescriptor; + while (nullptr != (pNextDescriptor = USBD_ParseDescriptors( + (PVOID)pConfigurationDescriptor, + (ULONG)configDescSize, + (PVOID)pCurrent, + (LONG)USB_ENDPOINT_DESCRIPTOR_TYPE))) + { + // pNextDescriptor is valid, make sure in search area for this interface + if ((PVOID)pNextDescriptor >= pEnd) + { + // Hit end of this interface descriptor + break; + } + + // Get info from Endpoint Descriptor + pEndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)pNextDescriptor; + ASSERT(pEndpointDescriptor); + isInEndpoint = (pEndpointDescriptor->bEndpointAddress & 0x80) ? true : false; + + // Advance to next descriptor which should be Class Specific Endpoint Descriptor + pCurrent = (PUCHAR)pNextDescriptor + pNextDescriptor->bLength; + + // Check the subtype and process accordingly + midi_desc_header_common_t* pCommonHdr = (midi_desc_header_common_t*)pCurrent; + + // Is it correct descriptor + if (pCommonHdr->bDescriptorType != MIDI_CS_ENDPOINT || pCommonHdr->bDescriptorSubType != MIDI20_CS_ENDPOINT_GENERAL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "Expected MIDI2.0 CS Endpoint not found."); + goto exit; + } + + midi2_desc_streaming_data_endpoint_t* pCSEndpointHdr = (midi2_desc_streaming_data_endpoint_t*)pCommonHdr; + + // If there are defined GTB IDs and the device does not already have defined GTB IDs for endpoint + // then create and load + if (pCSEndpointHdr->bNumGrpTrmBlock && (isInEndpoint ? !pDevCtx->DeviceInGTBIDs : !pDevCtx->DeviceOutGTBIDs)) + { + // Create temporary memory for holding the GTB data from device + WDF_OBJECT_ATTRIBUTES_INIT(&deviceConfigAttrib); + deviceConfigAttrib.ParentObject = pDevCtx->UsbDevice; + PUCHAR pGTBIDs; + status = WdfMemoryCreate( + &deviceConfigAttrib, + NonPagedPoolNx, + USBMIDI_POOLTAG, + (size_t)pCSEndpointHdr->bNumGrpTrmBlock, + (isInEndpoint) ? &pDevCtx->DeviceInGTBIDs : &pDevCtx->DeviceOutGTBIDs, + (PVOID*)&pGTBIDs + ); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "Error allocating memory for GTB IDs. %!STATUS!", status); + goto exit; + } + RtlCopyMemory(pGTBIDs, (PUCHAR)&pCSEndpointHdr->bAssoGrpTrmBlkID, (size_t)pCSEndpointHdr->bNumGrpTrmBlock); + } + } + +exit: + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit"); + return status; +} + _Use_decl_annotations_ NONPAGED_CODE_SEG VOID USBMIDI2DriverEvtReadComplete( @@ -1755,14 +2069,15 @@ Return Value: NTSTATUS status; PUINT8 pReceivedBuffer; PUINT32 pReceivedWords; - UMP_PACKET umpPacket; + static UMP_PACKET umpPacket; // Keep to fill over two USB packets UINT32 receivedIndex = 0; UINT32 receivedNumWords; - struct + static struct { UMPDATAFORMAT umpHeader; UINT32 umpData[4]; } UMP_Packet_Struct; + static UINT32 wordsRemain = 0; // To know how many words remaining to process Pipe; @@ -1795,7 +2110,7 @@ Return Value: continue; } - // If not alternate indicating USB MIDI 1.0 + // If indicating USB MIDI 1.0 if (pDeviceContext->UsbMIDIbcdMSC == MIDI_CS_BCD_MIDI1) { // Need Cable Number @@ -1821,47 +2136,85 @@ Return Value: } else if (pDeviceContext->UsbMIDIbcdMSC == MIDI_CS_BCD_MIDI2) { - // Put data into buffer to pass - UMP_Packet_Struct.umpHeader.Position = NULL; // For now allow service to tag time - // TODO: Processing for JR Timestamps - umpPacket.wordCount = 0; // use to store information - - PUINT8 pWord = (PUINT8)&pReceivedWords[receivedIndex]; + // Determine if there remains data to transfer meaning UMP broken over two USB packets + if (wordsRemain) + { + UINT32 bytesToCopy; + if (wordsRemain <= (receivedNumWords - receivedIndex)) + { + bytesToCopy = wordsRemain * sizeof(UINT32); + wordsRemain = 0; + } + else + { + bytesToCopy = (receivedNumWords - receivedIndex) * sizeof(UINT32); + wordsRemain -= bytesToCopy / sizeof(UINT32); + } - // Determine amount of data to copy based on message type - switch (pWord[3] & 0xf0) + // Copy more data from bridging UMP over USB packets + RtlCopyMemory( + (PVOID)&UMP_Packet_Struct.umpData[UMP_Packet_Struct.umpHeader.ByteCount / sizeof(UINT32)], + (PVOID)&pReceivedWords[receivedIndex], + bytesToCopy + ); + UMP_Packet_Struct.umpHeader.ByteCount += bytesToCopy; + receivedIndex += bytesToCopy / sizeof(UINT32); + } + else { - case UMP_MT_UTILITY: - case UMP_MT_SYSTEM: - case UMP_MT_MIDI1_CV: - umpPacket.wordCount = 1; - break; + // Put data into buffer to pass + UMP_Packet_Struct.umpHeader.Position = NULL; // For now allow service to tag time + // TODO: Processing for JR Timestamps + umpPacket.wordCount = 0; // use to store information - case UMP_MT_DATA_64: - case UMP_MT_MIDI2_CV: - umpPacket.wordCount = 2; - break; + PUINT8 pWord = (PUINT8)&pReceivedWords[receivedIndex]; - case UMP_MT_DATA_128: - case UMP_MT_FLEX_128: - case UMP_MT_STREAM_128: - umpPacket.wordCount = 4; + // Determine amount of data to copy based on message type + switch (pWord[3] & 0xf0) + { + case UMP_MT_UTILITY: + case UMP_MT_SYSTEM: + case UMP_MT_MIDI1_CV: + umpPacket.wordCount = 1; break; - default: - // Could not process packet so skip current word and try with next one - receivedIndex++; - continue; - } - UMP_Packet_Struct.umpHeader.ByteCount = umpPacket.wordCount * sizeof(UINT32); + case UMP_MT_DATA_64: + case UMP_MT_MIDI2_CV: + umpPacket.wordCount = 2; + break; - // Copy appropriate data - RtlCopyMemory( - (PVOID)&UMP_Packet_Struct.umpData, - (PVOID)&pReceivedWords[receivedIndex], - UMP_Packet_Struct.umpHeader.ByteCount - ); - receivedIndex += umpPacket.wordCount; + case UMP_MT_DATA_128: + case UMP_MT_FLEX_128: + case UMP_MT_STREAM_128: + umpPacket.wordCount = 4; + break; + + default: + // Could not process packet so skip current word and try with next one + receivedIndex++; + continue; + } + + // Determine if all data available to complete UMP packet + if (umpPacket.wordCount <= (receivedNumWords - receivedIndex)) + { + UMP_Packet_Struct.umpHeader.ByteCount = umpPacket.wordCount * sizeof(UINT32); + wordsRemain = 0; // no more to fill data + } + else + { + UMP_Packet_Struct.umpHeader.ByteCount = (receivedNumWords - receivedIndex) * sizeof(UINT32); + wordsRemain = umpPacket.wordCount - (receivedNumWords - receivedIndex); + } + + // Copy appropriate data + RtlCopyMemory( + (PVOID)&UMP_Packet_Struct.umpData, + (PVOID)&pReceivedWords[receivedIndex], + UMP_Packet_Struct.umpHeader.ByteCount + ); + receivedIndex += UMP_Packet_Struct.umpHeader.ByteCount / sizeof(UINT32); + } } else { @@ -1871,24 +2224,27 @@ Return Value: } // Send to circuit - if (pDeviceContext->pStreamEngine) + if (!wordsRemain) { - if (!pDeviceContext->pStreamEngine->FillReadStream( - (PUINT8)&UMP_Packet_Struct, - (size_t)(UMP_Packet_Struct.umpHeader.ByteCount) + sizeof(UMPDATAFORMAT) - )) + if (pDeviceContext->pStreamEngine) { - TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, - "Error submitting to read queue prep buffer.\n"); + if (!pDeviceContext->pStreamEngine->FillReadStream( + (PUINT8)&UMP_Packet_Struct, + (size_t)(UMP_Packet_Struct.umpHeader.ByteCount) + sizeof(UMPDATAFORMAT) + )) + { + TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, + "Error submitting to read queue prep buffer.\n"); + goto ReadCompleteExit; + } + } + else + { + TraceEvents(TRACE_LEVEL_WARNING, TRACE_DEVICE, + "No StreamEngine found in Device Context for filling read stream.\n"); goto ReadCompleteExit; } } - else - { - TraceEvents(TRACE_LEVEL_WARNING, TRACE_DEVICE, - "No StreamEngine found in Device Context for filling read stream.\n"); - goto ReadCompleteExit; - } } } @@ -1964,13 +2320,12 @@ Return Value:Amy PDEVICE_CONTEXT pDeviceContext = NULL; WDFUSBPIPE pipe = NULL; PUCHAR pBuffer; - PUCHAR pWriteBuffer = NULL; - size_t writeBufferIndex = 0; - WDFREQUEST usbRequest = NULL; - WDFMEMORY writeMemory = NULL; PUINT32 pWriteWords = NULL; WDF_OBJECT_ATTRIBUTES writeMemoryAttributes; - + bool bEnterSysex; + bool bEndSysex; + UINT8 numberBytes; + UINT8 sysexStatus; TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry"); pDeviceContext = GetDeviceContext(Device); @@ -2116,9 +2471,10 @@ Return Value:Amy break; case UMP_MT_DATA_64: - { - bool bEnterSysex = false; - bool bEndSysex = false; + bEnterSysex = false; + bEndSysex = false; + + umpWritePacket.wordCount = 0; // Determine if sysex will end after this message switch (umpPacket.umpData.umpBytes[1] & UMP_SYSEX7_STATUS_MASK) @@ -2141,135 +2497,114 @@ Return Value:Amy // Determine if believed already in Sysex and if so, reset converter if (pDeviceContext->midi1OutSysex[cbl_num].inSysex) { - // Need to flush any available bytes from converter - while (pDeviceContext->midi1OutSysex[cbl_num].umpToBS.availableBS()) - { - pDeviceContext->midi1OutSysex[cbl_num].umpToBS.readBS(); - } pDeviceContext->midi1OutSysex[cbl_num].inSysex = false; } } + if (bEnterSysex && !pDeviceContext->midi1OutSysex[cbl_num].inSysex) { - pDeviceContext->midi1OutSysex[cbl_num].usbMIDI1Pos = 1; // first byte position to stream into + pDeviceContext->midi1OutSysex[cbl_num].usbMIDI1Head = 0; + pDeviceContext->midi1OutSysex[cbl_num].usbMIDI1Tail = 0; pDeviceContext->midi1OutSysex[cbl_num].inSysex = true; } - // Use AM Lib to convert current UMP SYSEX7 into MIDIByte Stream - for (int count = 0; count < umpPacket.wordCount; count++) + UINT8 byteStream[UMPTOBS_BUFFER]; + sysexStatus = (umpPacket.umpData.umpBytes[1] >> 4); + numberBytes = 0; + + if (sysexStatus <= 1 && numberBytes < UMPTOBS_BUFFER) { - pDeviceContext->midi1OutSysex[cbl_num].umpToBS.UMPStreamParse(umpPacket.umpData.umpWords[count]); + byteStream[numberBytes++] = SYSEX_START; } - - // Capture byte stream into outgoing data - umpWritePacket.wordCount = 0; // For now we have no data to transfer to USB MIDI 1.0 - // move BS to umpWritePacket - - -#if 0 - // determine the size and move the data in - UINT8 sysexSize = umpPacket.umpData.umpBytes[1] & UMP_SYSEX7_SIZE_MASK; - UINT8 umpDataByteCount = 0; - while (sysexSize--) + for (UINT8 count = 0; count < (umpPacket.umpData.umpBytes[1] & 0xf); count++) { - pDeviceContext->midi1OutSysex[cbl_num].buffer[pDeviceContext->midi1OutSysex[cbl_num].head++] - = umpPacket.umpData.umpBytes[umpDataByteCount++]; - pDeviceContext->midi1OutSysex[cbl_num].head %= MIDI_STREAM_BUF_SIZE; // it should not be possible to overflow buffer + if (numberBytes < UMPTOBS_BUFFER) + { + byteStream[numberBytes++] = umpPacket.umpData.umpBytes[2 + count]; + } } - - // If ending - if (bEndSysex && pDeviceContext->midi1OutSysex[cbl_num].inSysex) + if ((sysexStatus == 0 || sysexStatus == 3) && numberBytes < UMPTOBS_BUFFER) { - // We are responsible to start the Sysex flag for USB MIDI 1.0 - pDeviceContext->midi1OutSysex[cbl_num].buffer[pDeviceContext->midi1OutSysex[cbl_num].head++] = 0xf7; - pDeviceContext->midi1OutSysex[cbl_num].head %= MIDI_STREAM_BUF_SIZE; - pDeviceContext->midi1OutSysex[cbl_num].inSysex = false; + byteStream[numberBytes++] = SYSEX_STOP; } - // determine the number of USB MIDI 1 packets to be created - sysexSize = (pDeviceContext->midi1OutSysex[cbl_num].head >= pDeviceContext->midi1OutSysex[cbl_num].tail) - ? (pDeviceContext->midi1OutSysex[cbl_num].head - pDeviceContect->midiOutSystex[cbl_num].tail) - : ((MIDI_STREAM_BUF_SIZE - pDeviceContext->midi1OutSysex[cbl_num].tail) + pDeviceContext->midi1OutSysex[cbl_num].head); - UINT8 numWordsNeeded = sysexSize / 3; - UINT8 numBytesRemain = sysexSize % 3; - if (bEndSysex && numBytesRemain) + // Move into sysex circular buffer queue + for (UINT8 count = 0; count < numberBytes; count++) { - numWordsNeeded++; // add word for any remaining sysex data + pDeviceContext->midi1OutSysex[cbl_num].sysexBS[pDeviceContext->midi1OutSysex[cbl_num].usbMIDI1Head++] + = byteStream[count]; + pDeviceContext->midi1OutSysex[cbl_num].usbMIDI1Head %= SYSEX_BS_RB_SIZE; } - umpWritePacket.wordCount = numWordsNeeded; - UINT8 sysexCount = 0; - UINT8 sysexWordCount = 0; - while (sysexCount < sysexSize && sysexWordCount < numWordsNeeded) + // How many bytes available in BS + numberBytes = (pDeviceContext->midi1OutSysex[cbl_num].usbMIDI1Head > pDeviceContext->midi1OutSysex[cbl_num].usbMIDI1Tail) + ? pDeviceContext->midi1OutSysex[cbl_num].usbMIDI1Head - pDeviceContext->midi1OutSysex[cbl_num].usbMIDI1Tail + : (SYSEX_BS_RB_SIZE - pDeviceContext->midi1OutSysex[cbl_num].usbMIDI1Head) + pDeviceContext->midi1OutSysex[cbl_num].usbMIDI1Tail; + + while (numberBytes && umpWritePacket.wordCount < 4) { - UINT8 currentWord; - while (sysexCount < sysexSize) - { + umpWritePacket.umpData.umpWords[umpWritePacket.wordCount] = 0; + if (numberBytes > 2) + { + PUINT8 pumpBytes = (PUINT8) & umpWritePacket.umpData.umpWords[umpWritePacket.wordCount]; + for (UINT8 count = 0; count < 3; count++) + { + pumpBytes[count + 1] = + pDeviceContext->midi1OutSysex[cbl_num].sysexBS[pDeviceContext->midi1OutSysex[cbl_num].usbMIDI1Tail++]; + pDeviceContext->midi1OutSysex[cbl_num].usbMIDI1Tail %= SYSEX_BS_RB_SIZE; + numberBytes--; + } + // Mark cable number and CIN for start / continue SYSEX in USB MIDI 1.0 format + if (bEndSysex && !numberBytes) + { + pumpBytes[0] = (UINT8)(cbl_num << 4) | MIDI_CIN_SYSEX_END_3BYTE; + } + else + { + pumpBytes[0] = (UINT8)(cbl_num << 4) | MIDI_CIN_SYSEX_START; + } } - pDeviceContext->midi1OutSysex[cbl_num].buffer[pDeviceContext->midi1OutSysex[cbl_num].index++] - = umpPacket.umpData.umpBytes[2 + sysexCount++]; - - // is current packet build full - if (pDeviceContext->midi1OutSysex[cbl_num].index == 4) + else { - pDeviceContext->midi1OutSysex[cbl_num].buffer[0] = (cbl_num << 4); + // If less than two and we have a word to populate, check if the end of sysex if (bEndSysex) { - if (sysexCount == sysexSize) + // Process bytes + PUINT8 pumpBytes = (PUINT8)&umpWritePacket.umpData.umpWords[umpWritePacket.wordCount]; + UINT8 count; + for (count = 0; numberBytes; count++) { - pDeviceContext->midi1OutSysex[cbl_num].buffer[0] |= MIDI_CIN_SYSEX_END_3BYTE; + pumpBytes[count + 1] = + pDeviceContext->midi1OutSysex[cbl_num].sysexBS[pDeviceContext->midi1OutSysex[cbl_num].usbMIDI1Tail++]; + pDeviceContext->midi1OutSysex[cbl_num].usbMIDI1Tail %= SYSEX_BS_RB_SIZE; + numberBytes--; } - else + // Mark cable number and CIN for start / continue SYSEX in USB MIDI 1.0 format + switch (count) { - pDeviceContext->midi1OutSysex[cbl_num].buffer[0] |= MIDI_CIN_SYSEX_START; + case 1: + pumpBytes[0] = (UINT8)(cbl_num << 4) | MIDI_CIN_SYSEX_END_1BYTE; + break; + + case 2: + default: + pumpBytes[0] = (UINT8)(cbl_num << 4) | MIDI_CIN_SYSEX_END_2BYTE; + break; } } else { - pDeviceContext->midi1OutSysex[cbl_num].buffer[0] |= MIDI_CIN_SYSEX_START; + break; } - - // Fill Word into write packet and reset index - umpWritePacket.umpData.umpWords[sysexWordCount++] = *(PUINT32)&pDeviceContext->midi1OutSysex[cbl_num].buffer; - pDeviceContext->midi1OutSysex[cbl_num].index = 1; } + umpWritePacket.wordCount++; } - - // Determine if need to terminate current word - if (bEndSysex && numBytesRemain) - { - // Fill rest of buffer - while (pDeviceContext->midi1OutSysex[cbl_num].index < 4) // WRONG LOGIC HERE - { - pDeviceContext->midi1OutSysex[cbl_num].buffer[pDeviceContext->midi1OutSysex[cbl_num].index++] = 0x00; - } - switch (numBytesRemain) - { - case 1: - pDeviceContext->midi1OutSysex[cbl_num].buffer[0] = (cbl_num << 4) | MIDI_CIN_SYSEX_END_1BYTE; - break; - - case 2: - pDeviceContext->midi1OutSysex[cbl_num].buffer[0] = (cbl_num << 4) | MIDI_CIN_SYSEX_END_2BYTE; - break; - - default: - // should never get here, but use full packet in error - pDeviceContext->midi1OutSysex[cbl_num].buffer[0] = (cbl_num << 4) | MIDI_CIN_SYSEX_END_3BYTE; - } - - // Fill Word into write packet - umpWritePacket.umpData.umpWords[sysexWordCount++] = *(PUINT32)&pDeviceContext->midi1OutSysex[cbl_num].buffer; - pDeviceContext->midi1OutSysex[cbl_num].index = 1; - } -#endif break; - } default: // Not handled so ignore - numProcessed += umpPacket.wordCount; + numProcessed += umpPacket.wordCount; // ignore this UMP packet as corrupted umpWritePacket.wordCount = 0; } @@ -2278,13 +2613,13 @@ Return Value:Amy numProcessed += umpPacket.wordCount; // If currently no write buffer, create one - if (!pWriteBuffer) + if (!pDeviceContext->DeviceWriteBuffer) { // Create Request status = WdfRequestCreate( NULL, // attributes WdfUsbTargetPipeGetIoTarget(pipe), - &usbRequest // retuest object + &pDeviceContext->DeviceUSBWriteRequest // retuest object ); if (!NT_SUCCESS(status)) { @@ -2294,7 +2629,7 @@ Return Value:Amy } WDF_OBJECT_ATTRIBUTES_INIT(&writeMemoryAttributes); - writeMemoryAttributes.ParentObject = usbRequest; + writeMemoryAttributes.ParentObject = pDeviceContext->DeviceUSBWriteRequest; // Create Memory Object status = WdfMemoryCreate( @@ -2302,7 +2637,7 @@ Return Value:Amy NonPagedPoolNx, USBMIDI_POOLTAG, pDeviceContext->MidiOutMaxSize, - &writeMemory, + &pDeviceContext->DeviceWriteMemory, NULL ); if (!NT_SUCCESS(status)) @@ -2311,24 +2646,24 @@ Return Value:Amy "%!FUNC! could not create WdfMemory with status: %!STATUS!", status); goto DriverIoWriteExit; } - pWriteBuffer = (PUCHAR)WdfMemoryGetBuffer(writeMemory, NULL); - pWriteWords = (PUINT32)pWriteBuffer; + pDeviceContext->DeviceWriteBuffer = (PUCHAR)WdfMemoryGetBuffer(pDeviceContext->DeviceWriteMemory, NULL); } + pWriteWords = (PUINT32)pDeviceContext->DeviceWriteBuffer; // Write into buffer for (int count = 0; count < umpWritePacket.wordCount; count++) { - pWriteWords[writeBufferIndex++] = umpWritePacket.umpData.umpWords[count]; + pWriteWords[pDeviceContext->DeviceWriteBufferIndex++] = umpWritePacket.umpData.umpWords[count]; } - if ((writeBufferIndex*sizeof(UINT32)) == pDeviceContext->MidiOutMaxSize) + if ((pDeviceContext->DeviceWriteBufferIndex*sizeof(UINT32)) == pDeviceContext->MidiOutMaxSize) { // Write to buffer if (!USBMIDI2DriverSendToUSB( - usbRequest, - writeMemory, + pDeviceContext->DeviceUSBWriteRequest, + pDeviceContext->DeviceWriteMemory, pipe, - writeBufferIndex*sizeof(UINT32), + pDeviceContext->DeviceWriteBufferIndex*sizeof(UINT32), pDeviceContext, true // delete this request when complete )) @@ -2337,23 +2672,22 @@ Return Value:Amy } // Indicate new buffer needed - pWriteBuffer = NULL; - writeBufferIndex = 0; + pDeviceContext->DeviceWriteBuffer = NULL; + pDeviceContext->DeviceWriteBufferIndex = 0; } } } // Check if anything leftover to write to USB - if (writeBufferIndex && !isMoreData) // and there is not more data coming + if (pDeviceContext->DeviceWriteBufferIndex && !isMoreData) // and there is not more data coming { - // NEED TO FILL REST OF BUFFER WITH NULL // // Write to buffer if (!USBMIDI2DriverSendToUSB( - usbRequest, - writeMemory, + pDeviceContext->DeviceUSBWriteRequest, + pDeviceContext->DeviceWriteMemory, pipe, - writeBufferIndex*sizeof(UINT32), + pDeviceContext->DeviceWriteBufferIndex*sizeof(UINT32), pDeviceContext, true // delete this request when complete )) @@ -2362,8 +2696,8 @@ Return Value:Amy } // Indicate new buffer needed - pWriteBuffer = NULL; - writeBufferIndex = 0; + pDeviceContext->DeviceWriteBuffer = NULL; + pDeviceContext->DeviceWriteBufferIndex = 0; } } else if (pDeviceContext->UsbMIDIbcdMSC == MIDI_CS_BCD_MIDI2) @@ -2376,70 +2710,90 @@ Return Value:Amy while (transferPos < numBytes) { - thisTransferSize = numBytes - transferPos; - - // Enusre not bigger than max - if (thisTransferSize > pDeviceContext->MidiOutMaxSize) + // If there is currently no USB packet being worked on, create a working space + if (!pDeviceContext->DeviceWriteBuffer) { - thisTransferSize = pDeviceContext->MidiOutMaxSize; - } + pDeviceContext->DeviceWriteBufferIndex = 0; - // Create request, buffer and copy data into buffer - // Create Request - status = WdfRequestCreate( - NULL, // attributes - WdfUsbTargetPipeGetIoTarget(pipe), - &usbRequest // retuest object - ); - if (!NT_SUCCESS(status)) - { - TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, - "%!FUNC! Error creating request for USB Write with status: %!STATUS!", status); - goto DriverIoWriteExit; + // Create Request + status = WdfRequestCreate( + NULL, // attributes + WdfUsbTargetPipeGetIoTarget(pipe), + &pDeviceContext->DeviceUSBWriteRequest // retuest object + ); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, + "%!FUNC! Error creating request for USB Write with status: %!STATUS!", status); + goto DriverIoWriteExit; + } + + WDF_OBJECT_ATTRIBUTES_INIT(&writeMemoryAttributes); + writeMemoryAttributes.ParentObject = pDeviceContext->DeviceUSBWriteRequest; + + // Create Memory Object + status = WdfMemoryCreate( + &writeMemoryAttributes, + NonPagedPoolNx, + USBMIDI_POOLTAG, + pDeviceContext->MidiOutMaxSize, + &pDeviceContext->DeviceWriteMemory, + NULL + ); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, + "%!FUNC! could not create WdfMemory with status: %!STATUS!", status); + goto DriverIoWriteExit; + } + pDeviceContext->DeviceWriteBuffer = (PUCHAR)WdfMemoryGetBuffer(pDeviceContext->DeviceWriteMemory, NULL); } - WDF_OBJECT_ATTRIBUTES_INIT(&writeMemoryAttributes); - writeMemoryAttributes.ParentObject = usbRequest; + thisTransferSize = numBytes - transferPos; - // Create Memory Object - status = WdfMemoryCreate( - &writeMemoryAttributes, - NonPagedPoolNx, - USBMIDI_POOLTAG, - pDeviceContext->MidiOutMaxSize, - &writeMemory, - NULL - ); - if (!NT_SUCCESS(status)) + bool pushUSBTransfer = false; + PUINT32 pWriteMem = (PUINT32)pDeviceContext->DeviceWriteBuffer; + + // Can we transfer current into buffer? + if ((thisTransferSize + pDeviceContext->DeviceWriteBufferIndex*sizeof(UINT32)) <= pDeviceContext->MidiOutMaxSize) { - TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, - "%!FUNC! could not create WdfMemory with status: %!STATUS!", status); - goto DriverIoWriteExit; + // Copy necessary data into the buffer performing byte swap + PUINT32 pReadMem = (PUINT32)&pBuffer[transferPos]; + for (size_t count = 0; count < (thisTransferSize / sizeof(UINT32)); count++) + { + pWriteMem[pDeviceContext->DeviceWriteBufferIndex++] = pReadMem[count]; // USB is Little Endian format + } + transferPos += thisTransferSize; } - - // Copy necessary data into the buffer performing byte swap - PUINT32 pWriteMem = (PUINT32)WdfMemoryGetBuffer(writeMemory, NULL); - PUINT32 pReadMem = (PUINT32)&pBuffer[transferPos]; - for (size_t count = 0; count < (thisTransferSize / sizeof(UINT32)); count++) + else { - pWriteMem[count] = pReadMem[count]; // USB is Little Endian format + pushUSBTransfer = true; } - // Transfer to USB - if (!USBMIDI2DriverSendToUSB( - usbRequest, - writeMemory, - pipe, - thisTransferSize, - pDeviceContext, - true // delete this request when complete - )) + if (pushUSBTransfer || !isMoreData) { - goto DriverIoWriteExit; - } + // Fill rest of buffer + while (pDeviceContext->DeviceWriteBufferIndex * sizeof(UINT32) < pDeviceContext->MidiOutMaxSize) + { + pWriteMem[pDeviceContext->DeviceWriteBufferIndex++] = 0; + } + + // Write to buffer + if (!USBMIDI2DriverSendToUSB( + pDeviceContext->DeviceUSBWriteRequest, + pDeviceContext->DeviceWriteMemory, + pipe, + pDeviceContext->DeviceWriteBufferIndex * sizeof(UINT32), + pDeviceContext, + true // delete this request when complete + )) + { + goto DriverIoWriteExit; + } - // Increment position - transferPos += thisTransferSize; + pDeviceContext->DeviceWriteBuffer = NULL; + pDeviceContext->DeviceWriteBufferIndex = 0; + } } } else @@ -2727,41 +3081,60 @@ Return Value: } } + UINT8 firstByte = 1; + UINT8 lastByte = 4; + UINT8 copyPos; + switch (code_index) { - case MIDI_CIN_SYSEX_START: - umpPkt->umpData.umpBytes[0] = UMP_MT_DATA_64 | cbl_num; // Message Type and group - - // As this is start of SYSEX, need to set status to indicate so and copy 3 bytes of data - umpPkt->umpData.umpBytes[1] = UMP_SYSEX7_START | 3; + case MIDI_CIN_SYSEX_START: // or continue + + if (!*pbIsInSysex) + { + // SYSEX Start means first byte should be SYSEX start + if (pBuffer[1] != SYSEX_START) return false; + firstByte = 2; + lastByte = 4; - // Set that in SYSEX - *pbIsInSysex = true; + // As this is start of SYSEX, need to set status to indicate so and copy 2 bytes of data + // as first byte of SYSEX_START + umpPkt->umpData.umpBytes[1] = UMP_SYSEX7_START | 2; - // Copy in rest of data - for (int count = 1; count < 4; count++) + // Set that in SYSEX + *pbIsInSysex = true; + } + else { - umpPkt->umpData.umpBytes[count + 1] = pBuffer[count]; + firstByte = 1; + lastByte = 4; + + // As this is in SYSEX, then need to indicate continue + umpPkt->umpData.umpBytes[1] = UMP_SYSEX7_CONTINUE | 3; } - // Pad rest of data - umpPkt->umpData.umpBytes[5] = 0x00; - umpPkt->umpData.umpBytes[6] = 0x00; - umpPkt->umpData.umpBytes[7] = 0x00; + + // Capture Cable number + umpPkt->umpData.umpBytes[0] = UMP_MT_DATA_64 | cbl_num; // Message Type and group umpPkt->wordCount = 2; + // Transfer in bytes + copyPos = firstByte; + for (UINT8 count = 2; count < 8; count++) + { + umpPkt->umpData.umpBytes[count] = (copyPos < lastByte) + ? pBuffer[copyPos++] : 0x00; + } break; case MIDI_CIN_SYSEX_END_1BYTE: // or single byte System Common // Determine if a system common - if ((pBuffer[1] & 0x80) // most significant bit set and not sysex - && (pBuffer[1] != MIDI_STATUS_SYSEX_END)) + if ( (pBuffer[1] & 0x80) // most significant bit set and not sysex ending + && (pBuffer[1] != SYSEX_STOP)) { umpPkt->umpData.umpBytes[0] = UMP_MT_SYSTEM | cbl_num; umpPkt->umpData.umpBytes[1] = pBuffer[1]; - umpPkt->umpData.umpBytes[2] = 0x00; - umpPkt->umpData.umpBytes[3] = 0x00; - umpPkt->wordCount = 1; - break; + firstByte = 1; + lastByte = 1; + goto COMPLETE_1BYTE; } umpPkt->umpData.umpBytes[0] = UMP_MT_DATA_64 | cbl_num; @@ -2769,21 +3142,27 @@ Return Value: // Determine if complete based on if currently in SYSEX if (*pbIsInSysex) { - umpPkt->umpData.umpBytes[1] = UMP_SYSEX7_END | 1; + if (pBuffer[1] != SYSEX_STOP) return false; + umpPkt->umpData.umpBytes[1] = UMP_SYSEX7_END | 0; *pbIsInSysex = false; // we are done with SYSEX + firstByte = 1; + lastByte = 1; } else { - umpPkt->umpData.umpBytes[1] = UMP_SYSEX7_COMPLETE | 1; + // should not get here + return false; } - // Copy in the data, assumes the original USB MIDI 1.0 data has padded data - for (int count = 1; count < 4; count++) +COMPLETE_1BYTE: + umpPkt->wordCount = 2; + // Transfer in bytes + copyPos = firstByte; + for (UINT8 count = 2; count < 8; count++) { - umpPkt->umpData.umpBytes[count + 1] = pBuffer[count]; + umpPkt->umpData.umpBytes[count] = (copyPos < lastByte) + ? pBuffer[copyPos++] : 0x00; } - - umpPkt->wordCount = 2; break; case MIDI_CIN_SYSEX_END_2BYTE: @@ -2792,24 +3171,28 @@ Return Value: // Determine if complete based on if currently in SYSEX if (*pbIsInSysex) { - umpPkt->umpData.umpBytes[1] = UMP_SYSEX7_END | 2; + if (pBuffer[2] != SYSEX_STOP) return false; + umpPkt->umpData.umpBytes[1] = UMP_SYSEX7_END | 1; *pbIsInSysex = false; // we are done with SYSEX + firstByte = 1; + lastByte = 2; } else { - umpPkt->umpData.umpBytes[1] = UMP_SYSEX7_COMPLETE | 2; + umpPkt->umpData.umpBytes[1] = UMP_SYSEX7_COMPLETE | 0; + *pbIsInSysex = false; // we are done with SYSEX + firstByte = 1; + lastByte = 1; } - // Copy in the data, assumes the original USB MIDI 1.0 data has padded data - for (int count = 1; count < 4; count++) + umpPkt->wordCount = 2; + // Transfer in bytes + copyPos = firstByte; + for (UINT8 count = 2; count < 8; count++) { - umpPkt->umpData.umpBytes[count + 1] = pBuffer[count]; + umpPkt->umpData.umpBytes[count] = (copyPos < lastByte) + ? pBuffer[copyPos++] : 0x00; } - // Pad rest of data - umpPkt->umpData.umpBytes[6] = 0x00; - umpPkt->umpData.umpBytes[7] = 0x00; - - umpPkt->wordCount = 2; break; case MIDI_CIN_SYSEX_END_3BYTE: @@ -2818,24 +3201,29 @@ Return Value: // Determine if complete based on if currently in SYSEX if (*pbIsInSysex) { - umpPkt->umpData.umpBytes[1] = UMP_SYSEX7_END | 3; + if (pBuffer[3] != SYSEX_STOP) return false; + umpPkt->umpData.umpBytes[1] = UMP_SYSEX7_END | 2; *pbIsInSysex = false; // we are done with SYSEX + firstByte = 1; + lastByte = 3; } else { - umpPkt->umpData.umpBytes[1] = UMP_SYSEX7_COMPLETE | 3; + if (pBuffer[1] != SYSEX_START || pBuffer[3] != SYSEX_STOP) return false; + umpPkt->umpData.umpBytes[1] = UMP_SYSEX7_COMPLETE | 1; + *pbIsInSysex = false; // we are done with SYSEX + firstByte = 2; + lastByte = 3; } - // Copy in the data, assumes the original USB MIDI 1.0 data has padded data - for (int count = 1; count < 4; count++) + umpPkt->wordCount = 2; + // Transfer in bytes + copyPos = firstByte; + for (UINT8 count = 2; count < 8; count++) { - umpPkt->umpData.umpBytes[count + 1] = pBuffer[count]; + umpPkt->umpData.umpBytes[count] = (copyPos < lastByte) + ? pBuffer[copyPos++] : 0x00; } - // Pad rest of data - umpPkt->umpData.umpBytes[6] = 0x00; - umpPkt->umpData.umpBytes[7] = 0x00; - - umpPkt->wordCount = 2; break; // MIDI1 Channel Voice Messages diff --git a/src/api/Drivers/USBMIDI2/Driver/Device.h b/src/api/Drivers/USBMIDI2/Driver/Device.h index 21c009520..647f2c423 100644 --- a/src/api/Drivers/USBMIDI2/Driver/Device.h +++ b/src/api/Drivers/USBMIDI2/Driver/Device.h @@ -49,7 +49,11 @@ Module Name: #include "Public.h" #include "Common.h" #include "StreamEngine.h" -#include + +// Used for handling exchange of SYSEX between USB MIDI 1.0 and UMP +#define UMPTOBS_BUFFER 12 +#define SYSEX_START 0xF0 +#define SYSEX_STOP 0xF7 /* make prototypes usable from C++ */ #ifdef __cplusplus @@ -59,15 +63,18 @@ extern "C" { // Maximum number of groups per UMP endpoint or virual cables for USB MIDI 1.0 #define MAX_NUM_GROUPS_CABLES 16 +// Size of ring buffers for sysex bytestream +#define SYSEX_BS_RB_SIZE UMPTOBS_BUFFER + 4 // size coming in plus at least one USB MIDI1.0 SYSEX Packet + // // Structure to aid in UMP SYSEX to USB MIDI 1.0 // typedef struct UMP_TO_MIDI1_SYSEX_t { bool inSysex; - umpToBytestream umpToBS; - UINT8 usbMIDI1Pkt[4]; - UINT8 usbMIDI1Pos; + UINT8 sysexBS[SYSEX_BS_RB_SIZE]; + UINT8 usbMIDI1Tail; + UINT8 usbMIDI1Head; } UMP_TO_MIDI1_SYSEX; typedef struct @@ -121,6 +128,12 @@ typedef struct _DEVICE_CONTEXT { WDFMEMORY DeviceNameMemory; WDFMEMORY DeviceSNMemory; WDFMEMORY DeviceGTBMemory; + WDFMEMORY DeviceInGTBIDs; + WDFMEMORY DeviceOutGTBIDs; + WDFMEMORY DeviceWriteMemory; + PUCHAR DeviceWriteBuffer; + size_t DeviceWriteBufferIndex; + WDFREQUEST DeviceUSBWriteRequest; // // Streaming Engine @@ -136,6 +149,8 @@ EVT_WDF_DRIVER_DEVICE_ADD EvtBusDeviceAdd; EVT_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware; EVT_WDF_DEVICE_RELEASE_HARDWARE EvtDeviceReleaseHardware; EVT_WDF_DEVICE_CONTEXT_CLEANUP EvtDeviceContextCleanup; +EVT_WDF_DEVICE_D0_ENTRY EvtDeviceD0Entry; +EVT_WDF_DEVICE_D0_EXIT EvtDeviceD0Exit; /* make internal prototypes usable from C++ */ #ifdef __cplusplus @@ -200,6 +215,18 @@ USBMIDI2DriverCreateGTB( _In_ WDFDEVICE Device ); +// +// Function to get flags indicating in and Out GTB IDs active +// from Endpoint information in USB descriptors. +// +_Must_inspect_result_ +__drv_requiresIRQL(PASSIVE_LEVEL) +PAGED_CODE_SEG +NTSTATUS +USBMIDI2DriverGetGTBIndexes( + _In_ WDFDEVICE Device +); + // // Function to connect and prepare pipes for use // From 43d3570647e7a80b2b9120f69f32fcf1efee44e5 Mon Sep 17 00:00:00 2001 From: Michael Loh Date: Mon, 8 Jul 2024 21:28:30 -0600 Subject: [PATCH 6/8] Removing MUTEX Use Removing Mutex use in not allowed driver areas. Code cleanup. --- src/api/Drivers/USBMIDI2/Driver/StreamEngine.cpp | 4 ++-- src/api/Drivers/USBMIDI2/Driver/StreamEngine.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/api/Drivers/USBMIDI2/Driver/StreamEngine.cpp b/src/api/Drivers/USBMIDI2/Driver/StreamEngine.cpp index 2d01ec2b2..8d2fcf568 100644 --- a/src/api/Drivers/USBMIDI2/Driver/StreamEngine.cpp +++ b/src/api/Drivers/USBMIDI2/Driver/StreamEngine.cpp @@ -298,7 +298,7 @@ Return Value: // Current mechanism to determine if currently processing data is that // the StreamEngine is not null. TBD this mechanism needs to be fixed. - auto lock = m_MidiInLock.acquire(); + //auto lock = m_MidiInLock.acquire(); if (m_IsRunning) { @@ -579,7 +579,7 @@ StreamEngine::Run() { // m_IsRunning is used to indicate running state. If m_IsRunning true, the out worker // thread will output data to the connected device, otherwise data will be thrown away. - auto lock = m_MidiInLock.acquire(); + //auto lock = m_MidiInLock.acquire(); WDFDEVICE devCtx = AcxCircuitGetWdfDevice(AcxPinGetCircuit(m_Pin)); PDEVICE_CONTEXT pDevCtx = GetDeviceContext(devCtx); diff --git a/src/api/Drivers/USBMIDI2/Driver/StreamEngine.h b/src/api/Drivers/USBMIDI2/Driver/StreamEngine.h index b16d71658..c4f80dc94 100644 --- a/src/api/Drivers/USBMIDI2/Driver/StreamEngine.h +++ b/src/api/Drivers/USBMIDI2/Driver/StreamEngine.h @@ -235,9 +235,7 @@ class StreamEngine wil::kernel_event_auto_reset m_ThreadExitEvent; wil::kernel_event_manual_reset m_ThreadExitedEvent {true}; - // m_StandardStreamingLock m_LoopbackMessageQueue are only used // for standard streaming of loopback messages - wil::fast_mutex_with_critical_region m_StandardStreamingLock; wil::fast_mutex_with_critical_region m_MidiInLock; LIST_ENTRY m_LoopbackMessageQueue {nullptr}; }; From 6d036b5947e7b23486e0d4cb8ac69c57aee9d617 Mon Sep 17 00:00:00 2001 From: Michael Loh Date: Mon, 8 Jul 2024 21:28:53 -0600 Subject: [PATCH 7/8] Handling GTB Indexing --- src/api/Drivers/USBMIDI2/Driver/ump.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/Drivers/USBMIDI2/Driver/ump.h b/src/api/Drivers/USBMIDI2/Driver/ump.h index 7db84c3b2..73bb20056 100644 --- a/src/api/Drivers/USBMIDI2/Driver/ump.h +++ b/src/api/Drivers/USBMIDI2/Driver/ump.h @@ -126,6 +126,7 @@ Module Name: typedef enum { MIDI_CS_INTERFACE = 0x24, + MIDI_CS_ENDPOINT = 0x25, MIDI_CS_INTERFACE_GR_TRM_BLOCK = 0x26, } midi_cs_interface_types; From 61012f38efe3c1d340633c40f61e718befe4c132 Mon Sep 17 00:00:00 2001 From: Michael Loh Date: Mon, 8 Jul 2024 21:29:11 -0600 Subject: [PATCH 8/8] Project Cleanup --- src/api/Drivers/USBMIDI2/Driver/USBMidi2.inf | Bin 6994 -> 6972 bytes .../Drivers/USBMIDI2/Driver/USBMidi2.vcxproj | 18 +++++++++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/api/Drivers/USBMIDI2/Driver/USBMidi2.inf b/src/api/Drivers/USBMIDI2/Driver/USBMidi2.inf index 73819f02943cac2945707fe4e55b5287973e569a..f53749a11686dbf83a363797fa6c07a37a9ce694 100644 GIT binary patch delta 67 zcmca)w#RJ4BR)-A1_cHK1~UeI1|tSzFlhi}nK0-u7y_XlP)-j*Z|3LU%*758GG;K` Jd|R@d5dgJ|3^D)! delta 89 zcmdmEcFAnRBR*XP1_cINAU0sIWYA|YVlW1i24I#BP~4C~4=4x0Mw_|$H*-mDbgengKernelDebugger USBMidi2 $(SolutionDir)VSFiles\$(Platform)\$(Configuration)\ - $(SolutionDir)VSFiles\intermediate\usbmidi2\$(Platform)\$(Configuration)\ - $(IncludePath) + $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\ DbgengKernelDebugger @@ -91,8 +90,7 @@ DbgengKernelDebugger USBMidi2 $(SolutionDir)VSFiles\$(Platform)\$(Configuration)\ - $(SolutionDir)VSFiles\intermediate\usbmidi2\$(Platform)\$(Configuration)\ - $(IncludePath) + $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\ DbgengKernelDebugger @@ -101,7 +99,8 @@ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\ - true + false + false @@ -109,14 +108,14 @@ true trace.h true - false + true sha256 %(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib;acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR)\acxstub.lib;$(DDK_LIB_PATH)\libcntpr.lib;$(DDK_LIB_PATH)\wpprecorder.lib;$(DDK_LIB_PATH)\Usbd.lib - false + true %(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR);. @@ -178,11 +177,11 @@ true trace.h true - false + true %(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib;acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR)\acxstub.lib;$(DDK_LIB_PATH)\libcntpr.lib;$(DDK_LIB_PATH)\wpprecorder.lib;$(DDK_LIB_PATH)\Usbd.lib - false + true stdcpp17 @@ -222,6 +221,7 @@ +