// Copyright (C) 2004 Intel Corporation #include #include #include #include #include #include #include #include #include #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" "); }