Forum Widgets
Latest Discussions
USB Audio 2.0 Mixer Unit control
Hi, I am developing a USB audio 2.0 (UAC2) device. This device has a USB mixer unit (as defined by the usb audio 2.0 standard) and I was wondering how I can control/set it with the default usbaudio2.sys driver? According to the official docs: https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/usb-2-0-audio-drivers I should be able to send a SET request to a mixer unit with the default drivers. I extracted some logs from the usbaudio2.sys driver and can see that it recognizes the Mixer unit: USBAudio2] MixerUnit ID=0x50 'MY MIXER' [2]0004.29B0::04/11/2022-15:46:32.392 [USBAudio2] Controls=0x0001 [2]0004.29B0::04/11/2022-15:46:32.392 [USBAudio2] NumInputPins=1 [2]0004.29B0::04/11/2022-15:46:32.392 [USBAudio2] [0] --> SourceID=0x20 'USB AUDIO DEMO' InputChannelCount=2 [2]0004.29B0::04/11/2022-15:46:32.392 [USBAudio2] OutputChannelCount=2 [2]0004.29B0::04/11/2022-15:46:32.392 [USBAudio2] AudioChannelCluster: NrChannels=2 ChanConfig=0x00000003 FirstStringIndex=0 NumStrings=0 [2]0004.29B0::04/11/2022-15:46:32.392 [USBAudio2] NumInputPins=1 TotalNumInputChannels=2 NumOutputChannels=2 [2]0004.29B0::04/11/2022-15:46:32.392 [USBAudio2] Mixer Controls: [2]0004.29B0::04/11/2022-15:46:32.392 [USBAudio2] MCN 0 PROGRAMMABLE min=-18176 (0xb900) max=0 (0x0000) res=256 (0x0100) [2]0004.29B0::04/11/2022-15:46:32.392 [USBAudio2] MCN 1 PROGRAMMABLE min=-18176 (0xb900) max=0 (0x0000) res=256 (0x0100) [2]0004.29B0::04/11/2022-15:46:32.392 [USBAudio2] MCN 2 PROGRAMMABLE min=-18176 (0xb900) max=0 (0x0000) res=256 (0x0100) [2]0004.29B0::04/11/2022-15:46:32.392 [USBAudio2] MCN 3 PROGRAMMABLE min=-18176 (0xb900) max=0 (0x0000) res=256 (0x0100) I can also see GET requests for this mixer unit in the logs on my device so the windows usb audio2 driver does seem to recognize it and the min/max/res above are indeed the ones I programmed. I can confirm that I can control the mixer unit from a Linux machine through alsamixer but would like to be able to do this from a Windows PC as well (preferably with the default driver since it has support for it). I don't see anything in the default sound control panel window or anything to actually control a mixer unit? Thanks for any info!MyrmidonApr 12, 2022Copper Contributor105Views0likes0CommentsEnumerated USB Audio CODEC
In Windows 10 (and I assume 7 and earlier) if I plug a USB hardware device into several different USB ports on my computer running Windows 10, a new enumeration results even though the same driver is used. Example; if I plug the hardware into my computer's left most USB port on the front panel the hardware is enumerated as USB Audio CODEC. When I plug the same hardware into my computer's right most USB port on the front panel the hardware is enumerated as USB- 1 USB Audio CODEC. The saga continues especially when using USB hubs and the enumeration could easily get to be double digit enumeration names. 3rd party software that uses this hardware depends on seeing consist naming of the hardware that is plugged in, so the user must go to the software setup section and verify the correct hardware is selected in case the hardware was plugged into a different USB port on the computer. I'd like to be able to wipe the USB enumeration table from my Windows 10 installation since I've now decided what exact USB port the hardware will always be connected to (so the only enumeration name would be USB Audio CODEC). The Microsoft Community (non tech) suggested I use the USBDeview utility to delete the table. I have tried that and it did not work. As a test I deleted the last two enumerated devices; USB- 8 Audio CODEC and USB- 9 Audio CODEC from the list, rebooted. I then plugged the hardware into a new USB port on my computer, the OS enumerated the hardware as USB- 10 Audio CODEC. Is there a way to fix this issue or should I just live with the problem? Is there a limit to the number of enumerated names? Regards, SteveEEByDesignFeb 07, 2022Copper Contributor398Views0likes1CommentHigh speed USB printer device communication issue on WINDOWS 11
I encountered an issue that windows 11 keeps enumerating the high speed usb printer based on LPC546 mcu, until the OS switched to full speed mode and the enumeration successed. I used ellisys USB protocol analyzer to capture the enumeration process, the result shows as the picture below. It's wired that the OS suspended the device after getting device ID, and resumed and started over the enumeration multiple times until the OS enumerated in full speed mode. I tested the same printer on WINDOWS 10, and it worked perfectly in high speed mode. So, does anyone have encountered the same problem and solution to it, please tell me. Much appreciate!! JasonJasonNotMeJan 14, 2022Copper Contributor195Views0likes0Commentswinusb driver - isochronous endpoint not working
Hi We have a usb device that working with our WDM driver written about 15 years ago . It works on Windows XP to Windows 10 32 and 64 bit. Device sends analog data of 2 bytes every 1ms to PC ( Data sample rate = 1000) I tried to switch working with Microsoft winusb driver in Windows 10. Driver installed OK; I write some wrapper code (So my Application will work as is) to use winusb driver on isochronous pipe streaming and get very strange behave ... I am missing packets , on All empty packets i get Status of USBD_STATUS_ISO_NOT_ACCESSED_BY_HW USBD_STATUS_ISO_NOT_ACCESSED_BY_HW Extended isochronous error codes returned by USBD. These errors appear in the packet status field of an isochronous transfer. [0xC0020000] For some reason the controller did not access the TD associated with this packet: /* ----- IF Using WinUSB.sys driver --------------- */ #ifdef USE_WINUSB_DRIVER #include <tchar.h> #include <strsafe.h> #include <winusb.h> #include <usb.h> #include <cstdlib> #include <initguid.h> #include <cfgmgr32.h> #include <combaseapi.h> // // Device Interface GUID. // Used by all WinUsb devices that this application talks to. // Must match "DeviceInterfaceGUIDs" registry value specified in the INF file. // yyyyyy-yyyy-yyyy-xxxx-yyyyyyyy // DEFINE_GUID(GUID_DEVINTERFACE_ECGUSB1, 0xyyyyyyyy, 0xyyyy, 0xyyy, 0xxx, 0xxx, 0xyy, 0xyy, 0xyy, 0xyy, 0xyy, 0xyy); #define ISOCH_DATA_SIZE_MS 10 #define ISOCH_TRANSFER_COUNT 2 //will need to be at least 2 /* * My device sends one sample of 2 bytes every 1ms .. => data sample rate = 1000s/s * * Problem !! * Only Transfer 1 has the data all next (ISOCH_TRANSFER_COUNT) are empty * As a result i see data arriving at sample rate of 1000 / ISOCH_TRANSFER_COUNT in Read application * * Why ????? * nvUSB.lib: Current Frame number=261744397 nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer. nvUSB.lib: bRead() Transfer 1 completed. Read 100 bytes. nvUSB.lib: Current Frame number=261744447 nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer. nvUSB.lib: bRead() Transfer 2 completed. Read 0 bytes. <-- ?? nvUSB.lib: Current Frame number=261744497 nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer. nvUSB.lib: bRead() Transfer 1 completed. Read 100 bytes. nvUSB.lib: Current Frame number=261744547 nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer. nvUSB.lib: bRead() Transfer 2 completed. Read 0 bytes. <--- ?? nvUSB.lib: Current Frame number=261744597 nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer. nvUSB.lib: bRead() Transfer 1 completed. Read 100 bytes. nvUSB.lib: Current Frame number=261744647 nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer. nvUSB.lib: bRead() Transfer 2 completed. Read 0 bytes. nvUSB.lib: Current Frame number=261744697 */ typedef struct _PCECG_PIPE_INFORMATION_EX { USBD_PIPE_TYPE PipeType; UCHAR PipeId; USHORT MaximumPacketSize; UCHAR Interval; ULONG MaximumBytesPerInterval; int index; } PCECG_PIPE_INFORMATION_EX, * PPCECG_PIPE_INFORMATION_EX; struct PIPE_ID { // Note: // Each USB device can define up to 32 endpoints(16 inputs and 16 outputs though one must be a control endpoint) // Here i assume that we will use maximum 2 for each type.. PCECG_PIPE_INFORMATION_EX Bulk_Pipe[2]; // [0] -for IN type ; [1] -for OUT type PCECG_PIPE_INFORMATION_EX Int_Pipe[2]; PCECG_PIPE_INFORMATION_EX Iso_Pipe[2]; }; typedef struct _RING_BUFFER { PUCHAR buffer; PUCHAR inPtr; PUCHAR outPtr; SIZE_T totalSize; SIZE_T currentSize; KSPIN_LOCK spinLock; SIZE_T Size; PUCHAR Base; PUCHAR End; PUCHAR Head; PUCHAR Tail; } RING_BUFFER, * PRING_BUFFER; class CUsbPCECGHelper { public: // constructor CUsbPCECGHelper(); // destructor virtual ~CUsbPCECGHelper(); BOOL GetDeviceHandle(GUID guidDeviceInterface, PHANDLE hDeviceHandle); BOOL GetWinUSBHandle(HANDLE hDeviceHandle, PWINUSB_INTERFACE_HANDLE phWinUSBHandle); BOOL GetUSBDeviceSpeed(WINUSB_INTERFACE_HANDLE hDeviceHandle, UCHAR* pDeviceSpeed); BOOL QueryDeviceEndpoints(WINUSB_INTERFACE_HANDLE hDeviceHandle, PIPE_ID* pipeid); void ClearIsobuffers(void); void ClearDeviceHandles(void); void ClearThreadHandles(void); DWORD StartThreadHandles(void); HANDLE m_hDeviceHandle ; WINUSB_INTERFACE_HANDLE m_hWinUSBHandle[2]; PIPE_ID PipeID; DRIVER_VERSION drvver; BOOL RealTimeInProgress; ULONG IsochInTransferSize; ULONG IsochInPacketCount; PUCHAR readBuffer; LPOVERLAPPED overlapped; WINUSB_ISOCH_BUFFER_HANDLE isochReadBufferHandle; PUSBD_ISO_PACKET_DESCRIPTOR isochPacketDescriptors; //reading execution thread handle HANDLE m_hEventThread; //event handle to close execution thread HANDLE m_hCloseThread; //event handle for read HANDLE m_hReadAsync[ISOCH_TRANSFER_COUNT]; DWORD m_dwInterval; BOOL m_bResult; DWORD ReadIsoBuffer(DWORD eventIndex); // Data Event thread procedure. static DWORD WINAPI AsyncReadThreadProc(__in LPVOID pvData); PRING_BUFFER m_DataRingBuffer; PRING_BUFFER AllocRingBuffer( SIZE_T Size ); VOID FreeRingBuffer( PRING_BUFFER ringBuffer); SIZE_T ReadRingBuffer( PRING_BUFFER ringBuffer, PUCHAR readBuffer, SIZE_T numberOfBytesToRead ); SIZE_T WriteRingBuffer(PRING_BUFFER ringBuffer, PUCHAR writeBuffer, SIZE_T numberOfBytesToWrite); VOID RingBufferGetAvailableSpace(PRING_BUFFER ringBuffer, SIZE_T* AvailableSpace ); VOID RingBufferGetAvailableData( PRING_BUFFER ringBuffer, SIZE_T* AvailableData ); }; CUsbPCECGHelper helperfunctionsc_class; #endif #ifdef USE_WINUSB_DRIVER CUsbPCECGHelper::CUsbPCECGHelper() { m_hDeviceHandle = INVALID_HANDLE_VALUE; m_hWinUSBHandle[0] = INVALID_HANDLE_VALUE; m_hWinUSBHandle[1] = INVALID_HANDLE_VALUE; drvver.MajorVersion = 0; drvver.MinorVersion = 0; drvver.BuildVersion = 0; PipeID.Bulk_Pipe[0].index = -1; PipeID.Int_Pipe [0].index = -1; PipeID.Iso_Pipe [0].index = -1; PipeID.Bulk_Pipe[1].index = -1; PipeID.Int_Pipe [1].index = -1; PipeID.Iso_Pipe [1].index = -1; RealTimeInProgress = FALSE; readBuffer = NULL; isochPacketDescriptors = NULL; overlapped = NULL; isochReadBufferHandle = INVALID_HANDLE_VALUE; m_hEventThread = NULL; m_hCloseThread = NULL; m_bResult = FALSE; m_DataRingBuffer = NULL; m_DataRingBuffer = AllocRingBuffer(64 * 1024); } CUsbPCECGHelper::~CUsbPCECGHelper() { ClearThreadHandles(); ClearIsobuffers(); ClearDeviceHandles(); FreeRingBuffer(m_DataRingBuffer); } void CUsbPCECGHelper::ClearThreadHandles(void) { if (NULL != m_hCloseThread) { // Stop the event thread. ::SetEvent(m_hCloseThread); // Wait for the thread to end. ::WaitForSingleObject(m_hEventThread, INFINITE); if (NULL != m_hEventThread) { CloseHandle(m_hEventThread); m_hEventThread = NULL; } CloseHandle(m_hCloseThread); m_hCloseThread = NULL; } } void CUsbPCECGHelper::ClearIsobuffers(void) { //ULONG i; if (isochReadBufferHandle != INVALID_HANDLE_VALUE) { WinUsb_UnregisterIsochBuffer(isochReadBufferHandle); isochReadBufferHandle = INVALID_HANDLE_VALUE; } if (readBuffer != NULL) { delete[] readBuffer; readBuffer = NULL; } if (isochPacketDescriptors != NULL) { delete[] isochPacketDescriptors; isochPacketDescriptors = NULL; } /* for (i = 0; i < ISOCH_TRANSFER_COUNT; i++) { if (overlapped[i].hEvent != NULL) { CloseHandle(overlapped[i].hEvent); overlapped[i].hEvent = NULL; } }*/ if (overlapped != NULL) { delete[] overlapped; overlapped = NULL; } } void CUsbPCECGHelper::ClearDeviceHandles(void) { if (m_hWinUSBHandle[0] != INVALID_HANDLE_VALUE) { WinUsb_Free(m_hWinUSBHandle[0]); m_hWinUSBHandle[0] = INVALID_HANDLE_VALUE; } if (m_hWinUSBHandle[1] != INVALID_HANDLE_VALUE) { WinUsb_Free(m_hWinUSBHandle[1]); m_hWinUSBHandle[1] = INVALID_HANDLE_VALUE; } if (m_hDeviceHandle != INVALID_HANDLE_VALUE) { CloseHandle(m_hDeviceHandle); m_hDeviceHandle = INVALID_HANDLE_VALUE; } } DWORD CUsbPCECGHelper::StartThreadHandles(void) { DWORD result = S_OK; if (m_hWinUSBHandle[0] == INVALID_HANDLE_VALUE) { return E_HANDLE; } // Create the event used to close the thread. if (NULL == m_hCloseThread) { m_hCloseThread = ::CreateEvent(NULL, FALSE, FALSE, TEXT("CloseThreadEvent")); } if (NULL == m_hCloseThread) { result=E_UNEXPECTED; } if (SUCCEEDED(result) && (m_hEventThread == NULL)) { m_hEventThread = ::CreateThread(NULL, // Cannot be inherited by child process 0, // Default stack size &CUsbPCECGHelper::AsyncReadThreadProc, // Thread proc (LPVOID)this, // Thread proc argument 0, // Starting state = running NULL); // No thread identifier if (NULL == m_hEventThread) { result = E_UNEXPECTED; } else { //DWORD dwError, dwThreadPri; if (!SetThreadPriority(m_hEventThread, THREAD_PRIORITY_HIGHEST)) { //dwError = GetLastError(); result = E_UNEXPECTED; } //dwThreadPri = GetThreadPriority(m_hEventThread); } } return result; } DWORD WINAPI CUsbPCECGHelper::AsyncReadThreadProc(__in LPVOID pvData) { #if(1) //-------------- HANDLE hEvents[ISOCH_TRANSFER_COUNT+1]; DWORD dwWait = 0; DWORD dwNum = 0; USHORT headerSize = 3; ULONG bytesRead = 0; BOOL b = FALSE; ULONG i; BOOL result = FALSE; // Cast the argument to the correct type CUsbPCECGHelper* pThis = static_cast<CUsbPCECGHelper*>(pvData); // New threads must always CoInitialize HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); ULONG totalTransferSize = pThis->IsochInTransferSize * ISOCH_TRANSFER_COUNT; pThis->readBuffer = new UCHAR[totalTransferSize]; if (pThis->readBuffer == NULL) { //sprintf_s(s, sizeof(s), "nvUSB.lib: bStart() Unable to allocate memory\n"); //OutputDebugString((LPCSTR)s); hr = E_UNEXPECTED; } else { ZeroMemory(pThis->readBuffer, totalTransferSize); } hEvents[0] = pThis->m_hCloseThread; for (i = 0; i < ISOCH_TRANSFER_COUNT; i++) { pThis->m_hReadAsync[i] = CreateEvent( NULL, // default security attribute TRUE, // manual-reset event FALSE, // initial state = not signaled NULL); // unnamed event object } for (i = 1; i < (ISOCH_TRANSFER_COUNT+1); i++) hEvents[i] = pThis->m_hReadAsync[i-1]; if (SUCCEEDED(hr)) { pThis->overlapped = new OVERLAPPED[ISOCH_TRANSFER_COUNT]; ZeroMemory(pThis->overlapped, (sizeof(OVERLAPPED) * ISOCH_TRANSFER_COUNT)); for (i = 0; i < ISOCH_TRANSFER_COUNT; i++) { // pThis->overlapped[i].hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); pThis->overlapped[i].hEvent = pThis->m_hReadAsync[i]; // Initialize the rest of the OVERLAPPED structure to zero. pThis->overlapped[i].Internal = 0; pThis->overlapped[i].InternalHigh = 0; pThis->overlapped[i].Offset = 0; pThis->overlapped[i].OffsetHigh = 0; if (pThis->overlapped[i].hEvent == NULL) { //sprintf_s(s, sizeof(s), "nvUSB.lib: bStart() Unable to set event for overlapped operation\n"); //OutputDebugString((LPCSTR)s); hr = E_UNEXPECTED; } } } if (SUCCEEDED(hr)) { result = WinUsb_RegisterIsochBuffer( pThis->m_hWinUSBHandle[0], // An opaque handle to an interface in the selected configuration. That handle must be created by a previous call to WinUsb_Initialize or WinUsb_GetAssociatedInterface. pThis->PipeID.Iso_Pipe[0].PipeId, // Derived from Bit 3...0 of the bEndpointAddress field in the endpoint descriptor. pThis->readBuffer, // Pointer to the transfer buffer to be registered. totalTransferSize, // Length, in bytes, of the transfer buffer pointed to by Buffer. &pThis->isochReadBufferHandle); // Receives an opaque handle to the registered buffer. This handle is required by other WinUSB functions that perform isochronous transfers. To release the handle, call the WinUsb_UnregisterIsochBuffer function. if (!result) { //sprintf_s(s, sizeof(s), "nvUSB.lib: bStart() Isoch buffer registration failed.\n"); //OutputDebugString((LPCSTR)s); hr = E_UNEXPECTED; } } if (SUCCEEDED(hr)) { pThis->isochPacketDescriptors = new USBD_ISO_PACKET_DESCRIPTOR[pThis->IsochInPacketCount * ISOCH_TRANSFER_COUNT]; ZeroMemory(pThis->isochPacketDescriptors, pThis->IsochInPacketCount * ISOCH_TRANSFER_COUNT); //for iso endpoints read this //https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/getting-set-up-to-use-windows-devices-usb // for (i = 0; i < ISOCH_TRANSFER_COUNT; i++) { result = WinUsb_ReadIsochPipeAsap( pThis->isochReadBufferHandle, // An opaque handle to the transfer buffer that was registered by a previous call to WinUsb_RegisterIsochBuffer. pThis->IsochInTransferSize * i, // Offset into the buffer relative to the start the transfer. pThis->IsochInTransferSize, // Length in bytes of the transfer buffer. (i == 0) ? FALSE : TRUE, // Indicates that the transfer should only be submitted if it can be scheduled in the first frame after the last pending transfer. pThis->IsochInPacketCount, // Total number of isochronous packets required to hold the transfer buffer.Also indicates the number of elements in the array pointed to by IsoPacketDescriptors. &pThis->isochPacketDescriptors[i * pThis->IsochInPacketCount], //An array of USBD_ISO_PACKET_DESCRIPTOR that receives the details of each isochronous packet in the transfer. &pThis->overlapped[i]); // Pointer to an OVERLAPPED structure used for asynchronous operations. if (!result) { DWORD lastError = GetLastError(); if (lastError != ERROR_IO_PENDING) { //sprintf_s(s, sizeof(s), "nvUSB.lib: bStart() Failed to start a read operation with error %x\n", lastError); //OutputDebugString((LPCSTR)s); hr = E_UNEXPECTED; } } } } //-------------- if (SUCCEEDED(hr)) { while (true) { for (i = 0; i < ISOCH_TRANSFER_COUNT; i++) pThis->m_bResult = ResetEvent(pThis->m_hReadAsync[i]); dwWait = WaitForMultipleObjects(ISOCH_TRANSFER_COUNT+1, // number of event objects hEvents, // array of event objects FALSE, // does not wait for all INFINITE // waits indefinitely ); if (dwWait == WAIT_OBJECT_0) //STOP_THREAD { CoUninitialize(); for (i = 0; i < ISOCH_TRANSFER_COUNT; i++) CloseHandle(pThis->m_hReadAsync[i]); return 0; } else { for (i = 1; i < (ISOCH_TRANSFER_COUNT + 1); i++) { if (dwWait == (WAIT_OBJECT_0 + i)) { pThis->ReadIsoBuffer((i-1)); } } } } } #endif #if(0) OVERLAPPED oOverlap; HANDLE hEvents[2]; DWORD dwWait = 0; DWORD dwNum = 0; const DWORD STOP_THREAD = WAIT_OBJECT_0; const DWORD READ_EVENT = WAIT_OBJECT_0 + 1; USHORT headerSize = 3; UCHAR buffer[3]; ULONG bytesRead = 0; BOOL b = FALSE; // Cast the argument to the correct type CUsbPCECGHelper* pThis = static_cast<CUsbPCECGHelper*>(pvData); // New threads must always CoInitialize HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); hEvents[0] = pThis->m_hCloseThread; pThis->m_hReadAsync = CreateEvent( NULL, // default security attribute TRUE, // manual-reset event FALSE, // initial state = not signaled NULL); // unnamed event object hEvents[1] = pThis->m_hReadAsync; /* oOverlap.hEvent = pThis->m_hReadAsync; // Initialize the rest of the OVERLAPPED structure to zero. oOverlap.Internal = 0; oOverlap.InternalHigh = 0; oOverlap.Offset = 0; oOverlap.OffsetHigh = 0; */ if (SUCCEEDED(hr)) { while (true) { /* pThis->m_bResult = ResetEvent(pThis->m_hReadAsync); pThis->ReadHeader(buffer, headerSize, &bytesRead, &oOverlap); dwWait = WaitForMultipleObjects(2, // number of event objects hEvents, // array of event objects FALSE, // does not wait for all INFINITE // waits indefinitely ); b = WinUsb_GetOverlappedResult(pThis->m_UsbHandle[1], &oOverlap, &dwNum, FALSE); */ pThis->m_bResult = ResetEvent(pThis->m_hReadAsync); dwWait = WaitForMultipleObjects(2, // number of event objects hEvents, // array of event objects FALSE, // does not wait for all INFINITE // waits indefinitely ); switch (dwWait) { case STOP_THREAD: CoUninitialize(); CloseHandle(pThis->m_hReadAsync); return 0; //break; case READ_EVENT: /* //reads the rest of the message if exist, throws events if needed if (b) { pThis->ParseDataMessage(buffer); } else { //error WinUsb_FlushPipe(pThis->m_UsbHandle[1], pThis->m_bulkInPipe); } break; */ default: break; } } } #endif //code not reached return 1; } DWORD CUsbPCECGHelper::ReadIsoBuffer(DWORD eventIndex) { #if(1) /* //for iso endpoints read this //https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/getting-set-up-to-use-windows-devices-usb //https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/transfer-data-to-isochronous-endpoints // */ char s[256]; DWORD Status = UsbPCECG_ERR_SUCCESS; ULONG i, j; BOOL result; DWORD lastError; ULONG numBytes = 0; BOOL ContinueStream = TRUE; ULONG frameNumber; ULONG startFrame; LARGE_INTEGER timeStamp; if (helperfunctionsc_class.m_hWinUSBHandle[0] == INVALID_HANDLE_VALUE) { return UsbPCECG_ERR_READISOBUFF; } result = WinUsb_GetCurrentFrameNumber( helperfunctionsc_class.m_hWinUSBHandle[0], &frameNumber, &timeStamp); if (!result) { sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() WinUsb_GetCurrentFrameNumber failed. \n"); OutputDebugString((LPCSTR)s); return UsbPCECG_ERR_READISOBUFF; } sprintf_s(s, sizeof(s), "nvUSB.lib: Current Frame number=%d\n", frameNumber); OutputDebugString((LPCSTR)s); startFrame = frameNumber + 10; i = eventIndex; // for (i = 0; i < ISOCH_TRANSFER_COUNT; i++) { if (helperfunctionsc_class.RealTimeInProgress == FALSE) { return UsbPCECG_ERR_READISOBUFF; } result = WinUsb_GetOverlappedResult( helperfunctionsc_class.m_hWinUSBHandle[0], &helperfunctionsc_class.overlapped[i], &numBytes, TRUE); if (!result || numBytes == 0) { //0x1F = ERROR_GEN_FAILURE A device attached to the system is not functioning. //0x7A = ERROR_INSUFFICIENT_BUFFER The data area passed to a system call is too small. //0x57 = ERROR_INVALID_PARAMETER The parameter is incorrect. //0x3E5 = ERROR_IO_PENDING Overlapped I/O operation is in progress. lastError = GetLastError(); if (lastError == ERROR_IO_PENDING) //The transfer is pending.. { // try again.. if (i > 0) i--; // continue; } sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() Failed to read with error %x \n", lastError); OutputDebugString((LPCSTR)s); return UsbPCECG_ERR_READISOBUFF; } else { numBytes = 0; for (j = 0; j < helperfunctionsc_class.IsochInPacketCount; j++) { numBytes += helperfunctionsc_class.isochPacketDescriptors[j].Length; //sprintf_s(s, sizeof(s), "%d-%d-%d\n", helperfunctionsc_class.isochPacketDescriptors[j].Length, helperfunctionsc_class.isochPackets[j].Offset, helperfunctionsc_class.isochPackets[j].Status); //OutputDebugString((LPCSTR)s); /* if (helperfunctionsc_class.isochPacketDescriptors[j].Length != 0 && helperfunctionsc_class.isochPackets[j].Status == 0) { memcpy(inBuffer, helperfunctionsc_class.readBuffer + helperfunctionsc_class.isochPacketDescriptors[j].Offset, helperfunctionsc_class.isochPacketDescriptors[j].Length); *nWriten += helperfunctionsc_class.isochPacketDescriptors[j].Length; inBuffer += helperfunctionsc_class.isochPacketDescriptors[j].Length; } */ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! sprintf_s(s, sizeof(s), "nvUSB.lib: desc.lenght=%d bytes descr.status=%x\n", helperfunctionsc_class.isochPacketDescriptors[j].Length, helperfunctionsc_class.isochPacketDescriptors[j].Status); OutputDebugString((LPCSTR)s); for ECGUSB1D-EX get nvUSB.lib: desc.lenght=2 bytes descr.status=0 if OK nvUSB.lib: desc.lenght=0 bytes descr.status=c0020000 if empty packet WD_USBD_STATUS_ISO_NOT_ACCESSED_BY_HW Extended isochronous error codes returned by USBD. These errors appear in the packet status field of an isochronous transfer. [0xC0020000] For some reason the controller did not access the TD associated with this packet: ! When the USB driver stack processes the URB, the driver discards all isochronous packets in the URB whose frame numbers are lower than the current frame number. The driver stack sets the Status member of the packet descriptor for each discarded packet to USBD_STATUS_ISO_NA_LATE_USBPORT, USBD_STATUS_ISO_NOT_ACCESSED_BY_HW, or USBD_STATUS_ISO_NOT_ACCESSED_LATE. Even though some packets in the URB are discarded, the driver stack attempts to transmit only those packets whose frame numbers are higher than the current frame number. !! */ /* if (helperfunctionsc_class.isochPacketDescriptors[j].Length == 0 && helperfunctionsc_class.isochPacketDescriptors[j].Status == USBD_STATUS_ISO_NOT_ACCESSED_BY_HW) { if (!(WinUsb_FlushPipe(helperfunctionsc_class.m_hWinUSBHandle[0], helperfunctionsc_class.PipeID.Iso_Pipe[0].PipeId))) { sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() error flush pipe %d.\n", GetLastError()); OutputDebugString((LPCSTR)s); return UsbPCECG_ERR_RESETPIPE; } } */ if (helperfunctionsc_class.isochPacketDescriptors[j].Length != 0 && helperfunctionsc_class.isochPacketDescriptors[j].Status == 0) { WriteRingBuffer( helperfunctionsc_class.m_DataRingBuffer, (helperfunctionsc_class.readBuffer + helperfunctionsc_class.isochPacketDescriptors[j].Offset), helperfunctionsc_class.isochPacketDescriptors[j].Length ); } } sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() Requested %d bytes in %d packets per transfer.\n", helperfunctionsc_class.IsochInTransferSize, helperfunctionsc_class.IsochInPacketCount); OutputDebugString((LPCSTR)s); } sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() Transfer %d completed. Read %d bytes. \n", i + 1, numBytes); OutputDebugString((LPCSTR)s); result = WinUsb_ReadIsochPipeAsap( helperfunctionsc_class.isochReadBufferHandle, helperfunctionsc_class.IsochInTransferSize * i, helperfunctionsc_class.IsochInTransferSize, ContinueStream, helperfunctionsc_class.IsochInPacketCount, &helperfunctionsc_class.isochPacketDescriptors[i * helperfunctionsc_class.IsochInPacketCount], &helperfunctionsc_class.overlapped[i]); /* // not working // return with nvUSB.lib: bRead() Failed to read with error 1f after first time.. result = WinUsb_ReadIsochPipe( helperfunctionsc_class.isochReadBufferHandle, helperfunctionsc_class.IsochInTransferSize * i, helperfunctionsc_class.IsochInTransferSize, &startFrame, helperfunctionsc_class.IsochInPacketCount, &helperfunctionsc_class.isochPacketDescriptors[i * helperfunctionsc_class.IsochInPacketCount], &helperfunctionsc_class.overlapped[i]); */ if (!result) { lastError = GetLastError(); if (lastError == ERROR_INVALID_PARAMETER && ContinueStream) { ContinueStream = FALSE; // continue; } if (lastError != ERROR_IO_PENDING) { sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() Failed to start a read operation with error %x\n", lastError); OutputDebugString((LPCSTR)s); return UsbPCECG_ERR_READISOBUFF; } ContinueStream = TRUE; } } return(Status); #endif #if(0) /* //for iso endpoints read this //https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/getting-set-up-to-use-windows-devices-usb //https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/transfer-data-to-isochronous-endpoints // */ char s[256]; DWORD Status = UsbPCECG_ERR_SUCCESS; ULONG i, j; BOOL result; DWORD lastError; ULONG numBytes=0; BOOL ContinueStream = TRUE; ULONG frameNumber; ULONG startFrame; LARGE_INTEGER timeStamp; if (helperfunctionsc_class.m_hWinUSBHandle[0] == INVALID_HANDLE_VALUE) { return UsbPCECG_ERR_READISOBUFF; } result = WinUsb_GetCurrentFrameNumber( helperfunctionsc_class.m_hWinUSBHandle[0], &frameNumber, &timeStamp); if (!result) { sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() WinUsb_GetCurrentFrameNumber failed. \n"); OutputDebugString((LPCSTR)s); return UsbPCECG_ERR_READISOBUFF; } startFrame = frameNumber + 10; for (i = 0; i < ISOCH_TRANSFER_COUNT; i++) { if (helperfunctionsc_class.RealTimeInProgress == FALSE) { return UsbPCECG_ERR_READISOBUFF; } result = WinUsb_GetOverlappedResult( helperfunctionsc_class.m_hWinUSBHandle[0], &helperfunctionsc_class.overlapped[i], &numBytes, TRUE); if (!result || numBytes==0) { //0x1F = ERROR_GEN_FAILURE A device attached to the system is not functioning. //0x7A = ERROR_INSUFFICIENT_BUFFER The data area passed to a system call is too small. //0x57 = ERROR_INVALID_PARAMETER The parameter is incorrect. //0x3E5 = ERROR_IO_PENDING Overlapped I/O operation is in progress. lastError = GetLastError(); if (lastError == ERROR_IO_PENDING) //The transfer is pending.. { // try again.. if (i > 0) i--; continue; } sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() Failed to read with error %x \n", lastError); OutputDebugString((LPCSTR)s); return UsbPCECG_ERR_READISOBUFF; } else { numBytes = 0; for (j = 0; j < helperfunctionsc_class.IsochInPacketCount; j++) { numBytes += helperfunctionsc_class.isochPacketDescriptors[j].Length; //sprintf_s(s, sizeof(s), "%d-%d-%d\n", helperfunctionsc_class.isochPacketDescriptors[j].Length, helperfunctionsc_class.isochPackets[j].Offset, helperfunctionsc_class.isochPackets[j].Status); //OutputDebugString((LPCSTR)s); /* if (helperfunctionsc_class.isochPacketDescriptors[j].Length != 0 && helperfunctionsc_class.isochPackets[j].Status == 0) { memcpy(inBuffer, helperfunctionsc_class.readBuffer + helperfunctionsc_class.isochPacketDescriptors[j].Offset, helperfunctionsc_class.isochPacketDescriptors[j].Length); *nWriten += helperfunctionsc_class.isochPacketDescriptors[j].Length; inBuffer += helperfunctionsc_class.isochPacketDescriptors[j].Length; } */ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! sprintf_s(s, sizeof(s), "nvUSB.lib: desc.lenght=%d bytes descr.status=%x\n", helperfunctionsc_class.isochPacketDescriptors[j].Length, helperfunctionsc_class.isochPacketDescriptors[j].Status); OutputDebugString((LPCSTR)s); for ECGUSB1D-EX get nvUSB.lib: desc.lenght=2 bytes descr.status=0 if OK nvUSB.lib: desc.lenght=0 bytes descr.status=c0020000 if empty packet WD_USBD_STATUS_ISO_NOT_ACCESSED_BY_HW Extended isochronous error codes returned by USBD. These errors appear in the packet status field of an isochronous transfer. [0xC0020000] For some reason the controller did not access the TD associated with this packet: ! When the USB driver stack processes the URB, the driver discards all isochronous packets in the URB whose frame numbers are lower than the current frame number. The driver stack sets the Status member of the packet descriptor for each discarded packet to USBD_STATUS_ISO_NA_LATE_USBPORT, USBD_STATUS_ISO_NOT_ACCESSED_BY_HW, or USBD_STATUS_ISO_NOT_ACCESSED_LATE. Even though some packets in the URB are discarded, the driver stack attempts to transmit only those packets whose frame numbers are higher than the current frame number. !! */ if (helperfunctionsc_class.isochPacketDescriptors[j].Length != 0 && helperfunctionsc_class.isochPacketDescriptors[j].Status == 0) { WriteRingBuffer( helperfunctionsc_class.m_DataRingBuffer, (helperfunctionsc_class.readBuffer + helperfunctionsc_class.isochPacketDescriptors[j].Offset), helperfunctionsc_class.isochPacketDescriptors[j].Length ); } } sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() Requested %d bytes in %d packets per transfer.\n", helperfunctionsc_class.IsochInTransferSize, helperfunctionsc_class.IsochInPacketCount); OutputDebugString((LPCSTR)s); } sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() Transfer %d completed. Read %d bytes. \n", i + 1, numBytes); OutputDebugString((LPCSTR)s); result = WinUsb_ReadIsochPipeAsap( helperfunctionsc_class.isochReadBufferHandle, helperfunctionsc_class.IsochInTransferSize * i, helperfunctionsc_class.IsochInTransferSize, ContinueStream, helperfunctionsc_class.IsochInPacketCount, &helperfunctionsc_class.isochPacketDescriptors[i * helperfunctionsc_class.IsochInPacketCount], &helperfunctionsc_class.overlapped[i]); /* // not working // return with nvUSB.lib: bRead() Failed to read with error 1f after first time.. result = WinUsb_ReadIsochPipe( helperfunctionsc_class.isochReadBufferHandle, helperfunctionsc_class.IsochInTransferSize * i, helperfunctionsc_class.IsochInTransferSize, &startFrame, helperfunctionsc_class.IsochInPacketCount, &helperfunctionsc_class.isochPacketDescriptors[i * helperfunctionsc_class.IsochInPacketCount], &helperfunctionsc_class.overlapped[i]); */ if (!result) { lastError = GetLastError(); if (lastError == ERROR_INVALID_PARAMETER && ContinueStream) { ContinueStream = FALSE; continue; } if (lastError != ERROR_IO_PENDING) { sprintf_s(s, sizeof(s), "nvUSB.lib: bRead() Failed to start a read operation with error %x\n", lastError); OutputDebugString((LPCSTR)s); return UsbPCECG_ERR_READISOBUFF; } ContinueStream = TRUE; } } return(Status); #endif } /* //----------------------------------------------------------------------------- // GetDeviceHandle() // // Parameters: // guidDeviceInterface: DEVICE GUID defined in WinUSB inf file // hDeviceHandle : device handle returned // // Return Values: // true : success // false: fail // // Remarks: // Function to create file handle for USB device //----------------------------------------------------------------------------- */ BOOL CUsbPCECGHelper::GetDeviceHandle(GUID guidDeviceInterface, PHANDLE hDeviceHandle) { char s[256]; #if(1) HRESULT result; HDEVINFO deviceInfo; SP_DEVINFO_DATA deviceInfoData; SP_DEVICE_INTERFACE_DATA deviceInterfaceData; SP_DRVINFO_DATA_A DriverInfo; PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData; ULONG requiredLength; LPTSTR devicePath; size_t length; BOOL ret = FALSE; result = S_OK; interfaceDetailData = NULL; requiredLength = 0; devicePath = NULL; deviceInfo = SetupDiGetClassDevs( &guidDeviceInterface, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE ); if (deviceInfo == INVALID_HANDLE_VALUE) { result = E_HANDLE; } if (SUCCEEDED(result)) { // Check that a query for a second interface fails, but that the // first interface succeeds deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); if ( !SetupDiEnumDeviceInfo(deviceInfo, 1, &deviceInfoData) && SetupDiEnumDeviceInfo(deviceInfo, 0, &deviceInfoData)) { // Get the specific device interface deviceInterfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA); if (!SetupDiEnumDeviceInterfaces(deviceInfo, &deviceInfoData,&guidDeviceInterface, 0, &deviceInterfaceData) ) { result = HRESULT_FROM_WIN32(GetLastError()); sprintf_s(s, sizeof(s), "nvUSB.lib: SetupDiEnumDeviceInterfaces failed %d.\n", result); OutputDebugString((LPCSTR)s); } // Check the size needed for the device interface details and // allocate the data needed to get the details if ( SUCCEEDED(result) && !SetupDiGetDeviceInterfaceDetail(deviceInfo,&deviceInterfaceData, NULL, 0, &requiredLength, NULL)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER && requiredLength > 0) { interfaceDetailData =(PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, (SIZE_T)requiredLength); if (interfaceDetailData == NULL) { result = E_OUTOFMEMORY; } else { result = S_OK; } } else { result = HRESULT_FROM_WIN32(GetLastError()); } } // Get the device interface details if (SUCCEEDED(result) && interfaceDetailData != NULL) { interfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); if (!SetupDiGetDeviceInterfaceDetail(deviceInfo,&deviceInterfaceData, interfaceDetailData,requiredLength, NULL, &deviceInfoData)) { result = HRESULT_FROM_WIN32(GetLastError()); sprintf_s(s, sizeof(s), "nvUSB.lib: SetupDiGetDeviceInterfaceDetail failed %d.\n", result); OutputDebugString((LPCSTR)s); } } if (SUCCEEDED(result) && interfaceDetailData != NULL) { // Build the null terminated device path for the device length = _tcslen(interfaceDetailData->DevicePath) + 1; devicePath = (TCHAR*)LocalAlloc(LPTR, length * sizeof(TCHAR)); if (devicePath != NULL) { StringCchCopy(devicePath, length,interfaceDetailData->DevicePath); devicePath[length - 1] = 0; sprintf_s(s, sizeof(s), "nvUSB.lib: Device path: %s\n", devicePath); OutputDebugString((LPCSTR)s); //This what i get on Windows 10 as output: // nvUSB.lib: Device path: \\?\usb#vid_10c4&pid_825f#7&1b060a7f&0&3#{93bd88a4-eb10-4706-8304-c512f18b8e42} //------------------ Get winusb driver version ----------------------------------------------------------- if (!SetupDiBuildDriverInfoList(deviceInfo, &deviceInfoData, SPDIT_COMPATDRIVER)) { result = HRESULT_FROM_WIN32(GetLastError()); sprintf_s(s, sizeof(s), "nvUSB.lib: SetupDiBuildDriverInfoList failed %d.\n", result); OutputDebugString((LPCSTR)s); } else { DriverInfo.cbSize = sizeof(SP_DRVINFO_DATA_A); if ((SetupDiEnumDriverInfoA(deviceInfo, &deviceInfoData, SPDIT_COMPATDRIVER, 0, &DriverInfo))) { sprintf_s(s, sizeof(s), "nvUSB.lib: SetupDiEnumDriverInfoA \n"); OutputDebugString((LPCSTR)s); sprintf_s(s, sizeof(s), "nvUSB.lib: winusb driver version %s v.%u.%u.%u.%u\n", DriverInfo.Description, (DWORD32)(DriverInfo.DriverVersion >> 48) & 0xFFFF, (DWORD32)(DriverInfo.DriverVersion >> 32) & 0xFFFF, (DWORD32)(DriverInfo.DriverVersion >> 16) & 0xFFFF, (DWORD32)(DriverInfo.DriverVersion >> 0) & 0xFFFF ); OutputDebugString((LPCSTR)s); drvver.MajorVersion = (WORD)(DriverInfo.DriverVersion >> 48) & 0xFFFF; drvver.MinorVersion = (WORD)(DriverInfo.DriverVersion >> 32) & 0xFFFF; drvver.BuildVersion = (WORD)(DriverInfo.DriverVersion >> 16) & 0xFFFF; } else { result = HRESULT_FROM_WIN32(GetLastError()); sprintf_s(s, sizeof(s), "nvUSB.lib: SetupDiEnumDriverInfoA failed %d.\n", result); OutputDebugString((LPCSTR)s); } } //------------------------------------------------------------------------------------------------------------- } else { result = E_OUTOFMEMORY; } } } } if (SUCCEEDED(result) && devicePath != NULL) { ret = TRUE; // Open the device handle *hDeviceHandle = CreateFile( devicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL ); if (*hDeviceHandle == INVALID_HANDLE_VALUE) { result = HRESULT_FROM_WIN32(GetLastError()); sprintf_s(s, sizeof(s), "nvUSB.lib: CreateFile failed %d.\n", result); OutputDebugString((LPCSTR)s); ret = FALSE; } } // Perform cleanup of the allocated data if (devicePath != NULL) { LocalFree(devicePath); } if (interfaceDetailData != NULL) { LocalFree(interfaceDetailData); } if (deviceInfo != INVALID_HANDLE_VALUE) { (void)SetupDiDestroyDeviceInfoList(deviceInfo); } return ret; #endif #if(0) BOOL bResult = TRUE; HDEVINFO hDeviceInfo; SP_DEVINFO_DATA DeviceInfoData; SP_DRVINFO_DATA_A DriverInfo; DriverInfo.cbSize = sizeof(SP_DRVINFO_DATA_A); SP_DEVICE_INTERFACE_DATA deviceInterfaceData; PSP_DEVICE_INTERFACE_DETAIL_DATA pInterfaceDetailData = NULL; ULONG requiredLength = 0; LPTSTR lpDevicePath = NULL; DWORD index = 0; sprintf_s(s, sizeof(s), "nvUSB.lib: Enter to GetDeviceHandle\n"); OutputDebugString((LPCSTR)s); // if (guidDeviceInterface == GUID_NULL) { // return FALSE; // } // Get information about all the installed devices for the specified // device interface class. hDeviceInfo = SetupDiGetClassDevs( &guidDeviceInterface, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (hDeviceInfo == INVALID_HANDLE_VALUE) { // ERROR sprintf_s(s, sizeof(s), "nvUSB.lib: Error SetupDiGetClassDevs: %d.\n", GetLastError()); OutputDebugString((LPCSTR)s); bResult = FALSE; goto done; } //Enumerate all the device interfaces in the device information set. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); for (index = 0; SetupDiEnumDeviceInfo(hDeviceInfo, index, &DeviceInfoData); index++) { //Reset for this iteration if (lpDevicePath) { LocalFree(lpDevicePath); lpDevicePath = NULL; } if (pInterfaceDetailData) { LocalFree(pInterfaceDetailData); pInterfaceDetailData = NULL; } // Check if last item if (GetLastError() == ERROR_NO_MORE_ITEMS) { break; } deviceInterfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA); //Get information about the device interface. bResult = SetupDiEnumDeviceInterfaces( hDeviceInfo, &DeviceInfoData, &guidDeviceInterface, index, &deviceInterfaceData); bResult = SetupDiEnumDeviceInterfaces( hDeviceInfo, &DeviceInfoData, &guidDeviceInterface, index, &deviceInterfaceData); // Check if last item if (GetLastError() == ERROR_NO_MORE_ITEMS) { sprintf_s(s, sizeof(s), "nvUSB.lib: SetupDiEnumDeviceInterfaces ERROR_NO_MORE_ITEMS (%d) \n", index); OutputDebugString((LPCSTR)s); break; } //Check for some other error if (!bResult) { sprintf_s(s, sizeof(s), "nvUSB.lib: Error SetupDiEnumDeviceInterfaces: %d.\n", GetLastError()); OutputDebugString((LPCSTR)s); bResult = FALSE; goto done; } //Interface data is returned in SP_DEVICE_INTERFACE_DETAIL_DATA //which we need to allocate, so we have to call this function twice. //First to get the size so that we know how much to allocate //Second, the actual call with the allocated buffer bResult = SetupDiGetDeviceInterfaceDetail( hDeviceInfo, &deviceInterfaceData, NULL, 0, &requiredLength, NULL); //Check for some other error if (!bResult) { if ((ERROR_INSUFFICIENT_BUFFER == GetLastError()) && (requiredLength > 0)) { //we got the size, allocate buffer pInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, requiredLength); if (!pInterfaceDetailData) { // ERROR //printf("Error allocating memory for the device detail buffer.\n"); sprintf_s(s, sizeof(s), "nvUSB.lib: Error allocating memory for the device detail buffer.\n"); OutputDebugString((LPCSTR)s); bResult = FALSE; goto done; } } else { //printf("Error SetupDiEnumDeviceInterfaces: %d.\n", GetLastError()); sprintf_s(s, sizeof(s), "nvUSB.lib: Error SetupDiEnumDeviceInterfaces: %d.\n", GetLastError()); OutputDebugString((LPCSTR)s); bResult = FALSE; goto done; } } //get the interface detailed data pInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); //Now call it with the correct size and allocated buffer bResult = SetupDiGetDeviceInterfaceDetail( hDeviceInfo, &deviceInterfaceData, pInterfaceDetailData, requiredLength, NULL, &DeviceInfoData); //Check for some other error if (!bResult) { //printf("Error SetupDiGetDeviceInterfaceDetail: %d.\n", GetLastError()); sprintf_s(s, sizeof(s), "nvUSB.lib: Error SetupDiGetDeviceInterfaceDetail: %d.\n", GetLastError()); OutputDebugString((LPCSTR)s); bResult = FALSE; goto done; } if (!SetupDiBuildDriverInfoList(hDeviceInfo, &DeviceInfoData, SPDIT_COMPATDRIVER)) { sprintf_s(s, sizeof(s), "nvUSB.lib: Error SetupDiBuildDriverInfoList: %d.\n", GetLastError()); OutputDebugString((LPCSTR)s); } else { if ((SetupDiEnumDriverInfoA(hDeviceInfo, &DeviceInfoData, SPDIT_COMPATDRIVER, index, &DriverInfo)) != FALSE) { sprintf_s(s, sizeof(s), "nvUSB.lib: SetupDiEnumDriverInfoA \n"); OutputDebugString((LPCSTR)s); sprintf_s(s, sizeof(s), "nvUSB.lib: winusb driver version %s v.%u.%u.%u.%u\n", DriverInfo.Description, (DWORD32)(DriverInfo.DriverVersion >> 48) & 0xFFFF, (DWORD32)(DriverInfo.DriverVersion >> 32) & 0xFFFF, (DWORD32)(DriverInfo.DriverVersion >> 16) & 0xFFFF, (DWORD32)(DriverInfo.DriverVersion >> 0) & 0xFFFF ); OutputDebugString((LPCSTR)s); drvver.MajorVersion = (WORD)(DriverInfo.DriverVersion >> 48) & 0xFFFF; drvver.MinorVersion = (WORD)(DriverInfo.DriverVersion >> 32) & 0xFFFF; drvver.BuildVersion = (WORD)(DriverInfo.DriverVersion >> 16) & 0xFFFF; //copy device path size_t nLength = _tcslen(pInterfaceDetailData->DevicePath) + 1; lpDevicePath = (TCHAR*)LocalAlloc(LPTR, nLength * sizeof(TCHAR)); StringCchCopy(lpDevicePath, nLength, pInterfaceDetailData->DevicePath); lpDevicePath[nLength - 1] = 0; sprintf_s(s, sizeof(s), "nvUSB.lib: Device path: %s\n", lpDevicePath); OutputDebugString((LPCSTR)s); //This what i get on Windows 10 as output: // nvUSB.lib: Device path: \\?\usb#vid_10c4&pid_825f#7&1b060a7f&0&3#{93bd88a4-eb10-4706-8304-c512f18b8e42} break; //connect to to only one device } } }//for (index = 0; SetupDiEnumDeviceInfo(hDeviceInfo, index, &DeviceInfoData); index++) if (!lpDevicePath) { //Error. //printf("Error %d.", GetLastError()); sprintf_s(s, sizeof(s), "nvUSB.lib: lpDevicePath Error %d.\n", GetLastError()); OutputDebugString((LPCSTR)s); bResult = FALSE; goto done; } //Open the device *hDeviceHandle = CreateFile( lpDevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (*hDeviceHandle == INVALID_HANDLE_VALUE) { //Error. //printf("Error %d.", GetLastError()); sprintf_s(s, sizeof(s), "nvUSB.lib: CreateFile Error %d.\n", GetLastError()); OutputDebugString((LPCSTR)s); bResult = FALSE; goto done; } done: if (lpDevicePath) { LocalFree(lpDevicePath); } if (pInterfaceDetailData) { LocalFree(pInterfaceDetailData); } if (!bResult) { if (hDeviceInfo != INVALID_HANDLE_VALUE) SetupDiDestroyDeviceInfoList(hDeviceInfo); } else { if (hDeviceInfo != INVALID_HANDLE_VALUE) bResult = SetupDiDestroyDeviceInfoList(hDeviceInfo); } sprintf_s(s, sizeof(s), "nvUSB.lib: Exit from GetDeviceHandle\n"); OutputDebugString((LPCSTR)s); return bResult; #endif } // End of GetDeviceHandle() /* //----------------------------------------------------------------------------- // GetWinUSBHandle() // // Parameters: // hDeviceHandle : device handle created for the USB device // phWinUSBHandle : WinUSB Interface handle returned // // Return Values: // true : success // false: fail // // Remarks: // Function to get WinUSB Interface Handle for the device //----------------------------------------------------------------------------- */ BOOL CUsbPCECGHelper::GetWinUSBHandle(HANDLE hDeviceHandle, PWINUSB_INTERFACE_HANDLE phWinUSBHandle) { char s[256]; BOOL bResult = FALSE; sprintf_s(s, sizeof(s), "nvUSB.lib: Enter to GetWinUSBHandle\n"); OutputDebugString((LPCSTR)s); if (hDeviceHandle == INVALID_HANDLE_VALUE) { sprintf_s(s, sizeof(s), "nvUSB.lib: Exit from GetWinUSBHandle (hDeviceHandle not valid) \n"); OutputDebugString((LPCSTR)s); return FALSE; } /* [in] DeviceHandle The handle to the device that CreateFile returned.WinUSB uses overlapped I / O, so FILE_FLAG_OVERLAPPED must be specified in the dwFlagsAndAttributes parameter of CreateFile call for DeviceHandle to have the characteristics necessary for WinUsb_Initialize to function properly. [out] InterfaceHandle Receives an opaque handle to the first(default) interface on the device.This handle is required by other WinUSB routines that perform operations on the default interface.To release the handle, call the WinUSB_Free function. WinUsb_Initialize returns TRUE if the operation succeeds. Otherwise, this routine returns FALSE, and the caller can retrieve the logged error by calling GetLastError. */ bResult = WinUsb_Initialize(hDeviceHandle, phWinUSBHandle); if (!bResult) { //Error. //printf("WinUsb_Initialize Error %d.", GetLastError()); sprintf_s(s, sizeof(s), "nvUSB.lib: WinUsb_Initialize Error %d.", GetLastError()); OutputDebugString((LPCSTR)s); return FALSE; } sprintf_s(s, sizeof(s), "nvUSB.lib: Exit from GetWinUSBHandle \n"); OutputDebugString((LPCSTR)s); return bResult; } // End of GetWinUSBHandle() /* //----------------------------------------------------------------------------- // GetUSBDeviceSpeed() // // Parameters: // hDeviceHandle : WinUSB Interface Handle // pDeviceSpeed : Device Speed returned // // Return Values: // true : success // false: fail // // Remarks: // Function to get device speed //----------------------------------------------------------------------------- */ BOOL CUsbPCECGHelper::GetUSBDeviceSpeed(WINUSB_INTERFACE_HANDLE hDeviceHandle, UCHAR* pDeviceSpeed) { char s[256]; sprintf_s(s, sizeof(s), "nvUSB.lib: Enter to GetUSBDeviceSpeed() \n"); OutputDebugString((LPCSTR)s); if (!pDeviceSpeed || hDeviceHandle == INVALID_HANDLE_VALUE) { return FALSE; } BOOL bResult = TRUE; ULONG length = sizeof(UCHAR); bResult = WinUsb_QueryDeviceInformation(hDeviceHandle, DEVICE_SPEED, &length, pDeviceSpeed); if (!bResult) { sprintf_s(s, sizeof(s), "nvUSB.lib: Error getting device speed: %d.\n", GetLastError()); OutputDebugString((LPCSTR)s); goto done; } /* if (*pDeviceSpeed == LowSpeed) { sprintf_s(s, sizeof(s), "nvUSB.lib: Device speed: %d (Low speed).\n", *pDeviceSpeed); OutputDebugString((LPCSTR)s); goto done; } if (*pDeviceSpeed == FullSpeed) { sprintf_s(s, sizeof(s), "nvUSB.lib: Device speed: %d (Full speed).\n", *pDeviceSpeed); OutputDebugString((LPCSTR)s); goto done; } */ if (*pDeviceSpeed == 1) { //---!! printf("Device speed: %d - Full speed or lower (initial documentation on MSDN was wrong).\n", *pDeviceSpeed); sprintf_s(s, sizeof(s), "nvUSB.lib: Device speed: %d (Full speed or lower).\n", *pDeviceSpeed); OutputDebugString((LPCSTR)s); goto done; } if (*pDeviceSpeed == HighSpeed) { sprintf_s(s, sizeof(s), "nvUSB.lib: Device speed: %d (High speed).\n", *pDeviceSpeed); OutputDebugString((LPCSTR)s); goto done; } sprintf_s(s, sizeof(s), "nvUSB.lib: Exit from GetUSBDeviceSpeed() \n"); OutputDebugString((LPCSTR)s); done: return bResult; } // End of GetUSBDeviceSpeed() /* //----------------------------------------------------------------------------- // QueryDeviceEndpoints() // // Parameters: // hDeviceHandle : WinUSB Interface Handle // pipeid : Pipe ID returned // // Return Values: // true : success // false: fail // // Remarks: // Function to check end points and get pipe ID //----------------------------------------------------------------------------- */ BOOL CUsbPCECGHelper::QueryDeviceEndpoints(WINUSB_INTERFACE_HANDLE hDeviceHandle, PIPE_ID* pipeid) { char s[256]; sprintf_s(s, sizeof(s), "nvUSB.lib: Enter to QueryDeviceEndpoints() \n"); OutputDebugString((LPCSTR)s); if (hDeviceHandle == INVALID_HANDLE_VALUE) { return FALSE; } BOOL bResult = TRUE; USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; ZeroMemory(&InterfaceDescriptor, sizeof(USB_INTERFACE_DESCRIPTOR)); WINUSB_PIPE_INFORMATION_EX Pipe; ZeroMemory(&Pipe, sizeof(WINUSB_PIPE_INFORMATION_EX)); //WINUSB_PIPE_INFORMATION Pipe; ZeroMemory(&Pipe, sizeof(WINUSB_PIPE_INFORMATION)); bResult = WinUsb_QueryInterfaceSettings(hDeviceHandle, 0, &InterfaceDescriptor); if (bResult) { for (int index = 0; index < InterfaceDescriptor.bNumEndpoints; index++) { bResult = WinUsb_QueryPipeEx(hDeviceHandle, 0, index, &Pipe); //bResult = WinUsb_QueryPipe(hDeviceHandle, 0, index, &Pipe); if (bResult) { if (Pipe.PipeType == UsbdPipeTypeControl) { if (USB_ENDPOINT_DIRECTION_IN(Pipe.PipeId)) { sprintf_s(s, sizeof(s), "nvUSB.lib: Endpoint index: %d Pipe type: Control IN Pipe ID: %d.\n", index, Pipe.PipeId); OutputDebugString((LPCSTR)s); } if (USB_ENDPOINT_DIRECTION_OUT(Pipe.PipeId)) { sprintf_s(s, sizeof(s), "nvUSB.lib: Endpoint index: %d Pipe type: Control OUT Pipe ID: %d.\n", index, Pipe.PipeId); OutputDebugString((LPCSTR)s); } } if (Pipe.PipeType == UsbdPipeTypeIsochronous) { if (USB_ENDPOINT_DIRECTION_IN(Pipe.PipeId)) { //Printout for ECGUSB1D-EX : //nvUSB.lib: Endpoint index: 0 Pipe type: Isochronous IN Pipe ID: 129. sprintf_s(s, sizeof(s), "nvUSB.lib: Endpoint index: %d Pipe type: Isochronous IN Pipe ID: %d.\n", index, Pipe.PipeId); OutputDebugString((LPCSTR)s); pipeid->Iso_Pipe[0].PipeType = Pipe.PipeType; pipeid->Iso_Pipe[0].PipeId = Pipe.PipeId; pipeid->Iso_Pipe[0].Interval = Pipe.Interval; pipeid->Iso_Pipe[0].MaximumPacketSize = Pipe.MaximumPacketSize; pipeid->Iso_Pipe[0].index = index; pipeid->Iso_Pipe[0].MaximumBytesPerInterval = Pipe.MaximumBytesPerInterval; //Printout for ECGUSB1D-EX : //nvUSB.lib: Type=1 , Interval=1 , MaximumPacketSize=24 ,MaximumBytesPerInterval=24 sprintf_s(s, sizeof(s), "nvUSB.lib: Type=%d , Interval=%d , MaximumPacketSize=%d ,MaximumBytesPerInterval=%d\n", Pipe.PipeType, Pipe.Interval, Pipe.MaximumPacketSize, Pipe.MaximumBytesPerInterval ); OutputDebugString((LPCSTR)s); /* MaximumPacketSize The maximum size, in bytes, of the packets that are transmitted on the pipe. MaximumBytesPerInterval The maximum number of bytes that can be transmitted in single interval. This value may be a larger than the MaximumPacketSize value on high-bandwidth, high-speed periodic endpoints and SuperSpeed periodic endpoints, such as isochronous endpoints. */ } if (USB_ENDPOINT_DIRECTION_OUT(Pipe.PipeId)) { sprintf_s(s, sizeof(s), "nvUSB.lib: Endpoint index: %d Pipe type: Isochronous OUT Pipe ID: %d.\n", index, Pipe.PipeId); OutputDebugString((LPCSTR)s); pipeid->Iso_Pipe[1].PipeType = Pipe.PipeType; pipeid->Iso_Pipe[1].PipeId = Pipe.PipeId; pipeid->Iso_Pipe[1].Interval = Pipe.Interval; pipeid->Iso_Pipe[1].MaximumPacketSize = Pipe.MaximumPacketSize; pipeid->Iso_Pipe[1].index = index; pipeid->Iso_Pipe[1].MaximumBytesPerInterval = Pipe.MaximumBytesPerInterval; } } if (Pipe.PipeType == UsbdPipeTypeBulk) { if (USB_ENDPOINT_DIRECTION_IN(Pipe.PipeId)) { sprintf_s(s, sizeof(s), "nvUSB.lib: Endpoint index: %d Pipe type: Bulk IN Pipe ID: %d.\n", index, Pipe.PipeId); OutputDebugString((LPCSTR)s); pipeid->Bulk_Pipe[0].PipeType = Pipe.PipeType; pipeid->Bulk_Pipe[0].PipeId = Pipe.PipeId; pipeid->Bulk_Pipe[0].Interval = Pipe.Interval; pipeid->Bulk_Pipe[0].MaximumPacketSize = Pipe.MaximumPacketSize; pipeid->Bulk_Pipe[0].index = index; pipeid->Bulk_Pipe[0].MaximumBytesPerInterval = Pipe.MaximumBytesPerInterval; } if (USB_ENDPOINT_DIRECTION_OUT(Pipe.PipeId)) { sprintf_s(s, sizeof(s), "nvUSB.lib: Endpoint index: %d Pipe type: Bulk OUT Pipe ID: %d.\n", index, Pipe.PipeId); OutputDebugString((LPCSTR)s); pipeid->Bulk_Pipe[1].PipeType = Pipe.PipeType; pipeid->Bulk_Pipe[1].PipeId = Pipe.PipeId; pipeid->Bulk_Pipe[1].Interval = Pipe.Interval; pipeid->Bulk_Pipe[1].MaximumPacketSize = Pipe.MaximumPacketSize; pipeid->Bulk_Pipe[1].index = index; pipeid->Bulk_Pipe[1].MaximumBytesPerInterval = Pipe.MaximumBytesPerInterval; } } if (Pipe.PipeType == UsbdPipeTypeInterrupt) { if (USB_ENDPOINT_DIRECTION_IN(Pipe.PipeId)) { sprintf_s(s, sizeof(s), "nvUSB.lib: Endpoint index: %d Pipe type: Int IN Pipe ID: %d.\n", index, Pipe.PipeId); OutputDebugString((LPCSTR)s); pipeid->Int_Pipe[0].PipeType = Pipe.PipeType; pipeid->Int_Pipe[0].PipeId = Pipe.PipeId; pipeid->Int_Pipe[0].Interval = Pipe.Interval; pipeid->Int_Pipe[0].MaximumPacketSize = Pipe.MaximumPacketSize; pipeid->Int_Pipe[0].index = index; pipeid->Int_Pipe[0].MaximumBytesPerInterval = Pipe.MaximumBytesPerInterval; } if (USB_ENDPOINT_DIRECTION_OUT(Pipe.PipeId)) { sprintf_s(s, sizeof(s), "nvUSB.lib: Endpoint index: %d Pipe type: Int OUT Pipe ID: %d.\n", index, Pipe.PipeId); OutputDebugString((LPCSTR)s); pipeid->Int_Pipe[1].PipeType = Pipe.PipeType; pipeid->Int_Pipe[1].PipeId = Pipe.PipeId; pipeid->Int_Pipe[1].Interval = Pipe.Interval; pipeid->Int_Pipe[1].MaximumPacketSize = Pipe.MaximumPacketSize; pipeid->Int_Pipe[1].index = index; pipeid->Int_Pipe[1].MaximumBytesPerInterval = Pipe.MaximumBytesPerInterval; } } } else { continue; } } } //done: return bResult; } // End of QueryDeviceEndpoints() PRING_BUFFER CUsbPCECGHelper::AllocRingBuffer( SIZE_T Size ) { PRING_BUFFER ringBuffer = NULL; ringBuffer = new RING_BUFFER[sizeof(RING_BUFFER)]; if (!ringBuffer) return NULL; ringBuffer->buffer = new UCHAR[Size]; if (!ringBuffer->buffer) { free(ringBuffer); return NULL; } ringBuffer->Size = Size; ringBuffer->Base = ringBuffer->buffer; ringBuffer->End = ringBuffer->buffer + Size; ringBuffer->Head = ringBuffer->buffer; ringBuffer->Tail = ringBuffer->buffer; ringBuffer->inPtr = ringBuffer->buffer; ringBuffer->outPtr = ringBuffer->buffer; ringBuffer->totalSize = Size; ringBuffer->currentSize = 0; // KeInitializeSpinLock(&ringBuffer->spinLock); return ringBuffer; } VOID CUsbPCECGHelper::FreeRingBuffer( PRING_BUFFER ringBuffer ) { free(ringBuffer->buffer); free(ringBuffer); } VOID CUsbPCECGHelper::RingBufferGetAvailableSpace( PRING_BUFFER ringBuffer, SIZE_T* AvailableSpace ) { PUCHAR headSnapshot = NULL; PUCHAR tailSnapshot = NULL; PUCHAR tailPlusOne = NULL; if (!AvailableSpace) return; // ASSERT(AvailableSpace); // // Take a snapshot of the head and tail pointers. We will compute the // available space based on this snapshot. This is safe to do in a // single-producer, single-consumer model, because - // * A producer will call GetAvailableSpace() to determine whether // there is enough space to write the data it is trying to write. // The only other thread that could modify the amount of space // available is the consumer thread, which can only increase the // amount of space available. Hence it is safe for the producer // to write based on this snapshot. // * A consumer thread will call GetAvailableSpace() to determine // whether there is enough data in the buffer for it to read. // (Available data = Buffer size - Available space). The only // other thread that could modify the amount of space available // is the producer thread, which can only decrease the amount of // space available (thereby increasing the amount of data // available. Hence it is safe for the consumer to read based on // this snapshot. // headSnapshot = ringBuffer->Head; tailSnapshot = ringBuffer->Tail; // // In order to distinguish between a full buffer and an empty buffer, // we always leave the last byte of the buffer unused. So, an empty // buffer is denoted by - // tail == head // ... and a full buffer is denoted by - // (tail+1) == head // tailPlusOne = ((tailSnapshot + 1) == ringBuffer->End) ? ringBuffer->Base : (tailSnapshot + 1); if (tailPlusOne == headSnapshot) { // // Buffer full // *AvailableSpace = 0; } else if (tailSnapshot == headSnapshot) { // // Buffer empty // The -1 in the computation below is to account for the fact that // we always leave the last byte of the ring buffer unused in order // to distinguish between an empty buffer and a full buffer. // *AvailableSpace = ringBuffer->Size - 1; } else { if (tailSnapshot > headSnapshot) { // // Data has not wrapped around the end of the buffer // The -1 in the computation below is to account for the fact // that we always leave the last byte of the ring buffer unused // in order to distinguish between an empty buffer and a full // buffer. // *AvailableSpace = ringBuffer->Size - (tailSnapshot - headSnapshot) - 1; } else { // // Data has wrapped around the end of the buffer // The -1 in the computation below is to account for the fact // that we always leave the last byte of the ring buffer unused // in order to distinguish between an empty buffer and a full // buffer. // *AvailableSpace = (headSnapshot - tailSnapshot) - 1; } } } VOID CUsbPCECGHelper::RingBufferGetAvailableData( PRING_BUFFER ringBuffer, SIZE_T* AvailableData ) { SIZE_T availableSpace; // KIRQL oldIrql; if (!AvailableData) return; //ASSERT(AvailableData); // KeAcquireSpinLock(&ringBuffer->spinLock, &oldIrql); RingBufferGetAvailableSpace(ringBuffer, &availableSpace); // KeReleaseSpinLock(&ringBuffer->spinLock, oldIrql); // // The -1 in the arithmetic below accounts for the fact that we always // keep 1 byte of the ring buffer unused in order to distinguish // between a full buffer and an empty buffer. // *AvailableData = ringBuffer->Size - availableSpace - 1; } SIZE_T CUsbPCECGHelper::ReadRingBuffer( PRING_BUFFER ringBuffer, PUCHAR readBuffer, SIZE_T numberOfBytesToRead ) /* Routine Description: This routine reads data from a ring buffer. Arguments: ringBuffer - pointer to a ring buffer structure readBuffer - pointer to a user supplied buffer to transfer data into numberOfBytesToRead - number of bytes to read from the ring buffer Return Value: ULONG - number of bytes read. May be smaller than requested number of bytes. */ { SIZE_T byteCount; // KIRQL oldIrql; SIZE_T l_currentsize; // KeAcquireSpinLock(&ringBuffer->spinLock, &oldIrql); l_currentsize = ringBuffer->currentSize; // KeReleaseSpinLock(&ringBuffer->spinLock, oldIrql); // MarlinUSB_DbgPrint(1, ("Marlin.sys: ReadRingBuffer() enter\n")); if (numberOfBytesToRead > ringBuffer->totalSize) return 0; if (l_currentsize == 0) return 0; if (numberOfBytesToRead > l_currentsize) byteCount = l_currentsize; else byteCount = numberOfBytesToRead; // // two cases. Read either wraps or it doesn't. // Handle the non-wrapped case first // if ((ringBuffer->outPtr + byteCount - 1) < (ringBuffer->buffer + ringBuffer->totalSize)) { // MarlinUSB_DbgPrint(1, ("Marlin.sys: ReadRingBuffer() about to copy a\n")); RtlCopyMemory(readBuffer, ringBuffer->outPtr, byteCount); ringBuffer->outPtr += byteCount; if (ringBuffer->outPtr == ringBuffer->buffer + ringBuffer->totalSize) ringBuffer->outPtr = ringBuffer->buffer; } // now handle the wrapped case else { //ULONG fragSize; //Boris, 18.04.2021 (Get error: conversion from '__int64' to 'ULONG', possible loss of data) SIZE_T fragSize; // MarlinUSB_DbgPrint(1, ("Marlin.sys: ReadRingBuffer() about to copy b\n")); // get the first half of the read //Boris, 16.02.2009 ,WDK 6001.18002 build //fragSize = ringBuffer->buffer + ringBuffer->totalSize - ringBuffer->outPtr; //fragSize = ringBuffer->totalSize + (ULONG)(ringBuffer->buffer - ringBuffer->outPtr); //Boris, 18.04.2021 fragSize = (ringBuffer->totalSize + ringBuffer->buffer) - ringBuffer->outPtr; RtlCopyMemory(readBuffer, ringBuffer->outPtr, fragSize); // now get the rest RtlCopyMemory(readBuffer + fragSize, ringBuffer->buffer, byteCount - fragSize); ringBuffer->outPtr = ringBuffer->buffer + byteCount - fragSize; } // // update the current size of the ring buffer. Use spinlock to insure // atomic operation. // // KeAcquireSpinLock(&ringBuffer->spinLock, &oldIrql); ringBuffer->currentSize -= byteCount; // KeReleaseSpinLock(&ringBuffer->spinLock, oldIrql); // MarlinUSB_DbgPrint(1, ("Marlin.sys: ReadRingBuffer() exit\n")); return byteCount; /* SIZE_T availableData=0; SIZE_T dataFromCurrToEnd; SIZE_T DataSize=0; SIZE_T BytesCopied = 0; if(!readBuffer) return 0; if (numberOfBytesToRead == 0) return 0; if (ringBuffer->Head >= ringBuffer->End) return 0; // // Get the amount of data available in the buffer // RingBufferGetAvailableData(ringBuffer, &availableData); if (availableData == 0) return 0; DataSize = numberOfBytesToRead; if (DataSize > availableData) { DataSize = availableData; } BytesCopied = DataSize; if ((ringBuffer->Head + DataSize) > ringBuffer->End) { // // The data requested by the caller is wrapped around the end of the // buffer. So we'll do the copy in two steps - // * Copy X bytes from the current position to the end buffer into // the caller's buffer // * Copy (DataSize - X) bytes from the beginning to the buffer into // the caller's buffer // // // The first step of the copy ... // dataFromCurrToEnd = ringBuffer->End - ringBuffer->Head; RtlCopyMemory(readBuffer, ringBuffer->Head, dataFromCurrToEnd); readBuffer += dataFromCurrToEnd; DataSize -= dataFromCurrToEnd; // // The second step of the copy ... // RtlCopyMemory(readBuffer, ringBuffer->Base, DataSize); // // Advance the head pointer // ringBuffer->Head = ringBuffer->Base + DataSize; } else { // // The data in the buffer is NOT wrapped around the end of the buffer. // Simply copy the data over to the caller's buffer in a single step. // RtlCopyMemory(readBuffer, ringBuffer->Head, DataSize); // // Advance the head pointer // ringBuffer->Head += DataSize; if (ringBuffer->Head == ringBuffer->End) { // // We have exactly reached the end of the buffer. The next // read should wrap around and start from the beginning. // ringBuffer->Head = ringBuffer->Base; } } if (!(ringBuffer->Head < ringBuffer->End)) return 0; return BytesCopied; */ } SIZE_T CUsbPCECGHelper::WriteRingBuffer( PRING_BUFFER ringBuffer, PUCHAR writeBuffer, SIZE_T numberOfBytesToWrite ) /* Routine Description: This routine writes data to a ring buffer. If the requested write size exceeds available space in the ring buffer, then the write is rejected. Arguments: ringBuffer - pointer to a ring buffer structure readBuffer - pointer to a user supplied buffer of data to copy to the ring buffer numberOfBytesToRead - number of bytes to write to the ring buffer Return Value: ULONG - number of bytes written. */ { SIZE_T byteCount; // KIRQL oldIrql; SIZE_T l_currentsize; // KeAcquireSpinLock(&ringBuffer->spinLock, &oldIrql); l_currentsize = ringBuffer->currentSize; // KeReleaseSpinLock(&ringBuffer->spinLock, oldIrql); if (numberOfBytesToWrite > (ringBuffer->totalSize - l_currentsize)) { //MarlinUSB_DbgPrint(1, ("Marlin.sys: WriteRingBuffer() OVERFLOW\n")); return 0; } byteCount = numberOfBytesToWrite; // // two cases. Write either wraps or it doesn't. // Handle the non-wrapped case first // if ((ringBuffer->inPtr + byteCount - 1) < (ringBuffer->buffer + ringBuffer->totalSize)) { RtlCopyMemory(ringBuffer->inPtr, writeBuffer, byteCount); ringBuffer->inPtr += byteCount; if (ringBuffer->inPtr == ringBuffer->buffer + ringBuffer->totalSize) ringBuffer->inPtr = ringBuffer->buffer; } // now handle the wrapped case else { //ULONG fragSize; //Boris, 18.04.2021 (Get error: conversion from '__int64' to 'ULONG', possible loss of data) SIZE_T fragSize; // write the first fragment //Boris, 16.02.2009 ,WDK 6001.18002 build //fragSize = ringBuffer->buffer + ringBuffer->totalSize - ringBuffer->inPtr; //fragSize = ringBuffer->totalSize + (ULONG)(ringBuffer->buffer - ringBuffer->inPtr); //Boris, 18.04.2021 (Get error: conversion from '__int64' to 'ULONG', possible loss of data) fragSize = (ringBuffer->totalSize + ringBuffer->buffer) - ringBuffer->inPtr; RtlCopyMemory(ringBuffer->inPtr, writeBuffer, fragSize); // now write the rest RtlCopyMemory(ringBuffer->buffer, writeBuffer + fragSize, byteCount - fragSize); ringBuffer->inPtr = ringBuffer->buffer + byteCount - fragSize; } // // update the current size of the ring buffer. Use spinlock to insure // atomic operation. // // KeAcquireSpinLock(&ringBuffer->spinLock, &oldIrql); ringBuffer->currentSize += byteCount; // KeReleaseSpinLock(&ringBuffer->spinLock, oldIrql); //MarlinUSB_DbgPrint(1, ("Marlin.sys: WriteRingBuffer() %d bytes\n", byteCount)); return byteCount; /* SIZE_T availableSpace = 0; SIZE_T spaceFromCurrToEnd; SIZE_T bytesToCopy; SIZE_T bytesCopied=0; KIRQL oldIrql; if (!writeBuffer) return 0; if (numberOfBytesToWrite == 0) return 0; if (ringBuffer->Tail >= ringBuffer->End) return 0; // // Get the amount of space available in the buffer // KeAcquireSpinLock(&ringBuffer->spinLock, &oldIrql); RingBufferGetAvailableSpace(ringBuffer, &availableSpace); KeReleaseSpinLock(&ringBuffer->spinLock, oldIrql); // // If there is not enough space to fit in all the data passed in by the // caller then copy as much as possible and throw away the rest // if (availableSpace < numberOfBytesToWrite) { bytesToCopy = availableSpace; } else { bytesToCopy = numberOfBytesToWrite; } bytesCopied = bytesToCopy; if (bytesToCopy) { // // The buffer has some space at least // if ((ringBuffer->Tail + bytesToCopy) > ringBuffer->End) { // // The data being written will wrap around the end of the buffer. // So the copy has to be done in two steps - // * X bytes from current position to end of the buffer // * the remaining (bytesToCopy - X) from the start of the buffer // // // The first step of the copy ... // spaceFromCurrToEnd = ringBuffer->End - ringBuffer->Tail; RtlCopyMemory(ringBuffer->Tail, writeBuffer, spaceFromCurrToEnd); writeBuffer += spaceFromCurrToEnd; bytesToCopy -= spaceFromCurrToEnd; // // The second step of the copy ... // RtlCopyMemory(ringBuffer->Base, writeBuffer, bytesToCopy); // // Advance the tail pointer // ringBuffer->Tail = ringBuffer->Base + bytesToCopy; } else { // // Data does NOT wrap around the end of the buffer. Just copy it // over in a single step // RtlCopyMemory(ringBuffer->Tail, writeBuffer, bytesToCopy); // // Advance the tail pointer // ringBuffer->Tail += bytesToCopy; if (ringBuffer->Tail == ringBuffer->End) { // // We have exactly reached the end of the buffer. The next // write should wrap around and start from the beginning. // ringBuffer->Tail = ringBuffer->Base; } } if (!(ringBuffer->Tail < ringBuffer->End)) return 0; } return bytesCopied; */ } //========================================================================================================================================================== #define ISOCH_DATA_SIZE_MS 10 #define ISOCH_TRANSFER_COUNT 2 //will need to be at least 2 /* * My device sends one sample of 2 bytes every 1ms .. => data sample rate = 1000s/s * * Problem !! * Only Transfer 1 has the data all next (ISOCH_TRANSFER_COUNT) are empty * As a result i see data arriving at sample rate of 1000 / ISOCH_TRANSFER_COUNT in Read application * * Why ????? * nvUSB.lib: Current Frame number=261744397 nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer. nvUSB.lib: bRead() Transfer 1 completed. Read 100 bytes. nvUSB.lib: Current Frame number=261744447 nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer. nvUSB.lib: bRead() Transfer 2 completed. Read 0 bytes. <-- ?? nvUSB.lib: Current Frame number=261744497 nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer. nvUSB.lib: bRead() Transfer 1 completed. Read 100 bytes. nvUSB.lib: Current Frame number=261744547 nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer. nvUSB.lib: bRead() Transfer 2 completed. Read 0 bytes. <--- ?? nvUSB.lib: Current Frame number=261744597 nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer. nvUSB.lib: bRead() Transfer 1 completed. Read 100 bytes. nvUSB.lib: Current Frame number=261744647 nvUSB.lib: bRead() Requested 1200 bytes in 50 packets per transfer. nvUSB.lib: bRead() Transfer 2 completed. Read 0 bytes. nvUSB.lib: Current Frame number=261744697BorisW560Nov 25, 2021Copper Contributor204Views0likes0CommentsUSB Companion Controller Problem
I'm hoping I can find some help here. I have multiple USB 3.0 controllers, both on my motherboard and on two PCI-E 1.0 boards, and all of them recognize USB 3.0 devices as USB 2.0. I am including two USB Viewer snapshots that show the device (Samsung Odyssey Plus WMR headset) plugged into two different USB sources. The tree viewer does show the companion USB 3.0 ports, but neither the motherboard nor the PCI-E boards will connect my device to the USB 3.0 controllers. I don't think its a hardware issue because this issue is happening on two different types of hardware. This has effectively made the USB 3.0 audio headphones on the WMR headset unusable. I have updated my BIOS and all of my drivers, and cannot find the problem. I've also found posts like this (Reasons to avoid companion controllers - Microsoft Tech Community) that urge hardware developers not to use companion controllers. Any suggested solutions would be very much appreciated. Thank you!Paul_GreggFeb 21, 2021Copper Contributor255Views0likes0CommentsCapturing HID data in ETW traces
Can someone give some current hints on how to capture HID data for a USB device? I started this quest using Logman to create an ETW session using the Microsoft-Windows-USB-USBPORT and Microsoft-Windows-USB-USBHUB providers from Windows 10, but although I get a ETL file with USB information in it I'm not seeing the actual data going to/from the device. I then found a blog recommending to use the GUIDs for HidClass and HidUSB, but I get the same result then as well. This article (https://techcommunity.microsoft.com/t5/microsoft-usb-blog/how-to-capture-and-read-hid-traces-in-windows-8-1/ba-p/270839) doesn't go into much depth on viewing the ETL file, and I see that both Network Monitor and Message Analyser have been EOLd. Is TraceView really the only way we're meant to view the files now? And where does one go in 2021 to get the most recent copy?PaulAttrydeFeb 12, 2021Copper Contributor279Views0likes0CommentsNo admin rights for external hard drives and USB
I have a USB drive on the laptop. Strangely, I have no access to external drives. Keyboard and connection with the mobile phone via drive is possible. I have the latest Windows update. I suspected the problem was with the security settings or registers. Unfortunately, I have no idea what I can do to solve the problem. Windows support couldn't help either.ChleeNSep 04, 2020Copper Contributor236Views0likes0Commentsslow USB 2.0 bulk transfer on Windows 10
We are moving our USB 2.0 device from a custom driver to WinUSB. The device must continue to work with both the older driver and the new WinUSB approach so changing to isochronous for example would not be possible. In our testing we are seeing significantly slower bulk transfer speeds on Windows 10 vs Windows 7 - Windows 10 takes approximately 60% longer to transfer. This same slowdown occurs whether we use the older custom driver or WinUSB. Our data is not large = ~10 Mb/s (1 Mb every 10 Hz revolution, i.e. 100 ms) In our base tests, we transfer two blocks of 470K, one block of 54k, and a final block of 107k. On Windows 7, each 470k blocks take just over 18 ms to transfer - overall ~43 ms for 1.1 Mb transfer On Windows 10, each 470k blocks take just over 29 ms to transfer == 61% longer - overall ~70 ms for 1.1 Mb transfer These times were verified using tracing on the device running under JTAG control as well as a USB 3 analyzer. Is there any knowledge, any information, any suggestions for the cause and possible solution for this significant difference in bulk transfer speeds? TIA!megabiteMar 11, 2020Copper Contributor491Views0likes0Commentsslow USB bulk transfers on Windows 10
We are moving our USB 2.0 device from a custom driver to WinUSB. The device must continue to work with both the older driver and the new WinUSB approach so changing to isochronous for example would not be possible. In our testing we are seeing significantly slower bulk transfer speeds on Windows 10 vs Windows 7 - Windows 10 takes approximately 60% longer to transfer. This same slowdown occurs whether we use the older custom driver or WinUSB. That seems to point to something in the OS implementation or interpretation. Our data is not large = ~10 Mb/s (1 Mb every 10 Hz revolution, i.e. 100 ms) In our base tests, we transfer two blocks of 470K, one block of 54k, and a final block of 107k. On Windows 7, each 470k blocks take just over 18 ms to transfer - overall transfer of 1.1 Mb takes about 43 ms On Windows 10, each 470k blocks take just over 29 ms to transfer == 61% longer - overall transfer of 1.1 Mb takes about 70 ms Is there any knowledge, any information, any suggestions for the cause and possible solution for this significant difference in bulk transfer speeds? TIA!megabiteMar 11, 2020Copper Contributor495Views0likes0Comments
Resources
Tags
- usb1 Topic
- Mixer Unit1 Topic
- audio1 Topic
- Audio devices1 Topic
- Mixer1 Topic
- USB Control1 Topic