Forum Discussion
winusb 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=261744697