/***************************************************************************** * * Hel.c * * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved. * * Abstract: * * Hardware emulation layer calls. Used to provide common functionality * for built-in device types we support ( WDM, serial and parallel) * While access to DCB could be built as internal COM object , it does not make * much sense to invest in it, because DCBs are exclusively owned and not shared * between application objects or different applications. We also want to minimize * any overhead when talking to raw device interface. * * Note1: We don't deal at this level with access control, lower level drivers are supposed * to take care of this. Queuing of requests for non-reentrant devices is also not done here. * This Hel is basically thin layer of imaging device primitives, used only to isolate * command translator from actual hardware. * * Note2: Hel is not made extensible . If command translator needs to talk to non-supported * device, it will need to establish direct link to it. There is no requirement to use * Hel , it is service we provide to conformant devices. * * Contents: * *****************************************************************************/ /* #include "wia.h" #include #include #include #include #include #include "stipriv.h" #include "debug.h" #define DbgFl DbgFlDevice */ #include "sticomm.h" #include "validate.h" #define DbgFl DbgFlDevice /***************************************************************************** * * Declare the interfaces we will be providing. * *****************************************************************************/ Primary_Interface(CWDMDeviceControl, IStiDeviceControl); Interface_Template_Begin(CWDMDeviceControl) Primary_Interface_Template(CWDMDeviceControl, IStiDeviceControl) Interface_Template_End(CWDMDeviceControl) /***************************************************************************** * * @doc INTERNAL * * @struct CWDMDeviceControl | * * The device object * * * @field IStiDeviceControl | stidev * * @comm * * *****************************************************************************/ typedef struct CWDMDeviceControl { /* Supported interfaces */ IStiDeviceControl devctl; DWORD dwVersion; DWORD dwDeviceType; DWORD dwMode; WCHAR wszPortName[MAX_PATH]; DWORD dwFlags; DWORD dwContext; DWORD dwLastOperationError; HANDLE hDeviceHandle; HANDLE hDeviceControlHandle; } CWDMDeviceControl, *PCWDMDeviceControl; #define ThisClass CWDMDeviceControl #define ThisInterface IStiDeviceControl #ifdef DEBUG Default_QueryInterface(CWDMDeviceControl) Default_AddRef(CWDMDeviceControl) Default_Release(CWDMDeviceControl) #else #define CWDMDeviceControl_QueryInterface Common_QueryInterface #define CWDMDeviceControl_AddRef Common_AddRef #define CWDMDeviceControl_Release Common_Release #endif #define CWDMDeviceControl_QIHelper Common_QIHelper #pragma BEGIN_CONST_DATA #pragma END_CONST_DATA /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | CWDMDeviceControl | RawReadData | * * @parm | | * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CWDMDeviceControl_RawReadData( PSTIDEVICECONTROL pDev, LPVOID lpBuffer, LPDWORD lpdwNumberOfBytes, LPOVERLAPPED lpOverlapped ) { HRESULT hres = STIERR_INVALID_PARAM; DWORD dwBytesReturned=0; BOOL fRet; EnterProc(CWDMDeviceControl_WDMRawReadData, (_ "pppp",pDev,lpBuffer,lpdwNumberOfBytes,lpOverlapped)); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCWDMDeviceControl this = _thisPv(pDev); // Validate parameters here if (SUCCEEDED(hres = hresFullValidReadPvCb(lpdwNumberOfBytes, 4, 3)) && SUCCEEDED(hres = hresFullValidReadPvCb(lpBuffer,*lpdwNumberOfBytes, 2)) && (!lpOverlapped || SUCCEEDED(hres = hresFullValidReadPx(lpOverlapped, OVERLAPPED, 4))) ){ // Call appropriate entry point fRet = ReadFile(this->hDeviceHandle, lpBuffer, *lpdwNumberOfBytes, lpdwNumberOfBytes, lpOverlapped ); this->dwLastOperationError = GetLastError(); hres = fRet ? STI_OK : HRESULT_FROM_WIN32(this->dwLastOperationError); } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | CWDMDeviceControl | WDMRawWriteData | * * @parm | | * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CWDMDeviceControl_RawWriteData( PSTIDEVICECONTROL pDev, LPVOID lpBuffer, DWORD dwNumberOfBytes, LPOVERLAPPED lpOverlapped ) { HRESULT hres = STIERR_INVALID_PARAM; DWORD dwBytesReturned=0; BOOL fRet; EnterProc(CWDMDeviceControl_WDMRawWriteData, (_ "ppup",pDev,lpBuffer,dwNumberOfBytes,lpOverlapped)); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCWDMDeviceControl this = _thisPv(pDev); // Validate parameters here hres = STIERR_INVALID_PARAM; if (SUCCEEDED(hres = hresFullValidReadPvCb(lpBuffer,dwNumberOfBytes, 2)) ) { if (!lpOverlapped || SUCCEEDED(hres = hresFullValidReadPx(lpOverlapped, OVERLAPPED, 4)) ){ // Call appropriate entry point fRet = WriteFile(this->hDeviceHandle, lpBuffer, dwNumberOfBytes, &dwBytesReturned, lpOverlapped ); this->dwLastOperationError = GetLastError(); hres = fRet ? STI_OK : HRESULT_FROM_WIN32(this->dwLastOperationError); } } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | CWDMDeviceControl | RawReadControl | * * @parm | | * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CWDMDeviceControl_RawReadCommand( PSTIDEVICECONTROL pDev, LPVOID lpBuffer, LPDWORD lpdwNumberOfBytes, LPOVERLAPPED lpOverlapped ) { HRESULT hres = STIERR_INVALID_PARAM; DWORD dwBytesReturned=0; BOOL fRet; EnterProc(CWDMDeviceControl_WDMRawReadData, (_ "pppp",pDev,lpBuffer,lpdwNumberOfBytes,lpOverlapped)); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCWDMDeviceControl this = _thisPv(pDev); // Validate parameters here if (SUCCEEDED(hres = hresFullValidReadPvCb(lpdwNumberOfBytes, 4, 3)) && SUCCEEDED(hres = hresFullValidReadPvCb(lpBuffer,*lpdwNumberOfBytes, 2)) && (!lpOverlapped || SUCCEEDED(hres = hresFullValidReadPx(lpOverlapped, OVERLAPPED, 4))) ){ // Call appropriate entry point fRet = ReadFile(this->hDeviceControlHandle, lpBuffer, *lpdwNumberOfBytes, lpdwNumberOfBytes, lpOverlapped ); this->dwLastOperationError = GetLastError(); hres = fRet ? STI_OK : HRESULT_FROM_WIN32(this->dwLastOperationError); } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | CWDMDeviceControl | WDMRawWriteData | * * @parm | | * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CWDMDeviceControl_RawWriteCommand( PSTIDEVICECONTROL pDev, LPVOID lpBuffer, DWORD dwNumberOfBytes, LPOVERLAPPED lpOverlapped ) { HRESULT hres = STIERR_INVALID_PARAM; DWORD dwBytesReturned=0; BOOL fRet; EnterProc(CWDMDeviceControl_WDMRawWriteData, (_ "ppup",pDev,lpBuffer,dwNumberOfBytes,lpOverlapped)); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCWDMDeviceControl this = _thisPv(pDev); // Validate parameters here hres = STIERR_INVALID_PARAM; if (SUCCEEDED(hres = hresFullValidReadPvCb(lpBuffer,dwNumberOfBytes, 2)) ) { if (!lpOverlapped || SUCCEEDED(hres = hresFullValidReadPx(lpOverlapped, OVERLAPPED, 4)) ){ // Call appropriate entry point fRet = WriteFile(this->hDeviceControlHandle, lpBuffer, dwNumberOfBytes, &dwBytesReturned, lpOverlapped ); this->dwLastOperationError = GetLastError(); hres = fRet ? STI_OK : HRESULT_FROM_WIN32(this->dwLastOperationError); } } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | CWDMDeviceControl | RawReadControl | * * @parm | | * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CWDMDeviceControl_GetLastError( PSTIDEVICECONTROL pDev, LPDWORD lpdwLastError ) { HRESULT hres = STIERR_INVALID_PARAM; DWORD dwBytesReturned=0; EnterProc(CWDMDeviceControl_GetLastError, (_ "pppp",pDev,lpdwLastError)); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCWDMDeviceControl this = _thisPv(pDev); // Validate parameters here if (SUCCEEDED(hres = hresFullValidReadPvCb(lpdwLastError,4, 2))) { *lpdwLastError = this->dwLastOperationError ; hres = STI_OK; } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | CWDMDeviceControl | GetMyDevicePortName | * * @parm | | * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CWDMDeviceControl_GetMyDevicePortName( PSTIDEVICECONTROL pDev, LPWSTR lpszDevicePath, DWORD cwDevicePathSize ) { HRESULT hres = STIERR_INVALID_PARAM; DWORD dwBytesReturned=0; EnterProc(CWDMDeviceControl_GetMyDevicePortName, (_ "pp",pDev,lpszDevicePath)); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCWDMDeviceControl this = _thisPv(pDev); // Validate parameters here if (SUCCEEDED(hres = hresFullValidReadPvCb(lpszDevicePath,4, 2)) && SUCCEEDED(hres = hresFullValidReadPvCb(lpszDevicePath,sizeof(WCHAR)*cwDevicePathSize, 2)) ) { if (cwDevicePathSize > OSUtil_StrLenW(this->wszPortName)) { OSUtil_lstrcpyW(lpszDevicePath,this->wszPortName); hres = STI_OK; } else { hres = HRESULT_FROM_WIN32(ERROR_MORE_DATA); } } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | CWDMDeviceControl | GetMyDeviceHandle | * * @parm | | * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CWDMDeviceControl_GetMyDeviceHandle( PSTIDEVICECONTROL pDev, LPHANDLE pHandle ) { HRESULT hres = STIERR_INVALID_PARAM; DWORD dwBytesReturned=0; EnterProc(CWDMDeviceControl_GetMyDeviceHandle, (_ "pp",pDev,pHandle)); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCWDMDeviceControl this = _thisPv(pDev); // Validate parameters here if (SUCCEEDED(hres = hresFullValidReadPvCb(pHandle,4, 2)) ) { if (INVALID_HANDLE_VALUE != this->hDeviceHandle) { *pHandle = this->hDeviceHandle; hres = STI_OK; } else { hres = HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE); } } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | CWDMDeviceControl | pdwOpenMode | * * @parm | | * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CWDMDeviceControl_GetMyDeviceOpenMode( PSTIDEVICECONTROL pDev, LPDWORD pdwOpenMode ) { HRESULT hres = STIERR_INVALID_PARAM; DWORD dwBytesReturned=0; EnterProc(CWDMDeviceControl_GetMyDeviceOpenMode, (_ "pp",pDev,pdwOpenMode)); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCWDMDeviceControl this = _thisPv(pDev); // Validate parameters here if (SUCCEEDED(hres = hresFullValidReadPvCb(pdwOpenMode,4, 2)) ) { *pdwOpenMode = this->dwMode; hres = STI_OK; } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | CWDMDeviceControl | RawReadControl | * * @parm | | * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CWDMDeviceControl_RawDeviceControl( PSTIDEVICECONTROL pDev, USD_CONTROL_CODE EscapeFunction, LPVOID lpInData, DWORD cbInDataSize, LPVOID pOutData, DWORD dwOutDataSize, LPDWORD pdwActualData ) { HRESULT hres = STIERR_INVALID_PARAM; DWORD dwBytesReturned=0; EnterProc(CWDMDeviceControl_RawDeviceControl, (_ "p",pDev)); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCWDMDeviceControl this = _thisPv(pDev); // Validate parameters here hres = STIERR_UNSUPPORTED; } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | CWDMDeviceControl | WriteToErrorLog | * * @parm | | * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CWDMDeviceControl_WriteToErrorLog( PSTIDEVICECONTROL pDev, DWORD dwMessageType, LPCWSTR pszMessage, DWORD dwErrorCode ) { HRESULT hres = STIERR_INVALID_PARAM; DWORD dwBytesReturned=0; EnterProc(CWDMDeviceControl_WriteToErrorLog, (_ "p",pDev)); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCWDMDeviceControl this = _thisPv(pDev); // // Validate parameters here // if (SUCCEEDED(hres = hresFullValidReadPvCb(pszMessage,2, 3))) { #ifdef UNICODE ReportStiLogMessage(g_hStiFileLog, dwMessageType, pszMessage ); #else LPTSTR lpszAnsi = NULL; if ( SUCCEEDED(OSUtil_GetAnsiString(&lpszAnsi,pszMessage))) { ReportStiLogMessage(g_hStiFileLog, dwMessageType, lpszAnsi ); FreePpv(&lpszAnsi); } #endif } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @mfunc HRESULT | CWDMDeviceControl | Initialize | * * Initialize a DeviceControl object. * * @cwrap PSTIDEVICECONTROL | pDev * * @returns * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * = : The operation completed successfully. * * : The device had already been initialized with * the instance GUID passed in

. * * *****************************************************************************/ STDMETHODIMP CWDMDeviceControl_Initialize( PSTIDEVICECONTROL pDev, DWORD dwDeviceType, DWORD dwDeviceMode, LPCWSTR pwszPortName, DWORD dwFlags ) { HRESULT hres = STI_OK; WCHAR wszDeviceSymbolicName[MAX_PATH] = {L'\0'}; //LPSTR pszAnsiDeviceName; EnterProcR(CWDMDeviceControl::Initialize,(_ "pp", pDev, pwszPortName)); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCWDMDeviceControl this = _thisPv(pDev); this->dwDeviceType = dwDeviceType; lstrcpynW(this->wszPortName,pwszPortName, sizeof(this->wszPortName) / sizeof(this->wszPortName[0])); // // Create symbolic name for the device we are trying to talk to // Try to open device data and control handles. // this->dwMode = dwDeviceMode; if (dwFlags & STI_HEL_OPEN_DATA) { OSUtil_lstrcatW(wszDeviceSymbolicName,this->wszPortName); // For devices with separate channels open them specially. Kernel mode // driver will need to understand convention // OSUtil_lstrcatW(wszDeviceSymbolicName,L"\\Data"); this->hDeviceHandle = OSUtil_CreateFileW(wszDeviceSymbolicName, GENERIC_READ | GENERIC_WRITE, // Access mask 0, // Share mode NULL, // SA OPEN_EXISTING, // Create disposition FILE_ATTRIBUTE_SYSTEM, // Attributes NULL // Template ); this->dwLastOperationError = GetLastError(); hres = (this->hDeviceHandle != INVALID_HANDLE_VALUE) ? S_OK : MAKE_HRESULT(SEVERITY_ERROR,FACILITY_WIN32,this->dwLastOperationError); } // // If needed open control handle for the device // if (SUCCEEDED(hres) && (dwFlags & STI_HEL_OPEN_CONTROL)) { OSUtil_lstrcpyW(wszDeviceSymbolicName,REGSTR_PATH_STIDEVICES_W); OSUtil_lstrcatW(wszDeviceSymbolicName,L"\\"); OSUtil_lstrcatW(wszDeviceSymbolicName,this->wszPortName); // For devices with separate channels open them specially. Kernel mode // driver will need to understand convention // OSUtil_lstrcatW(wszDeviceSymbolicName,L"\\Control"); this->hDeviceControlHandle = OSUtil_CreateFileW(wszDeviceSymbolicName, GENERIC_READ | GENERIC_WRITE, // Access mask 0, // Share mode NULL, // SA OPEN_EXISTING, // Create disposition FILE_ATTRIBUTE_SYSTEM, // Attributes NULL // Template ); this->dwLastOperationError = GetLastError(); hres = (this->hDeviceControlHandle != INVALID_HANDLE_VALUE) ? S_OK : MAKE_HRESULT(SEVERITY_ERROR,FACILITY_WIN32,this->dwLastOperationError); } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc INTERNAL * * @mfunc void | CWDMDeviceControl | Init | * * Initialize the internal parts of the StiDevice object. * *****************************************************************************/ void INLINE CWDMDeviceControl_Init( PCWDMDeviceControl this ) { // Initialize instance variables this->dwContext = 0L; this->dwLastOperationError = NO_ERROR; this->hDeviceHandle = INVALID_HANDLE_VALUE; this->hDeviceControlHandle = INVALID_HANDLE_VALUE; } /***************************************************************************** * * @doc INTERNAL * * @func void | CWDMDeviceControl_Finalize | * * Releases the resources of a generic device. * * @parm PV | pvObj | * * Object being released. Note that it may not have been * completely initialized, so everything should be done * carefully. * *****************************************************************************/ void INTERNAL CWDMDeviceControl_Finalize(PV pvObj) { HRESULT hres = STI_OK; PCWDMDeviceControl this = pvObj; // Close device handles if (IsValidHANDLE(this->hDeviceHandle)) { CloseHandle(this->hDeviceHandle); } if (IsValidHANDLE(this->hDeviceControlHandle)) { CloseHandle(this->hDeviceControlHandle ); } this->dwContext = 0L; this->dwLastOperationError = NO_ERROR; this->hDeviceHandle = INVALID_HANDLE_VALUE; this->hDeviceControlHandle = INVALID_HANDLE_VALUE; } /***************************************************************************** * * @doc INTERNAL * * @mfunc HRESULT | CWDMDeviceControl | New | * * Create a new IDeviceControl object, uninitialized. * * @parm IN PUNK | punkOuter | * * Controlling unknown for aggregation. * * @parm IN RIID | riid | * * Desired interface to new object. * * @parm OUT PPV | ppvObj | * * Output pointer for new object. * *****************************************************************************/ STDMETHODIMP CWDMDeviceControl_New(PUNK punkOuter, RIID riid, PPV ppvObj) { HRESULT hres; EnterProcR(CWDMDeviceControl::, (_ "Gp", riid, punkOuter)); hres = Common_NewRiid(CWDMDeviceControl, punkOuter, riid, ppvObj); if (SUCCEEDED(hres)) { PCWDMDeviceControl this = _thisPv(*ppvObj); CWDMDeviceControl_Init(this); } ExitOleProcPpvR(ppvObj); return hres; } /***************************************************************************** * * @doc INTERNAL * * @func HRESULT | NewDeviceControl | * * Creates and initializes DCB for given device. * *****************************************************************************/ STDMETHODIMP NewDeviceControl( DWORD dwDeviceType, DWORD dwDeviceMode, LPCWSTR pwszPortName, DWORD dwFlags, PSTIDEVICECONTROL *ppDevCtl ) { HRESULT hres = STI_OK; EnterProc(NewDeviceControl,(_ "xpp", dwDeviceType,pwszPortName,ppDevCtl)); // Validate device type #ifdef DEBUG hres = STI_OK; switch (dwDeviceType) { case HEL_DEVICE_TYPE_WDM: break; case HEL_DEVICE_TYPE_PARALLEL: break; case HEL_DEVICE_TYPE_SERIAL: break; default: ValidateF(0,("Invalid dwvice type passed to DcbNew")); return STIERR_INVALID_PARAM; } // Validate string if (!pwszPortName || !*pwszPortName) { //AssertF(0,("Invalid device name passed to DcbNew")); hres = STIERR_INVALID_PARAM; } else { hres = hresFullValidPdwOut(ppDevCtl,3); } #else if (!pwszPortName || !*pwszPortName) { hres = STIERR_INVALID_PARAM; } #endif if (SUCCEEDED(hres)) { // // Now call appropriate initialization routine // switch (dwDeviceType) { case HEL_DEVICE_TYPE_WDM: case HEL_DEVICE_TYPE_PARALLEL: hres = CWDMDeviceControl_New(NULL, &IID_IStiDeviceControl,ppDevCtl); break; case HEL_DEVICE_TYPE_SERIAL: hres = CCommDeviceControl_New(NULL, &IID_IStiDeviceControl,ppDevCtl); break; default: ValidateF(0,("Invalid device type passed to DcbNew")); return STIERR_INVALID_PARAM; } } if (SUCCEEDED(hres)) { hres = IStiDeviceControl_Initialize(*ppDevCtl,dwDeviceType,dwDeviceMode,pwszPortName,dwFlags); } ExitOleProc(); return hres; } /***************************************************************************** * * The long-awaited vtbls and templates * *****************************************************************************/ #pragma BEGIN_CONST_DATA #define CWDMDeviceControl_Signature (DWORD)'WDM' Primary_Interface_Begin(CWDMDeviceControl, IStiDeviceControl) CWDMDeviceControl_Initialize, CWDMDeviceControl_RawReadData, CWDMDeviceControl_RawWriteData, CWDMDeviceControl_RawReadCommand, CWDMDeviceControl_RawWriteCommand, CWDMDeviceControl_RawDeviceControl, CWDMDeviceControl_GetLastError, CWDMDeviceControl_GetMyDevicePortName, CWDMDeviceControl_GetMyDeviceHandle, CWDMDeviceControl_GetMyDeviceOpenMode, CWDMDeviceControl_WriteToErrorLog, Primary_Interface_End(CWDMDeviceControl, IStiDeviceControl)