mirror of
https://github.com/arehnman/yttrium-virtio-gpu.git
synced 2026-11-07 02:06:32 +00:00
215 lines
5.0 KiB
C++
215 lines
5.0 KiB
C++
#include "StdAfx.h"
|
|
|
|
SerialPort::SerialPort(wstring LinkName, PnPControl *ptr)
|
|
{
|
|
Name = LinkName;
|
|
Notify = NULL;
|
|
NotificationPair.first = NULL;
|
|
NotificationPair.second = NULL;
|
|
Reference = 0;
|
|
Handle = CreateFile(Name.c_str(),
|
|
GENERIC_WRITE | GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if (Handle == INVALID_HANDLE_VALUE)
|
|
{
|
|
return;
|
|
}
|
|
ULONG ulReturnedLength = 0;
|
|
BYTE buf[512];
|
|
PVIRTIO_PORT_INFO inf = (PVIRTIO_PORT_INFO)buf;
|
|
BOOL res = DeviceIoControl(Handle, IOCTL_GET_INFORMATION, NULL, 0, buf, sizeof(buf), &ulReturnedLength, NULL);
|
|
if (res == FALSE)
|
|
{
|
|
printf("Error. DeviceIoControl failed %d.\n", GetLastError());
|
|
return;
|
|
}
|
|
HostConnected = inf->HostConnected;
|
|
string s = inf->Name;
|
|
|
|
SymbolicName.resize(s.length(), L' ');
|
|
copy(s.begin(), s.end(), SymbolicName.begin());
|
|
|
|
Control = ptr;
|
|
CloseHandle(Handle);
|
|
Handle = INVALID_HANDLE_VALUE;
|
|
}
|
|
SerialPort::~SerialPort()
|
|
{
|
|
ClosePort();
|
|
}
|
|
void SerialPort::AddRef()
|
|
{
|
|
InterlockedIncrement(&Reference);
|
|
}
|
|
void SerialPort::Release()
|
|
{
|
|
if (InterlockedDecrement(&Reference) == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
}
|
|
BOOL SerialPort::OpenPort()
|
|
{
|
|
Handle = CreateFile(Name.c_str(), GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
|
if (Handle == INVALID_HANDLE_VALUE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
ULONG ulReturnedLength = 0;
|
|
BYTE buf[512];
|
|
PVIRTIO_PORT_INFO inf = (PVIRTIO_PORT_INFO)buf;
|
|
BOOL res = DeviceIoControl(Handle, IOCTL_GET_INFORMATION, NULL, 0, buf, sizeof(buf), &ulReturnedLength, NULL);
|
|
if (res == FALSE)
|
|
{
|
|
printf("Error. DeviceIoControl failed %d.\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
HostConnected = inf->HostConnected;
|
|
Notify = Control->RegisterHandleNotify(Handle);
|
|
return TRUE;
|
|
}
|
|
void SerialPort::ClosePort()
|
|
{
|
|
if (Notify != NULL)
|
|
{
|
|
UnregisterDeviceNotification(Notify);
|
|
Notify = NULL;
|
|
}
|
|
if (Handle != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(Handle);
|
|
Handle = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
BOOL SerialPort::ReadPort(PVOID buf, size_t *len)
|
|
{
|
|
BOOL res = FALSE;
|
|
DWORD ret;
|
|
DWORD bytes = (DWORD)(*len);
|
|
OVERLAPPED ol = {0};
|
|
|
|
if (buf == NULL || *len == 0)
|
|
{
|
|
*len = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
if (ol.hEvent == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
res = ReadFile(Handle, buf, bytes, &ret, &ol);
|
|
if (!res)
|
|
{
|
|
DWORD err = GetLastError();
|
|
if (err != ERROR_IO_PENDING)
|
|
{
|
|
printf("Read failed but isn't delayed. Error = %d\n", err);
|
|
res = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (!GetOverlappedResult(Handle, &ol, &ret, TRUE))
|
|
{
|
|
res = FALSE;
|
|
}
|
|
else
|
|
{
|
|
*len = ret;
|
|
res = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*len = ret;
|
|
res = TRUE;
|
|
}
|
|
|
|
CloseHandle(ol.hEvent);
|
|
return res;
|
|
}
|
|
|
|
BOOL SerialPort::WritePort(PVOID buf, size_t *len)
|
|
{
|
|
BOOL res = FALSE;
|
|
ULONG ret = 0;
|
|
DWORD bytes = (DWORD)(*len);
|
|
OVERLAPPED ol = {0};
|
|
|
|
if (buf == NULL || *len == 0)
|
|
{
|
|
*len = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
if (ol.hEvent == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
res = WriteFile(Handle, buf, bytes, &ret, &ol);
|
|
if (!res)
|
|
{
|
|
DWORD err = GetLastError();
|
|
if (err != ERROR_IO_PENDING)
|
|
{
|
|
printf("Write failed but isn't delayed. Error = %d\n", err);
|
|
res = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (!GetOverlappedResult(Handle, &ol, &ret, TRUE))
|
|
{
|
|
res = FALSE;
|
|
}
|
|
else
|
|
{
|
|
*len = ret;
|
|
res = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*len = ret;
|
|
res = TRUE;
|
|
}
|
|
|
|
CloseHandle(ol.hEvent);
|
|
return res;
|
|
}
|
|
|
|
void SerialPort::handleEvent(const PnPControl &ref)
|
|
{
|
|
PnPNotification Notification = ref.GetNotification();
|
|
switch (Notification.wParam)
|
|
{
|
|
case DBT_CUSTOMEVENT:
|
|
{
|
|
PDEV_BROADCAST_HANDLE pHdr;
|
|
pHdr = (PDEV_BROADCAST_HANDLE)Notification.lParam;
|
|
if (IsEqualGUID(GUID_VIOSERIAL_PORT_CHANGE_STATUS, pHdr->dbch_eventguid) &&
|
|
(pHdr->dbch_handle == Handle))
|
|
{
|
|
PVIRTIO_PORT_STATUS_CHANGE pEventInfo = (PVIRTIO_PORT_STATUS_CHANGE)pHdr->dbch_data;
|
|
HostConnected = pEventInfo->Reason;
|
|
if (NotificationPair.first)
|
|
{
|
|
NotificationPair.first(NotificationPair.second);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|