377 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			377 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*********************************************************************
 | |
| * Copyright (c) Intel Corporation 2011 - 2020
 | |
| * SPDX-License-Identifier: Apache-2.0
 | |
| **********************************************************************/
 | |
| 
 | |
| #ifndef _MINCORE
 | |
| 
 | |
| #include <windows.h>
 | |
| #include <setupapi.h>
 | |
| #include <initguid.h>
 | |
| #include <winioctl.h>
 | |
| #include "HECIWin.h"
 | |
| #include "heci_if.h"
 | |
| 
 | |
| #define false 0
 | |
| #define true 1
 | |
| #define HECI_MAX_LINE_LEN 300 
 | |
| 
 | |
| DEFINE_GUID(GUID_DEVINTERFACE_HECI, 0xE2D1FF34, 0x3458, 0x49A9, 0x88, 0xDA, 0x8E, 0x69, 0x15, 0xCE, 0x9B, 0xE5);
 | |
| DEFINE_GUID(HECI_PTHI_GUID        , 0x12F80028, 0xB4B7, 0x4b2d, 0xAC, 0xA8, 0x46, 0xE0, 0xFF, 0x65, 0x81, 0x4c);
 | |
| DEFINE_GUID(LMS_GUID              , 0x6733a4db, 0x0476, 0x4e7b, 0xb3, 0xaf, 0xbc, 0xfc, 0x29, 0xbe, 0xe7, 0xa7);
 | |
| DEFINE_GUID(MKHI_GUID             , 0x8E6A6715, 0x9ABC, 0x4043, 0x88, 0xEF, 0x9E, 0x39, 0xC6, 0xF6, 0x3E, 0x0F);
 | |
| 
 | |
| //VOID _displayHECIError(UINT32 errorCode,DWORD lastError);
 | |
| //VOID _displayHECIData(UINT32 messageId);
 | |
| int heci_doIoctl(struct MEImodule* module, DWORD code, void *inbuf, int inlen, void *outbuf, int outlen);
 | |
| 
 | |
| struct MEImodule MEI_global;
 | |
| 
 | |
| /***************************** public functions *****************************/
 | |
| 
 | |
| unsigned int heci_GetBufferSize(struct MEImodule* module) { if (module != NULL) return module->_bufSize; else return MEI_global._bufSize; }
 | |
| unsigned char heci_GetProtocolVersion(struct MEImodule* module) { if (module != NULL) return module->_protocolVersion; else return MEI_global._protocolVersion; }
 | |
| bool heci_IsInitialized(struct MEImodule* module) { if (module != NULL) return module->_initialized; else return MEI_global._initialized; }
 | |
| 
 | |
| bool heci_GetHeciVersion(struct MEImodule* module, HECI_VERSION *version)
 | |
| {
 | |
| 	if (module == NULL) module = &MEI_global;
 | |
| 	
 | |
| 	if (module->m_haveHeciVersion)
 | |
| 	{
 | |
| 		memcpy_s(version, sizeof(HECI_VERSION), &(module->m_heciVersion), sizeof(HECI_VERSION));
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| bool heci_Init(struct MEImodule* module, HECI_CLIENTS client)
 | |
| {
 | |
|     PSP_DEVICE_INTERFACE_DETAIL_DATA deviceDetail = NULL;
 | |
|     HDEVINFO hDeviceInfo;
 | |
|     DWORD bufferSize;
 | |
| 	SP_DEVICE_INTERFACE_DATA interfaceData;  
 | |
|     LONG ii = 0;
 | |
| 	int result;
 | |
| 	HECI_CLIENT properties;
 | |
| 	GUID guid;
 | |
| 
 | |
| 	if (client == PTHI_CLIENT) guid = HECI_PTHI_GUID;
 | |
| 	if (client == LMS_CLIENT) guid = LMS_GUID;
 | |
| 	if (client == MKHI_CLIENT) guid = MKHI_GUID;
 | |
| 	if (module == NULL) module = &MEI_global;
 | |
| 	module->_verbose = false;
 | |
| 
 | |
| 	if (module->_initialized) {
 | |
| 		heci_Deinit(module);
 | |
| 	}
 | |
| 
 | |
| 	// 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 (module->_verbose) {
 | |
|             //_displayHECIError(GET_CLASS_DEVS,GetLastError());
 | |
| 		}
 | |
|         return false; //GET_CLASS_DEVS;
 | |
|     }
 | |
| 
 | |
| 	// 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 (module->_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 (module->_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 (module->_verbose) {
 | |
|             //_displayHECIError(FIND_HECI_FAILURE,0);
 | |
| 		}
 | |
| 		return false; //FIND_HECI_FAILURE;
 | |
| 	}
 | |
| 
 | |
| 	module->_handle = CreateFile(deviceDetail->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
 | |
| 	free(deviceDetail);
 | |
| 
 | |
| 	if (module->_handle == INVALID_HANDLE_VALUE) {
 | |
| 		if (module->_verbose) {			
 | |
|             //_displayHECIError(CREATE_HECI_FILE_FAILURE,GetLastError());
 | |
| 		}
 | |
| 		return false; //CREATE_HECI_FILE_FAILURE;
 | |
| 	}
 | |
| 	module->_initialized = true;
 | |
| 
 | |
| 	result = heci_doIoctl(module, (DWORD)IOCTL_HECI_GET_VERSION, NULL, 0, &(module->m_heciVersion), sizeof(HECI_VERSION));
 | |
| 	if (result != sizeof(HECI_VERSION)) {
 | |
| 		if (module->_verbose) {
 | |
|             //_displayHECIError(GET_HECI_DRIVER_VERSION_FAILURE,0);
 | |
| 		}
 | |
| 		heci_Deinit(module);
 | |
| 		return false; //GET_HECI_DRIVER_VERSION_FAILURE;
 | |
| 	}
 | |
| 	module->m_haveHeciVersion = true;
 | |
| 
 | |
| 	if (module->_verbose) {
 | |
|         //_displayHECIData(HECI_DRIVER_VERSION);
 | |
| 		//_ftprintf(stdout,_T("%d.%d.%d.%d\n"), (m_heciVersion).major, (m_heciVersion).minor, (m_heciVersion).hotfix, (m_heciVersion).build);
 | |
| 	}
 | |
| 
 | |
| 	memset(&properties, 0, sizeof(properties));
 | |
| 	result = heci_doIoctl(module, (DWORD)IOCTL_HECI_CONNECT_CLIENT, (void*)(&guid), sizeof(GUID), &properties, sizeof(properties));
 | |
| 	if (result != sizeof(properties))
 | |
| 	{
 | |
| 		if (module->_verbose) {
 | |
|             //_displayHECIError(HECI_CONNECT_TO_PTHI_CLIENT_FAILURE,0);
 | |
| 		}
 | |
| 		//Deinit();
 | |
| 		return false; //HECI_CONNECT_TO_PTHI_CLIENT_FAILURE;
 | |
| 	}
 | |
| 	module->_bufSize = properties.MaxMessageLength;
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| void heci_Deinit(struct MEImodule* module)
 | |
| {
 | |
| 	if (module == NULL) module = &MEI_global;
 | |
| 	if (module->_initialized == false) return;
 | |
| 	module->_initialized = false;
 | |
| 	module->_bufSize = 0;
 | |
| 
 | |
| 	if (module->_handle != INVALID_HANDLE_VALUE)
 | |
| 	{
 | |
| 		CloseHandle(module->_handle);
 | |
| 		module->_handle = INVALID_HANDLE_VALUE;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int heci_ReceiveMessage(struct MEImodule* module, unsigned char *buffer, int len, unsigned long timeout) // Timeout default is 2000
 | |
| {
 | |
| 	DWORD bytesRead = 0;
 | |
| 	int res;
 | |
| 	HANDLE h_event = NULL;
 | |
| 	OVERLAPPED overlapped;
 | |
| 	DWORD error;
 | |
| 	DWORD eventRes;
 | |
| 	
 | |
| 	if (module == NULL) module = &MEI_global;
 | |
| 	if ((h_event = CreateEvent(NULL, FALSE, FALSE, NULL)) == 0) goto out;
 | |
| 	overlapped.hEvent = h_event;
 | |
| 	overlapped.Offset = 0;
 | |
| 	overlapped.OffsetHigh = 0;
 | |
| 
 | |
| 	res = ReadFile(module->_handle, buffer, len, &bytesRead, &overlapped);
 | |
| 	error = GetLastError();
 | |
| 	if ((0 == res) && (ERROR_IO_PENDING != error)) {
 | |
| 		if (module->_verbose) {
 | |
| 			//_displayHECIError(READ_FILE,GetLastError());
 | |
| 		}
 | |
| 		bytesRead = (DWORD)-1;
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	eventRes = WaitForSingleObject(h_event, timeout);
 | |
| 	if (eventRes == WAIT_TIMEOUT) {
 | |
| 		bytesRead = 0;
 | |
| 		goto out;
 | |
| 	}
 | |
| 	
 | |
| 	res = GetOverlappedResult(module->_handle, &overlapped, &bytesRead, true);
 | |
| 	
 | |
| 	if (res == 0) {
 | |
| 		if (module->_verbose) {
 | |
|             //_displayHECIError(READ_FILE,GetLastError());
 | |
| 		}
 | |
| 		bytesRead = (DWORD)-1;
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| out:
 | |
| 	if (h_event != NULL) CloseHandle(h_event);
 | |
| 	if (bytesRead <= 0) heci_Deinit(module);
 | |
| 
 | |
| 	return bytesRead;
 | |
| }
 | |
| 
 | |
| int heci_SendMessage(struct MEImodule* module, const unsigned char *buffer, int len, unsigned long timeout)  // Timeout default is 2000
 | |
| {
 | |
| 	DWORD bytesWritten = 0;
 | |
| 	int res;
 | |
| 	HANDLE h_event = NULL;
 | |
| 	OVERLAPPED overlapped;
 | |
| 	DWORD lastError;
 | |
| 	DWORD eventRes;
 | |
| 
 | |
| 	if (module == NULL) module = &MEI_global;
 | |
| 	if ((h_event = CreateEvent(NULL, FALSE, FALSE, NULL)) == 0) goto out;
 | |
| 	overlapped.hEvent = h_event;
 | |
| 	overlapped.Offset = 0;
 | |
| 	overlapped.OffsetHigh = 0;
 | |
|     
 | |
| 	res = WriteFile(module->_handle, buffer, len, &bytesWritten, &overlapped);
 | |
| 	
 | |
|     lastError = GetLastError();
 | |
| 	if ((0 == res) && (ERROR_IO_PENDING !=lastError )) {
 | |
| 		if (module->_verbose) {
 | |
|             //_displayHECIError(WRITE_FILE,GetLastError());
 | |
| 		}
 | |
| 		bytesWritten = (DWORD)-1;
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	eventRes = WaitForSingleObject(h_event, timeout);
 | |
| 	if (eventRes == WAIT_TIMEOUT) {
 | |
| 		if (module->_verbose) {
 | |
|             //_displayHECIError(WRITE_FILE_TIME_OUT,0);
 | |
| 		}
 | |
| 		bytesWritten = 0;
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	res = GetOverlappedResult(module->_handle, &overlapped, &bytesWritten, false);
 | |
| 
 | |
| 	if (res == 0) {
 | |
| 		if (module->_verbose) {
 | |
|             //_displayHECIError(WRITE_FILE,GetLastError());
 | |
| 		}
 | |
| 		bytesWritten = (DWORD)-1;
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| out:
 | |
| 	if (h_event != NULL) CloseHandle(h_event);
 | |
| 	if (bytesWritten <= 0) heci_Deinit(module);
 | |
| 
 | |
| 	return bytesWritten;
 | |
| }
 | |
| 
 | |
| int heci_doIoctl(struct MEImodule* module, DWORD code, void *inbuf, int inlen, void *outbuf, int outlen)
 | |
| {
 | |
| 	int res;
 | |
| 	DWORD bytesRead = 0;
 | |
| 	HANDLE h_event = NULL;
 | |
| 	OVERLAPPED overlapped;
 | |
| 
 | |
| 	if (module == NULL) module = &MEI_global;
 | |
| 	if (!module->_initialized) return -1;
 | |
| 
 | |
| 	if ((h_event = CreateEvent(NULL, FALSE, FALSE, NULL)) == 0) goto out;
 | |
| 	overlapped.hEvent = h_event;
 | |
| 	overlapped.Offset = 0;
 | |
| 	overlapped.OffsetHigh = 0;
 | |
| 
 | |
| 	res = DeviceIoControl(module->_handle, code, inbuf, inlen, outbuf, outlen, &bytesRead, &overlapped);
 | |
| 	
 | |
| 	if ((0 == res) && (ERROR_IO_PENDING != GetLastError())) {
 | |
| 		if (module->_verbose) {
 | |
| 			 //_displayHECIError(IOCTL_COMMAND,GetLastError());
 | |
| 		}
 | |
| 		bytesRead = (DWORD)-1;
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	WaitForSingleObject(h_event, INFINITE);
 | |
| 
 | |
| 	res = GetOverlappedResult(module->_handle, &overlapped, &bytesRead, true);
 | |
| 	if (res == 0) {
 | |
| 		if (module->_verbose) {
 | |
|             //_displayHECIError(IOCTL_COMMAND,GetLastError());
 | |
| 		}
 | |
| 		bytesRead = (DWORD)-1;
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| out:
 | |
| 	if (h_event != NULL) CloseHandle(h_event);
 | |
| 	if (bytesRead == (DWORD)-1) heci_Deinit(module);
 | |
| 
 | |
| 	return bytesRead;
 | |
| }
 | |
| 
 | |
| TCHAR *_getErrMsg(DWORD err)
 | |
| {
 | |
| 	static TCHAR buffer[1024];
 | |
| 	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
 | |
| 					NULL,
 | |
| 					err,
 | |
| 					0,
 | |
| 					buffer,
 | |
| 					sizeof(buffer) - 1,
 | |
| 					0);
 | |
| 
 | |
| 	return buffer;
 | |
| }
 | |
| 
 | |
| /*
 | |
| // Display a HECI error message
 | |
| void _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 _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" ");
 | |
| }
 | |
| */
 | |
| 
 | |
| #endif
 |