419 lines
9.1 KiB
C++

// Copyright (C) 2004 Intel Corporation
#include <windows.h>
#include <stdio.h>
#include <process.h>
#include <commctrl.h>
#include <setupapi.h>
#include <initguid.h>
#include <tchar.h>
#include <winioctl.h>
#include <errno.h>
#include "HECIWin.h"
#include "HECI_if.h"
#include "resource.h"
/***************************** public functions *****************************/
HECIWin::HECIWin(const GUID guid, bool verbose): HECI(guid, verbose), _handle(INVALID_HANDLE_VALUE)
{
}
HECIWin::~HECIWin()
{
if (_handle != INVALID_HANDLE_VALUE) {
CloseHandle(_handle);
}
}
/*
* Open the related HECI driver file and connect to the FW HECI Client.
*
* Return value:
* True on success.
*/
bool HECIWin::Init()
{
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceDetail = NULL;
HDEVINFO hDeviceInfo;
DWORD bufferSize;
SP_DEVICE_INTERFACE_DATA interfaceData;
LONG ii = 0;
if (_initialized) {
Deinit();
}
// Find all devices that have our interface
hDeviceInfo = SetupDiGetClassDevs((LPGUID)&GUID_DEVINTERFACE_HECI,
NULL,
NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDeviceInfo == INVALID_HANDLE_VALUE) {
if (_verbose) {
_displayHECIError(GET_CLASS_DEVS,GetLastError());
}
return false;
}
// Setup the interface data struct
interfaceData.cbSize = sizeof(interfaceData);
for (ii = 0;
SetupDiEnumDeviceInterfaces(hDeviceInfo,
NULL,
(LPGUID)&GUID_DEVINTERFACE_HECI,
ii,
&interfaceData);
++ii) {
// Found our device instance
if (!SetupDiGetDeviceInterfaceDetail(hDeviceInfo,
&interfaceData,
NULL,
0,
&bufferSize,
NULL)) {
DWORD err = GetLastError();
if (err != ERROR_INSUFFICIENT_BUFFER) {
if (_verbose) {
_displayHECIError(GET_INTERFACE_DETAIL,err);
}
continue;
}
}
// Allocate a big enough buffer to get detail data
deviceDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(bufferSize);
if (deviceDetail == NULL) {
if (_verbose) {
_displayHECIError(ALLOCATE_MEMORY_ERROR,0);
}
continue;
}
// Setup the device interface struct
deviceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
// Try again to get the device interface detail info
if (!SetupDiGetDeviceInterfaceDetail(hDeviceInfo,
&interfaceData,
deviceDetail,
bufferSize,
NULL,
NULL)) {
if (_verbose) {
DWORD err = GetLastError();
_displayHECIError(GET_INTERFACE_DETAIL,err);
}
free(deviceDetail);
deviceDetail = NULL;
continue;
}
break;
}
SetupDiDestroyDeviceInfoList(hDeviceInfo);
if (deviceDetail == NULL) {
if (_verbose) {
_displayHECIError(FIND_HECI_FAILURE,0);
}
return false;
}
_handle = CreateFile(deviceDetail->DevicePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
free(deviceDetail);
if (_handle == INVALID_HANDLE_VALUE) {
if (_verbose) {
_displayHECIError(CREATE_HECI_FILE_FAILURE,GetLastError());
}
return false;
}
_initialized = true;
int result;
HECI_VERSION version;
result = _doIoctl(IOCTL_HECI_GET_VERSION, NULL, NULL, &version, sizeof(version));
if (result != sizeof(version)) {
if (_verbose) {
_displayHECIError(GET_HECI_DRIVER_VERSION_FAILURE,0);
}
Deinit();
return false;
}
if (_verbose) {
_displayHECIData(HECI_DRIVER_VERSION);
_ftprintf(stdout,_T("%d.%d.%d.%d\n"),
version.major, version.minor, version.hotfix, version.build);
}
HECI_CLIENT properties;
result = _doIoctl(IOCTL_HECI_CONNECT_CLIENT, (void*)&_guid,
sizeof(GUID), &properties, sizeof(properties));
if (result != sizeof(properties)) {
if (_verbose) {
_displayHECIError(HECI_CONNECT_TO_PTHI_CLIENT_FAILURE,0);
}
//Deinit();
return false;
}
_bufSize = properties.MaxMessageLength;
return true;
}
/*
* Close the related HECI driver file.
*
* Return value:
* True on success.
*/
void HECIWin::Deinit()
{
if (_handle != INVALID_HANDLE_VALUE) {
CloseHandle(_handle);
_handle = INVALID_HANDLE_VALUE;
}
_bufSize = 0;
_initialized = false;
}
/*
* Receive a message from the FW HECI client.
* Arguments:
* buffer - holds the message to be read.
* len - number of bytes to read.
* timeout - timeout for the read operation.
* Return value:
* The number of read bytes.
*/
int HECIWin::ReceiveMessage(UCHAR *buffer, int len, unsigned long timeout)
{
DWORD bytesRead = 0;
int res;
HANDLE event = NULL;
event = CreateEvent(NULL, FALSE, FALSE, NULL);
OVERLAPPED overlapped;
overlapped.hEvent = event;
overlapped.Offset = 0;
overlapped.OffsetHigh = 0;
res = ReadFile(_handle, buffer, len, &bytesRead, &overlapped);
DWORD error = GetLastError();
if ((0 == res) && (ERROR_IO_PENDING != error)) {
if (_verbose) {
_displayHECIError(READ_FILE,GetLastError());
}
bytesRead = -1;
goto out;
}
DWORD eventRes = WaitForSingleObject(event, timeout);
if (eventRes == WAIT_TIMEOUT) {
bytesRead = 0;
goto out;
}
res = GetOverlappedResult(_handle, &overlapped, &bytesRead, true);
if (res == 0) {
if (_verbose) {
_displayHECIError(READ_FILE,GetLastError());
}
bytesRead = -1;
goto out;
}
out:
if (event != NULL) {
CloseHandle(event);
}
if (bytesRead <= 0) {
Deinit();
}
return bytesRead;
}
/*
* Send a message to the FW HECI client.
* Arguments:
* buffer - holds the message to be send.
* len - number of bytes to send.
* timeout - timeout for the send operation.
* Return value:
* The number of written bytes.
*/
int HECIWin::SendMessage(UCHAR *buffer, int len, unsigned long timeout)
{
DWORD bytesWritten = 0;
int res;
HANDLE event = NULL;
event = CreateEvent(NULL, FALSE, FALSE, NULL);
OVERLAPPED overlapped;
overlapped.hEvent = event;
overlapped.Offset = 0;
overlapped.OffsetHigh = 0;
res = WriteFile(_handle, buffer, len, &bytesWritten, &overlapped);
DWORD lastError=GetLastError();
if ((0 == res) && (ERROR_IO_PENDING !=lastError )) {
if (_verbose) {
_displayHECIError(WRITE_FILE,GetLastError());
}
bytesWritten = -1;
goto out;
}
DWORD eventRes = WaitForSingleObject(event, timeout);
if (eventRes == WAIT_TIMEOUT) {
if (_verbose) {
_displayHECIError(WRITE_FILE_TIME_OUT,0);
}
bytesWritten = 0;
goto out;
}
res = GetOverlappedResult(_handle, &overlapped, &bytesWritten, false);
if (res == 0) {
if (_verbose) {
_displayHECIError(WRITE_FILE,GetLastError());
}
bytesWritten = -1;
goto out;
}
out:
if (event != NULL) {
CloseHandle(event);
}
if (bytesWritten <= 0) {
Deinit();
}
return bytesWritten;
}
/*
* Allow userspace code to communicate with HECI driver.
*/
int HECIWin::_doIoctl(DWORD code, void *inbuf, int inlen, void *outbuf, int outlen)
{
DWORD bytesRead = 0;
int res;
HANDLE event = NULL;
if (!_initialized) {
return -1;
}
event = CreateEvent(NULL, FALSE, FALSE, NULL);
OVERLAPPED overlapped;
overlapped.hEvent = event;
overlapped.Offset = 0;
overlapped.OffsetHigh = 0;
res = DeviceIoControl(_handle, code, inbuf, inlen, outbuf, outlen, &bytesRead, &overlapped);
if ((0 == res) && (ERROR_IO_PENDING != GetLastError())) {
if (_verbose) {
_displayHECIError(IOCTL_COMMAND,GetLastError());
}
bytesRead = -1;
goto out;
}
WaitForSingleObject(event, INFINITE);
res = GetOverlappedResult(_handle, &overlapped, &bytesRead, true);
if (res == 0) {
if (_verbose) {
_displayHECIError(IOCTL_COMMAND,GetLastError());
}
bytesRead = -1;
goto out;
}
out:
if (event != NULL) {
CloseHandle(event);
}
if (bytesRead == -1) {
Deinit();
}
return bytesRead;}
/*
* Return an appropriate message according to the err it gets.
*/
TCHAR *HECIWin::_getErrMsg(DWORD err)
{
static TCHAR buffer[1024];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
err,
0,
buffer,
sizeof(buffer) - 1,
0);
return buffer;
}
/*
* Return the file handle of the HECI driver.
*/
HANDLE HECIWin::GetHandle()
{
return _handle;
}
/*
* Display a HECI error message.
*/
VOID HECIWin::_displayHECIError(UINT32 errorCode,DWORD lastError)
{
TCHAR str[HECI_MAX_LINE_LEN];
TCHAR *msg;
LoadString(GetModuleHandle(NULL), HECI_ERROR_MESSAGE, str, sizeof(str)/sizeof(TCHAR));
_ftprintf(stderr,_T("%s"),str);
_ftprintf(stderr,_T("%s"),L" ");
LoadString(GetModuleHandle(NULL), errorCode , str, sizeof(str)/sizeof(TCHAR));
if(0!= lastError)
{
msg = _getErrMsg(lastError);
_ftprintf(stderr, _T("%s (%d): %s\n"),str, lastError, msg);
}
else
{
_ftprintf(stderr, _T("%s\n"),str);
}
}
/*
* Display a HECI data message.
*/
VOID HECIWin::_displayHECIData(UINT32 messageId)
{
TCHAR str[HECI_MAX_LINE_LEN];
LoadString(GetModuleHandle(NULL), messageId , str, sizeof(str)/sizeof(TCHAR));
_ftprintf(stdout,_T("%s"),str);
_ftprintf(stdout,_T("%s"),L" ");
}