Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- How to compile:
- cl /EHsc /I "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\shared" /I "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\um" /I "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\winrt" /I "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\ucrt" main.cpp /link /LIBPATH:"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\um\x64" /LIBPATH:"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\ucrt\x64" /LIBPATH:"F:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.42.34433\lib\x64" winusb.lib SetupAPI.lib cfgmgr32.lib
- */
- #include <windows.h>
- #include <winusb.h>
- #include <setupapi.h>
- #include <usb.h>
- #include <iostream>
- #include <string>
- #include <stdio.h> // For printf
- #define BUFFER_SIZE 3072
- #define ISOCH_DATA_SIZE_MS 1 // 1 millisecond of isochronous data
- #define ISOCH_TRANSFER_COUNT 1 // Number of transfers to perform
- typedef struct _DEVICE_DATA {
- BOOL HandlesOpen;
- WINUSB_INTERFACE_HANDLE WinusbHandle;
- HANDLE DeviceHandle;
- TCHAR DevicePath[MAX_PATH];
- UCHAR IsochOutPipe;
- UCHAR IsochInPipe;
- ULONG IsochInTransferSize;
- ULONG IsochOutTransferSize;
- ULONG IsochInPacketCount;
- WINUSB_INTERFACE_HANDLE AssociatedInterfaceHandle; // Add this
- WINUSB_PIPE_INFORMATION_EX PipeInfo; // Add this
- } DEVICE_DATA, *PDEVICE_DATA;
- void ParseDescriptors(UCHAR* buffer, ULONG length) {
- UCHAR* ptr = buffer;
- UCHAR* end = buffer + length;
- while (ptr < end)
- {
- PUSB_COMMON_DESCRIPTOR commonDesc = (PUSB_COMMON_DESCRIPTOR)ptr;
- if (commonDesc->bLength < 2) {
- std::cerr << "Invalid descriptor length" << std::endl;
- break;
- }
- // Move to the next descriptor
- ptr += commonDesc->bLength;
- }
- }
- std::string GetErrorMessage(HRESULT hr) {
- LPSTR messageBuffer = nullptr;
- DWORD bufferLength = FormatMessageA(
- FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- nullptr,
- hr,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- reinterpret_cast<LPSTR>(&messageBuffer),
- 0,
- nullptr);
- if (bufferLength == 0) {
- return "Unknown error";
- }
- std::string errorMessage(messageBuffer, bufferLength);
- LocalFree(messageBuffer);
- return errorMessage;
- }
- HRESULT GetIsochPipes(_Inout_ PDEVICE_DATA DeviceData) {
- BOOL result;
- USB_INTERFACE_DESCRIPTOR usbInterface;
- HRESULT hr = S_OK;
- UCHAR i;
- // Use the DeviceData->AssociatedInterfaceHandle instead of a local variable
- result = WinUsb_GetAssociatedInterface(DeviceData->WinusbHandle, 0, &DeviceData->AssociatedInterfaceHandle);
- if (result == FALSE) {
- hr = HRESULT_FROM_WIN32(GetLastError());
- std::cerr << "WinUsb_GetAssociatedInterface failed to get handle for interface 0." << std::endl;
- return hr;
- }
- result = WinUsb_QueryInterfaceSettings(DeviceData->AssociatedInterfaceHandle, 1, &usbInterface);
- if (result == FALSE) {
- hr = HRESULT_FROM_WIN32(GetLastError());
- std::cerr << "WinUsb_QueryInterfaceSettings failed to get USB interface for Alternate Setting 1." << std::endl;
- WinUsb_Free(DeviceData->AssociatedInterfaceHandle);
- return hr;
- }
- std::cout << "\n\nChecking Alternate Setting 1 with [" << (int)usbInterface.bNumEndpoints << "] endpoints:" << std::endl;
- for (i = 0; i < usbInterface.bNumEndpoints; i++) {
- // Use the DeviceData->PipeInfo instead of a local variable
- result = WinUsb_QueryPipeEx(
- DeviceData->AssociatedInterfaceHandle,
- 1,
- i,
- &DeviceData->PipeInfo);
- if (result == FALSE) {
- hr = HRESULT_FROM_WIN32(GetLastError());
- std::cerr << "WinUsb_QueryPipeEx failed to get USB pipe for endpoint " << (int)i << " in Alternate Setting 1." << std::endl;
- CloseHandle(DeviceData->DeviceHandle);
- return hr;
- }
- if ((DeviceData->PipeInfo.PipeType == UsbdPipeTypeIsochronous) && (!(DeviceData->PipeInfo.PipeId == 0x82))) {
- DeviceData->IsochOutPipe = DeviceData->PipeInfo.PipeId;
- if ((DeviceData->PipeInfo.MaximumBytesPerInterval == 0) || (DeviceData->PipeInfo.Interval == 0)) {
- hr = E_INVALIDARG;
- printf("Isoch Out: MaximumBytesPerInterval or Interval value is 0.\n");
- CloseHandle(DeviceData->DeviceHandle);
- return hr;
- } else {
- DeviceData->IsochOutTransferSize = ISOCH_DATA_SIZE_MS * DeviceData->PipeInfo.MaximumBytesPerInterval * (8 / DeviceData->PipeInfo.Interval);
- std::cout << "Isochronous Out Pipe Transfer Size: " << DeviceData->IsochOutTransferSize << std::endl;
- }
- } else if (DeviceData->PipeInfo.PipeType == UsbdPipeTypeIsochronous) {
- DeviceData->IsochInPipe = DeviceData->PipeInfo.PipeId;
- if (DeviceData->PipeInfo.MaximumBytesPerInterval == 0 || (DeviceData->PipeInfo.Interval == 0)) {
- hr = E_INVALIDARG;
- printf("Isoch In: MaximumBytesPerInterval or Interval value is 0.\n");
- CloseHandle(DeviceData->DeviceHandle);
- return hr;
- } else {
- DeviceData->IsochInTransferSize = ISOCH_DATA_SIZE_MS * DeviceData->PipeInfo.MaximumBytesPerInterval * (8 / DeviceData->PipeInfo.Interval);
- DeviceData->IsochInPacketCount = DeviceData->IsochInTransferSize / DeviceData->PipeInfo.MaximumBytesPerInterval;
- std::cout << "Isochronous In Pipe Transfer Size: " << DeviceData->IsochInTransferSize << std::endl;
- std::cout << "Isochronous In Pipe Packet Count: " << DeviceData->IsochInPacketCount << std::endl;
- }
- }
- std::cout << "Pipe " << (int)i << " in Alternate Setting 1: "
- << "PipeId = " << (int)DeviceData->PipeInfo.PipeId << ", PipeType = " << (int)DeviceData->PipeInfo.PipeType
- << ", MaximumBytesPerInterval = " << DeviceData->PipeInfo.MaximumBytesPerInterval
- << ", Interval = " << (int)DeviceData->PipeInfo.Interval << "\n" << std::endl;
- }
- return hr;
- }
- VOID SendIsochInTransfer(
- _Inout_ PDEVICE_DATA DeviceData,
- _In_ BOOL AsapTransfer
- ) {
- PUCHAR readBuffer = nullptr;
- LPOVERLAPPED overlapped = nullptr;
- ULONG numBytes = 0;
- BOOL result = FALSE;
- DWORD lastError = 0;
- WINUSB_ISOCH_BUFFER_HANDLE isochReadBufferHandle;
- PUSBD_ISO_PACKET_DESCRIPTOR isochPackets = nullptr;
- ULONG i = 0;
- ULONG j = 0;
- ULONG totalTransferSize;
- readBuffer = NULL;
- isochPackets = NULL;
- overlapped = NULL;
- isochReadBufferHandle = INVALID_HANDLE_VALUE;
- printf("\n\nInitiating Read transfer.\n\n");
- totalTransferSize = DeviceData->IsochInTransferSize * ISOCH_TRANSFER_COUNT;
- if (totalTransferSize % DeviceData->IsochInTransferSize != 0) {
- printf("Error: Transfer size must end at a frame boundary.\n");
- goto Error;
- }
- // Allocate aligned buffer
- readBuffer = new UCHAR[totalTransferSize];
- if (readBuffer == nullptr) {
- printf("Failed to allocate memory for aligned buffer.\n");
- goto Error;
- }
- ZeroMemory(readBuffer, totalTransferSize);
- // Print transfer parameters for debugging:
- printf("\nParameters, BEFORE calling `WinUsb_RegisterIsochBuffer`:\n");
- printf("Original Buffer Address: %p\n", readBuffer);
- printf("Buffer Size in Memory (Bytes): %zu\n", sizeof(readBuffer));
- printf("WinusbHandle Address: %p\n", DeviceData->WinusbHandle);
- printf("IsochReadBufferHandle: Address %p\n", isochReadBufferHandle);
- // Allocate overlapped structures
- overlapped = new OVERLAPPED[ISOCH_TRANSFER_COUNT];
- ZeroMemory(overlapped, (sizeof(OVERLAPPED) * ISOCH_TRANSFER_COUNT));
- for (i = 0; i < ISOCH_TRANSFER_COUNT; i++) {
- overlapped[i].hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (overlapped[i].hEvent == NULL) {
- printf("Unable to set event for overlapped operation.\n");
- goto Error;
- }
- }
- // Allocate packet descriptors using new
- isochPackets = new USBD_ISO_PACKET_DESCRIPTOR[DeviceData->IsochInPacketCount * ISOCH_TRANSFER_COUNT];
- if (isochPackets == nullptr) {
- printf("Failed to allocate packet descriptors.\n");
- goto Error;
- }
- // Zero-initialize the allocated memory
- ZeroMemory(isochPackets, DeviceData->IsochInPacketCount * ISOCH_TRANSFER_COUNT);
- // Register isochronous buffer
- result = WinUsb_RegisterIsochBuffer(
- DeviceData->WinusbHandle,
- DeviceData->IsochInPipe,
- readBuffer,
- DeviceData->IsochInTransferSize * ISOCH_TRANSFER_COUNT,
- &isochReadBufferHandle);
- // Print transfer parameters for debugging
- printf("\nWinUsb_ReadIsochPipeAsap Parameters, AFTER calling `WinUsb_RegisterIsochBuffer`:\n");
- printf("IsochReadBufferHandle: Address %p\n", isochReadBufferHandle);
- printf("TransferSize: %lu\n", DeviceData->IsochInTransferSize);
- printf("PacketCount: %lu\n", DeviceData->IsochInPacketCount);
- printf("Buffer Address: %p\n", readBuffer);
- printf("Buffer Size in Memory (Bytes): %zu\n", sizeof(readBuffer));
- printf("WinusbHandle Address: %p\n", DeviceData->WinusbHandle);
- printf("BufferLength: %lu\n\n", DeviceData->IsochInTransferSize * ISOCH_TRANSFER_COUNT);
- if (!result) {
- // Convert the DWORD error code to an HRESULT
- HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
- // Get the human-readable error message
- std::string errorMessage = GetErrorMessage(hr);
- // Print the error message
- printf("Isoch buffer registration failed. Error Code: [%d], Meaning: [%s]\n", GetLastError(), errorMessage.c_str());
- goto Error;
- }
- // Send read requests
- for (i = 0; i < ISOCH_TRANSFER_COUNT; i++) {
- printf("Transfer %d: Offset = %lu\n\n", i + 1, DeviceData->IsochInTransferSize * i);
- if (AsapTransfer) {
- result = WinUsb_ReadIsochPipeAsap(
- isochReadBufferHandle,
- DeviceData->IsochInTransferSize * i, // Offset should start at 0
- DeviceData->IsochInTransferSize,
- (i == 0) ? FALSE : TRUE, // ASAP flag for subsequent transfers
- DeviceData->IsochInPacketCount,
- &isochPackets[i * DeviceData->IsochInPacketCount],
- &overlapped[i]);
- printf("Read transfer sent by using ASAP flag.\n\n");
- }
- if (!result) {
- lastError = GetLastError();
- if (lastError != ERROR_IO_PENDING) {
- // Convert the DWORD error code to an HRESULT
- HRESULT hr = HRESULT_FROM_WIN32(lastError);
- // Get the human-readable error message
- std::string errorMessage = GetErrorMessage(hr);
- // Trim trailing newline characters
- errorMessage.erase(errorMessage.find_last_not_of("\r\n") + 1);
- // Print the error message:
- printf("Failed to start a `WinUsb_ReadIsochPipe` request. ---->: Error Code: [ %x ], Error Meaning: [ %s ]\n\n", lastError, errorMessage.c_str());
- }
- }
- }
- // Wait for transfers to complete
- for (i = 0; i < ISOCH_TRANSFER_COUNT; i++) {
- result = WinUsb_GetOverlappedResult(
- DeviceData->WinusbHandle,
- &overlapped[i],
- &numBytes,
- TRUE);
- if (!result) {
- lastError = GetLastError();
- printf("Failed to read with error %x\n", lastError);
- } else {
- numBytes = 0;
- for (j = 0; j < DeviceData->IsochInPacketCount; j++) {
- numBytes += isochPackets[j].Length;
- }
- printf("Requested %d bytes in %d packets per transfer.\n", DeviceData->IsochInTransferSize, DeviceData->IsochInPacketCount);
- }
- printf("Transfer %d completed. Read %d bytes. \n\n", i + 1, numBytes);
- }
- Error:
- if (isochReadBufferHandle != INVALID_HANDLE_VALUE) {
- result = WinUsb_UnregisterIsochBuffer(isochReadBufferHandle);
- if (!result) {
- printf("Failed to unregister isoch read buffer. \n");
- }
- }
- if (readBuffer != nullptr) {
- delete [] readBuffer;
- }
- if (isochPackets != nullptr) {
- delete [] isochPackets;
- }
- for (i = 0; i < ISOCH_TRANSFER_COUNT; i++) {
- if (overlapped[i].hEvent != NULL) {
- CloseHandle(overlapped[i].hEvent);
- }
- }
- if (overlapped != nullptr) {
- delete[] overlapped;
- }
- return;
- }
- int main()
- {
- DEVICE_DATA deviceData = {0};
- deviceData.DeviceHandle = INVALID_HANDLE_VALUE;
- deviceData.WinusbHandle = INVALID_HANDLE_VALUE;
- const wchar_t* devicePath = L"\\\\.\\USB#VID_EBA4&PID_7588&MI_02#6&63DE0D9&0&0002#{99DA2DEC-C919-4F9D-9384-DAA7EBBD40EC}";
- deviceData.DeviceHandle = CreateFileW(
- devicePath,
- GENERIC_WRITE | GENERIC_READ,
- FILE_SHARE_WRITE | FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
- NULL);
- if (deviceData.DeviceHandle == INVALID_HANDLE_VALUE)
- {
- std::cerr << "Error opening device: " << GetLastError() << std::endl;
- return 1;
- }
- if (!WinUsb_Initialize(deviceData.DeviceHandle, &deviceData.WinusbHandle))
- {
- std::cerr << "Error initializing WinUSB: " << GetLastError() << std::endl;
- CloseHandle(deviceData.DeviceHandle);
- return 1;
- }
- UCHAR buffer[BUFFER_SIZE];
- ULONG lengthTransferred;
- USB_DEVICE_DESCRIPTOR deviceDesc;
- if (WinUsb_GetDescriptor(deviceData.WinusbHandle, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, buffer, sizeof(buffer), &lengthTransferred)) {
- memcpy(&deviceDesc, buffer, sizeof(USB_DEVICE_DESCRIPTOR));
- }
- else
- {
- std::cerr << "Error getting device descriptor: " << GetLastError() << std::endl;
- }
- USB_CONFIGURATION_DESCRIPTOR configDesc;
- if (WinUsb_GetDescriptor(deviceData.WinusbHandle, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0, buffer, sizeof(buffer), &lengthTransferred)) {
- memcpy(&configDesc, buffer, sizeof(USB_CONFIGURATION_DESCRIPTOR));
- }
- else
- {
- std::cerr << "Error getting configuration descriptor: " << GetLastError() << std::endl;
- }
- UCHAR* configBuffer = new UCHAR[configDesc.wTotalLength];
- if (WinUsb_GetDescriptor(deviceData.WinusbHandle, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0, configBuffer, configDesc.wTotalLength, &lengthTransferred)) {
- ParseDescriptors(configBuffer, configDesc.wTotalLength);
- }
- else
- {
- std::cerr << "Error getting interface descriptors: " << GetLastError() << std::endl;
- }
- delete[] configBuffer;
- HRESULT hr = GetIsochPipes(&deviceData);
- if (FAILED(hr))
- {
- std::cerr << "Error getting isochronous pipes: " << GetErrorMessage(hr) << std::endl;
- }
- else
- {
- // Send isochronous IN transfer
- SendIsochInTransfer(&deviceData, TRUE); // <--- `True` if using ASAP.
- }
- WinUsb_Free(deviceData.WinusbHandle);
- CloseHandle(deviceData.DeviceHandle);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment