419 lines
9.1 KiB
C++
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" ");
|
|
}
|