2944 lines
95 KiB
C
2944 lines
95 KiB
C
/*++
|
||
|
||
*****************************************************************************
|
||
* *
|
||
* This software contains proprietary and confidential information of *
|
||
* *
|
||
* Digi International Inc. *
|
||
* *
|
||
* By accepting transfer of this copy, Recipient agrees to retain this *
|
||
* software in confidence, to prevent disclosure to others, and to make *
|
||
* no use of this software other than that for which it was delivered. *
|
||
* This is an unpublished copyrighted work of Digi International Inc. *
|
||
* Except as permitted by federal law, 17 USC 117, copying is strictly *
|
||
* prohibited. *
|
||
* *
|
||
*****************************************************************************
|
||
|
||
Module Name:
|
||
|
||
ntepc.c
|
||
|
||
Abstract:
|
||
|
||
This module is responsible for the hardware dependent functions for
|
||
DigiBoard EPC line of products.
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
/*
|
||
* $Log: /Components/Windows/NT/Async/NTEPC/NTEPC.C $
|
||
*
|
||
* 1 3/05/96 10:16a Stana
|
||
* Miniport driver for EPC
|
||
* Revision 2.2 1995/10/04 12:54:52 dirkh
|
||
* Change loop variable names in GetEpcConfigInfo to be self-documenting
|
||
* which fixes bug of not supporting multiple EBI modules on a single EPC/CON.
|
||
* Revision 2.1 1995/09/19 18:26:42 dirkh
|
||
* Remove unused routines: StartIo, Read, Write, Flush, IoControl.
|
||
* Collapse to NtcxSuccess several identical routines (Cleanup, [Query,Set]Info, QueryVolumeInfo).
|
||
* Handle shared memory window locking more cleanly.
|
||
* Longest timeout interval is 0.1s (instead of 1s).
|
||
* Consistent init timeouts: 3s reset, 10/20s BIOS, 5/10s FEP.
|
||
* Revision 2.0 1995/09/19 14:56:06 dirkh
|
||
* Sort baud rate table.
|
||
* Declare baud rate and modem signal tables as constant arrays.
|
||
*
|
||
* Revision 1.12 1994/12/20 23:45:36 rik
|
||
* conditionally compile LargeInteger manipulations.
|
||
*
|
||
* Revision 1.11 1994/12/09 14:31:10 rik
|
||
* #if Int32x32 back to RtlLarge for NT 3.1 release
|
||
*
|
||
* Revision 1.10 1994/11/28 09:31:38 rik
|
||
* Updated conc. images.
|
||
* changed RtlLarge math functions to direct 64-bit manipulation.
|
||
*
|
||
* Revision 1.9 1994/10/10 10:41:03 rik
|
||
* Changed READ_REGISTER_USHORT to READ_REGISTER_UCHAR to fix an alignment
|
||
* problem on the PowerPC.
|
||
*
|
||
* Revision 1.8 1994/08/19 09:27:58 rik
|
||
* Updated conc. download to handle moving window if necessary.
|
||
*
|
||
* Revision 1.7 1994/07/31 14:38:02 rik
|
||
* Added 200 baud to baud table
|
||
*
|
||
* Fixed problem with getting line configuration.
|
||
*
|
||
* Revision 1.6 1994/06/18 12:59:59 rik
|
||
* Closed files and freeing memory which wasn't happening before.
|
||
* Update DigiLogError msg's to include Line # of error.
|
||
*
|
||
* Revision 1.5 1994/05/11 13:21:26 rik
|
||
* Updated for new build version preprocessing.
|
||
*
|
||
* Revision 1.4 1994/04/10 14:51:51 rik
|
||
* cleanup compiler warnings.
|
||
*
|
||
* Revision 1.3 1994/02/23 03:34:30 rik
|
||
* Changed so the controllers firmware can be downloaded from a binary file.
|
||
* This releases some physical memory was just wasted previously.
|
||
*
|
||
* Also updated so when compiling with a Windows NT OS and tools release greater
|
||
* than 528, then pagable code is compiled into the driver. This greatly
|
||
* reduced the size of in memory code, especially the hardware specific
|
||
* miniports.
|
||
*
|
||
* Revision 1.2 1994/01/31 13:52:26 rik
|
||
* Updated to fix problems with downloading CX conc. images.
|
||
* Fixed problem with EBI modules being part of the configuration and
|
||
* not allowing the driver to init properly.
|
||
*
|
||
* Revision 1.1 1994/01/25 19:06:46 rik
|
||
* Initial revision
|
||
*
|
||
*/
|
||
|
||
|
||
|
||
#include <stddef.h>
|
||
#include <ntddk.h>
|
||
#include <ntverp.h> // Include to determine what version of NT
|
||
|
||
//
|
||
// This is a fix for changes in DDK releases.
|
||
//
|
||
#ifdef VER_PRODUCTBUILD
|
||
#define rmm VER_PRODUCTBUILD
|
||
#endif
|
||
|
||
#include "ntddser.h"
|
||
|
||
#include "ntfep5.h"
|
||
#undef DbgPrint
|
||
|
||
#include "ntepc.h"
|
||
#include "epcbin.h"
|
||
#include "cxbin.h"
|
||
|
||
#include "ntepclog.h"
|
||
|
||
#include "digifile.h"
|
||
|
||
#ifndef _NTEPC_DOT_C
|
||
# define _NTEPC_DOT_C
|
||
static char RCSInfo_NTEPCDotC[] = "$Header: /Components/Windows/NT/Async/NTEPC/NTEPC.C 1 3/05/96 10:16a Stana $";
|
||
#endif
|
||
|
||
static const SHORT BaudTable[NUMBER_OF_BAUD_RATES] =
|
||
{
|
||
B50, B75, B110, B134, B150, B200, B300, B600,
|
||
B1200, B1800, B2000, B2400, B3600, B4800, B7200, B9600,
|
||
B14400, B19200, B28800, B38400, B56000, B57600,
|
||
B115200, B128000, B256000, B512000
|
||
};
|
||
|
||
static const UCHAR ModemSignalTable[NUMBER_OF_SIGNALS] =
|
||
{
|
||
DTR_CONTROL, RTS_CONTROL, RESERVED1, RESERVED2,
|
||
CTS_STATUS, DSR_STATUS, RI_STATUS, DCD_STATUS
|
||
};
|
||
|
||
ULONG DigiDebugLevel = ( DIGIERRORS | DIGIMEMORY | DIGIASSERT | DIGIINIT | DIGIIOCTL );
|
||
|
||
static const PHYSICAL_ADDRESS DigiPhysicalZero = {0};
|
||
|
||
static PDRIVER_OBJECT GlobalDriverObject;
|
||
|
||
USHORT MCAIOAddressTable[] = { 0x108, 0x118,
|
||
0x128, 0x208,
|
||
0x228, 0x308,
|
||
0x328, 0 };
|
||
|
||
USHORT MCAIrqTable[] = { 0, 3, 5, 7, 10, 11, 12, 15 };
|
||
|
||
UCHAR *ConcentratorImages[] = { EpcConcentratorCode, CXConcentratorCode };
|
||
|
||
|
||
//
|
||
// Helper prototypes which are used soley by this module.
|
||
//
|
||
NTSTATUS GetEpcConfigInfo( PUNICODE_STRING ControllerPath,
|
||
PUCHAR EPCConfigString,
|
||
PULONG EPCConfigStringSize,
|
||
PDIGI_CONTROLLER_EXTENSION ControllerExt );
|
||
|
||
DIGI_MEM_COMPARES DigiMemCompare( IN PHYSICAL_ADDRESS A,
|
||
IN ULONG SpanOfA,
|
||
IN PHYSICAL_ADDRESS B,
|
||
IN ULONG SpanOfB );
|
||
|
||
VOID DigiLogError( IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
||
IN PHYSICAL_ADDRESS P1,
|
||
IN PHYSICAL_ADDRESS P2,
|
||
IN ULONG SequenceNumber,
|
||
IN UCHAR MajorFunctionCode,
|
||
IN UCHAR RetryCount,
|
||
IN ULONG UniqueErrorValue,
|
||
IN NTSTATUS FinalStatus,
|
||
IN NTSTATUS SpecificIOStatus,
|
||
IN ULONG LengthOfInsert1,
|
||
IN PWCHAR Insert1,
|
||
IN ULONG LengthOfInsert2,
|
||
IN PWCHAR Insert2 );
|
||
|
||
NTSTATUS NtEpcInitMCA( PUNICODE_STRING ControllerPath,
|
||
PDIGI_CONTROLLER_EXTENSION ControllerExt );
|
||
|
||
USHORT DigiWstrLength( IN PWSTR WStr );
|
||
|
||
NTSTATUS EpcFepDownload( PDIGI_CONTROLLER_EXTENSION ControllerExt,
|
||
PUCHAR FEPFImage,
|
||
ULONG FEPFLength );
|
||
|
||
|
||
//
|
||
// Exported functions for Windows NT Device
|
||
//
|
||
|
||
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath );
|
||
|
||
NTSTATUS NtEpcFlush( IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp );
|
||
|
||
NTSTATUS NtEpcSuccess( IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp );
|
||
|
||
NTSTATUS NtEpcInternalIoControl( IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp );
|
||
|
||
NTSTATUS NtEpcClose( IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp );
|
||
|
||
NTSTATUS NtEpcCreate( IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp );
|
||
|
||
VOID NtEpcUnload( IN PDRIVER_OBJECT DriverObject );
|
||
|
||
|
||
//
|
||
// Exported functions for DigiBoard Hardware interface
|
||
//
|
||
|
||
NTSTATUS NtEpcXXPrepInit( PDIGI_CONTROLLER_EXTENSION pControllerExt,
|
||
PUNICODE_STRING ControllerPath );
|
||
|
||
NTSTATUS NtEpcXXInit( IN PDRIVER_OBJECT DriverObject,
|
||
PUNICODE_STRING ControllerPath,
|
||
PDIGI_CONTROLLER_EXTENSION pControllerExt );
|
||
|
||
VOID NtEpcEnableWindow( IN PDIGI_CONTROLLER_EXTENSION pControllerExt,
|
||
IN USHORT Window );
|
||
|
||
VOID NtEpcDisableWindow( IN PDIGI_CONTROLLER_EXTENSION pControllerExt );
|
||
|
||
VOID NtEpcXXDownload( PDIGI_CONTROLLER_EXTENSION pControllerExt );
|
||
|
||
NTSTATUS NtEpcBoard2Fep5Address( PDIGI_CONTROLLER_EXTENSION ControllerExt,
|
||
USHORT ControllerAddress,
|
||
PFEPOS5_ADDRESS FepAddress );
|
||
|
||
LARGE_INTEGER NtEpcDiagnose(PDIGI_CONTROLLER_EXTENSION pControllerExt);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text( INIT, DriverEntry )
|
||
|
||
#if rmm > 528
|
||
#pragma message( "\n\\\\\n\\\\ Including PAGED CODE\n\\\\ \n" )
|
||
|
||
//DH I don't believe this is accomplishing anything.
|
||
|
||
#pragma alloc_text( PAGEDIGIEPC, NtEpcXXPrepInit )
|
||
#pragma alloc_text( PAGEDIGIEPC, NtEpcXXInit )
|
||
#pragma alloc_text( PAGEDIGIEPC, GetEpcConfigInfo )
|
||
#pragma alloc_text( PAGEDIGIEPC, NtEpcInitMCA )
|
||
#pragma alloc_text( PAGEDIGIEPC, DigiWstrLength )
|
||
#pragma alloc_text( PAGEDIGIEPC, EpcFepDownload )
|
||
#pragma alloc_text( PAGEDIGIEPC, DigiLogError )
|
||
#pragma alloc_text( PAGEDIGIEPC, DigiMemCompare )
|
||
|
||
#pragma alloc_text( PAGEDIGIEPC, NtEpcSuccess )
|
||
#pragma alloc_text( PAGEDIGIEPC, NtEpcInternalIoControl )
|
||
#pragma alloc_text( PAGEDIGIEPC, NtEpcCreate )
|
||
#pragma alloc_text( PAGEDIGIEPC, NtEpcClose )
|
||
#pragma alloc_text( PAGEDIGIEPC, NtEpcUnload )
|
||
#endif
|
||
|
||
#endif
|
||
|
||
|
||
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath )
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Entry point for loading driver.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to this drivers object.
|
||
|
||
RegistryPath - Pointer to a unicode string which points to this
|
||
drivers registry entry.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - If the driver was successfully loaded, otherwise,
|
||
a value which indicates why it wasn't able to load.
|
||
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
PDEVICE_OBJECT DeviceObject;
|
||
|
||
WCHAR NtEpcDeviceNameBuffer[100];
|
||
UNICODE_STRING NtEpcDeviceName;
|
||
|
||
GlobalDriverObject = DriverObject;
|
||
|
||
NtEpcDeviceName.Length = 0;
|
||
NtEpcDeviceName.MaximumLength = sizeof(NtEpcDeviceNameBuffer);
|
||
NtEpcDeviceName.Buffer = &NtEpcDeviceNameBuffer[0];
|
||
|
||
RtlZeroMemory( NtEpcDeviceName.Buffer, NtEpcDeviceName.MaximumLength );
|
||
RtlAppendUnicodeToString( &NtEpcDeviceName, L"\\Device\\ntepc" );
|
||
|
||
Status = IoCreateDevice( DriverObject,
|
||
0, &NtEpcDeviceName,
|
||
FILE_DEVICE_SERIAL_PORT, 0, TRUE,
|
||
&DeviceObject );
|
||
|
||
DigiDump( DIGIINIT, ("NTEPC: DriverObject = 0x%x DeviceObject = 0x%x\n",
|
||
DriverObject, DeviceObject) );
|
||
if( !NT_SUCCESS(Status) )
|
||
{
|
||
DigiLogError( GlobalDriverObject,
|
||
NULL,
|
||
DigiPhysicalZero,
|
||
DigiPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
__LINE__,
|
||
STATUS_INSUFFICIENT_RESOURCES,
|
||
SERIAL_INSUFFICIENT_RESOURCES,
|
||
0,
|
||
NULL,
|
||
0,
|
||
NULL );
|
||
return( STATUS_INSUFFICIENT_RESOURCES );
|
||
}
|
||
|
||
DeviceObject->Flags |= DO_BUFFERED_IO;
|
||
|
||
DriverObject->DriverUnload = NtEpcUnload;
|
||
|
||
DriverObject->MajorFunction[IRP_MJ_CREATE] = NtEpcCreate;
|
||
DriverObject->MajorFunction[IRP_MJ_CLOSE] = NtEpcClose;
|
||
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
|
||
NtEpcInternalIoControl;
|
||
DriverObject->MajorFunction[IRP_MJ_CLEANUP] =
|
||
DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
|
||
DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =
|
||
DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] =
|
||
NtEpcSuccess;
|
||
|
||
return( STATUS_SUCCESS );
|
||
} // end DriverEntry
|
||
|
||
|
||
|
||
NTSTATUS NtEpcXXPrepInit( PDIGI_CONTROLLER_EXTENSION pControllerExt,
|
||
PUNICODE_STRING ControllerPath )
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
pControllerExt -
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status=STATUS_SUCCESS;
|
||
KIRQL OldIrql;
|
||
#if rmm > 528
|
||
PVOID lockPtr;
|
||
|
||
lockPtr = MmLockPagableCodeSection( NtEpcXXPrepInit );
|
||
#endif
|
||
|
||
DigiDump( DIGIFLOW, ("Entering NtEpcXXPrepInit\n") );
|
||
|
||
//
|
||
// At this point, determine if we are using a MCA controller.
|
||
// If we are, then we need to read the POS to get the
|
||
// Memory address and I/O address.
|
||
//
|
||
if( pControllerExt->BusType == MicroChannel )
|
||
{
|
||
Status = NtEpcInitMCA( ControllerPath, pControllerExt );
|
||
|
||
if( Status != STATUS_SUCCESS )
|
||
goto EpcXXPrepInitExit;
|
||
}
|
||
|
||
//
|
||
// Make sure we have exclusive access to the controller
|
||
// extension
|
||
//
|
||
KeAcquireSpinLock( &pControllerExt->ControlAccess,
|
||
&OldIrql );
|
||
|
||
pControllerExt->IOSpan = 4;
|
||
|
||
if( pControllerExt->WindowSize == 0 )
|
||
pControllerExt->WindowSize = 0x8000L;
|
||
|
||
pControllerExt->Global.Window = FEP_GLOBAL_WINDOW;
|
||
pControllerExt->Global.Offset = 0;
|
||
|
||
pControllerExt->EventQueue.Window = FEP_EVENT_WINDOW;
|
||
pControllerExt->EventQueue.Offset = FEP_EVENT_OFFSET;
|
||
|
||
pControllerExt->CommandQueue.Window = FEP_COMMAND_WINDOW;
|
||
pControllerExt->CommandQueue.Offset = FEP_COMMAND_OFFSET;
|
||
|
||
pControllerExt->BaudTable = &BaudTable[0];
|
||
pControllerExt->ModemSignalTable = &ModemSignalTable[0];
|
||
|
||
//
|
||
// Make sure we release exclusive access to the controller
|
||
// extension
|
||
//
|
||
KeReleaseSpinLock( &pControllerExt->ControlAccess,
|
||
OldIrql );
|
||
|
||
DigiDump( DIGIFLOW, ("Exiting NtEpcXXPrepInit\n") );
|
||
|
||
EpcXXPrepInitExit:;
|
||
|
||
#if rmm > 528
|
||
MmUnlockPagableImageSection( lockPtr );
|
||
#endif
|
||
|
||
return( Status );
|
||
} // end NtEpcXXPrepInit
|
||
|
||
|
||
|
||
NTSTATUS NtEpcXXInit( IN PDRIVER_OBJECT DriverObject,
|
||
PUNICODE_STRING ControllerPath,
|
||
PDIGI_CONTROLLER_EXTENSION pControllerExt )
|
||
{
|
||
ULONG i;
|
||
ULONG Address;
|
||
NTSTATUS Status;
|
||
UCHAR ByteValue;
|
||
|
||
TIME Timeout;
|
||
|
||
PHYSICAL_ADDRESS TempPhyAddr;
|
||
|
||
NTSTATUS FStatus;
|
||
|
||
HANDLE BiosFHandle=0;
|
||
ULONG BiosFLength=0;
|
||
PUCHAR BiosFImage=NULL;
|
||
|
||
HANDLE FEPFHandle=0;
|
||
ULONG FEPFLength=0;
|
||
PUCHAR FEPFImage=NULL;
|
||
|
||
|
||
USHORT CurrentAddressOffset;
|
||
UCHAR CurrentWindow;
|
||
|
||
UCHAR EPCConfigString[128];
|
||
ULONG EPCConfigStringSize=0;
|
||
#if rmm > 528
|
||
PVOID lockPtr;
|
||
|
||
lockPtr = MmLockPagableCodeSection( NtEpcXXInit );
|
||
#endif
|
||
|
||
DigiDump( DIGIFLOW, ("Entering NtEpcXXInit\n") );
|
||
|
||
Status = GetEpcConfigInfo( ControllerPath,
|
||
EPCConfigString,
|
||
&EPCConfigStringSize,
|
||
pControllerExt );
|
||
|
||
if( !NT_SUCCESS(Status) )
|
||
{
|
||
// There was some type of problem with the configuration,
|
||
// just return.
|
||
#if rmm > 528
|
||
MmUnlockPagableImageSection( lockPtr );
|
||
#endif
|
||
return( Status );
|
||
}
|
||
|
||
DigiDump( DIGIINIT, ("NTEPC: Concentrator Config string:\n"
|
||
"----- ") );
|
||
|
||
for( i = 0; i < EPCConfigStringSize; i++ )
|
||
{
|
||
DigiDump( DIGIINIT, (" 0x%X", EPCConfigString[i]) );
|
||
|
||
// Count the number of total ports on this controller
|
||
if( (i+1) % 2 )
|
||
{
|
||
// skip Host Adapter Line entries
|
||
if( (EPCConfigString[i] == 0) || (EPCConfigString[i] == 0xFF) )
|
||
continue;
|
||
}
|
||
}
|
||
|
||
DigiDump( DIGIINIT, ("\n") );
|
||
DigiDump( DIGIINIT, ("Number of Ports = %u\n",
|
||
pControllerExt->NumberOfPorts) );
|
||
|
||
//
|
||
//
|
||
// IMPORTANT NOTE:
|
||
//
|
||
// I map the Bios and FEP images in here before acquiring the
|
||
// spinlock because acquiring a spinlock raises the current IRQL
|
||
// level, and the open file, etc calls can not be access at
|
||
// the raised IRQL level because it is pageable code
|
||
//
|
||
//
|
||
|
||
|
||
//
|
||
// Open and map in the Bios and FEP images
|
||
//
|
||
|
||
RtlFillMemory( &TempPhyAddr, sizeof(TempPhyAddr), 0xFF );
|
||
|
||
DigiOpenFile( &FStatus,
|
||
&BiosFHandle,
|
||
&BiosFLength,
|
||
&pControllerExt->BiosImagePath,
|
||
TempPhyAddr );
|
||
|
||
if( FStatus == STATUS_SUCCESS )
|
||
{
|
||
DigiDump( DIGIINIT, ("NTEPC: NdisOpenFile was successful!\n") );
|
||
|
||
DigiMapFile( &FStatus,
|
||
&(PVOID)BiosFImage,
|
||
BiosFHandle );
|
||
|
||
if( FStatus == STATUS_SUCCESS )
|
||
{
|
||
DigiDump( DIGIINIT, ("NTEPC: NdisMapFile was successful!\n") );
|
||
}
|
||
else
|
||
{
|
||
DigiDump( DIGIINIT, ("NTEPC: NdisMapFile was UN-successful!\n") );
|
||
DigiLogError( GlobalDriverObject,
|
||
NULL,
|
||
DigiPhysicalZero,
|
||
DigiPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
__LINE__,
|
||
STATUS_DEVICE_NOT_INITIALIZED,
|
||
SERIAL_FILE_NOT_FOUND,
|
||
pControllerExt->BiosImagePath.Length + sizeof(WCHAR),
|
||
pControllerExt->BiosImagePath.Buffer,
|
||
0,
|
||
NULL );
|
||
Status = STATUS_DEVICE_NOT_INITIALIZED;
|
||
goto XXInitExit;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DigiDump( DIGIINIT, ("NTEPC: NdisOpenFile was UN-successful!\n") );
|
||
|
||
DigiLogError( GlobalDriverObject,
|
||
NULL,
|
||
DigiPhysicalZero,
|
||
DigiPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
__LINE__,
|
||
STATUS_DEVICE_NOT_INITIALIZED,
|
||
SERIAL_FILE_NOT_FOUND,
|
||
pControllerExt->BiosImagePath.Length + sizeof(WCHAR),
|
||
pControllerExt->BiosImagePath.Buffer,
|
||
0,
|
||
NULL );
|
||
Status = STATUS_DEVICE_NOT_INITIALIZED;
|
||
goto XXInitExit;
|
||
}
|
||
|
||
RtlFillMemory( &TempPhyAddr, sizeof(TempPhyAddr), 0xFF );
|
||
|
||
DigiOpenFile( &FStatus,
|
||
&FEPFHandle,
|
||
&FEPFLength,
|
||
&pControllerExt->FEPImagePath,
|
||
TempPhyAddr );
|
||
|
||
if( FStatus == STATUS_SUCCESS )
|
||
{
|
||
DigiDump( DIGIINIT, ("NTEPC: NdisOpenFile was successful!\n") );
|
||
|
||
DigiMapFile( &FStatus,
|
||
&(PVOID)FEPFImage,
|
||
FEPFHandle );
|
||
|
||
if( FStatus == STATUS_SUCCESS )
|
||
{
|
||
DigiDump( DIGIINIT, ("NTEPC: NdisMapFile was successful!\n") );
|
||
}
|
||
else
|
||
{
|
||
DigiDump( DIGIINIT, ("NTEPC: NdisMapFile was UN-successful!\n") );
|
||
DigiLogError( GlobalDriverObject,
|
||
NULL,
|
||
DigiPhysicalZero,
|
||
DigiPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
__LINE__,
|
||
STATUS_DEVICE_NOT_INITIALIZED,
|
||
SERIAL_FILE_NOT_FOUND,
|
||
pControllerExt->BiosImagePath.Length + sizeof(WCHAR),
|
||
pControllerExt->BiosImagePath.Buffer,
|
||
0,
|
||
NULL );
|
||
Status = STATUS_DEVICE_NOT_INITIALIZED;
|
||
goto XXInitExit;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DigiDump( DIGIINIT, ("NTEPC: NdisOpenFile was UN-successful!\n") );
|
||
|
||
DigiLogError( GlobalDriverObject,
|
||
NULL,
|
||
DigiPhysicalZero,
|
||
DigiPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
__LINE__,
|
||
STATUS_DEVICE_NOT_INITIALIZED,
|
||
SERIAL_FILE_NOT_FOUND,
|
||
pControllerExt->FEPImagePath.Length + sizeof(WCHAR),
|
||
pControllerExt->FEPImagePath.Buffer,
|
||
0,
|
||
NULL );
|
||
|
||
Status = STATUS_DEVICE_NOT_INITIALIZED;
|
||
goto XXInitExit;
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
// Ensure exclusive access to the memory area.
|
||
KeAcquireSpinLock( &pControllerExt->MemoryAccess->Lock,
|
||
&pControllerExt->MemoryAccess->OldIrql );
|
||
#if DBG
|
||
pControllerExt->MemoryAccess->LockBusy = TRUE;
|
||
#endif
|
||
|
||
// reset board
|
||
WRITE_PORT_UCHAR( pControllerExt->VirtualIO, 4 );
|
||
|
||
// Create a 0.1 second timeout interval
|
||
#if rmm < 807
|
||
Timeout = RtlConvertLongToLargeInteger( -100 * 10000 );
|
||
#else
|
||
Timeout.QuadPart = -100 * 10000;
|
||
#endif
|
||
|
||
for( i = 0; i < 30; i++ )
|
||
{
|
||
ByteValue = (READ_PORT_UCHAR( pControllerExt->VirtualIO ) & 0x0E);
|
||
|
||
if( ByteValue != 0x04 )
|
||
KeDelayExecutionThread( KernelMode, FALSE, &Timeout );
|
||
else
|
||
break;
|
||
}
|
||
|
||
DigiDump( DIGIINIT, ("Wait confirm = 0x%x, expect %d.\n",
|
||
(ULONG)ByteValue, (ULONG)4 ) );
|
||
|
||
if( i == 30 )
|
||
{
|
||
//
|
||
// Unable to get confirmation of the controller responding.
|
||
//
|
||
DigiDump( DIGIINIT, ("Unable to confirm Board Reset, check I/O dip switches.\n") );
|
||
DigiLogError( GlobalDriverObject,
|
||
NULL,
|
||
DigiPhysicalZero,
|
||
DigiPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
__LINE__,
|
||
STATUS_SERIAL_NO_DEVICE_INITED,
|
||
SERIAL_NO_CONTROLLER_RESET_WAIT,
|
||
pControllerExt->ControllerName.Length + sizeof(WCHAR),
|
||
pControllerExt->ControllerName.Buffer,
|
||
0,
|
||
NULL );
|
||
Status = STATUS_SERIAL_NO_DEVICE_INITED;
|
||
goto XXInitExit;
|
||
}
|
||
|
||
|
||
// Tell the controller where to map the memory.
|
||
Address = (ULONG)(pControllerExt->PhysicalMemoryAddress.LowPart >> 8);
|
||
|
||
WRITE_PORT_UCHAR( pControllerExt->VirtualIO+2, (UCHAR)(Address & 0x00FF));
|
||
WRITE_PORT_UCHAR( pControllerExt->VirtualIO+3, (UCHAR)((Address>>8)&0xFF));
|
||
if (pControllerExt->BusType == Eisa)
|
||
{
|
||
DigiDump( DIGIINIT, ("NTEPC: Eisa card, writing address+4\n"));
|
||
WRITE_PORT_UCHAR( pControllerExt->VirtualIO+4, (UCHAR)((Address>>16)&0xFF));
|
||
}
|
||
|
||
WRITE_PORT_UCHAR( pControllerExt->VirtualIO+1, 0x80 );
|
||
|
||
|
||
DigiDump( DIGIINIT, ("Dword @ VirtualAddress, before memory check = 0x%x\n",
|
||
READ_REGISTER_ULONG( (PULONG)pControllerExt->VirtualAddress )) );
|
||
WRITE_REGISTER_ULONG( (PULONG)pControllerExt->VirtualAddress,
|
||
0xA55A3CC3 );
|
||
|
||
DigiDump( DIGIINIT, ("Dword @ VirtualAddress, after memory check = 0x%x, expected 0xa55a3cc3\n",
|
||
READ_REGISTER_ULONG( (PULONG)pControllerExt->VirtualAddress )) );
|
||
|
||
DigiDump( DIGIINIT, ("Dword @ VirtualAddress+WindowSize-4, before memory check = 0x%x\n",
|
||
READ_REGISTER_ULONG( (PULONG)(pControllerExt->VirtualAddress +
|
||
pControllerExt->WindowSize -
|
||
sizeof(ULONG)) )) );
|
||
|
||
WRITE_REGISTER_ULONG( (PULONG)(pControllerExt->VirtualAddress + pControllerExt->WindowSize - sizeof(ULONG)),
|
||
0x5AA5C33C );
|
||
|
||
DigiDump( DIGIINIT, ("Dword @ VirtualAddress+WindowSize-4, after memory check = 0x%x, expected 0x5aa5c33c\n",
|
||
READ_REGISTER_ULONG( (PULONG)(pControllerExt->VirtualAddress +
|
||
pControllerExt->WindowSize -
|
||
sizeof(ULONG)) )) );
|
||
|
||
if( (READ_REGISTER_ULONG( (PULONG)pControllerExt->VirtualAddress ) != 0xA55A3CC3) ||
|
||
(READ_REGISTER_ULONG( (PULONG)(pControllerExt->VirtualAddress +
|
||
pControllerExt->WindowSize -
|
||
sizeof(ULONG)) ) != 0x5AA5C33C) )
|
||
{
|
||
DigiDump( DIGIERRORS, ("**** Board memory failure! ***\n"
|
||
" Unable to verify board memory. (%s:%d)\n",
|
||
(PUCHAR)__FILE__, (int)__LINE__) );
|
||
DigiLogError( GlobalDriverObject,
|
||
NULL,
|
||
DigiPhysicalZero,
|
||
DigiPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
__LINE__,
|
||
STATUS_SERIAL_NO_DEVICE_INITED,
|
||
SERIAL_CONTROLLER_MEMORY_TEST_FAILED,
|
||
pControllerExt->ControllerName.Length + sizeof(WCHAR),
|
||
pControllerExt->ControllerName.Buffer,
|
||
0,
|
||
NULL );
|
||
Status = STATUS_SERIAL_NO_DEVICE_INITED;
|
||
goto XXInitExit;
|
||
}
|
||
|
||
|
||
// Clear POSTAREA
|
||
for( i = 0; i < 15; i++ )
|
||
{
|
||
WRITE_REGISTER_UCHAR( (PUCHAR)((PUCHAR)pControllerExt->VirtualAddress +
|
||
0x0C00 + i), 0 );
|
||
}
|
||
|
||
//
|
||
// Download BIOS on Epc host adapter
|
||
//
|
||
|
||
// reset board
|
||
WRITE_PORT_UCHAR( pControllerExt->VirtualIO, 4 );
|
||
|
||
// Select top memory window.
|
||
WRITE_PORT_UCHAR( pControllerExt->VirtualIO+1, 0x80 );
|
||
|
||
WRITE_REGISTER_ULONG( (PULONG)(pControllerExt->VirtualAddress),
|
||
0x0BF00401);
|
||
WRITE_REGISTER_ULONG( (PULONG)((PUCHAR)pControllerExt->VirtualAddress+4),
|
||
0x00000000 );
|
||
|
||
DigiDump( DIGIINIT, ("Epc BIOS size = %u bytes.\n", BiosFLength) );
|
||
|
||
// write the BIOS from our local variable the controller.
|
||
CurrentAddressOffset = 0x1000;
|
||
CurrentWindow = 0x80;
|
||
for( i = 0; i < BiosFLength; i++ )
|
||
{
|
||
if( CurrentAddressOffset >= pControllerExt->WindowSize )
|
||
{
|
||
// go to the next window.
|
||
CurrentWindow++;
|
||
WRITE_PORT_UCHAR( pControllerExt->VirtualIO+1, CurrentWindow );
|
||
CurrentAddressOffset = 0;
|
||
}
|
||
WRITE_REGISTER_UCHAR( (PUCHAR)((PUCHAR)pControllerExt->VirtualAddress +
|
||
CurrentAddressOffset),
|
||
BiosFImage[i] );
|
||
CurrentAddressOffset++;
|
||
}
|
||
|
||
// Make sure top memory window is still valid.
|
||
WRITE_PORT_UCHAR( pControllerExt->VirtualIO+1, 0x80 );
|
||
|
||
// Clear confirm word
|
||
WRITE_REGISTER_USHORT( (PUSHORT)(pControllerExt->VirtualAddress + 0x0C00),
|
||
0 );
|
||
|
||
DigiDump( DIGIINIT,
|
||
("before BIOS download memw[0C00h] = 0x%hx\n",
|
||
READ_REGISTER_USHORT( (PUSHORT)(pControllerExt->VirtualAddress+0x0C00) )) );
|
||
|
||
// Release reset
|
||
WRITE_PORT_UCHAR( pControllerExt->VirtualIO, 0 );
|
||
|
||
//
|
||
// We generate a wait event for 100, 0.1 second intervals to verify
|
||
// the BIOS download.
|
||
//
|
||
|
||
for( i = 0; i < 100; i++ )
|
||
{
|
||
if( READ_REGISTER_USHORT( (PUSHORT)(pControllerExt->VirtualAddress+0x0C00) )
|
||
== *(USHORT *)"GD" )
|
||
{
|
||
break;
|
||
}
|
||
|
||
KeDelayExecutionThread( KernelMode, FALSE, &Timeout );
|
||
}
|
||
|
||
if( i == 100 )
|
||
{
|
||
// The BIOS didn't initialize within 10 seconds.
|
||
DigiDump( DIGIERRORS, ("*** Epc BIOS did NOT initialize. ***\n") );
|
||
DigiLogError( GlobalDriverObject,
|
||
NULL,
|
||
DigiPhysicalZero,
|
||
DigiPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
__LINE__,
|
||
STATUS_SERIAL_NO_DEVICE_INITED,
|
||
SERIAL_BIOS_DOWNLOAD_FAILED,
|
||
pControllerExt->ControllerName.Length + sizeof(WCHAR),
|
||
pControllerExt->ControllerName.Buffer,
|
||
0,
|
||
NULL );
|
||
Status = STATUS_SERIAL_NO_DEVICE_INITED;
|
||
goto XXInitExit;
|
||
}
|
||
|
||
DigiDump( DIGIINIT, ("after BIOS download memw[0C00h] = %c%c, expect %s\n",
|
||
READ_REGISTER_UCHAR( (PUCHAR)(pControllerExt->VirtualAddress+0x0C00) ),
|
||
READ_REGISTER_UCHAR( (PUCHAR)(pControllerExt->VirtualAddress+0x0C01) ),
|
||
"GD") );
|
||
|
||
//
|
||
// Load the EPC concentrator configuration
|
||
//
|
||
// Select Page 0 and Enable Memory
|
||
WRITE_PORT_UCHAR( pControllerExt->VirtualIO+1, 0x80 );
|
||
|
||
// write the concentrator string from our local variable the controller.
|
||
WRITE_REGISTER_BUFFER_UCHAR( (PUCHAR)(pControllerExt->VirtualAddress + 0x0CD0),
|
||
(PUCHAR)&EPCConfigString[0],
|
||
EPCConfigStringSize );
|
||
|
||
Status = EpcFepDownload( pControllerExt,
|
||
FEPFImage,
|
||
FEPFLength );
|
||
|
||
if( !NT_SUCCESS(Status) )
|
||
goto XXInitExit;
|
||
|
||
//
|
||
// Normally, we would generate a wait event for 5 seconds to verify
|
||
// the FEPs execution.
|
||
//
|
||
|
||
WRITE_PORT_UCHAR( pControllerExt->VirtualIO+1, 0x80 );
|
||
|
||
for( i = 0; i < 50; i++ )
|
||
{
|
||
if( READ_REGISTER_USHORT( (PUSHORT)(pControllerExt->VirtualAddress+0x0D20) ) == *(USHORT *)"OS" )
|
||
{
|
||
break;
|
||
}
|
||
|
||
KeDelayExecutionThread( KernelMode, FALSE, &Timeout );
|
||
}
|
||
|
||
if( i == 50 )
|
||
{
|
||
// The FEPOS didn't initialize within 5 seconds.
|
||
DigiDump( DIGIERRORS, ("*** Epc FEPOS did NOT initialize! ***\n") );
|
||
DigiLogError( GlobalDriverObject,
|
||
NULL,
|
||
DigiPhysicalZero,
|
||
DigiPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
__LINE__,
|
||
STATUS_SERIAL_NO_DEVICE_INITED,
|
||
SERIAL_FEPOS_INIT_FAILURE,
|
||
pControllerExt->ControllerName.Length + sizeof(WCHAR),
|
||
pControllerExt->ControllerName.Buffer,
|
||
0,
|
||
NULL );
|
||
Status = STATUS_SERIAL_NO_DEVICE_INITED;
|
||
goto XXInitExit;
|
||
}
|
||
|
||
XXInitExit:
|
||
|
||
// Disable Memory
|
||
WRITE_PORT_UCHAR( pControllerExt->VirtualIO+1, 0 );
|
||
#if DBG
|
||
pControllerExt->MemoryAccess->LockBusy = FALSE;
|
||
#endif
|
||
KeReleaseSpinLock( &pControllerExt->MemoryAccess->Lock,
|
||
pControllerExt->MemoryAccess->OldIrql );
|
||
|
||
//
|
||
// Unmap and close the file
|
||
//
|
||
if( BiosFHandle )
|
||
{
|
||
DigiUnmapFile( BiosFHandle );
|
||
DigiCloseFile( BiosFHandle );
|
||
}
|
||
|
||
//
|
||
// Unmap and close the file
|
||
//
|
||
if( FEPFHandle )
|
||
{
|
||
DigiUnmapFile( FEPFHandle );
|
||
DigiCloseFile( FEPFHandle );
|
||
}
|
||
|
||
DigiDump( DIGIFLOW, ("Exiting NtEpcXXInit\n") );
|
||
|
||
#if rmm > 528
|
||
MmUnlockPagableImageSection( lockPtr );
|
||
#endif
|
||
|
||
return( Status );
|
||
} // end NtEpcXXInit
|
||
|
||
|
||
|
||
//
|
||
// We make sure the correct window on the controller is selected and
|
||
// enabled.
|
||
//
|
||
VOID NtEpcEnableWindow( IN PDIGI_CONTROLLER_EXTENSION pControllerExt,
|
||
IN USHORT Window )
|
||
{
|
||
#if DBG
|
||
BOOLEAN wasBusy = pControllerExt->MemoryAccess->LockBusy;
|
||
#endif
|
||
|
||
// Ensure exclusive access to the memory area.
|
||
KeAcquireSpinLock( &pControllerExt->MemoryAccess->Lock,
|
||
&pControllerExt->MemoryAccess->OldIrql );
|
||
#if DBG
|
||
if( wasBusy )
|
||
++pControllerExt->MemoryAccess->LockContention;
|
||
pControllerExt->MemoryAccess->LockBusy = TRUE;
|
||
#endif
|
||
|
||
WRITE_PORT_UCHAR( (pControllerExt->VirtualIO)+1, (UCHAR)(Window | FEP_MEM_ENABLE) );
|
||
if (pControllerExt->DoubleIO)
|
||
{
|
||
(void)READ_PORT_UCHAR( (pControllerExt->VirtualIO)+1 );
|
||
}
|
||
} // end NtEpcEnableWindow
|
||
|
||
|
||
|
||
//
|
||
// Disable the memory window.
|
||
//
|
||
VOID NtEpcDisableWindow( IN PDIGI_CONTROLLER_EXTENSION pControllerExt )
|
||
{
|
||
|
||
WRITE_PORT_UCHAR( (pControllerExt->VirtualIO)+1, 0 );
|
||
if (pControllerExt->DoubleIO)
|
||
{
|
||
(void)READ_PORT_UCHAR( (pControllerExt->VirtualIO)+1 );
|
||
}
|
||
|
||
#if DBG
|
||
pControllerExt->MemoryAccess->LockBusy = FALSE;
|
||
#endif
|
||
// Release exclusive access to the memory area.
|
||
KeReleaseSpinLock( &pControllerExt->MemoryAccess->Lock,
|
||
pControllerExt->MemoryAccess->OldIrql );
|
||
} // end NtEpcDisableWindow
|
||
|
||
|
||
|
||
VOID NtEpcXXDownload( PDIGI_CONTROLLER_EXTENSION pControllerExt )
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
DigiFep5 entry point for satisfying concentrator download requests.
|
||
|
||
Arguments:
|
||
|
||
pControllerExt - pointer to this controllers specific information.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PFEP5_DOWNLOAD pCtrlConcImage, pDownloadConcImage;
|
||
int x;
|
||
USHORT offset, FepDownloadOffset;
|
||
ULONG bsize=0L;
|
||
|
||
EnableWindow( pControllerExt, pControllerExt->Global.Window );
|
||
|
||
FepDownloadOffset = READ_REGISTER_USHORT( (PUSHORT)(pControllerExt->VirtualAddress+FEP_DLREQ) );
|
||
if( FepDownloadOffset == 0 )
|
||
{
|
||
DisableWindow( pControllerExt );
|
||
return;
|
||
}
|
||
|
||
// Okay, we really do have a concentrator download request, lets
|
||
// make the controller happy.
|
||
x = 0x80;
|
||
while( FepDownloadOffset >= pControllerExt->WindowSize )
|
||
{
|
||
x++;
|
||
//
|
||
// move the controller memory window.
|
||
//
|
||
WRITE_PORT_UCHAR( pControllerExt->VirtualIO+1, (UCHAR)x );
|
||
FepDownloadOffset -= ((USHORT)(pControllerExt->WindowSize));
|
||
}
|
||
|
||
pCtrlConcImage = (PFEP5_DOWNLOAD)( pControllerExt->VirtualAddress +
|
||
FepDownloadOffset );
|
||
|
||
DigiDump( (DIGIINIT|DIGICONC),
|
||
("Concentrator download request from controller object extension = 0x%x, Seq = 0x%hx.\n",
|
||
pCtrlConcImage,
|
||
READ_REGISTER_UCHAR( (PUCHAR)((PUCHAR)pCtrlConcImage +
|
||
FIELD_OFFSET(FEP5_DOWNLOAD, Seq)) )));
|
||
|
||
if( READ_REGISTER_UCHAR( (PUCHAR)((PUCHAR)pCtrlConcImage +
|
||
FIELD_OFFSET(FEP5_DOWNLOAD, Seq)) ) == 0 )
|
||
{
|
||
DigiDump( (DIGICONC), (" EpcConcentratorCode = 0x%x, CXConcentratorCode = 0x%x\n",
|
||
(ULONG)EpcConcentratorCode,
|
||
(ULONG)CXConcentratorCode) );
|
||
// Find image for hardware rev range.
|
||
for( x = 0; x < NIMAGES; x++ )
|
||
{
|
||
DigiDump( (DIGICONC), (" Concentrator[%d] = 0x%x\n",
|
||
x, ConcentratorImages[x]) );
|
||
pDownloadConcImage = (PFEP5_DOWNLOAD)ConcentratorImages[x];
|
||
DigiDump( (DIGICONC),
|
||
(" pDownloadConcImage = 0x%x, pDownloadConcImage->Size = 0x%hx\n"
|
||
" pDownloadConcImage->LRev = 0x%hx, pCtrlConcImage->LRev = 0x%hx\n"
|
||
" pDownloadConcImage->HRev = 0x%hx, pCtrlConcImage->HRev = 0x%hx\n",
|
||
" pDownloadConcImage->SRev = 0x%hx, pCtrlConcImage->SRev = 0x%hx\n",
|
||
pDownloadConcImage,
|
||
(USHORT)pDownloadConcImage->Size,
|
||
(USHORT)pDownloadConcImage->LRev,
|
||
(USHORT)READ_REGISTER_USHORT( (PUSHORT)((PUCHAR)pCtrlConcImage +
|
||
FIELD_OFFSET(FEP5_DOWNLOAD, LRev)) ),
|
||
(USHORT)pDownloadConcImage->HRev,
|
||
(USHORT)READ_REGISTER_USHORT( (PUSHORT)((PUCHAR)pCtrlConcImage +
|
||
FIELD_OFFSET(FEP5_DOWNLOAD, HRev)) ),
|
||
(USHORT)pDownloadConcImage->SRev,
|
||
(USHORT)READ_REGISTER_USHORT( (PUSHORT)((PUCHAR)pCtrlConcImage +
|
||
FIELD_OFFSET(FEP5_DOWNLOAD, SRev)) )
|
||
) );
|
||
if( (pDownloadConcImage->LRev <=
|
||
READ_REGISTER_USHORT( (PUSHORT)((PUCHAR)pCtrlConcImage +
|
||
FIELD_OFFSET(FEP5_DOWNLOAD, LRev)) )) &&
|
||
(READ_REGISTER_USHORT( (PUSHORT)((PUCHAR)pCtrlConcImage +
|
||
FIELD_OFFSET(FEP5_DOWNLOAD, HRev)) ) <=
|
||
pDownloadConcImage->HRev) )
|
||
break;
|
||
}
|
||
|
||
if( x >= NIMAGES )
|
||
{
|
||
// Didn't find a valid concentrator image.
|
||
DigiDump( DIGIERRORS,
|
||
("*** XXDownload: No valid concentrator images exist. ***\n") );
|
||
DisableWindow( pControllerExt );
|
||
return;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// find image version required
|
||
for( x = 0; x < NIMAGES; x++ )
|
||
{
|
||
DigiDump( (DIGICONC), (" Concentrator[%d] = 0x%x\n",
|
||
x, ConcentratorImages[x]) );
|
||
|
||
DigiDump( (DIGICONC), (" pDownloadConcImage->SRev = 0x%hx, pCtrlConcImage->SRev = 0x%hx\n",
|
||
pDownloadConcImage->HRev,
|
||
READ_REGISTER_USHORT( (PUSHORT)((PUCHAR)pCtrlConcImage +
|
||
FIELD_OFFSET(FEP5_DOWNLOAD, HRev)) )
|
||
) );
|
||
|
||
pDownloadConcImage = (PFEP5_DOWNLOAD)ConcentratorImages[x];
|
||
|
||
if( pDownloadConcImage->SRev ==
|
||
READ_REGISTER_USHORT( (PUSHORT)((PUCHAR)pCtrlConcImage +
|
||
FIELD_OFFSET(FEP5_DOWNLOAD, SRev)) ) )
|
||
break;
|
||
}
|
||
|
||
if( x >= NIMAGES )
|
||
{
|
||
// No valid images exist
|
||
DigiDump( DIGIERRORS,
|
||
("*** XXDownload: No valid concentrator images exist. ***\n") );
|
||
ASSERT( x < NIMAGES );
|
||
DisableWindow( pControllerExt );
|
||
return;
|
||
}
|
||
}
|
||
|
||
// Download block of image
|
||
|
||
offset = 1024 * READ_REGISTER_UCHAR( (PUCHAR)((PUCHAR)pCtrlConcImage +
|
||
FIELD_OFFSET(FEP5_DOWNLOAD, Seq)) );
|
||
|
||
DigiDump( DIGICONC, (" offset = 0x%hx\n", offset) );
|
||
|
||
if( offset < pDownloadConcImage->Size )
|
||
{
|
||
// Determine block size, set segment, set size, set pointers,
|
||
// and copy block.
|
||
if(( (USHORT)bsize = pDownloadConcImage->Size - offset ) > 1024 )
|
||
bsize = 1024;
|
||
|
||
// Copy image version infor to download area
|
||
WRITE_REGISTER_USHORT( (PUSHORT)((PUCHAR)pCtrlConcImage +
|
||
FIELD_OFFSET(FEP5_DOWNLOAD, SRev) ),
|
||
pDownloadConcImage->SRev );
|
||
WRITE_REGISTER_USHORT( (PUSHORT)((PUCHAR)pCtrlConcImage +
|
||
FIELD_OFFSET(FEP5_DOWNLOAD, LRev) ),
|
||
pDownloadConcImage->LRev );
|
||
WRITE_REGISTER_USHORT( (PUSHORT)((PUCHAR)pCtrlConcImage +
|
||
FIELD_OFFSET(FEP5_DOWNLOAD, HRev) ),
|
||
pDownloadConcImage->HRev );
|
||
|
||
WRITE_REGISTER_USHORT( (PUSHORT)((PUCHAR)pCtrlConcImage +
|
||
FIELD_OFFSET(FEP5_DOWNLOAD, Seg) ),
|
||
(USHORT)((READ_REGISTER_UCHAR( (PUCHAR)pCtrlConcImage +
|
||
FIELD_OFFSET(FEP5_DOWNLOAD, Seq) )
|
||
* 64) +
|
||
pDownloadConcImage->Seg) );
|
||
WRITE_REGISTER_USHORT( (PUSHORT)((PUCHAR)pCtrlConcImage +
|
||
FIELD_OFFSET(FEP5_DOWNLOAD, Size) ),
|
||
(USHORT)bsize );
|
||
|
||
// Copy the data
|
||
WRITE_REGISTER_BUFFER_UCHAR( (PUCHAR)((PUCHAR)pCtrlConcImage +
|
||
FIELD_OFFSET(FEP5_DOWNLOAD, Data)),
|
||
(PUCHAR)((PUCHAR)pDownloadConcImage + offset),
|
||
bsize );
|
||
}
|
||
else
|
||
{
|
||
// Image has been downloaded, set segment and size to indicate
|
||
// no more blocks.
|
||
WRITE_REGISTER_USHORT( (PUSHORT)((PUCHAR)pCtrlConcImage +
|
||
FIELD_OFFSET(FEP5_DOWNLOAD, Seg) ),
|
||
pDownloadConcImage->Seg );
|
||
WRITE_REGISTER_USHORT( (PUSHORT)((PUCHAR)pCtrlConcImage +
|
||
FIELD_OFFSET(FEP5_DOWNLOAD, Size) ),
|
||
0 );
|
||
}
|
||
|
||
WRITE_PORT_UCHAR( pControllerExt->VirtualIO+1, (UCHAR)0x80 );
|
||
WRITE_REGISTER_USHORT( (PUSHORT)(pControllerExt->VirtualAddress+FEP_DLREQ),
|
||
0 );
|
||
DisableWindow( pControllerExt );
|
||
} // end NtEpcXXDownload
|
||
|
||
|
||
|
||
//
|
||
// Given a segment address as viewed from the controller's CPU, generate
|
||
// a FEPOS5_ADDRESS.
|
||
//
|
||
NTSTATUS NtEpcBoard2Fep5Address( PDIGI_CONTROLLER_EXTENSION ControllerExt,
|
||
USHORT ControllerAddress,
|
||
PFEPOS5_ADDRESS FepAddress )
|
||
{
|
||
ULONG Temp;
|
||
|
||
Temp = ((ULONG)ControllerAddress & 0x0000FFFF) << 4;
|
||
|
||
FepAddress->Window = (USHORT)((Temp / ControllerExt->WindowSize) & 0xFFFF);
|
||
FepAddress->Offset = (USHORT)(Temp -
|
||
( FepAddress->Window * (USHORT)(ControllerExt->WindowSize) ));
|
||
|
||
return( STATUS_SUCCESS );
|
||
} // end NtEpcBoard2Fep5Address
|
||
|
||
//
|
||
// NtEpcDiagnose will examine and return info about a particular card, and also
|
||
// try to fix the card if possible.
|
||
//
|
||
LARGE_INTEGER NtEpcDiagnose(PDIGI_CONTROLLER_EXTENSION pControllerExt)
|
||
{
|
||
LARGE_INTEGER Result;
|
||
|
||
Result.HighPart = 0;
|
||
Result.LowPart = 0;
|
||
|
||
Result.LowPart += pControllerExt->BusType;
|
||
|
||
return Result;
|
||
}
|
||
|
||
|
||
NTSTATUS GetEpcConfigInfo( PUNICODE_STRING ControllerPath,
|
||
PUCHAR EPCConfigString,
|
||
PULONG EPCConfigStringSize,
|
||
PDIGI_CONTROLLER_EXTENSION ControllerExt )
|
||
{
|
||
UNICODE_STRING ParametersPath, LinePath, ConcentratorPath,
|
||
PortPath, EBIPath;
|
||
UNICODE_STRING CurNtNameForPort, CurSymbolicLinkName;
|
||
|
||
PWSTR ParametersString=L"Parameters";
|
||
NTSTATUS Status=STATUS_SUCCESS;
|
||
PRTL_QUERY_REGISTRY_TABLE TableInfo = NULL;
|
||
|
||
PDIGI_CONFIG_INFO NewConfigInfo;
|
||
|
||
OBJECT_ATTRIBUTES ParametersAttributes;
|
||
HANDLE ParametersHandle;
|
||
|
||
ULONG LineSpeed, DefaultLineSpeed;
|
||
int line;
|
||
|
||
#if rmm > 528
|
||
PVOID lockPtr;
|
||
|
||
lockPtr = MmLockPagableCodeSection( GetEpcConfigInfo );
|
||
#endif
|
||
|
||
LineSpeed = 0L;
|
||
DefaultLineSpeed = DEFAULT_LINE_SPEED;
|
||
*EPCConfigStringSize = 0L;
|
||
ControllerExt->NumberOfPorts = 0;
|
||
|
||
RtlInitUnicodeString( &ParametersPath, NULL );
|
||
RtlInitUnicodeString( &LinePath, NULL );
|
||
RtlInitUnicodeString( &ConcentratorPath, NULL );
|
||
RtlInitUnicodeString( &PortPath, NULL );
|
||
RtlInitUnicodeString( &EBIPath, NULL );
|
||
|
||
RtlInitUnicodeString( &CurNtNameForPort, NULL );
|
||
RtlInitUnicodeString( &CurSymbolicLinkName, NULL );
|
||
|
||
// Allocate memory for creating a path to the Parameters
|
||
// folder
|
||
|
||
ParametersPath.MaximumLength = ControllerPath->Length +
|
||
(sizeof(WCHAR) * 20);
|
||
|
||
ParametersPath.Buffer = DigiAllocMem( PagedPool,
|
||
ParametersPath.MaximumLength );
|
||
|
||
if( !ParametersPath.Buffer )
|
||
{
|
||
DigiDump( DIGIERRORS, ("NTEPC: Could not allocate string for Parameters path\n"
|
||
"----- to LineX for %wZ\n",
|
||
ControllerPath) );
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto GetEPCConfigInfoExit;
|
||
}
|
||
|
||
RtlCopyUnicodeString( &ParametersPath, ControllerPath );
|
||
RtlAppendUnicodeToString( &ParametersPath, L"\\" );
|
||
RtlAppendUnicodeToString( &ParametersPath, ParametersString );
|
||
|
||
// Allocate memory for creating a path to the Parameters\LineX
|
||
// folder
|
||
|
||
LinePath.MaximumLength = ControllerPath->Length +
|
||
(sizeof(WCHAR) * 257);
|
||
|
||
LinePath.Buffer = DigiAllocMem( PagedPool,
|
||
LinePath.MaximumLength );
|
||
|
||
if( !LinePath.Buffer )
|
||
{
|
||
DigiDump( DIGIERRORS, ("NTEPC: Could not allocate string for path\n"
|
||
"----- to LineX for %wZ\n",
|
||
ControllerPath) );
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto GetEPCConfigInfoExit;
|
||
}
|
||
|
||
// Allocate memory for creating a path to the
|
||
// Parameters\LineX\ConcentratorY folder
|
||
|
||
ConcentratorPath.MaximumLength = ControllerPath->Length +
|
||
(sizeof(WCHAR) * 257);
|
||
|
||
ConcentratorPath.Buffer = DigiAllocMem( PagedPool,
|
||
ConcentratorPath.MaximumLength );
|
||
|
||
if( !ConcentratorPath.Buffer )
|
||
{
|
||
DigiDump( DIGIERRORS, ("NTEPC: Could not allocate string for path\n"
|
||
"----- to LineX\\ConcentratorY for %wZ\n",
|
||
ControllerPath) );
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto GetEPCConfigInfoExit;
|
||
}
|
||
|
||
PortPath.MaximumLength = ControllerPath->Length +
|
||
(sizeof(WCHAR) * 257);
|
||
|
||
PortPath.Buffer = DigiAllocMem( PagedPool,
|
||
PortPath.MaximumLength );
|
||
|
||
if( !PortPath.Buffer )
|
||
{
|
||
DigiDump( DIGIERRORS, ("NTEPC: Could not allocate string for path\n"
|
||
"----- to LineX\\ConcentratorY\\PortZ for %wZ",
|
||
ControllerPath) );
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto GetEPCConfigInfoExit;
|
||
}
|
||
|
||
EBIPath.MaximumLength = ConcentratorPath.MaximumLength +
|
||
(sizeof(WCHAR) * 4);
|
||
|
||
EBIPath.Buffer = DigiAllocMem( PagedPool,
|
||
EBIPath.MaximumLength );
|
||
|
||
if( !EBIPath.Buffer )
|
||
{
|
||
DigiDump( DIGIERRORS, ("NTEPC: Could not allocate string for path\n"
|
||
"----- to LineX\\ConcentratorY\\EBIZ for %wZ",
|
||
ControllerPath) );
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto GetEPCConfigInfoExit;
|
||
}
|
||
|
||
CurNtNameForPort.MaximumLength = ControllerPath->Length +
|
||
(sizeof(WCHAR) * 257);
|
||
|
||
CurNtNameForPort.Buffer = DigiAllocMem( PagedPool,
|
||
CurNtNameForPort.MaximumLength );
|
||
|
||
if( !CurNtNameForPort.Buffer )
|
||
{
|
||
DigiDump( DIGIERRORS, ("NTEPC: Could not allocate string for NtNameForPort.\n") );
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto GetEPCConfigInfoExit;
|
||
}
|
||
|
||
CurSymbolicLinkName.MaximumLength = ControllerPath->Length +
|
||
(sizeof(WCHAR) * 257);
|
||
|
||
CurSymbolicLinkName.Buffer = DigiAllocMem( PagedPool,
|
||
CurSymbolicLinkName.MaximumLength );
|
||
|
||
if( !CurSymbolicLinkName.Buffer )
|
||
{
|
||
DigiDump( DIGIERRORS, ("NTEPC: Could not allocate string for NtNameForPort.\n") );
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto GetEPCConfigInfoExit;
|
||
}
|
||
|
||
TableInfo = DigiAllocMem( PagedPool,
|
||
sizeof( RTL_QUERY_REGISTRY_TABLE ) * 4 );
|
||
|
||
if( !TableInfo )
|
||
{
|
||
DigiDump( DIGIERRORS, ("NTEPC: Could not allocate table for rtl query\n"
|
||
"----- to for %wZ\n",
|
||
ControllerPath ) );
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto GetEPCConfigInfoExit;
|
||
}
|
||
|
||
RtlZeroMemory( TableInfo, sizeof(RTL_QUERY_REGISTRY_TABLE) * 4 );
|
||
|
||
InitializeObjectAttributes( &ParametersAttributes,
|
||
&ParametersPath,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL, NULL );
|
||
|
||
if( !NT_SUCCESS( Status = ZwOpenKey( &ParametersHandle, MAXIMUM_ALLOWED,
|
||
&ParametersAttributes ) ) )
|
||
{
|
||
DigiDump( DIGIERRORS, ("NTEPC: Could not open the drivers Parameters key %wZ\n",
|
||
&ParametersPath ) );
|
||
goto GetEPCConfigInfoExit;
|
||
}
|
||
|
||
//
|
||
// Look for Line1 and Line2 keys
|
||
//
|
||
for( line = 1; line < 3; line++ )
|
||
{
|
||
OBJECT_ATTRIBUTES LineAttributes;
|
||
HANDLE LineHandle;
|
||
|
||
PWSTR LineString=L"Line";
|
||
|
||
UNICODE_STRING LineNumberUString;
|
||
WCHAR LineNumberBuffer[8];
|
||
|
||
NTSTATUS LocalScopeStatus;
|
||
|
||
RtlInitUnicodeString( &LineNumberUString, NULL );
|
||
LineNumberUString.MaximumLength = sizeof(LineNumberBuffer);
|
||
LineNumberUString.Buffer = &LineNumberBuffer[0];
|
||
RtlIntegerToUnicodeString( line, 10, &LineNumberUString );
|
||
|
||
RtlZeroMemory( LinePath.Buffer, LinePath.MaximumLength );
|
||
RtlCopyUnicodeString( &LinePath, &ParametersPath );
|
||
RtlAppendUnicodeToString( &LinePath, L"\\" );
|
||
RtlAppendUnicodeToString( &LinePath, LineString );
|
||
RtlAppendUnicodeStringToString( &LinePath, &LineNumberUString );
|
||
|
||
InitializeObjectAttributes( &LineAttributes,
|
||
&LinePath,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL, NULL );
|
||
|
||
|
||
if( !NT_SUCCESS( ZwOpenKey( &LineHandle,
|
||
KEY_READ,
|
||
&LineAttributes )))
|
||
{
|
||
//
|
||
// This Line entry does not exist, look for the next.
|
||
//
|
||
EPCConfigString[(*EPCConfigStringSize)++] = 0;
|
||
EPCConfigString[(*EPCConfigStringSize)++] = (UCHAR)DefaultLineSpeed;
|
||
continue;
|
||
}
|
||
|
||
|
||
//
|
||
// We should have a registry path something like:
|
||
// ..\<AdapterName>\Parameters\Line1
|
||
//
|
||
|
||
//
|
||
// From this position in the registry, we should look for
|
||
// a LineSpeed entry to try to override our default. This
|
||
// value is suppose to represent the speed from the host adapter
|
||
// to the first concentrator.
|
||
//
|
||
|
||
//
|
||
// Setup any defaults.
|
||
//
|
||
DefaultLineSpeed = DEFAULT_LINE_SPEED;
|
||
|
||
TableInfo[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
TableInfo[0].Name = L"LineSpeed";
|
||
TableInfo[0].EntryContext = &LineSpeed;
|
||
TableInfo[0].DefaultType = REG_DWORD;
|
||
TableInfo[0].DefaultData = &DefaultLineSpeed;
|
||
TableInfo[0].DefaultLength = sizeof(DefaultLineSpeed);
|
||
|
||
LocalScopeStatus = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE,
|
||
LinePath.Buffer,
|
||
TableInfo,
|
||
NULL, NULL );
|
||
|
||
if( NT_SUCCESS(LocalScopeStatus) )
|
||
{
|
||
int conc;
|
||
ULONG DefaultNumberOfPorts, NumberOfPorts;
|
||
|
||
//
|
||
// Some data may have been found. Let's process it.
|
||
//
|
||
DigiDump( DIGIINIT, ("NTEPC: %wZ registry info\n"
|
||
"----- LineSpeed = 0x%x\n",
|
||
&LinePath, LineSpeed) );
|
||
|
||
EPCConfigString[(*EPCConfigStringSize)++] = 00;
|
||
EPCConfigString[(*EPCConfigStringSize)++] = (UCHAR)LineSpeed;
|
||
|
||
// Look for up to 14 Concentrators on the main concentrator line
|
||
|
||
for( conc = 1; conc < 15; conc++ )
|
||
{
|
||
OBJECT_ATTRIBUTES ConcentratorAttributes;
|
||
HANDLE ConcentratorHandle;
|
||
|
||
PWSTR ConcentratorString=L"Concentrator";
|
||
|
||
UNICODE_STRING ConcentratorNumberUString;
|
||
WCHAR ConcentratorNumberBuffer[8];
|
||
BOOLEAN KeyFound = FALSE;
|
||
|
||
RtlInitUnicodeString( &ConcentratorNumberUString, NULL );
|
||
ConcentratorNumberUString.MaximumLength = sizeof(ConcentratorNumberBuffer);
|
||
ConcentratorNumberUString.Buffer = &ConcentratorNumberBuffer[0];
|
||
RtlIntegerToUnicodeString( conc, 10, &ConcentratorNumberUString );
|
||
|
||
RtlZeroMemory( ConcentratorPath.Buffer, ConcentratorPath.MaximumLength );
|
||
RtlCopyUnicodeString( &ConcentratorPath, &LinePath );
|
||
RtlAppendUnicodeToString( &ConcentratorPath, L"\\" );
|
||
RtlAppendUnicodeToString( &ConcentratorPath,
|
||
ConcentratorString );
|
||
RtlAppendUnicodeStringToString( &ConcentratorPath,
|
||
&ConcentratorNumberUString );
|
||
|
||
DigiDump( DIGIINIT, ("NTEPC: Attempting to open key:\n %wZ\n",
|
||
&ConcentratorPath) );
|
||
|
||
InitializeObjectAttributes( &ConcentratorAttributes,
|
||
&ConcentratorPath,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL, NULL );
|
||
|
||
if( !NT_SUCCESS( ZwOpenKey( &ConcentratorHandle,
|
||
KEY_READ,
|
||
&ConcentratorAttributes ) ) )
|
||
{
|
||
DigiDump( DIGIERRORS, ("NTEPC: Could not open the drivers %wZ key.\n",
|
||
&ConcentratorPath ) );
|
||
|
||
// Unlike the LineX key, we assume our configuration is
|
||
// such that our Concentrator entries are numerically
|
||
// ordered at all times.
|
||
break;
|
||
}
|
||
|
||
TableInfo[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
TableInfo[0].Name = L"LineSpeed";
|
||
TableInfo[0].EntryContext = &LineSpeed;
|
||
TableInfo[0].DefaultType = REG_DWORD;
|
||
TableInfo[0].DefaultData = &DefaultLineSpeed;
|
||
TableInfo[0].DefaultLength = sizeof(DefaultLineSpeed);
|
||
|
||
TableInfo[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
TableInfo[1].Name = L"NumberOfPorts";
|
||
TableInfo[1].EntryContext = &NumberOfPorts;
|
||
TableInfo[1].DefaultType = REG_DWORD;
|
||
TableInfo[1].DefaultData = &DefaultNumberOfPorts;
|
||
TableInfo[1].DefaultLength = sizeof(DefaultNumberOfPorts);
|
||
|
||
LineSpeed = DefaultLineSpeed = DEFAULT_LINE_SPEED;
|
||
NumberOfPorts = DefaultNumberOfPorts = DEFAULT_NUMBER_OF_PORTS;
|
||
|
||
LocalScopeStatus = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE,
|
||
ConcentratorPath.Buffer,
|
||
TableInfo,
|
||
NULL, NULL );
|
||
|
||
if( NT_SUCCESS(LocalScopeStatus) )
|
||
{
|
||
int port, ebi;
|
||
|
||
// Look for up to 128 ports on the current concentrator
|
||
|
||
for( port = 1; port < 129; port++ )
|
||
{
|
||
OBJECT_ATTRIBUTES PortAttributes;
|
||
HANDLE PortHandle;
|
||
NTSTATUS KeyExists;
|
||
|
||
PWSTR PortString=L"Port";
|
||
|
||
UNICODE_STRING PortNumberUString;
|
||
WCHAR PortNumberBuffer[8];
|
||
|
||
RtlInitUnicodeString( &PortNumberUString, NULL );
|
||
PortNumberUString.MaximumLength = sizeof(PortNumberBuffer);
|
||
PortNumberUString.Buffer = &PortNumberBuffer[0];
|
||
RtlIntegerToUnicodeString( port, 10, &PortNumberUString );
|
||
|
||
RtlZeroMemory( PortPath.Buffer, PortPath.MaximumLength );
|
||
RtlCopyUnicodeString( &PortPath, &ConcentratorPath );
|
||
RtlAppendUnicodeToString( &PortPath, L"\\" );
|
||
RtlAppendUnicodeToString( &PortPath, PortString );
|
||
RtlAppendUnicodeStringToString( &PortPath,
|
||
&PortNumberUString );
|
||
|
||
// DigiDump( DIGIINIT, ("NTEPC: Checking for key:\n %wZ\n",
|
||
// &PortPath) );
|
||
|
||
KeyExists = RtlCheckRegistryKey( RTL_REGISTRY_ABSOLUTE,
|
||
PortPath.Buffer );
|
||
|
||
if( !NT_SUCCESS(KeyExists) )
|
||
{
|
||
// I assume the PortZ keys are numberically ordered,
|
||
// so when a given PortZ entry is not found, it
|
||
// indicates the end of the number of ports
|
||
break;
|
||
}
|
||
|
||
|
||
RtlZeroMemory( CurNtNameForPort.Buffer,
|
||
CurNtNameForPort.MaximumLength );
|
||
RtlCopyUnicodeString( &CurNtNameForPort,
|
||
&ControllerExt->ControllerName );
|
||
RtlAppendUnicodeToString( &CurNtNameForPort,
|
||
LineString );
|
||
RtlAppendUnicodeStringToString( &CurNtNameForPort,
|
||
&LineNumberUString );
|
||
|
||
RtlAppendUnicodeToString( &CurNtNameForPort,
|
||
ConcentratorString );
|
||
RtlAppendUnicodeStringToString( &CurNtNameForPort,
|
||
&ConcentratorNumberUString );
|
||
|
||
RtlAppendUnicodeToString( &CurNtNameForPort, PortString );
|
||
RtlAppendUnicodeStringToString( &CurNtNameForPort,
|
||
&PortNumberUString );
|
||
// DigiDump( DIGIINIT, ("NTEPC: CurNtNameForPort = %wZ\n",
|
||
// &CurNtNameForPort) );
|
||
|
||
InitializeObjectAttributes( &PortAttributes,
|
||
&PortPath,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL, NULL );
|
||
|
||
Status = ZwOpenKey( &PortHandle,
|
||
KEY_READ,
|
||
&PortAttributes );
|
||
|
||
if( !NT_SUCCESS(Status) )
|
||
{
|
||
DigiDump( DIGIINIT, ("NTEPC: Error opening key:\n %wZ\n",
|
||
&PortPath) );
|
||
}
|
||
|
||
//
|
||
// We need to reset the CurSymbolicLinkName.MaximumLength
|
||
// to the appropriate value because of a "feature" in
|
||
// the RtlQueryRegistryValues call. If an entry is not
|
||
// found and the EntryContext is to a Unicode string, then
|
||
// Rtl function will reassign the MaximumLength to 0.
|
||
//
|
||
CurSymbolicLinkName.MaximumLength = ControllerPath->Length +
|
||
(sizeof(WCHAR) * 257);
|
||
|
||
RtlZeroMemory( CurSymbolicLinkName.Buffer,
|
||
CurSymbolicLinkName.MaximumLength );
|
||
// Read the registry for the DosDevices Name to use
|
||
TableInfo[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
TableInfo[0].Name = DEFAULT_DIRECTORY;
|
||
TableInfo[0].EntryContext = &CurSymbolicLinkName;
|
||
|
||
Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE,
|
||
PortPath.Buffer,
|
||
TableInfo,
|
||
NULL, NULL );
|
||
|
||
if( !NT_SUCCESS(Status) )
|
||
{
|
||
// Assign a bogus Name if a DosDevices Value
|
||
// is not found!
|
||
Status = Status;
|
||
DigiDump( DIGIINIT, ("NTEPC: Bogus SymbolicLinkName\n") );
|
||
}
|
||
else
|
||
{
|
||
// DigiDump( DIGIINIT, ("NTEPC: CurSymbolicLinkName = %wZ\n",
|
||
// &CurSymbolicLinkName) );
|
||
}
|
||
|
||
// DigiDump( DIGIINIT, ("NTEPC: After RtlQueryRegistryValues, CurSymbolicLinkName.MaxLength = %u\n",
|
||
// CurSymbolicLinkName.MaximumLength) );
|
||
|
||
ZwClose( PortHandle );
|
||
|
||
// Setup and initialize the config information
|
||
NewConfigInfo = DigiAllocMem( PagedPool,
|
||
sizeof(DIGI_CONFIG_INFO) );
|
||
if( !NewConfigInfo )
|
||
{
|
||
|
||
}
|
||
|
||
RtlInitUnicodeString( &NewConfigInfo->SymbolicLinkName, NULL );
|
||
NewConfigInfo->SymbolicLinkName.MaximumLength =
|
||
CurSymbolicLinkName.MaximumLength;
|
||
|
||
NewConfigInfo->SymbolicLinkName.Buffer =
|
||
#if DBG
|
||
DigiAllocMem( NonPagedPool,
|
||
NewConfigInfo->SymbolicLinkName.MaximumLength );
|
||
#else
|
||
DigiAllocMem( PagedPool,
|
||
NewConfigInfo->SymbolicLinkName.MaximumLength );
|
||
#endif
|
||
|
||
if( !NewConfigInfo->SymbolicLinkName.Buffer )
|
||
{
|
||
|
||
}
|
||
|
||
RtlInitUnicodeString( &NewConfigInfo->NtNameForPort, NULL );
|
||
NewConfigInfo->NtNameForPort.MaximumLength =
|
||
CurNtNameForPort.MaximumLength;
|
||
|
||
NewConfigInfo->NtNameForPort.Buffer =
|
||
DigiAllocMem( PagedPool,
|
||
NewConfigInfo->NtNameForPort.MaximumLength );
|
||
|
||
if( !NewConfigInfo->NtNameForPort.Buffer )
|
||
{
|
||
|
||
}
|
||
|
||
|
||
RtlCopyUnicodeString( &NewConfigInfo->NtNameForPort,
|
||
&CurNtNameForPort );
|
||
|
||
RtlCopyUnicodeString( &NewConfigInfo->SymbolicLinkName,
|
||
&CurSymbolicLinkName );
|
||
|
||
InsertTailList( &ControllerExt->ConfigList,
|
||
&NewConfigInfo->ListEntry );
|
||
|
||
} // end for( port = 1; port < 129; port++ )
|
||
|
||
NumberOfPorts = port - 1;
|
||
|
||
ControllerExt->NumberOfPorts += NumberOfPorts;
|
||
EPCConfigString[(*EPCConfigStringSize)++] = (UCHAR)NumberOfPorts;
|
||
|
||
//
|
||
// Look for an EBI1 key. If it exists, assume there are
|
||
// EBI modules on the current EPC concentrator. Otherwise,
|
||
// we continue on.
|
||
//
|
||
|
||
KeyFound = FALSE;
|
||
|
||
//
|
||
// Look for up to 3 EBI modules connected to the current
|
||
// EPC concentrator.
|
||
//
|
||
for( ebi = 1; ebi < 4; ebi++ )
|
||
{
|
||
NTSTATUS KeyExists;
|
||
|
||
PWSTR EBIString=L"Concentrator";
|
||
|
||
UNICODE_STRING EBINumberUString;
|
||
WCHAR EBINumberBuffer[8];
|
||
|
||
RtlInitUnicodeString( &EBINumberUString, NULL );
|
||
EBINumberUString.MaximumLength = sizeof(EBINumberBuffer);
|
||
EBINumberUString.Buffer = &EBINumberBuffer[0];
|
||
RtlIntegerToUnicodeString( ebi, 10, &EBINumberUString );
|
||
|
||
RtlZeroMemory( EBIPath.Buffer, EBIPath.MaximumLength );
|
||
RtlCopyUnicodeString( &EBIPath, &ConcentratorPath );
|
||
RtlAppendUnicodeToString( &EBIPath, L"\\" );
|
||
RtlAppendUnicodeToString( &EBIPath, EBIString );
|
||
RtlAppendUnicodeStringToString( &EBIPath,
|
||
&EBINumberUString );
|
||
|
||
|
||
DigiDump( DIGIINIT, ("NTEPC: Checking for key:\n %wZ\n",
|
||
&EBIPath) );
|
||
|
||
KeyExists = RtlCheckRegistryKey( RTL_REGISTRY_ABSOLUTE,
|
||
EBIPath.Buffer );
|
||
|
||
if( !NT_SUCCESS(KeyExists) )
|
||
{
|
||
//
|
||
// I assume the EBIZ keys are numberically ordered,
|
||
// so when a given EBIZ entry is not found, it
|
||
// indicates the end of the number of ports
|
||
//
|
||
break;
|
||
}
|
||
|
||
KeyFound = TRUE;
|
||
|
||
//
|
||
// Indicate we have more information to add.
|
||
//
|
||
EPCConfigString[(*EPCConfigStringSize)-1] |= 0x80;
|
||
|
||
//
|
||
// Look for the NumberOfPorts value so we know how many
|
||
// ports are on this EBI module.
|
||
//
|
||
TableInfo[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
TableInfo[0].Name = L"NumberOfPorts";
|
||
TableInfo[0].EntryContext = &NumberOfPorts;
|
||
TableInfo[0].DefaultType = REG_DWORD;
|
||
TableInfo[0].DefaultData = &DefaultNumberOfPorts;
|
||
TableInfo[0].DefaultLength = sizeof(DefaultNumberOfPorts);
|
||
|
||
NumberOfPorts = DefaultNumberOfPorts = DEFAULT_NUMBER_OF_PORTS;
|
||
|
||
LocalScopeStatus = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE,
|
||
EBIPath.Buffer,
|
||
TableInfo,
|
||
NULL, NULL );
|
||
|
||
if( NT_SUCCESS(LocalScopeStatus) )
|
||
{
|
||
int ebiport;
|
||
|
||
// Look for up to 128 ports on the current concentrator
|
||
|
||
for( ebiport = 1; ebiport < 129; ebiport++ )
|
||
{
|
||
OBJECT_ATTRIBUTES PortAttributes;
|
||
HANDLE PortHandle;
|
||
NTSTATUS KeyExists;
|
||
|
||
PWSTR PortString=L"Port";
|
||
|
||
UNICODE_STRING PortNumberUString;
|
||
WCHAR PortNumberBuffer[8];
|
||
|
||
RtlInitUnicodeString( &PortNumberUString, NULL );
|
||
PortNumberUString.MaximumLength = sizeof(PortNumberBuffer);
|
||
PortNumberUString.Buffer = &PortNumberBuffer[0];
|
||
RtlIntegerToUnicodeString( ebiport, 10, &PortNumberUString );
|
||
|
||
RtlZeroMemory( PortPath.Buffer, PortPath.MaximumLength );
|
||
RtlCopyUnicodeString( &PortPath, &EBIPath );
|
||
RtlAppendUnicodeToString( &PortPath, L"\\" );
|
||
RtlAppendUnicodeToString( &PortPath, PortString );
|
||
RtlAppendUnicodeStringToString( &PortPath,
|
||
&PortNumberUString );
|
||
|
||
DigiDump( DIGIINIT, ("NTEPC: Checking for key:\n %wZ\n",
|
||
&PortPath) );
|
||
|
||
KeyExists = RtlCheckRegistryKey( RTL_REGISTRY_ABSOLUTE,
|
||
PortPath.Buffer );
|
||
|
||
if( !NT_SUCCESS(KeyExists) )
|
||
{
|
||
// I assume the PortZ keys are numberically ordered,
|
||
// so when a given PortZ entry is not found, it
|
||
// indicates the end of the number of ports
|
||
break;
|
||
}
|
||
|
||
|
||
RtlZeroMemory( CurNtNameForPort.Buffer,
|
||
CurNtNameForPort.MaximumLength );
|
||
|
||
RtlCopyUnicodeString( &CurNtNameForPort,
|
||
&ControllerExt->ControllerName );
|
||
RtlAppendUnicodeToString( &CurNtNameForPort,
|
||
LineString );
|
||
RtlAppendUnicodeStringToString( &CurNtNameForPort,
|
||
&LineNumberUString );
|
||
|
||
RtlAppendUnicodeToString( &CurNtNameForPort,
|
||
ConcentratorString );
|
||
RtlAppendUnicodeStringToString( &CurNtNameForPort,
|
||
&ConcentratorNumberUString );
|
||
|
||
RtlAppendUnicodeToString( &CurNtNameForPort,
|
||
EBIString );
|
||
RtlAppendUnicodeStringToString( &CurNtNameForPort,
|
||
&EBINumberUString );
|
||
|
||
RtlAppendUnicodeToString( &CurNtNameForPort, PortString );
|
||
RtlAppendUnicodeStringToString( &CurNtNameForPort,
|
||
&PortNumberUString );
|
||
|
||
//
|
||
// We should now have an NT name space something
|
||
// like: ntepc01Line1Concentrator1EBI1Port1
|
||
//
|
||
// DigiDump( DIGIINIT, ("NTEPC: CurNtNameForPort = %wZ\n",
|
||
// &CurNtNameForPort) );
|
||
|
||
InitializeObjectAttributes( &PortAttributes,
|
||
&PortPath,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL, NULL );
|
||
|
||
Status = ZwOpenKey( &PortHandle,
|
||
KEY_READ,
|
||
&PortAttributes );
|
||
|
||
if( !NT_SUCCESS(Status) )
|
||
{
|
||
DigiDump( DIGIINIT, ("NTEPC: Error opening key:\n %wZ\n",
|
||
&PortPath) );
|
||
}
|
||
|
||
//
|
||
// We need to reset the CurSymbolicLinkName.MaximumLength
|
||
// to the appropriate value because of a "feature" in
|
||
// the RtlQueryRegistryValues call. If an entry is not
|
||
// found and the EntryContext is to a Unicode string, then
|
||
// Rtl function will reassign the MaximumLength to 0.
|
||
//
|
||
CurSymbolicLinkName.MaximumLength = ControllerPath->Length +
|
||
(sizeof(WCHAR) * 257);
|
||
|
||
RtlZeroMemory( CurSymbolicLinkName.Buffer,
|
||
CurSymbolicLinkName.MaximumLength );
|
||
// Read the registry for the DosDevices Name to use
|
||
TableInfo[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
TableInfo[0].Name = DEFAULT_DIRECTORY;
|
||
TableInfo[0].EntryContext = &CurSymbolicLinkName;
|
||
|
||
Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE,
|
||
PortPath.Buffer,
|
||
TableInfo,
|
||
NULL, NULL );
|
||
|
||
if( !NT_SUCCESS(Status) )
|
||
{
|
||
// Assign a bogus Name if a DosDevices Value
|
||
// is not found!
|
||
Status = Status;
|
||
DigiDump( DIGIINIT, ("NTEPC: Bogus SymbolicLinkName\n") );
|
||
}
|
||
else
|
||
{
|
||
// DigiDump( DIGIINIT, ("NTEPC: CurSymbolicLinkName = %wZ\n",
|
||
// &CurSymbolicLinkName) );
|
||
}
|
||
|
||
// DigiDump( DIGIINIT, ("NTEPC: After RtlQueryRegistryValues, CurSymbolicLinkName.MaxLength = %u\n",
|
||
// CurSymbolicLinkName.MaximumLength) );
|
||
|
||
ZwClose( PortHandle );
|
||
|
||
// Setup and initialize the config information
|
||
NewConfigInfo = DigiAllocMem( PagedPool,
|
||
sizeof(DIGI_CONFIG_INFO) );
|
||
if( !NewConfigInfo )
|
||
{
|
||
|
||
}
|
||
|
||
RtlInitUnicodeString( &NewConfigInfo->SymbolicLinkName, NULL );
|
||
NewConfigInfo->SymbolicLinkName.MaximumLength =
|
||
CurSymbolicLinkName.MaximumLength;
|
||
|
||
NewConfigInfo->SymbolicLinkName.Buffer =
|
||
#if DBG
|
||
DigiAllocMem( NonPagedPool,
|
||
NewConfigInfo->SymbolicLinkName.MaximumLength );
|
||
#else
|
||
DigiAllocMem( PagedPool,
|
||
NewConfigInfo->SymbolicLinkName.MaximumLength );
|
||
#endif
|
||
|
||
if( !NewConfigInfo->SymbolicLinkName.Buffer )
|
||
{
|
||
|
||
}
|
||
|
||
RtlInitUnicodeString( &NewConfigInfo->NtNameForPort, NULL );
|
||
NewConfigInfo->NtNameForPort.MaximumLength =
|
||
CurNtNameForPort.MaximumLength;
|
||
|
||
NewConfigInfo->NtNameForPort.Buffer =
|
||
DigiAllocMem( PagedPool,
|
||
NewConfigInfo->NtNameForPort.MaximumLength );
|
||
|
||
if( !NewConfigInfo->NtNameForPort.Buffer )
|
||
{
|
||
|
||
}
|
||
|
||
|
||
RtlCopyUnicodeString( &NewConfigInfo->NtNameForPort,
|
||
&CurNtNameForPort );
|
||
|
||
RtlCopyUnicodeString( &NewConfigInfo->SymbolicLinkName,
|
||
&CurSymbolicLinkName );
|
||
|
||
InsertTailList( &ControllerExt->ConfigList,
|
||
&NewConfigInfo->ListEntry );
|
||
|
||
} // end for( ebiport = 1; ebiport < 129; ebiport++ )
|
||
|
||
NumberOfPorts = ebiport - 1;
|
||
|
||
ControllerExt->NumberOfPorts += NumberOfPorts;
|
||
EPCConfigString[(*EPCConfigStringSize)++] = (UCHAR)NumberOfPorts;
|
||
} // if EBI present
|
||
} // for EBI
|
||
|
||
//
|
||
// Add the Line speed information
|
||
//
|
||
EPCConfigString[(*EPCConfigStringSize)++] = (UCHAR)LineSpeed;
|
||
|
||
// DigiDump( DIGIINIT, ("NTEPC: %wZ registry info\n"
|
||
// "----- LineSpeed = 0x%x\n",
|
||
// &ConcentratorPath, LineSpeed) );
|
||
//
|
||
// DigiDump( DIGIINIT, ("----- Number of Ports = %d\n",
|
||
// NumberOfPorts) );
|
||
} // if CONC present
|
||
|
||
ZwClose( ConcentratorHandle );
|
||
|
||
} // end for( conc = 1; conc < 16; conc++ )
|
||
|
||
ZwClose( LineHandle );
|
||
}
|
||
else // LINE not present
|
||
{
|
||
EPCConfigString[(*EPCConfigStringSize)++] = 00;
|
||
EPCConfigString[(*EPCConfigStringSize)++] = (UCHAR)LineSpeed;
|
||
// DigiDump( DIGIINIT, ("NTEPC: %wZ registry DEFAULT info\n"
|
||
// "----- LineSpeed = 0x%x\n"
|
||
// "----- return value = 0x%x\n",
|
||
// &LinePath, LineSpeed, LocalScopeStatus) );
|
||
}
|
||
|
||
} // end for( line = 1; line < 3; line++ )
|
||
|
||
ZwClose( ParametersHandle );
|
||
|
||
EPCConfigString[(*EPCConfigStringSize)++] = 0xFF;
|
||
|
||
|
||
GetEPCConfigInfoExit:;
|
||
|
||
if( ParametersPath.Buffer )
|
||
DigiFreeMem( ParametersPath.Buffer );
|
||
|
||
if( LinePath.Buffer )
|
||
DigiFreeMem( LinePath.Buffer );
|
||
|
||
if( ConcentratorPath.Buffer )
|
||
DigiFreeMem( ConcentratorPath.Buffer );
|
||
|
||
if( PortPath.Buffer )
|
||
DigiFreeMem( PortPath.Buffer );
|
||
|
||
if( CurNtNameForPort.Buffer )
|
||
DigiFreeMem( CurNtNameForPort.Buffer );
|
||
|
||
if( CurSymbolicLinkName.Buffer )
|
||
DigiFreeMem( CurSymbolicLinkName.Buffer );
|
||
|
||
if( TableInfo )
|
||
DigiFreeMem( TableInfo );
|
||
|
||
#if rmm > 528
|
||
MmUnlockPagableImageSection( lockPtr );
|
||
#endif
|
||
|
||
return( Status );
|
||
} // end GetEpcConfigInfo
|
||
|
||
|
||
|
||
NTSTATUS NtEpcSuccess( IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp )
|
||
/*++
|
||
|
||
Services NtEpcCleanup, NtEpcQueryInformation, NtEpcSetInformation,
|
||
and NtEpcQueryVolumeInformation requests.
|
||
|
||
--*/
|
||
{
|
||
DigiDump( DIGIFLOW, ("Entering NtEpcSuccess\n") );
|
||
|
||
Irp->IoStatus.Information = 0;
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
DigiDump( DIGIFLOW, ("Exiting NtEpcSuccess\n") );
|
||
|
||
return( STATUS_SUCCESS );
|
||
} // end NtEpcSuccess
|
||
|
||
|
||
|
||
NTSTATUS NtEpcInternalIoControl( IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp )
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine process private IOCTL requests which should only be called
|
||
from kernel level, i.e. other drivers.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to this devices object.
|
||
|
||
Irp - Pointer to the open IRP request.
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PIO_STACK_LOCATION IrpSp;
|
||
NTSTATUS Status=STATUS_INVALID_PARAMETER;
|
||
#if rmm > 528
|
||
PVOID lockPtr;
|
||
|
||
lockPtr = MmLockPagableCodeSection( NtEpcInternalIoControl );
|
||
#endif
|
||
|
||
DigiDump( DIGIFLOW, ("Entering NtEpcInternalIoControl\n") );
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
Irp->IoStatus.Information = 0L;
|
||
|
||
switch( IrpSp->Parameters.DeviceIoControl.IoControlCode )
|
||
{
|
||
case IOCTL_DIGI_GET_ENTRY_POINTS:
|
||
{
|
||
PDIGI_MINIPORT_ENTRY_POINTS EntryPoints;
|
||
|
||
DigiDump( DIGIIOCTL, ( "NtEpc: IOCTL_DIGI_GET_ENTRY_POINTS\n" ));
|
||
|
||
if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
||
sizeof(DIGI_MINIPORT_ENTRY_POINTS) )
|
||
{
|
||
Status = STATUS_BUFFER_TOO_SMALL;
|
||
break;
|
||
}
|
||
|
||
EntryPoints = (PDIGI_MINIPORT_ENTRY_POINTS)Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
EntryPoints->XXPrepInit = NtEpcXXPrepInit;
|
||
EntryPoints->XXInit = NtEpcXXInit;
|
||
EntryPoints->EnableWindow = NtEpcEnableWindow;
|
||
EntryPoints->DisableWindow = NtEpcDisableWindow;
|
||
EntryPoints->XXDownload = NtEpcXXDownload;
|
||
EntryPoints->Board2Fep5Address = NtEpcBoard2Fep5Address;
|
||
EntryPoints->Diagnose = NtEpcDiagnose;
|
||
|
||
Irp->IoStatus.Information = sizeof(DIGI_MINIPORT_ENTRY_POINTS);
|
||
Status = STATUS_SUCCESS;
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
Irp->IoStatus.Status = Status;
|
||
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
DigiDump( DIGIFLOW, ("Exiting NtEpcInternalIoControl\n") );
|
||
#if rmm > 528
|
||
MmUnlockPagableImageSection( lockPtr );
|
||
#endif
|
||
|
||
return( Status );
|
||
} // end NtEpcInternalIoControl
|
||
|
||
|
||
|
||
NTSTATUS NtEpcCreate( IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp )
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to open the device associated with DeviceObject.
|
||
We will always allow the driver to be opened.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to this devices object.
|
||
|
||
Irp - Pointer to the open IRP request.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS
|
||
|
||
--*/
|
||
{
|
||
#if rmm > 528
|
||
PVOID lockPtr;
|
||
|
||
lockPtr = MmLockPagableCodeSection( NtEpcCreate );
|
||
#endif
|
||
|
||
DigiDump( DIGIFLOW, ("Entering NtEpcCreate\n") );
|
||
|
||
Irp->IoStatus.Information = 0L;
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
DigiDump( DIGIFLOW, ("Exiting NtEpcCreate\n") );
|
||
|
||
#if rmm > 528
|
||
MmUnlockPagableImageSection( lockPtr );
|
||
#endif
|
||
|
||
return( STATUS_SUCCESS );
|
||
} // end NtEpcCreate
|
||
|
||
|
||
|
||
NTSTATUS NtEpcClose( IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp )
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to close the device associated with DeviceObject.
|
||
We will always close the device successfully.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to this devices object.
|
||
|
||
Irp - Pointer to the open IRP request.
|
||
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS
|
||
|
||
--*/
|
||
{
|
||
#if rmm > 528
|
||
PVOID lockPtr;
|
||
|
||
lockPtr = MmLockPagableCodeSection( NtEpcClose );
|
||
#endif
|
||
|
||
DigiDump( DIGIFLOW, ("Entering NtEpcClose\n") );
|
||
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
DigiDump( DIGIFLOW, ("Exiting NtEpcClose\n") );
|
||
|
||
#if rmm > 528
|
||
MmUnlockPagableImageSection( lockPtr );
|
||
#endif
|
||
|
||
return( STATUS_SUCCESS );
|
||
} // end NtEpcClose
|
||
|
||
|
||
|
||
VOID NtEpcUnload( IN PDRIVER_OBJECT DriverObject )
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
#if rmm > 528
|
||
PVOID lockPtr;
|
||
|
||
lockPtr = MmLockPagableCodeSection( NtEpcUnload );
|
||
#endif
|
||
|
||
DigiDump( DIGIFLOW, ("Entering NtEpcUnload\n") );
|
||
|
||
IoDeleteDevice( DriverObject->DeviceObject );
|
||
|
||
DigiDump( DIGIFLOW, ("Exiting NtEpcUnload\n") );
|
||
|
||
#if rmm > 528
|
||
MmUnlockPagableImageSection( lockPtr );
|
||
#endif
|
||
|
||
return;
|
||
} // end NtEpcUnload
|
||
|
||
|
||
|
||
DIGI_MEM_COMPARES DigiMemCompare( IN PHYSICAL_ADDRESS A,
|
||
IN ULONG SpanOfA,
|
||
IN PHYSICAL_ADDRESS B,
|
||
IN ULONG SpanOfB )
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Compare two phsical address.
|
||
|
||
Arguments:
|
||
|
||
A - One half of the comparison.
|
||
|
||
SpanOfA - In units of bytes, the span of A.
|
||
|
||
B - One half of the comparison.
|
||
|
||
SpanOfB - In units of bytes, the span of B.
|
||
|
||
|
||
Return Value:
|
||
|
||
The result of the comparison.
|
||
|
||
--*/
|
||
{
|
||
|
||
LARGE_INTEGER a;
|
||
LARGE_INTEGER b;
|
||
|
||
LARGE_INTEGER lower;
|
||
ULONG lowerSpan;
|
||
LARGE_INTEGER higher;
|
||
|
||
#if rmm < 807
|
||
a.LowPart = A.LowPart;
|
||
a.HighPart = A.HighPart;
|
||
b.LowPart = B.LowPart;
|
||
b.HighPart = B.HighPart;
|
||
|
||
if (RtlLargeIntegerEqualTo(
|
||
a,
|
||
b
|
||
)) {
|
||
|
||
return AddressesAreEqual;
|
||
|
||
}
|
||
|
||
if (RtlLargeIntegerGreaterThan(
|
||
a,
|
||
b
|
||
)) {
|
||
|
||
higher = a;
|
||
lower = b;
|
||
lowerSpan = SpanOfB;
|
||
|
||
} else {
|
||
|
||
higher = b;
|
||
lower = a;
|
||
lowerSpan = SpanOfA;
|
||
|
||
}
|
||
|
||
if (RtlLargeIntegerGreaterThanOrEqualTo(
|
||
RtlLargeIntegerSubtract(
|
||
higher,
|
||
lower
|
||
),
|
||
RtlConvertUlongToLargeInteger(lowerSpan)
|
||
)) {
|
||
|
||
return AddressesAreDisjoint;
|
||
|
||
}
|
||
#else
|
||
a = A;
|
||
b = B;
|
||
|
||
if (a.QuadPart == b.QuadPart) {
|
||
|
||
return AddressesAreEqual;
|
||
|
||
}
|
||
|
||
if (a.QuadPart > b.QuadPart) {
|
||
|
||
higher = a;
|
||
lower = b;
|
||
lowerSpan = SpanOfB;
|
||
|
||
} else {
|
||
|
||
higher = b;
|
||
lower = a;
|
||
lowerSpan = SpanOfA;
|
||
|
||
}
|
||
|
||
if ((higher.QuadPart - lower.QuadPart) >= lowerSpan) {
|
||
|
||
return AddressesAreDisjoint;
|
||
|
||
}
|
||
#endif
|
||
|
||
return AddressesOverlap;
|
||
|
||
} // end DigiMemCompare
|
||
|
||
|
||
|
||
VOID DigiLogError( IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
||
IN PHYSICAL_ADDRESS P1,
|
||
IN PHYSICAL_ADDRESS P2,
|
||
IN ULONG SequenceNumber,
|
||
IN UCHAR MajorFunctionCode,
|
||
IN UCHAR RetryCount,
|
||
IN ULONG UniqueErrorValue,
|
||
IN NTSTATUS FinalStatus,
|
||
IN NTSTATUS SpecificIOStatus,
|
||
IN ULONG LengthOfInsert1,
|
||
IN PWCHAR Insert1,
|
||
IN ULONG LengthOfInsert2,
|
||
IN PWCHAR Insert2 )
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates an error log entry, copies the supplied data
|
||
to it, and requests that it be written to the error log file.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - A pointer to the driver object for the device.
|
||
|
||
DeviceObject - A pointer to the device object associated with the
|
||
device that had the error, early in initialization, one may not
|
||
yet exist.
|
||
|
||
P1,P2 - If phyical addresses for the controller ports involved
|
||
with the error are available, put them through as dump data.
|
||
|
||
SequenceNumber - A ulong value that is unique to an IRP over the
|
||
life of the irp in this driver - 0 generally means an error not
|
||
associated with an irp.
|
||
|
||
MajorFunctionCode - If there is an error associated with the irp,
|
||
this is the major function code of that irp.
|
||
|
||
RetryCount - The number of times a particular operation has been
|
||
retried.
|
||
|
||
UniqueErrorValue - A unique long word that identifies the particular
|
||
call to this function.
|
||
|
||
FinalStatus - The final status given to the irp that was associated
|
||
with this error. If this log entry is being made during one of
|
||
the retries this value will be STATUS_SUCCESS.
|
||
|
||
SpecificIOStatus - The IO status for a particular error.
|
||
|
||
LengthOfInsert1 - The length in bytes (including the terminating NULL)
|
||
of the first insertion string.
|
||
|
||
Insert1 - The first insertion string.
|
||
|
||
LengthOfInsert2 - The length in bytes (including the terminating NULL)
|
||
of the second insertion string. NOTE, there must
|
||
be a first insertion string for their to be
|
||
a second insertion string.
|
||
|
||
Insert2 - The second insertion string.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_ERROR_LOG_PACKET errorLogEntry;
|
||
|
||
PVOID objectToUse;
|
||
SHORT dumpToAllocate = 0;
|
||
PUCHAR ptrToFirstInsert;
|
||
PUCHAR ptrToSecondInsert;
|
||
|
||
|
||
if( ARGUMENT_PRESENT(DeviceObject) )
|
||
{
|
||
objectToUse = DeviceObject;
|
||
}
|
||
else
|
||
{
|
||
objectToUse = DriverObject;
|
||
}
|
||
|
||
if( DigiMemCompare( P1, (ULONG)1,
|
||
DigiPhysicalZero, (ULONG)1 ) != AddressesAreEqual )
|
||
{
|
||
dumpToAllocate = (SHORT)sizeof(PHYSICAL_ADDRESS);
|
||
}
|
||
|
||
if( DigiMemCompare( P2, (ULONG)1,
|
||
DigiPhysicalZero, (ULONG)1 ) != AddressesAreEqual )
|
||
{
|
||
dumpToAllocate += (SHORT)sizeof(PHYSICAL_ADDRESS);
|
||
}
|
||
|
||
errorLogEntry = IoAllocateErrorLogEntry( objectToUse,
|
||
(UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
|
||
dumpToAllocate + LengthOfInsert1 +
|
||
LengthOfInsert2) );
|
||
|
||
if( errorLogEntry != NULL )
|
||
{
|
||
errorLogEntry->ErrorCode = SpecificIOStatus;
|
||
errorLogEntry->SequenceNumber = SequenceNumber;
|
||
errorLogEntry->MajorFunctionCode = MajorFunctionCode;
|
||
errorLogEntry->RetryCount = RetryCount;
|
||
errorLogEntry->UniqueErrorValue = UniqueErrorValue;
|
||
errorLogEntry->FinalStatus = FinalStatus;
|
||
errorLogEntry->DumpDataSize = dumpToAllocate;
|
||
|
||
if( dumpToAllocate )
|
||
{
|
||
RtlCopyMemory( &errorLogEntry->DumpData[0],
|
||
&P1, sizeof(PHYSICAL_ADDRESS) );
|
||
|
||
if( dumpToAllocate > sizeof(PHYSICAL_ADDRESS) )
|
||
{
|
||
RtlCopyMemory( ((PUCHAR)&errorLogEntry->DumpData[0]) +
|
||
sizeof(PHYSICAL_ADDRESS),
|
||
&P2,
|
||
sizeof(PHYSICAL_ADDRESS) );
|
||
|
||
ptrToFirstInsert =
|
||
((PUCHAR)&errorLogEntry->DumpData[0]) +
|
||
(2*sizeof(PHYSICAL_ADDRESS));
|
||
}
|
||
else
|
||
{
|
||
ptrToFirstInsert =
|
||
((PUCHAR)&errorLogEntry->DumpData[0]) +
|
||
sizeof(PHYSICAL_ADDRESS);
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
ptrToFirstInsert = (PUCHAR)&errorLogEntry->DumpData[0];
|
||
}
|
||
|
||
ptrToSecondInsert = ptrToFirstInsert + LengthOfInsert1;
|
||
|
||
if( LengthOfInsert1 )
|
||
{
|
||
errorLogEntry->NumberOfStrings = 1;
|
||
errorLogEntry->StringOffset = (USHORT)(ptrToFirstInsert -
|
||
(PUCHAR)errorLogEntry);
|
||
RtlCopyMemory( ptrToFirstInsert, Insert1, LengthOfInsert1 );
|
||
|
||
if( LengthOfInsert2 )
|
||
{
|
||
errorLogEntry->NumberOfStrings = 2;
|
||
RtlCopyMemory( ptrToSecondInsert, Insert2, LengthOfInsert2 );
|
||
}
|
||
}
|
||
|
||
IoWriteErrorLogEntry(errorLogEntry);
|
||
}
|
||
|
||
} // end DigiLogError
|
||
|
||
|
||
|
||
NTSTATUS NtEpcInitMCA( PUNICODE_STRING ControllerPath,
|
||
PDIGI_CONTROLLER_EXTENSION ControllerExt )
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will be called if it is determined the type of bus
|
||
is MCA. We verify that the controller is actually a DigiBoard
|
||
Epc controller, read the POS to determine the I/O address and
|
||
Memory Mapped address, so the initialization process can continue.
|
||
|
||
Arguments:
|
||
|
||
ControllerPath - pointer to the registry path where this controllers
|
||
configuration information is kept.
|
||
|
||
ControllerExt - pointer to this controller extension information
|
||
where the I/O and Memory address should be stored.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - If we were able to complete successfully
|
||
|
||
?? - We were not able to get the information required to continue.
|
||
|
||
--*/
|
||
{
|
||
PWSTR ParametersString=L"Parameters";
|
||
PWSTR MCAPosIdString=L"McaPosId";
|
||
PWSTR SlotNumberString=L"SlotNumber";
|
||
|
||
ULONG MCAPosId;
|
||
LONG SlotNumber;
|
||
|
||
USHORT ActualPosId, POSConfig;
|
||
USHORT IOPortOffset;
|
||
USHORT IRQAddress;
|
||
ULONG MemoryAddress;
|
||
|
||
OBJECT_ATTRIBUTES ControllerAttributes;
|
||
HANDLE ControllerHandle;
|
||
|
||
PRTL_QUERY_REGISTRY_TABLE MCAInfo = NULL;
|
||
|
||
PHYSICAL_ADDRESS TempAddress;
|
||
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
UCHAR OneByte;
|
||
|
||
//
|
||
// We need to read the POS Adapter ID and make sure the controller
|
||
// is one of ours. Get the Slot number and the POS ID we
|
||
// installed during configuration from the registry.
|
||
//
|
||
|
||
MCAInfo = DigiAllocMem( PagedPool,
|
||
sizeof( RTL_QUERY_REGISTRY_TABLE ) * 4 );
|
||
|
||
if( !MCAInfo )
|
||
{
|
||
DigiDump( DIGIERRORS, ("NTEPC: Could not allocate table for rtl query\n"
|
||
"----- to for %wZ\n",
|
||
ControllerPath ) );
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto NtEpcInitMCAExit;
|
||
}
|
||
|
||
RtlZeroMemory( MCAInfo, sizeof(RTL_QUERY_REGISTRY_TABLE) * 4 );
|
||
|
||
MCAInfo[0].QueryRoutine = NULL;
|
||
MCAInfo[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
|
||
MCAInfo[0].Name = ParametersString;
|
||
|
||
MCAInfo[1].Flags = RTL_QUERY_REGISTRY_REQUIRED |
|
||
RTL_QUERY_REGISTRY_DIRECT;
|
||
MCAInfo[1].Name = MCAPosIdString;
|
||
MCAInfo[1].EntryContext = &MCAPosId;
|
||
|
||
MCAInfo[2].Flags = RTL_QUERY_REGISTRY_REQUIRED |
|
||
RTL_QUERY_REGISTRY_DIRECT;
|
||
MCAInfo[2].Name = SlotNumberString;
|
||
MCAInfo[2].EntryContext = &SlotNumber;
|
||
|
||
RtlZeroMemory( &MCAPosId, sizeof(MCAPosId) );
|
||
SlotNumber = -1;
|
||
|
||
InitializeObjectAttributes( &ControllerAttributes,
|
||
ControllerPath,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL, NULL );
|
||
|
||
if( !NT_SUCCESS( Status = ZwOpenKey( &ControllerHandle, MAXIMUM_ALLOWED,
|
||
&ControllerAttributes ) ) )
|
||
{
|
||
DigiDump( DIGIERRORS, ("NTEPC: Could not open the drivers DigiBoard key %wZ\n",
|
||
ControllerPath ) );
|
||
// DigiLogError( GlobalDriverObject,
|
||
// NULL,
|
||
// DigiPhysicalZero,
|
||
// DigiPhysicalZero,
|
||
// 0,
|
||
// 0,
|
||
// 0,
|
||
// 8,
|
||
// Status,
|
||
// SERIAL_UNABLE_TO_OPEN_KEY,
|
||
// ControllerPath->Length + sizeof(WCHAR),
|
||
// ControllerPath->Buffer,
|
||
// 0,
|
||
// NULL );
|
||
goto NtEpcInitMCAExit;
|
||
}
|
||
|
||
DigiDump( DIGIINIT, ("NTEPC: registry path = %wZ\n",
|
||
ControllerPath) );
|
||
|
||
Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE,
|
||
ControllerPath->Buffer,
|
||
MCAInfo,
|
||
NULL, NULL );
|
||
|
||
if( !NT_SUCCESS(Status) )
|
||
{
|
||
if( !MCAPosId )
|
||
{
|
||
DigiDump( DIGIERRORS, ("NTEPC: Could not get %ws from registry.\n",
|
||
MCAPosIdString) );
|
||
DigiLogError( GlobalDriverObject,
|
||
NULL,
|
||
DigiPhysicalZero,
|
||
DigiPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
__LINE__,
|
||
Status,
|
||
SERIAL_REGISTRY_VALUE_NOT_FOUND,
|
||
DigiWstrLength(MCAPosIdString),
|
||
MCAPosIdString,
|
||
0,
|
||
NULL );
|
||
}
|
||
|
||
if( SlotNumber == -1 )
|
||
{
|
||
DigiDump( DIGIERRORS, ("NTEPC: Could not get %ws from registry.\n",
|
||
SlotNumberString) );
|
||
DigiLogError( GlobalDriverObject,
|
||
NULL,
|
||
DigiPhysicalZero,
|
||
DigiPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
__LINE__,
|
||
Status,
|
||
SERIAL_REGISTRY_VALUE_NOT_FOUND,
|
||
DigiWstrLength(SlotNumberString),
|
||
SlotNumberString,
|
||
0,
|
||
NULL );
|
||
}
|
||
|
||
goto NtEpcInitMCAExit;
|
||
}
|
||
|
||
DigiDump( DIGIINIT, ("NTEPC: %wZ registry info\n"
|
||
"--------- MCAPosId: 0x%x\n",
|
||
ControllerPath, MCAPosId) );
|
||
|
||
DigiDump( DIGIINIT, ("--------- SlotNumber: 0x%x\n",
|
||
SlotNumber) );
|
||
|
||
// Enable the POS information for the slot we are interested in.
|
||
WRITE_PORT_UCHAR( ControllerExt->VirtualPOSBaseAddress, (UCHAR)(SlotNumber + 7) );
|
||
|
||
OneByte = READ_PORT_UCHAR( ControllerExt->VirtualPOSInfoAddress + 1 );
|
||
ActualPosId = ((USHORT)OneByte << 8);
|
||
OneByte = READ_PORT_UCHAR( ControllerExt->VirtualPOSInfoAddress );
|
||
ActualPosId |= OneByte;
|
||
|
||
DigiDump( DIGIINIT, ("POS Adapter ID = 0x%hx\n", ActualPosId) );
|
||
|
||
TempAddress.LowPart = ActualPosId;
|
||
TempAddress.HighPart = 0;
|
||
|
||
OneByte = READ_PORT_UCHAR( ControllerExt->VirtualPOSInfoAddress + 4 );
|
||
MemoryAddress = ((ULONG)OneByte << 24);
|
||
OneByte = READ_PORT_UCHAR( ControllerExt->VirtualPOSInfoAddress + 3 );
|
||
MemoryAddress |= ((ULONG)OneByte << 16);
|
||
|
||
OneByte = READ_PORT_UCHAR( ControllerExt->VirtualPOSInfoAddress + 2 );
|
||
POSConfig = OneByte;
|
||
|
||
IOPortOffset = (POSConfig & MCA_IO_PORT_MASK) >> 4;
|
||
MemoryAddress |= ((ULONG)(POSConfig & MCA_MEMORY_MASK) << 8);
|
||
|
||
DigiDump( DIGIINIT, ("POS config read = 0x%hx\n"
|
||
" IOPortOffset = 0x%hx, MemoryAddress = 0x%x,"
|
||
" IOPort = 0x%hx\n",
|
||
POSConfig, IOPortOffset, MemoryAddress,
|
||
MCAIOAddressTable[IOPortOffset]) );
|
||
|
||
//
|
||
// If interrupts are enabled, we disable them for now.
|
||
//
|
||
IRQAddress = (USHORT)(POSConfig & MCA_IRQ_MASK);
|
||
if( IRQAddress )
|
||
{
|
||
OneByte = READ_PORT_UCHAR( ControllerExt->VirtualPOSInfoAddress + 2 );
|
||
OneByte &= ~MCA_IRQ_MASK;
|
||
WRITE_PORT_UCHAR( ControllerExt->VirtualPOSInfoAddress, OneByte );
|
||
}
|
||
|
||
ControllerExt->PhysicalIOPort.LowPart = MCAIOAddressTable[IOPortOffset];
|
||
ControllerExt->PhysicalIOPort.HighPart = 0;
|
||
|
||
ControllerExt->PhysicalMemoryAddress.LowPart = MemoryAddress;
|
||
ControllerExt->PhysicalMemoryAddress.HighPart = 0;
|
||
|
||
// Disable the POS information.
|
||
WRITE_PORT_UCHAR( ControllerExt->VirtualPOSBaseAddress, 0 );
|
||
|
||
NtEpcInitMCAExit:;
|
||
|
||
if( MCAInfo )
|
||
DigiFreeMem( MCAInfo );
|
||
|
||
return( Status );
|
||
} // end NtEpcInitMCA
|
||
|
||
|
||
|
||
USHORT DigiWstrLength( IN PWSTR Wstr )
|
||
{
|
||
USHORT Length=0;
|
||
|
||
while( *Wstr++ )
|
||
{
|
||
Length += sizeof(WCHAR);
|
||
}
|
||
return( Length );
|
||
} // end DigiWstrLength
|
||
|
||
|
||
|
||
NTSTATUS EpcFepDownload( PDIGI_CONTROLLER_EXTENSION ControllerExt,
|
||
PUCHAR FEPFImage,
|
||
ULONG FEPFLength )
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will download the EPC Fep image to the controller, taking
|
||
into account the possibility that the Fep image will cross window
|
||
boundaries.
|
||
|
||
Arguments:
|
||
|
||
ControllerExt - pointer to this controller specific information
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Successfully downloaded the intended fep image
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status=STATUS_SUCCESS;
|
||
ULONG CurrentBoardAddress;
|
||
ULONG BytesWritten;
|
||
UCHAR CurrentWindow;
|
||
|
||
DigiDump( DIGIFLOW, ("NTEPC: Entering EpcFepDownload.\n") );
|
||
|
||
//
|
||
// Download FEPOS on EPC host adapter
|
||
//
|
||
|
||
DigiDump( DIGIINIT, ("NTEPC: Epc FepCode size = %u bytes.\n", FEPFLength) );
|
||
|
||
// Select Page 0 and Enable Memory
|
||
CurrentBoardAddress = 0x1000;
|
||
CurrentWindow = 0x80;
|
||
BytesWritten = 0;
|
||
|
||
while( BytesWritten != FEPFLength )
|
||
{
|
||
ULONG CurrentAddressOffset=CurrentBoardAddress;
|
||
ULONG BytesToWrite;
|
||
|
||
CurrentWindow = (UCHAR)(CurrentAddressOffset / ControllerExt->WindowSize);
|
||
|
||
CurrentAddressOffset = CurrentBoardAddress -
|
||
( CurrentWindow * ControllerExt->WindowSize );
|
||
|
||
BytesToWrite = ControllerExt->WindowSize - CurrentAddressOffset;
|
||
|
||
if( (BytesWritten + BytesToWrite) > FEPFLength )
|
||
{
|
||
BytesToWrite = FEPFLength - BytesWritten;
|
||
}
|
||
|
||
DigiDump( DIGIINIT, ("NTEPC: CurrentBoardAddress = 0x%x, BytesWritten = 0x%x, BytesToWrite = 0x%x\n"
|
||
" CurrentWindow = 0x%x, CurrentAddressOffset = 0x%x\n",
|
||
CurrentBoardAddress,
|
||
BytesWritten,
|
||
BytesToWrite,
|
||
CurrentWindow,
|
||
CurrentAddressOffset) );
|
||
|
||
WRITE_PORT_UCHAR( ControllerExt->VirtualIO+1, (UCHAR)(0x80 | CurrentWindow) );
|
||
|
||
WRITE_REGISTER_BUFFER_UCHAR( (PUCHAR)((PUCHAR)ControllerExt->VirtualAddress +
|
||
CurrentAddressOffset),
|
||
&FEPFImage[BytesWritten],
|
||
BytesToWrite );
|
||
|
||
CurrentBoardAddress += BytesToWrite;
|
||
BytesWritten += BytesToWrite;
|
||
}
|
||
|
||
//
|
||
// Form BIOS execute request
|
||
//
|
||
|
||
WRITE_PORT_UCHAR( ControllerExt->VirtualIO+1, 0x80 );
|
||
|
||
WRITE_REGISTER_USHORT( (PUSHORT)(ControllerExt->VirtualAddress + 0x0D20),
|
||
0x0000 );
|
||
WRITE_REGISTER_ULONG( (PULONG)(ControllerExt->VirtualAddress + 0x0C34),
|
||
0xBFC01004 );
|
||
WRITE_REGISTER_ULONG( (PULONG)(ControllerExt->VirtualAddress + 0x0C30),
|
||
0x3L );
|
||
|
||
DigiDump( DIGIFLOW, ("NTEPC: Exiting EpcFepDownload.\n") );
|
||
|
||
return( Status );
|
||
} // end EpcFepDownload
|
||
|