Files
yttrium-virtio-gpu/vioserial/app/device.cpp
T
Yuri Benditovich 064c9b2946 vioser-test: add flexibility to the test
If the port can't be open (probably opened by vdservice), go to
the next one.
Add ability to increase write buffer size and send
entire buffer filled by characters without getting data from the
console.
This helps testing corner cases of vioser.sys, for example:
configure additional test port port with tcp socket backend,
connect to it with 'nc', press ^Z to suspend the 'nc' and send
several large (512K) buffers.
At some point the write does not return immediately and closing
test application causes cancellation flow.
Another scenarion: if 1M buffer sent, the driver fails the operation
due to too large SG table.

Signed-off-by: Yuri Benditovich <[email protected]>
2019-12-11 13:55:04 +01:00

343 lines
7.7 KiB
C++

#include "device.h"
#include "assert.h"
CDevice::CDevice()
{
m_hDevice = INVALID_HANDLE_VALUE;
}
CDevice::~CDevice()
{
if (m_hDevice != INVALID_HANDLE_VALUE)
{
CloseHandle(m_hDevice);
m_hDevice = INVALID_HANDLE_VALUE;
}
}
BOOL CDevice::Init(BOOL ovrl, UINT index)
{
PWCHAR DevicePath = NULL;
if ((DevicePath = GetDevicePath(index, (LPGUID)&GUID_VIOSERIAL_PORT)) != NULL)
{
m_hDevice = CreateFile(DevicePath,
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
ovrl ? FILE_FLAG_OVERLAPPED : FILE_ATTRIBUTE_NORMAL,
NULL );
if (m_hDevice != INVALID_HANDLE_VALUE)
{
printf("Open vioserial device %S.\n", DevicePath);
return TRUE;
}
}
DWORD err = GetLastError();
printf("Cannot find vioserial device. %S , error = %d\n", DevicePath, err );
return FALSE;
}
BOOL CDevice::Write(PVOID buf, size_t *size)
{
BOOL res = FALSE;
ULONG ret = 0;
DWORD bytes = *size;
if (!buf) return FALSE;
res = WriteFile ( m_hDevice,
buf,
bytes,
&ret,
NULL
);
if (!res)
{
printf("Cannot write vioserial device.\n");
}
else if ( ret != bytes)
{
printf("Write vioserial device error. written = 0x%x, expected = 0x%x\n", ret, bytes);
*size = ret;
ret = FALSE;
}
return res;
}
BOOL CDevice::WriteEx(PVOID buf, size_t *size)
{
BOOL res = FALSE;
ULONG ret = 0;
DWORD bytes = *size;
OVERLAPPED ol = {0};
assert( buf );
ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!ol.hEvent)
{
printf("Event creation failed.\n");
return FALSE;
}
res = WriteFile ( m_hDevice,
buf,
bytes,
&ret,
&ol
);
if (!res)
{
if (GetLastError() != ERROR_IO_PENDING)
{
printf("Write failed but isn't delayed.\n");
res = FALSE;
}
else
{
if (!GetOverlappedResult(m_hDevice, &ol, &ret, TRUE))
{
res = FALSE;
}
else
{
*size = ret;
res = TRUE;
}
}
}
else
{
*size = ret;
res = TRUE;
}
CloseHandle( ol.hEvent );
return res;
}
BOOL CDevice::Read(PVOID buf, size_t *size)
{
BOOL res = FALSE;
DWORD ret;
DWORD bytes = *size;
if (!buf) return FALSE;
memset(buf, '\0', bytes);
res = ReadFile ( m_hDevice,
buf,
bytes,
&ret,
NULL
);
if (!res)
{
printf ("PerformReadTest: ReadFile failed: "
"Error %d\n", GetLastError());
}
else if ( ret != bytes)
{
printf("Read vioserial device error. get = 0x%x, expected = 0x%x\n", ret, bytes);
*size = ret;
ret = FALSE;
}
return res;
}
BOOL CDevice::ReadEx(PVOID buf, size_t *size)
{
BOOL res = FALSE;
DWORD ret;
DWORD bytes = *size;
OVERLAPPED ol = {0};
assert(buf);
memset(buf, '\0', bytes);
ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!ol.hEvent)
{
printf("Event creation failed.\n");
return FALSE;
}
res = ReadFile ( m_hDevice,
buf,
bytes,
&ret,
&ol
);
if (!res)
{
if (GetLastError() != ERROR_IO_PENDING)
{
printf("Write failed but isn't delayed.\n");
res = FALSE;
}
else
{
if (!GetOverlappedResult(m_hDevice, &ol, &ret, TRUE))
{
res = FALSE;
}
else
{
*size = ret;
res = TRUE;
}
}
}
else
{
*size = ret;
res = TRUE;
}
CloseHandle( ol.hEvent );
return res;
if (!res)
{
printf ("PerformReadTest: ReadFile failed: "
"Error %d\n", GetLastError());
}
else if ( ret != bytes)
{
printf("Read vioserial device error. get = 0x%x, expected = 0x%x\n", ret, bytes);
*size = ret;
ret = FALSE;
}
return res;
}
BOOL CDevice::GetInfo(PVOID buf, size_t *size)
{
BOOL res = FALSE;
DWORD ulOutLength = *size;
ULONG ulReturnedLength = 0;
PVOID pBuffer = NULL;
DWORD err;
printf ("%s, buf = %p, size = %zd\n", __FUNCTION__, buf, *size);
res = DeviceIoControl(
m_hDevice,
IOCTL_GET_INFORMATION,
NULL,
0,
buf,
ulOutLength,
&ulReturnedLength,
NULL
);
if ( !res )
{ err = GetLastError();
if (err != ERROR_MORE_DATA)
{
printf("Ioctl failed with code %d\n", err );
}
}
*size = ulReturnedLength;
return res;
}
PTCHAR CDevice::GetDevicePath(UINT index, IN LPGUID InterfaceGuid )
{
HDEVINFO HardwareDeviceInfo;
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData = NULL;
ULONG Length, RequiredLength = 0;
BOOL bResult;
HardwareDeviceInfo = SetupDiGetClassDevs(
InterfaceGuid,
NULL,
NULL,
(DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)
);
if (HardwareDeviceInfo == INVALID_HANDLE_VALUE)
{
printf("Cannot get class devices.\n");
return NULL;
}
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
bResult = SetupDiEnumDeviceInterfaces(HardwareDeviceInfo,
0,
InterfaceGuid,
index,
&DeviceInterfaceData
);
if (bResult == FALSE) {
printf("Cannot get enumerate device interfaces.\n");
SetupDiDestroyDeviceInfoList(HardwareDeviceInfo);
return NULL;
}
SetupDiGetDeviceInterfaceDetail(
HardwareDeviceInfo,
&DeviceInterfaceData,
NULL,
0,
&RequiredLength,
NULL
);
DeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) LocalAlloc(LMEM_FIXED, RequiredLength);
if (DeviceInterfaceDetailData == NULL)
{
printf("Cannot allocate memory.\n");
SetupDiDestroyDeviceInfoList(HardwareDeviceInfo);
return NULL;
}
DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
Length = RequiredLength;
bResult = SetupDiGetDeviceInterfaceDetail(
HardwareDeviceInfo,
&DeviceInterfaceData,
DeviceInterfaceDetailData,
Length,
&RequiredLength,
NULL
);
if (bResult == FALSE)
{
printf("Cannot get device interface details.\n");
SetupDiDestroyDeviceInfoList(HardwareDeviceInfo);
LocalFree(DeviceInterfaceDetailData);
return NULL;
}
return DeviceInterfaceDetailData->DevicePath;
}