2025-04-27 07:49:33 -04:00

618 lines
16 KiB
C

/*****************************************************************************
*
* 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:
*
* Hel_DcbNew
* Hel_DcbDelete
*
* Hel_WDMInitialize
* Hel_WDMRawReadData
* Hel_WDMRawWriteData
* Hel_WDMRawReadCOmmand
* Hel_WDMRawWriteCommand
* Hel_WDMGetLastError
*
* Hel_ParallelRawReadData
* Hel_ParallelRawWriteData
* Hel_ParallelRawReadCOmmand
* Hel_ParallelRawWriteCommand
* Hel_ParallelGetLastError
*
* Hel_SerialRawReadData
* Hel_SerialRawWriteData
* Hel_SerialRawReadCOmmand
* Hel_SerialRawWriteCommand
* Hel_SerialGetLastError
*
*
*****************************************************************************/
#include "pch.h"
#define DbgFl DbgFlDevice
/*****************************************************************************
*
* @doc INTERNAL
*
* @func HRESULT | Hel_DcbNew |
*
* Creates and initializes DCB for given device.
*
*****************************************************************************/
STDMETHODIMP
Hel_DcbNew(
DWORD dwDeviceType,
LPCWSTR pwszPortName,
DWORD dwFlags,
PSTIDCB *ppStiDCB
)
{
HRESULT hres;
PSTIDCB pDcb;
EnterProc(Hel_DcbNew,(_ "xpp", dwDeviceType,pwszPortName,ppStiDCB));
// Validate device type
#ifdef DEBUG
switch (dwDeviceType) {
case HEL_DEVICE_TYPE_WDM:
// Validate string
if (!pwszPortName || !*pwszPortName) {
ValidateF(0,("Invalid device name passed to DcbNew"));
}
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;
}
hres = hresFullValidPdwOut(ppStiDCB,3);
#endif
//
// Allocate DCB from the heap
//
hres = AllocCbPpv(sizeof(STIDCB), ppStiDCB);
if (SUCCEEDED(hres)) {
//
// Initialize common fields ( note that heap block is assumed to be zero inited)
//
pDcb = *ppStiDCB;
pDcb->dwDeviceType = dwDeviceType;
OSUtil_lstrcpyW(pDcb->wszPortName,pwszPortName);
pDcb-> dwContext = 0L;
pDcb->dwLastOperationError = NO_ERROR;
pDcb->hDeviceHandle = INVALID_HANDLE_VALUE;
pDcb->hDeviceControlHandle = INVALID_HANDLE_VALUE;
//
// Now call appropriate initialization routine
//
switch (dwDeviceType) {
case HEL_DEVICE_TYPE_WDM:
hres = Hel_WDMInitialize(pDcb,dwFlags);
break;
default:
ValidateF(0,("Invalid device type passed to DcbNew"));
return STIERR_INVALID_PARAM;
}
}
// If we failed by some reasons , free allocated memory and bail out
if (!SUCCEEDED(hres)) {
FreePpv(ppStiDCB);
}
ExitOleProc();
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func void | Hel_DcbDelete |
*
* Destroys DCB. It is responsibility of a caller to protect itself from incorrectly
* destroying this block
*
*****************************************************************************/
STDMETHODIMP
Hel_DcbDelete(
PSTIDCB pDcb
)
{
HRESULT hres = STI_OK;
// Validate parameters
if (!pDcb) {
return STIERR_INVALID_PARAM;
}
// Close device handle
if (pDcb->hDeviceHandle) {
CloseHandle(pDcb->hDeviceHandle);
}
if (pDcb->hDeviceControlHandle ) {
CloseHandle(pDcb->hDeviceControlHandle );
}
// Free DCB and nullify pointer
FreePv(pDcb);
return hres;
}
/*****************************************************************************
*
* WDM device specific implementation
*
*****************************************************************************/
STDMETHODIMP
Hel_WDMInitialize(
PSTIDCB pDcb,
DWORD dwFlags
)
{
HRESULT hres;
WCHAR wszDeviceSymbolicName[MAX_PATH] = {L'\0'};
//LPSTR pszAnsiDeviceName;
//
// Create symbolic name for the device we are trying to talk to
// Try to open device data and control handles.
//
if (dwFlags & STI_HEL_OPEN_DATA) {
OSUtil_lstrcatW(wszDeviceSymbolicName,pDcb->wszPortName);
//
// For devices with separate channels could open them specially. Kernel mode
// driver will need to understand convention
// OSUtil_lstrcatW(wszDeviceSymbolicName,L"\\Data");
//
pDcb->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
);
pDcb->dwLastOperationError = GetLastError();
if (pDcb->hDeviceHandle != INVALID_HANDLE_VALUE) {
// Fill function pointers
pDcb->pfnRawReadData = Hel_WDMRawReadData;
pDcb->pfnRawWriteData= Hel_WDMRawWriteData;
pDcb->pfnGetLastError= Hel_WDMGetLastError;
hres = S_OK;
}
else {
hres = MAKE_HRESULT(SEVERITY_ERROR,FACILITY_WIN32,pDcb->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,pDcb->wszPortName);
// BUGBUG for devices with separate channels open them specially. Kernel mode
// driver will need to understand convention
// OSUtil_lstrcatW(wszDeviceSymbolicName,L"\\Control");
pDcb->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
);
pDcb->dwLastOperationError = GetLastError();
if (pDcb->hDeviceControlHandle != INVALID_HANDLE_VALUE) {
// Fill function pointers
pDcb->pfnRawReadCommand= Hel_WDMRawReadCommand;
pDcb->pfnRawWriteCommand= Hel_WDMRawWriteCommand;
hres = S_OK;
}
else {
hres = MAKE_HRESULT(SEVERITY_ERROR,FACILITY_WIN32,pDcb->dwLastOperationError);
}
}
return hres;
}
STDMETHODIMP
Hel_WDMRawReadData(
PSTIDCB pDcb,
LPVOID lpBuffer,
LPDWORD lpdwNumberOfBytes,
LPOVERLAPPED lpOverlapped
)
{
HRESULT hres;
DWORD dwBytesReturned=0;
BOOL fRet;
EnterProc(Hel_WDMRawReadData, (_ "pppp",pDcb,lpBuffer,lpdwNumberOfBytes,lpOverlapped));
// 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(pDcb->hDeviceHandle,
lpBuffer,
*lpdwNumberOfBytes,
lpdwNumberOfBytes,
lpOverlapped
);
pDcb->dwLastOperationError = GetLastError();
hres = S_OK;
if (!fRet) {
hres = HRESULT_FROM_WIN32(pDcb->dwLastOperationError);
}
} else {
hres = STIERR_INVALID_PARAM;
}
ExitOleProc();
return hres;
}
STDMETHODIMP
Hel_WDMRawWriteData(
PSTIDCB pDcb,
LPVOID lpBuffer,
DWORD dwNumberOfBytes,
LPOVERLAPPED lpOverlapped
)
{
HRESULT hres;
BOOL fRet;
DWORD dwReturnedBytes;
EnterProc(Hel_WDMRawWriteData, (_ "ppup",pDcb,lpBuffer,dwNumberOfBytes,lpOverlapped));
// 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(pDcb->hDeviceHandle,
lpBuffer,
dwNumberOfBytes,
&dwReturnedBytes,
lpOverlapped
);
pDcb->dwLastOperationError = GetLastError();
hres = S_OK;
if (!fRet) {
hres = HRESULT_FROM_WIN32(pDcb->dwLastOperationError);
}
}
}
ExitOleProc();
return hres;
}
STDMETHODIMP
Hel_WDMRawReadCommand(
PSTIDCB pDcb,
LPVOID lpBuffer,
LPDWORD lpdwNumberOfBytes,
LPOVERLAPPED lpOverlapped
)
{
HRESULT hres;
BOOL fRet;
EnterProc(Hel_WDMRawReadCommand, (_ "pppp",pDcb,lpBuffer,lpdwNumberOfBytes,lpOverlapped));
// Validate parameters here
if (SUCCEEDED(hres = hresFullValidReadPvCb(lpdwNumberOfBytes, 4, 3)) &&
SUCCEEDED(hres = hresFullValidReadPvCb(lpBuffer,*lpdwNumberOfBytes, 2)) &&
SUCCEEDED(hres = hresFullValidReadPx(lpOverlapped, OVERLAPPED, 4)) ){
// Call appropriate entry point
fRet = ReadFile(pDcb->hDeviceControlHandle,
lpBuffer,
*lpdwNumberOfBytes,
lpdwNumberOfBytes,
lpOverlapped
);
pDcb->dwLastOperationError = GetLastError();
hres = S_OK;
if (!fRet) {
hres = HRESULT_FROM_WIN32(pDcb->dwLastOperationError);
}
} else {
hres = STIERR_INVALID_PARAM;
}
ExitOleProc();
return hres;
}
STDMETHODIMP
Hel_WDMRawWriteCommand(
PSTIDCB pDcb,
LPVOID lpBuffer,
DWORD dwNumberOfBytes,
LPOVERLAPPED lpOverlapped
)
{
HRESULT hres;
BOOL fRet;
DWORD dwReturnedBytes;
EnterProc(Hel_WDMRawWriteCommand, (_ "ppup",pDcb,lpBuffer,dwNumberOfBytes,lpOverlapped));
// Validate parameters here
if (SUCCEEDED(hres = hresFullValidReadPvCb(lpBuffer,dwNumberOfBytes, 2)) &&
SUCCEEDED(hres = hresFullValidReadPx(lpOverlapped, OVERLAPPED, 4)) ){
// Call appropriate entry point
fRet = WriteFile(pDcb->hDeviceControlHandle,
lpBuffer,
dwNumberOfBytes,
&dwReturnedBytes,
lpOverlapped
);
pDcb->dwLastOperationError = GetLastError();
hres = S_OK;
if (!fRet) {
hres = HRESULT_FROM_WIN32(pDcb->dwLastOperationError);
}
} else {
hres = STIERR_INVALID_PARAM;
}
ExitOleProc();
return hres;
}
STDMETHODIMP
Hel_WDMGetLastError(
PSTIDCB pDcb,
LPDWORD lpdwLastError
)
{
if (!lpdwLastError) {
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
}
*lpdwLastError = pDcb->dwLastOperationError ;
return S_OK;
}
/*****************************************************************************
*
* Parallel port device specific implementation
*
*****************************************************************************/
STDMETHODIMP
Hel_ParallelRawReadData(
PSTIDCB pDcb,
LPVOID lpBuffer,
LPDWORD lpdwNumberOfBytes,
LPOVERLAPPED lpOverlapped
)
{
HRESULT hres = E_NOTIMPL;
return hres;
}
STDMETHODIMP
Hel_ParallelRawWriteData(
PSTIDCB pDcb,
LPVOID lpBuffer,
DWORD dwNumberOfBytes,
LPOVERLAPPED lpOverlapped
)
{
HRESULT hres = E_NOTIMPL;
return hres;
}
STDMETHODIMP
Hel_ParallelRawReadCommand(
PSTIDCB pDcb,
LPVOID lpBuffer,
LPDWORD lpdwNumberOfBytes,
LPOVERLAPPED lpOverlapped
)
{
HRESULT hres = E_NOTIMPL;
return hres;
}
STDMETHODIMP
Hel_ParallelRawWriteCommand(
PSTIDCB pDcb,
LPVOID lpBuffer,
DWORD dwNumberOfBytes,
LPOVERLAPPED lpOverlapped
)
{
HRESULT hres = E_NOTIMPL;
return hres;
}
STDMETHODIMP
Hel_ParallelGetLastError(
PSTIDCB pDcb,
LPDWORD lpdwLastError
)
{
HRESULT hres = E_NOTIMPL;
return hres;
}
/*****************************************************************************
*
* Serial device specific implementation
*
*****************************************************************************/
STDMETHODIMP
Hel_SerialRawReadData(
PSTIDCB pDcb,
LPVOID lpBuffer,
LPDWORD lpdwNumberOfBytes,
LPOVERLAPPED lpOverlapped
)
{
HRESULT hres = E_NOTIMPL;
return hres;
}
STDMETHODIMP
Hel_SerialRawWriteData(
PSTIDCB pDcb,
LPVOID lpBuffer,
DWORD dwNumberOfBytes,
LPOVERLAPPED lpOverlapped
)
{
HRESULT hres = E_NOTIMPL;
return hres;
}
STDMETHODIMP
Hel_SerialRawReadCommand(
PSTIDCB pDcb,
LPVOID lpBuffer,
LPDWORD lpdwNumberOfBytes,
LPOVERLAPPED lpOverlapped
)
{
HRESULT hres = E_NOTIMPL;
return hres;
}
STDMETHODIMP
Hel_SerialRawWriteCommand(
PSTIDCB pDcb,
LPVOID lpBuffer,
DWORD dwNumberOfBytes,
LPOVERLAPPED lpOverlapped
)
{
HRESULT hres = E_NOTIMPL;
return hres;
}
STDMETHODIMP
Hel_SerialGetLastError(
PSTIDCB pDcb,
LPDWORD lpdwLastError
)
{
HRESULT hres = E_NOTIMPL;
return hres;
}