480 lines
13 KiB
C
480 lines
13 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (C) Microsoft Corporation, 1993 - 1999
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
util.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains utility code used by other 1284 modules.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Robbie Harris (Hewlett-Packard) 20-May-1998
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode
|
|||
|
|
|||
|
Revision History :
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "pch.h"
|
|||
|
#include "ecp.h"
|
|||
|
|
|||
|
//============================================================================
|
|||
|
// NAME: BusReset()
|
|||
|
//
|
|||
|
// Performs a bus reset as defined in Chapter 7.2 of the
|
|||
|
// 1284-1994 spec.
|
|||
|
//
|
|||
|
// PARAMETERS:
|
|||
|
// DCRController - Supplies the base address of of the DCR.
|
|||
|
//
|
|||
|
// RETURNS:
|
|||
|
// nothing
|
|||
|
//============================================================================
|
|||
|
void BusReset(
|
|||
|
IN PUCHAR DCRController
|
|||
|
)
|
|||
|
{
|
|||
|
UCHAR dcr;
|
|||
|
|
|||
|
dcr = READ_PORT_UCHAR(DCRController);
|
|||
|
// Set 1284 and nInit low.
|
|||
|
dcr = UPDATE_DCR(dcr, DONT_CARE, DONT_CARE, INACTIVE, INACTIVE, DONT_CARE, DONT_CARE);
|
|||
|
WRITE_PORT_UCHAR(DCRController, dcr);
|
|||
|
KeStallExecutionProcessor(100); // Legacy Zip will hold what looks to be
|
|||
|
// a bus reset for 9us. Since this proc is used
|
|||
|
// to trigger a logic analyzer... let's hold
|
|||
|
// for 100us
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
CheckPort(
|
|||
|
IN PUCHAR wPortAddr,
|
|||
|
IN UCHAR bMask,
|
|||
|
IN UCHAR bValue,
|
|||
|
IN USHORT msTimeDelay
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
This routine will loop for a given time period (actual time is
|
|||
|
passed in as an arguement) and wait for the dsr to match
|
|||
|
predetermined value (dsr value is passed in).
|
|||
|
|
|||
|
Arguments:
|
|||
|
wPortAddr - Supplies the base address of the parallel port + some offset.
|
|||
|
This will have us point directly to the dsr (controller + 1).
|
|||
|
bMask - Mask used to determine which bits we are looking at
|
|||
|
bValue - Value we are looking for.
|
|||
|
msTimeDelay - Max time to wait for peripheral response (in ms)
|
|||
|
|
|||
|
Return Value:
|
|||
|
TRUE if a dsr match was found.
|
|||
|
FALSE if the time period expired before a match was found.
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UCHAR dsr;
|
|||
|
LARGE_INTEGER Wait;
|
|||
|
LARGE_INTEGER Start;
|
|||
|
LARGE_INTEGER End;
|
|||
|
|
|||
|
// Do a quick check in case we have one stinkingly fast peripheral!
|
|||
|
dsr = READ_PORT_UCHAR(wPortAddr);
|
|||
|
if ((dsr & bMask) == bValue)
|
|||
|
return TRUE;
|
|||
|
|
|||
|
Wait.QuadPart = (msTimeDelay * 10 * 1000) + KeQueryTimeIncrement();
|
|||
|
KeQueryTickCount(&Start);
|
|||
|
|
|||
|
CheckPort_Start:
|
|||
|
KeQueryTickCount(&End);
|
|||
|
dsr = READ_PORT_UCHAR(wPortAddr);
|
|||
|
if ((dsr & bMask) == bValue)
|
|||
|
return TRUE;
|
|||
|
|
|||
|
if ((End.QuadPart - Start.QuadPart) * KeQueryTimeIncrement() > Wait.QuadPart)
|
|||
|
{
|
|||
|
// We timed out!!!
|
|||
|
|
|||
|
// do one last check
|
|||
|
dsr = READ_PORT_UCHAR(wPortAddr);
|
|||
|
if ((dsr & bMask) == bValue)
|
|||
|
return TRUE;
|
|||
|
|
|||
|
#if DVRH_BUS_RESET_ON_ERROR
|
|||
|
BusReset(wPortAddr+1); // Pass in the dcr address
|
|||
|
#endif
|
|||
|
|
|||
|
#if DBG
|
|||
|
ParDump2(PARERRORS, ("CheckPort: Timeout\n"));
|
|||
|
ParDump2(PARERRORS, ("<==========================================================\n"));
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
for (i = 3; i < 8; i++) {
|
|||
|
|
|||
|
if ((bMask >> i) & 1) {
|
|||
|
|
|||
|
if (((bValue >> i) & 1) != ((dsr >> i) & 1)) {
|
|||
|
|
|||
|
ParDump2(PARERRORS, ("\t\t Bit %d is %d and should be %d!!!\n",
|
|||
|
i, (dsr >> i) & 1, (bValue >> i) & 1));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
ParDump2(PARERRORS, ("<==========================================================\n"));
|
|||
|
#endif
|
|||
|
goto CheckPort_TimeOut;
|
|||
|
}
|
|||
|
goto CheckPort_Start;
|
|||
|
|
|||
|
CheckPort_TimeOut:
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
CheckTwoPorts(
|
|||
|
PUCHAR pPortAddr1,
|
|||
|
UCHAR bMask1,
|
|||
|
UCHAR bValue1,
|
|||
|
PUCHAR pPortAddr2,
|
|||
|
UCHAR bMask2,
|
|||
|
UCHAR bValue2,
|
|||
|
USHORT msTimeDelay
|
|||
|
)
|
|||
|
{
|
|||
|
int i;
|
|||
|
UCHAR bPort1;
|
|||
|
UCHAR bPort2;
|
|||
|
LARGE_INTEGER Wait;
|
|||
|
LARGE_INTEGER Start;
|
|||
|
LARGE_INTEGER End;
|
|||
|
|
|||
|
// Do a quick check in case we have one stinkingly fast peripheral!
|
|||
|
bPort1 = READ_PORT_UCHAR( pPortAddr1 );
|
|||
|
if ( ( bPort1 & bMask1 ) == bValue1 )
|
|||
|
{
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
bPort2 = READ_PORT_UCHAR( pPortAddr2 );
|
|||
|
if ( ( bPort2 & bMask2 ) == bValue2 )
|
|||
|
{
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
Wait.QuadPart = (msTimeDelay * 10 * 1000) + KeQueryTimeIncrement();
|
|||
|
KeQueryTickCount(&Start);
|
|||
|
|
|||
|
CheckTwoPorts_Start:
|
|||
|
KeQueryTickCount(&End);
|
|||
|
|
|||
|
bPort1 = READ_PORT_UCHAR( pPortAddr1 );
|
|||
|
if ( ( bPort1 & bMask1 ) == bValue1 )
|
|||
|
{
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
bPort2 = READ_PORT_UCHAR( pPortAddr2 );
|
|||
|
if ( ( bPort2 & bMask2 ) == bValue2 )
|
|||
|
{
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if ((End.QuadPart - Start.QuadPart) * KeQueryTimeIncrement() > Wait.QuadPart)
|
|||
|
{
|
|||
|
// We timed out!!!
|
|||
|
// Recheck the values
|
|||
|
bPort1 = READ_PORT_UCHAR( pPortAddr1 );
|
|||
|
if ( ( bPort1 & bMask1 ) == bValue1 )
|
|||
|
{
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
bPort2 = READ_PORT_UCHAR( pPortAddr2 );
|
|||
|
if ( ( bPort2 & bMask2 ) == bValue2 )
|
|||
|
{
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
#if DVRH_BUS_RESET_ON_ERROR
|
|||
|
BusReset(pPortAddr1+1); // Pass in the dcr address
|
|||
|
#endif
|
|||
|
// Device never responded, return timeout status.
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
goto CheckTwoPorts_Start;
|
|||
|
|
|||
|
return FALSE;
|
|||
|
} // CheckPort2...
|
|||
|
|
|||
|
|
|||
|
PWSTR
|
|||
|
ParCreateWideStringFromUnicodeString(PUNICODE_STRING UnicodeString)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Create a UNICODE_NULL terminated WSTR given a UNICODE_STRING.
|
|||
|
|
|||
|
This function allocates PagedPool, copies the UNICODE_STRING buffer
|
|||
|
to the allocation, and appends a UNICODE_NULL to terminate the WSTR
|
|||
|
|
|||
|
*** This function allocates pool. ExFreePool must be called to free
|
|||
|
the allocation when the buffer is no longer needed.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
UnicodeString - The source
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
PWSTR - if successful
|
|||
|
|
|||
|
NULL - otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PWSTR buffer;
|
|||
|
ULONG length = UnicodeString->Length;
|
|||
|
|
|||
|
buffer = ExAllocatePool( PagedPool, length + sizeof(UNICODE_NULL) );
|
|||
|
if(!buffer) {
|
|||
|
return NULL; // unable to allocate pool, bail out
|
|||
|
} else {
|
|||
|
RtlCopyMemory(buffer, UnicodeString->Buffer, length);
|
|||
|
buffer[length/2] = UNICODE_NULL;
|
|||
|
return buffer;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ParCreateDevice(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN ULONG DeviceExtensionSize,
|
|||
|
IN PUNICODE_STRING DeviceName OPTIONAL,
|
|||
|
IN DEVICE_TYPE DeviceType,
|
|||
|
IN ULONG DeviceCharacteristics,
|
|||
|
IN BOOLEAN Exclusive,
|
|||
|
OUT PDEVICE_OBJECT *DeviceObject
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
status = IoCreateDevice( DriverObject,
|
|||
|
DeviceExtensionSize,
|
|||
|
DeviceName,
|
|||
|
DeviceType,
|
|||
|
(DeviceCharacteristics | FILE_DEVICE_SECURE_OPEN),
|
|||
|
Exclusive,
|
|||
|
DeviceObject );
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
ParInitializeExtension1284Info(
|
|||
|
IN PDEVICE_EXTENSION Extension
|
|||
|
)
|
|||
|
// make this a function since it is now called from two places:
|
|||
|
// - 1) when initializing a new devobj
|
|||
|
// - 2) from CreateOpen
|
|||
|
{
|
|||
|
USHORT i;
|
|||
|
|
|||
|
Extension->Connected = FALSE;
|
|||
|
if (DefaultModes)
|
|||
|
{
|
|||
|
USHORT rev = (USHORT) (DefaultModes & 0xffff);
|
|||
|
USHORT fwd = (USHORT)((DefaultModes & 0xffff0000)>>16);
|
|||
|
|
|||
|
switch (fwd)
|
|||
|
{
|
|||
|
case BOUNDED_ECP:
|
|||
|
Extension->IdxForwardProtocol = BOUNDED_ECP_FORWARD;
|
|||
|
break;
|
|||
|
case ECP_HW_NOIRQ:
|
|||
|
case ECP_HW_IRQ:
|
|||
|
Extension->IdxForwardProtocol = ECP_HW_FORWARD_NOIRQ;
|
|||
|
break;
|
|||
|
case ECP_SW:
|
|||
|
Extension->IdxForwardProtocol = ECP_SW_FORWARD;
|
|||
|
break;
|
|||
|
case EPP_HW:
|
|||
|
Extension->IdxForwardProtocol = EPP_HW_FORWARD;
|
|||
|
break;
|
|||
|
case EPP_SW:
|
|||
|
Extension->IdxForwardProtocol = EPP_SW_FORWARD;
|
|||
|
break;
|
|||
|
case IEEE_COMPATIBILITY:
|
|||
|
Extension->IdxForwardProtocol = IEEE_COMPAT_MODE;
|
|||
|
break;
|
|||
|
case CENTRONICS:
|
|||
|
default:
|
|||
|
Extension->IdxForwardProtocol = CENTRONICS_MODE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
switch (rev)
|
|||
|
{
|
|||
|
case BOUNDED_ECP:
|
|||
|
Extension->IdxReverseProtocol = BOUNDED_ECP_REVERSE;
|
|||
|
break;
|
|||
|
case ECP_HW_NOIRQ:
|
|||
|
case ECP_HW_IRQ:
|
|||
|
Extension->IdxReverseProtocol = ECP_HW_REVERSE_NOIRQ;
|
|||
|
break;
|
|||
|
case ECP_SW:
|
|||
|
Extension->IdxReverseProtocol = ECP_SW_REVERSE;
|
|||
|
break;
|
|||
|
case EPP_HW:
|
|||
|
Extension->IdxReverseProtocol = EPP_HW_REVERSE;
|
|||
|
break;
|
|||
|
case EPP_SW:
|
|||
|
Extension->IdxReverseProtocol = EPP_SW_REVERSE;
|
|||
|
break;
|
|||
|
case BYTE_BIDIR:
|
|||
|
Extension->IdxReverseProtocol = BYTE_MODE;
|
|||
|
break;
|
|||
|
case CHANNEL_NIBBLE:
|
|||
|
case NIBBLE:
|
|||
|
default:
|
|||
|
Extension->IdxReverseProtocol = NIBBLE_MODE;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Extension->IdxReverseProtocol = NIBBLE_MODE;
|
|||
|
Extension->IdxForwardProtocol = CENTRONICS_MODE;
|
|||
|
}
|
|||
|
Extension->bShadowBuffer = FALSE;
|
|||
|
Extension->ProtocolModesSupported = 0;
|
|||
|
Extension->BadProtocolModes = 0;
|
|||
|
Extension->IsCritical = FALSE;
|
|||
|
#if (1 == DVRH_USE_CORRECT_PTRS)
|
|||
|
Extension->fnRead = NULL;
|
|||
|
Extension->fnWrite = NULL;
|
|||
|
// Extension->fnRead = arpReverse[Extension->IdxReverseProtocol].fnRead;
|
|||
|
// Extension->fnWrite = afpForward[Extension->IdxForwardProtocol].fnWrite;
|
|||
|
#endif
|
|||
|
|
|||
|
Extension->ForwardInterfaceAddress = DEFAULT_ECP_CHANNEL;
|
|||
|
Extension->ReverseInterfaceAddress = DEFAULT_ECP_CHANNEL;
|
|||
|
Extension->SetForwardAddress = FALSE;
|
|||
|
Extension->SetReverseAddress = FALSE;
|
|||
|
Extension->bIsHostRecoverSupported = FALSE;
|
|||
|
Extension->IsIeeeTerminateOk = FALSE;
|
|||
|
|
|||
|
for (i = FAMILY_NONE; i < FAMILY_MAX; i++) {
|
|||
|
Extension->ProtocolData[i] = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#if (1 == DVRH_DELAY_THEORY)
|
|||
|
void DVRH_Diagnostic_Delay()
|
|||
|
{
|
|||
|
LARGE_INTEGER Interval;
|
|||
|
|
|||
|
//in 100ns increments
|
|||
|
Interval.QuadPart = 1000;
|
|||
|
KeDelayExecutionThread(
|
|||
|
KernelMode,
|
|||
|
FALSE,
|
|||
|
&Interval
|
|||
|
);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
VOID
|
|||
|
ParGetDriverParameterDword(
|
|||
|
IN PUNICODE_STRING ServicePath,
|
|||
|
IN PWSTR ParameterName,
|
|||
|
IN OUT PULONG ParameterValue
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Read registry DWORD from <ServicePath>\Parameters
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
RTL_QUERY_REGISTRY_TABLE paramTable[2];
|
|||
|
PWSTR suffix = L"\\Parameters";
|
|||
|
ULONG defaultValue;
|
|||
|
UNICODE_STRING path = {0,0,0};
|
|||
|
ULONG length;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Sanity check parameters
|
|||
|
//
|
|||
|
if( ( NULL == ServicePath->Buffer ) || ( NULL == ParameterName ) || ( NULL == ParameterValue ) ) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// set up table entries for call to RtlQueryRegistryValues
|
|||
|
//
|
|||
|
RtlZeroMemory( paramTable, sizeof(paramTable));
|
|||
|
|
|||
|
defaultValue = *ParameterValue;
|
|||
|
|
|||
|
paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|||
|
paramTable[0].Name = ParameterName;
|
|||
|
paramTable[0].EntryContext = ParameterValue;
|
|||
|
paramTable[0].DefaultType = REG_DWORD;
|
|||
|
paramTable[0].DefaultData = &defaultValue;
|
|||
|
paramTable[0].DefaultLength = sizeof(ULONG);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// leave paramTable[2] as all zeros - this terminates the table
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// compute the size of the path including the "parameters" suffix
|
|||
|
//
|
|||
|
length = ( sizeof(WCHAR) * wcslen( suffix ) ) + sizeof(UNICODE_NULL);
|
|||
|
length += RegistryPath.Length;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// construct the path as: <ServiceName>\Parameters
|
|||
|
//
|
|||
|
path.Buffer = ExAllocatePool( PagedPool, length );
|
|||
|
if( NULL == path.Buffer ) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
RtlZeroMemory( path.Buffer, length );
|
|||
|
path.MaximumLength = (USHORT)length;
|
|||
|
RtlCopyUnicodeString( &path, &RegistryPath );
|
|||
|
RtlAppendUnicodeToString( &path, suffix );
|
|||
|
ParDump2(PARREG,("util::ParGetDriverParameterDword - path = <%wZ>\n", &path));
|
|||
|
|
|||
|
ParDump2(PARREG,("util::ParGetDriverParameterDword - pre-query value = %x\n", *ParameterValue));
|
|||
|
|
|||
|
//
|
|||
|
// query registry
|
|||
|
//
|
|||
|
status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
|
|||
|
path.Buffer,
|
|||
|
¶mTable[0],
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
|
|||
|
RtlFreeUnicodeString( &path );
|
|||
|
|
|||
|
ParDump2(PARREG,("util::ParGetDriverParameterDword - post-query value = %x\n", *ParameterValue));
|
|||
|
ParDump2(PARREG,("util::ParGetDriverParameterDword - status from RtlQueryRegistryValues on SubKey = %x\n", status) );
|
|||
|
|
|||
|
return;
|
|||
|
}
|