This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/Tools/MonoDrv/sys/MONO.C

1410 lines
49 KiB
C

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Header$ */
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : MONO.C *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 01/04/97 *
* *
* Last Update : January 5, 1997 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* Mono_Clear_Screen -- Clears the monochrome screen & homes cursor. *
* Mono_Print -- Prints text (with formatting) to mono screen. *
* Mono_Print_Raw -- Print text (without processing) to mono screen. *
* Mono_Printf -- Print formatted text to the mono device. *
* Mono_Scroll -- Scroll the mono screen up one line. *
* Mono_Set_View_Pos -- Set the mono display ram view offset. *
* Mono_Pan -- Pan the mono screen over one column. *
* Mono_Detect_MGA_Adapter -- Try to detec the MGA adapter. *
* Mono_Get_Address_Ptr -- Converts a physical address into a usable pointer. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "ntddk.h"
#include "stdarg.h"
#include "stdio.h"
#include "monopub.h"
//
// Indices into & count of the above array
//
#define MONO_VIDEO_BUFFER 0
#define MONO_CRTC_REG 1
#define MONO_MODE_CTL_REG 2
#define MONO_NUMBER_RESOURCE_ENTRIES 2
//#define MONO_NUMBER_RESOURCE_ENTRIES 3
//
// Our user mode app will pass an initialized structure like this
// down to the kernel mode driver
//
//typedef struct
//{
// INTERFACE_TYPE InterfaceType; // Isa, Eisa, etc....
// ULONG BusNumber; // Bus number
// PHYSICAL_ADDRESS BusAddress; // Bus-relative address
// ULONG AddressSpace; // 0 is memory, 1 is I/O
// ULONG Length; // Length of section to map
//
//} PHYSICAL_MEMORY_INFO, *PPHYSICAL_MEMORY_INFO;
#define DEVICE_NAME L"\\Device\\Mono"
#define A_DEVICE_NAME "\\Device\\Mono"
#define SYMBOLIC_NAME L"\\DosDevices\\MONO"
#define A_SYMBOLIC_NAME "\\DosDevices\\MONO"
#define CRTC_REGISTER 0x3B4
#define MONO_MEMORY 0xB0000
#define MONO_MEM_LENGTH (0x10000-1)
#define MAX_PAGES 16
#define MONO_WIDTH 80
#define MONO_HEIGHT 25
#define SIZE_OF_SCREEN (MONO_WIDTH * MONO_HEIGHT * sizeof(unsigned short))
#define BUILD_CHAR(c, a) ((unsigned short)(((a) << 8) | ((c) & 0xFF)))
#define PINDEX_TO_CELL(index) ((index) * MONO_WIDTH * MONO_HEIGHT)
/*
** This controls the state information for each of the
** display pages.
*/
typedef struct BuffControl
{
int XPos;
int YPos;
/*
** This is the default attribute to use when displaying text.
*/
int Attribute;
/*
** This is the logical address of the display page that this
** buffer represents. This pointer is in the address space
** of this driver, NOT of the owner of the file object.
*/
unsigned short * Buffer;
/*
** This is a copy of a pointer to the page memory that is
** in mapped to the owning file object's address space.
*/
void * LockPtr;
/*
** If this page has been allocated, then this flag will
** be true.
*/
int Allocated;
} BuffControl;
/*
** This stores the global information for the monochrome driver.
*/
typedef struct MonoGlobals
{
/*
** Syncronizing object so that access to this device is
** serialized.
*/
KEVENT SyncEvent;
/*
** Logical pointer to the CRTC registers.
*/
unsigned char * CRTCRegisters;
/*
** Points to the first character of the MGA display
** memory.
*/
unsigned short * DisplayMemory;
/*
** Each of the display pages is managed by this buffer
** control array.
*/
BuffControl Control[MAX_PAGES];
/*
** This is the index of the currently visible display page.
*/
int CurrentVisible;
} MonoGlobals;
//
// A structure decribing a particular device resource
//
typedef struct _MONO_RESOURCE
{
PHYSICAL_ADDRESS PhysicalAddress;
unsigned long Length;
unsigned long AddressSpace;
unsigned long RangeSharable;
} MONO_RESOURCE, *PMONO_RESOURCE;
//
// A global that we keep around for use by the MonoDbgPrint function
// (when other drivers call MonoDbgPrint we need to be able to access
// the info stored in the device extension).
//
MonoGlobals * GlobalDeviceExtension = NULL;
//
// A variable which determines the verboseness of the messages printed by
// MonoDbgPrint.
//
unsigned long MonoDbgLevel = 3;
//
// Resources used by the monochrome video adapter
//
MONO_RESOURCE MonoResources[] =
{
{ MONO_MEMORY, 0x00000000, // the video buffer
MONO_MEM_LENGTH, // length
0, // in memory space
1 }, // shared with other drivers/devices (vga)
{ CRTC_REGISTER, 0x00000000, // the 6845 index & data regs
0x00000002, // length
1, // in I/O space
1 }, // shared with other drivers/devices (vga)
{ 0x000b03b8, 0x00000000, // mode control register
0x00000001, // length
1, // in I/O space
1 } // shared with other drivers/devices (vga)
};
/*
** Each cell is constructed of the actual character that is displayed and the
** attribute to use. This character pair is located at every position on the
** display (80 x 25). Since this cell pair can be represented by a "short"
** integer, certain speed optimizations are taken in the monochrome drawing
** code.
*/
typedef struct CellType {
unsigned char Character; // Character to display.
unsigned char Attribute; // Attribute.
} CellType;
NTSTATUS MonoDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp);
void MonoUnload(PDRIVER_OBJECT DriverObject);
BOOLEAN pMonoReportResourceUsage(PDRIVER_OBJECT DriverObject, PMONO_RESOURCE MonoResources, unsigned long NumberOfResources);
//NTSTATUS MapMemMapTheMemory(PDEVICE_OBJECT DeviceObject,PVOID IoBuffer, ULONG OutputBufferLength);
void * Mono_Get_Address_Ptr(PHYSICAL_ADDRESS PhysicalAddress, unsigned long AddressSpace, unsigned long NumberOfBytes);
void Mono_Set_View_Pos(MonoGlobals * device, int pos);
NTSTATUS Mono_Detect_MGA_Adapter(void);
void * Mono_Fetch_Ptr(PDEVICE_OBJECT DeviceObject);
void Mono_Printf(BuffControl * control, char const * DbgMessage, ...);
void Mono_Clear_Screen(BuffControl * control);
void Mono_Print_Raw(BuffControl * control, unsigned char * string, unsigned long length);
void Mono_Scroll(BuffControl * control);
void Mono_Print(BuffControl * control, unsigned char * string, unsigned long length);
void Mono_Bring_To_Top(MonoGlobals * device, int index);
void Mono_Pan(BuffControl * control);
void Display_Signon_Banner(BuffControl * control);
void Mono_Update_Cursor(MonoGlobals * device);
/*++
Routine Description:
Installable driver initialization entry point.
This entry point is called directly by the I/O system.
Arguments:
DriverObject - pointer to the driver object
RegistryPath - pointer to a unicode string representing the path
to driver-specific key in the registry
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
PDEVICE_OBJECT deviceObject = NULL;
NTSTATUS ntStatus;
UNICODE_STRING deviceNameUnicodeString;
MonoGlobals * deviceExtension;
BOOLEAN symbolicLinkCreated = FALSE;
UNICODE_STRING deviceLinkUnicodeString;
int j;
//
// Check to see if anybody else has claim the resources we want to
// used. We don't want to be partying on someone else's hardware,
// even when trying to locate our devicc.
//
if (!pMonoReportResourceUsage(DriverObject, MonoResources, MONO_NUMBER_RESOURCE_ENTRIES)) {
return STATUS_UNSUCCESSFUL;
}
//
// Try to locate a monochrome display adapter (MDA)
//
ntStatus = Mono_Detect_MGA_Adapter();
if (!NT_SUCCESS(ntStatus)) {
ntStatus = STATUS_UNSUCCESSFUL;
goto done_DriverEntry;
}
//
// OK, we've claimed our resources & found our h/w, so create
// a device and initialize stuff...
//
RtlInitUnicodeString(&deviceNameUnicodeString, DEVICE_NAME);
// RtlInitUnicodeString(&deviceNameUnicodeString, L"\\Device\\Mono");
//
// Create an EXCLUSIVE device, i.e. only 1 thread at a time can send
// i/o requests. If opened as non-exclusive, then we would need to
// implement a more robust synchronization scheme than the event
// mechanism we utilize below.
//
ntStatus = IoCreateDevice(DriverObject, sizeof(MonoGlobals), &deviceNameUnicodeString, FILE_DEVICE_MONO, 0, FALSE, &deviceObject);
if (NT_SUCCESS(ntStatus)) {
deviceObject->Flags |= DO_BUFFERED_IO;
GlobalDeviceExtension = deviceExtension = (MonoGlobals *) deviceObject->DeviceExtension;
//
// Initialize the dispatch event object. This allows us to
// synchronize access to the h/w registers...
//
KeInitializeEvent(&deviceExtension->SyncEvent, SynchronizationEvent, TRUE);
//
// Map all the required resources, save the addresses
//
deviceExtension->DisplayMemory =
(PUSHORT) Mono_Get_Address_Ptr(MonoResources[MONO_VIDEO_BUFFER].PhysicalAddress,
MonoResources[MONO_VIDEO_BUFFER].AddressSpace,
MonoResources[MONO_VIDEO_BUFFER].Length
);
deviceExtension->CRTCRegisters =
(unsigned char *) Mono_Get_Address_Ptr(MonoResources[MONO_CRTC_REG].PhysicalAddress,
MonoResources[MONO_CRTC_REG].AddressSpace,
MonoResources[MONO_CRTC_REG].Length
);
// deviceExtension->ModeControlRegister =
// (unsigned char *) Mono_Get_Address_Ptr (MonoResources[MONO_MODE_CTL_REG].PhysicalAddress,
// MonoResources[MONO_MODE_CTL_REG].AddressSpace,
// MonoResources[MONO_MODE_CTL_REG].Length
// );
if (deviceExtension->DisplayMemory == NULL || deviceExtension->CRTCRegisters == NULL) {
ntStatus = STATUS_UNSUCCESSFUL;
goto done_DriverEntry;
}
//
// Create a symbolic link that Win32 apps can specify to gain access
// to this driver/device
//
RtlInitUnicodeString(&deviceLinkUnicodeString, SYMBOLIC_NAME);
// RtlInitUnicodeString(&deviceLinkUnicodeString, L"\\DosDevices\\MONO");
ntStatus = IoCreateSymbolicLink(&deviceLinkUnicodeString, &deviceNameUnicodeString);
if (!NT_SUCCESS(ntStatus)) {
} else {
symbolicLinkCreated = TRUE;
}
//
// Create dispatch points for device control, create, close.
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = MonoDispatch;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = MonoDispatch;
DriverObject->MajorFunction[IRP_MJ_READ] = MonoDispatch;
DriverObject->MajorFunction[IRP_MJ_WRITE] = MonoDispatch;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = MonoDispatch;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MonoDispatch;
DriverObject->DriverUnload = MonoUnload;
//
// Set the Start Address registers (indicate which part of
// video buffer is displayed) to 0
//
Mono_Set_View_Pos(deviceExtension, 0);
deviceExtension->CurrentVisible = 0;
for (j = 0; j < MAX_PAGES; j++) {
deviceExtension->Control[j].Buffer = &deviceExtension->DisplayMemory[PINDEX_TO_CELL(j)];
deviceExtension->Control[j].XPos = 0;
deviceExtension->Control[j].YPos = 0;
deviceExtension->Control[j].Attribute = 0x07;
deviceExtension->Control[j].LockPtr = NULL;
deviceExtension->Control[j].Allocated = FALSE;
}
/*
** Display the signon banner.
*/
Display_Signon_Banner(&deviceExtension->Control[deviceExtension->CurrentVisible]);
Mono_Update_Cursor(deviceExtension);
}
done_DriverEntry:
if (!NT_SUCCESS(ntStatus)) {
//
// Something went wrong, so clean up
//
pMonoReportResourceUsage(DriverObject, NULL, 0);
if (symbolicLinkCreated) {
IoDeleteSymbolicLink(&deviceLinkUnicodeString);
}
if (deviceObject) {
IoDeleteDevice(deviceObject);
}
GlobalDeviceExtension = NULL;
}
return ntStatus;
}
/*++
Routine Description:
Process the IRPs sent to this device.
Arguments:
DeviceObject - pointer to a device object
Irp - pointer to an I/O Request Packet
Return Value:
--*/
NTSTATUS MonoDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
PIO_STACK_LOCATION irpStack;
MonoGlobals * deviceExtension;
void * ioBuffer;
unsigned long inputBufferLength;
unsigned long outputBufferLength;
unsigned long ioControlCode;
NTSTATUS ntStatus;
FILE_OBJECT * fileobject = NULL;
BuffControl * control = NULL;
int currentindex = -1;
/*
** Presume success in the command processing.
*/
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0; // Bytes read/written or other return value.
/*
** Get a pointer to the current location in the Irp. This is where
** the function codes and parameters are located.
*/
irpStack = IoGetCurrentIrpStackLocation(Irp);
/*
** Get a pointer to the device extension
*/
deviceExtension = DeviceObject->DeviceExtension;
/*
** Fetch the file object for this I/O request.
*/
fileobject = irpStack->FileObject;
if (fileobject != NULL) {
currentindex = (long)fileobject->FsContext;
}
/*
** Get the pointer to the input/output buffer and it's length
*/
ioBuffer = Irp->AssociatedIrp.SystemBuffer;
inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
/*
** Synchronize execution of the dispatch routine by acquiring the device
** event object. This ensures all request are serialized.
*/
KeWaitForSingleObject(&deviceExtension->SyncEvent, Executive, KernelMode, FALSE, NULL);
/*
** Get a working pointer to the display page.
*/
if (currentindex == -1) {
currentindex == deviceExtension->CurrentVisible;
}
control = &deviceExtension->Control[currentindex];
switch (irpStack->MajorFunction) {
case IRP_MJ_READ:
break;
/*
** Process WriteFile request to display text.
*/
case IRP_MJ_WRITE:
if (ioBuffer != NULL && irpStack->Parameters.Write.Length > 0) {
Mono_Print(control, ioBuffer, irpStack->Parameters.Write.Length);
Irp->IoStatus.Information = irpStack->Parameters.Write.Length;
}
break;
/*
** The create event is called when a file object is first created. At that
** time, designate a context buffer and inialize it.
*/
case IRP_MJ_CREATE: {
int j;
int avail = -1;
/*
** Search for a free page to use.
*/
for (j = 0; j < MAX_PAGES; j++) {
if (!deviceExtension->Control[j].Allocated) {
avail = j;
break;
}
}
/*
** If one is not found, then return with error.
*/
if (avail == -1) {
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
} else {
BuffControl * newcon = &deviceExtension->Control[avail];
newcon->XPos = 0;
newcon->YPos = 0;
newcon->Attribute = 0x07;
newcon->Allocated = TRUE;
Mono_Bring_To_Top(deviceExtension, avail);
fileobject->FsContext = (void*)avail;
}
}
break;
/*
** Closing the file occurs when the last reference to the object has been
** severed.
*/
case IRP_MJ_CLOSE:
if (currentindex != -1) {
deviceExtension->Control[currentindex].Allocated = FALSE;
fileobject->FsContext = NULL;
}
break;
case IRP_MJ_CLEANUP:
break;
case IRP_MJ_DEVICE_CONTROL:
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
switch (ioControlCode) {
case IOCTL_MONO_BRING_TO_TOP:
Mono_Bring_To_Top(deviceExtension, currentindex);
break;
case IOCTL_MONO_SCROLL:
Mono_Scroll(control);
break;
case IOCTL_MONO_PAN:
Mono_Pan(control);
break;
case IOCTL_MONO_SET_CURSOR:
if (inputBufferLength == sizeof(int)*2) {
control->XPos = *(int*)ioBuffer;
control->YPos = *(((int*)ioBuffer) + 1);
}
break;
case IOCTL_MONO_PRINT_RAW:
Mono_Print_Raw(control, ioBuffer, inputBufferLength);
break;
case IOCTL_MONO_SET_POS:
if (inputBufferLength == sizeof(int)) {
Mono_Set_View_Pos(deviceExtension, *(int*)ioBuffer);
}
break;
case IOCTL_MONO_CLEAR_SCREEN:
Mono_Clear_Screen(control);
break;
case IOCTL_MONO_SET_ATTRIBUTE:
control->Attribute = *(char *)ioBuffer;
break;
#ifdef NEVER
case IOCTL_MONO_LOCK:
if (deviceExtension->LockPtr != NULL) {
*(void**)ioBuffer = deviceExtension->LockPtr;
deviceExtension->LockCount++;
} else {
*(void**)ioBuffer = Mono_Fetch_Ptr(DeviceObject);
if (*(void**)ioBuffer != NULL) {
deviceExtension->LockPtr = *(void**)ioBuffer;
deviceExtension->LockCount++;
Irp->IoStatus.Information = sizeof(PVOID);
} else {
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
}
}
break;
case IOCTL_MONO_UNLOCK:
if (deviceExtension->LockCount > 0) {
deviceExtension->LockCount--;
if (deviceExtension->LockCount == 0) {
Irp->IoStatus.Status = ZwUnmapViewOfSection((HANDLE) -1, deviceExtension->LockPtr);
deviceExtension->LockPtr = NULL;
}
}
break;
#endif
default:
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
break;
}
break;
}
/*
** Only if the context drawn to is the currently visible one, will the
** cursor position be updated.
*/
if (currentindex == deviceExtension->CurrentVisible) {
Mono_Update_Cursor(deviceExtension);
}
KeSetEvent(&deviceExtension->SyncEvent, 0, FALSE);
ntStatus = Irp->IoStatus.Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return(ntStatus);
}
/*++
Routine Description:
Free all the allocated resources, etc.
Arguments:
DriverObject - pointer to a driver object
Return Value:
--*/
void MonoUnload(PDRIVER_OBJECT DriverObject)
{
// WCHAR deviceLinkBuffer[] = L"\\DosDevices\\MONO";
UNICODE_STRING deviceLinkUnicodeString;
//
// Unreport the resources
//
pMonoReportResourceUsage(DriverObject, NULL, 0);
//
// Delete the symbolic link
//
RtlInitUnicodeString(&deviceLinkUnicodeString, L"\\DosDevices\\MONO");
IoDeleteSymbolicLink(&deviceLinkUnicodeString);
//
// Delete the device object
//
IoDeleteDevice(DriverObject->DeviceObject);
}
/***********************************************************************************************
* Mono_Detect_MGA_Adapter -- Try to detec the MGA adapter. *
* *
* Tries to find the MGA adaptor by writing a few bytes to the CRTC register and checking *
* if they return a corresponding value. *
* *
* INPUT: none *
* *
* OUTPUT: Returns with the NT status code of the check. STATUS_SUCCESS if the MGA adapter *
* was found. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/05/1997 JLB : Created. *
*=============================================================================================*/
NTSTATUS Mono_Detect_MGA_Adapter(void)
{
PHYSICAL_ADDRESS physicalAddress;
unsigned char * crtcRegisters;
/*
** Get address to the CRTC registers.
*/
physicalAddress.LowPart = CRTC_REGISTER;
physicalAddress.HighPart = 0;
if ((crtcRegisters = Mono_Get_Address_Ptr(physicalAddress, 1, 2))) {
/*
** Set the mono cursor position and see if it changed. If so, then
** presume that the MGA adapter is present.
*/
WRITE_PORT_UCHAR(crtcRegisters, 0x0F);
WRITE_PORT_UCHAR(crtcRegisters+1, 0x55);
if (READ_PORT_UCHAR(crtcRegisters+1) != 0x55) {
return(STATUS_UNSUCCESSFUL);
}
WRITE_PORT_UCHAR(crtcRegisters+1, 0xAA);
if (READ_PORT_UCHAR(crtcRegisters+1) != 0xAA) {
return(STATUS_UNSUCCESSFUL);
}
WRITE_PORT_UCHAR(crtcRegisters+1, 0x00);
} else {
return(STATUS_UNSUCCESSFUL);
}
return(STATUS_SUCCESS);
}
/***********************************************************************************************
* Mono_Get_Address_Ptr -- Converts a physical address into a usable pointer. *
* *
* This routine will take the physical address specified and convert it into a pointer that *
* can be used to reference the address specified. *
* *
* INPUT: address -- The physical address to convert. *
* *
* space -- The address space that the specified address is in. 0 means memory, *
* 1 means I/O space (ports). *
* *
* length -- The length of the memory that will be referenced. *
* *
* OUTPUT: Returns with a usable pointer to the memory specified or NULL if it could not be *
* processed. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/05/1997 JLB : Created. *
*=============================================================================================*/
void * Mono_Get_Address_Ptr(PHYSICAL_ADDRESS address, unsigned long space, unsigned long length)
{
PHYSICAL_ADDRESS translatedAddress;
void * usable_ptr = NULL;
/*
** Translate a bus specific address into a logical system address.
*/
if (HalTranslateBusAddress(Isa, 0, address, &space, &translatedAddress)) {
/*
** If the space value is zero, then this idicates that a call to
** MmMapIoSpace is required. This is usually required for port addresses.
*/
if (space == 0) {
usable_ptr = MmMapIoSpace(translatedAddress, length, FALSE);
} else {
usable_ptr = (void *)translatedAddress.LowPart;
}
}
return(usable_ptr);
}
//
// NOTE: The following is commented out because some of the video miniport
// drivers provided with the system (and in the NT DDK) regsister
// their resources as exclusive; if these resources overlap with
// the resources used by the mono driver, then this driver will fail
// to load. This can be solved in one of two ways: by commenting
// out the code below, and using the resources without reporting them
// (not safe to do, but the easiest for this simple example); or, by
// editing the source file(s) of the appropriate miniport driver
// such that the VIDEO_ACCESS_RANGE.RangeSharable element is set to
// TRUE, and rebuilding the driver.
//
// A real driver should *always* report it's resources.
//
/*++
Routine Description:
Reports the resources used by a device.
Arguments:
DriverObject - pointer to a driver object
MonoResources - pointer to an array of resource information, or
NULL is unreporting resources for this driver
NumberOfResources - number of entries in the resource array, or
0 if unreporting resources for this driver
Return Value:
TRUE if resources successfully report (and no conflicts),
FALSE otherwise.
--*/
BOOLEAN pMonoReportResourceUsage(PDRIVER_OBJECT DriverObject, PMONO_RESOURCE MonoResources, unsigned long NumberOfResources)
{
unsigned long sizeOfResourceList = 0;
PCM_RESOURCE_LIST resourceList = NULL;
PCM_PARTIAL_RESOURCE_DESCRIPTOR partial;
unsigned long i;
UNICODE_STRING className;
BOOLEAN conflictDetected;
if (NumberOfResources > 0) {
//
// Alloc enough memory to build a resource list & zero it out
//
sizeOfResourceList = sizeof(CM_RESOURCE_LIST) + (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)*(NumberOfResources - 1));
resourceList = ExAllocatePool(PagedPool, sizeOfResourceList);
if (!resourceList) {
return FALSE;
}
RtlZeroMemory(resourceList, sizeOfResourceList);
//
// Fill in the reosurce list
//
// NOTE: Assume Isa, bus # 0
//
resourceList->Count = 1;
resourceList->List[0].InterfaceType = Isa;
resourceList->List[0].BusNumber = 0;
resourceList->List[0].PartialResourceList.Count = NumberOfResources;
partial = &resourceList->List[0].PartialResourceList.PartialDescriptors[0];
//
// Account for the space used by the controller.
//
for (i = 0; i < NumberOfResources; i++) {
if (MonoResources[i].AddressSpace) {
partial->Type = CmResourceTypePort;
partial->Flags = CM_RESOURCE_PORT_IO;
partial->u.Port.Start = MonoResources[i].PhysicalAddress;
partial->u.Port.Length = MonoResources[i].Length;
} else {
partial->Type = CmResourceTypeMemory;
partial->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
partial->u.Memory.Start = MonoResources[i].PhysicalAddress;
partial->u.Memory.Length = MonoResources[i].Length;
}
if (MonoResources[i].RangeSharable) {
partial->ShareDisposition = CmResourceShareShared;
} else {
partial->ShareDisposition = CmResourceShareDeviceExclusive;
}
partial++;
}
}
RtlInitUnicodeString(&className, L"LOADED MONO DRIVER RESOURCES");
IoReportResourceUsage(&className, DriverObject, resourceList, sizeOfResourceList, NULL, NULL, 0, FALSE, &conflictDetected);
if (resourceList) {
ExFreePool(resourceList);
if (conflictDetected) {
return FALSE;
} else {
return TRUE;
}
}
return TRUE;
}
void Mono_Update_Cursor(MonoGlobals * device)
{
int pos;
pos = device->Control[device->CurrentVisible].XPos + (device->Control[device->CurrentVisible].YPos * MONO_WIDTH);
WRITE_PORT_UCHAR(device->CRTCRegisters, 0x0E);
WRITE_PORT_UCHAR(device->CRTCRegisters+1, (unsigned char)(pos>>8));
WRITE_PORT_UCHAR(device->CRTCRegisters, 0x0F);
WRITE_PORT_UCHAR(device->CRTCRegisters+1, (unsigned char)(pos & 0xFF));
}
/***********************************************************************************************
* Mono_Print -- Prints text (with formatting) to mono screen. *
* *
* This routine will take the text specified and print it to the monochrome screen. If *
* there are any formatting characters present, then they will be processed accordingly. *
* *
* INPUT: control -- Poitner to the buffer to print to. *
* *
* string -- Pointer to the string to print. *
* *
* length -- The length of the string to print. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/04/1997 JLB : Created. *
*=============================================================================================*/
void Mono_Print(BuffControl * control, unsigned char * string, unsigned long length)
{
if (control != NULL) {
int x,y;
unsigned char space = ' ';
x = control->XPos;
y = control->YPos;
while (length > 0) {
unsigned char * blockstart;
int blocklen;
unsigned char bchar; // Breaking character.
/*
** Scan for a block of contiguous non-formatting characters to print.
*/
blockstart = string;
blocklen = 0;
bchar = '\0';
while (length > 0 && bchar == '\0') {
bchar = *string++;
length--;
switch (bchar) {
case '\b': // Backspace
case '\a': // Audible bell
case '\t': // Horizontal tab
case '\f': // Formfeed
case '\n': // Linefeed
case '\v': // Vertical tab
break;
/*
** If not a valid formatting character, then clear out the break
** character variable so that processing will continue.
*/
default:
blocklen++;
bchar = '\0';
break;
}
}
/*
** If a block has been scanned, then print it at this time.
*/
if (blocklen > 0) {
Mono_Print_Raw(control, blockstart, blocklen);
}
/*
** Conveniently get the cursor position into working variables.
** This helps because many of the formatting characters change
** the cursor position.
*/
x = control->XPos;
y = control->YPos;
/*
** If a formatting character was found, then process it at this
** time.
*/
switch (bchar) {
/*
** Backspace moves the cursor back one space (erasing what was there).
*/
case '\b':
if (x > 0) {
x--;
control->XPos = x;
Mono_Print_Raw(control, &space, 1);
control->XPos = x;
}
break;
/*
** Formfeed -- clears the screen.
*/
case '\f':
Mono_Clear_Screen(control);
break;
/*
** Linefeed -- in the tradition of C, this actually translates
** into a functional <CR><LF> pair.
*/
case '\n':
x = 0;
y++;
if (y >= MONO_HEIGHT) {
Mono_Scroll(control);
y--;
}
control->XPos = x;
control->YPos = y;
break;
/*
** Horizontal tab
*/
case '\t':
Mono_Print_Raw(control, &space, 1);
break;
/*
** Unrecognized formatting character.
*/
default:
break;
}
}
}
}
/***********************************************************************************************
* Mono_Scroll -- Scroll the mono screen up one line. *
* *
* Use this routine to scroll the mono screen up one line. The bottom line will be filled *
* with blanks. The cursor position is moved up one line as well. *
* *
* INPUT: control -- Pointer to the buffer to scroll. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/04/1997 JLB : Created. *
*=============================================================================================*/
void Mono_Scroll(BuffControl * control)
{
if (control != NULL) {
int j;
unsigned short * vidmem;
unsigned short blank = BUILD_CHAR(' ', control->Attribute);
vidmem = control->Buffer;
RtlMoveMemory(vidmem, vidmem+MONO_WIDTH, (MONO_HEIGHT-1) * MONO_WIDTH * sizeof(unsigned short));
/*
** Fill the bottom row with blanks.
*/
for (j = 0; j < MONO_WIDTH; j++) {
*(vidmem + j + ((MONO_HEIGHT-1) * MONO_WIDTH)) = blank;
}
control->YPos -= 1;
if (control->YPos < 0) {
control->YPos = 0;
}
}
}
/***********************************************************************************************
* Mono_Pan -- Pan the mono screen over one column. *
* *
* This will scroll (horizontally) the monochrome screen. The new column will be filled *
* with blank spaces. *
* *
* INPUT: control -- Pointer to the buffer to pan. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/04/1997 JLB : Created. *
*=============================================================================================*/
void Mono_Pan(BuffControl * control)
{
if (control != NULL) {
int j;
unsigned short * vidmem;
unsigned short blank = BUILD_CHAR(' ', control->Attribute);
vidmem = control->Buffer;
for (j = 0; j < MONO_HEIGHT; j++) {
RtlMoveMemory(vidmem+j*MONO_WIDTH, vidmem+j*MONO_WIDTH+1, (MONO_WIDTH-1) * sizeof(unsigned short));
*(vidmem + j*MONO_WIDTH + MONO_WIDTH-1) = blank;
}
control->XPos -= 1;
if (control->XPos < 0) {
control->XPos = 0;
}
}
}
/***********************************************************************************************
* Mono_Print_Raw -- Print text (without processing) to mono screen. *
* *
* This is a low level routine that will not process the characters submitted, but merely *
* draw them to the monochrome screen. The output will not wrap at right margin nor will *
* it scroll the screen when it tries to print past the bottom right character position. *
* This routine can be used to output characters that have a visual image even though they *
* line up with formatting control characters. *
* *
* INPUT: control -- Pointer to the buffer to print to. *
* *
* string -- Pointer to the string to output. *
* *
* length -- The length of the string in characters. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/04/1997 JLB : Created. *
*=============================================================================================*/
void Mono_Print_Raw(BuffControl * control, unsigned char * string, unsigned long length)
{
if (control != NULL) {
unsigned short * vidmem;
int x,y;
unsigned long i;
vidmem = control->Buffer;
x = control->XPos;
y = control->YPos;
for (i = 0; i < length; i++) {
unsigned char letter;
letter = *string++;
*(vidmem + x + (y * MONO_WIDTH)) = BUILD_CHAR(letter, control->Attribute);
x++;
/*
** Don't allow the cursor to extend past the right margin.
*/
if (x >= MONO_WIDTH) {
x = MONO_WIDTH-1;
}
}
control->XPos = x;
control->YPos = y;
}
}
/***********************************************************************************************
* Mono_Clear_Screen -- Clears the monochrome screen & homes cursor. *
* *
* This will erase the monochrome screen and move the output cursor to the upper left *
* corner. *
* *
* INPUT: control -- Pointer to the buffer to clear. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/04/1997 JLB : Created. *
*=============================================================================================*/
void Mono_Clear_Screen(BuffControl * control)
{
if (control != NULL) {
int i;
unsigned short * vidptr = control->Buffer;
unsigned short blank = BUILD_CHAR(' ', control->Attribute);
for (i = 0; i < MONO_HEIGHT*MONO_WIDTH; i++) {
*vidptr++ = blank;
}
control->XPos = 0;
control->YPos = 0;
}
}
/***********************************************************************************************
* Mono_Printf -- Print formatted text to the mono device. *
* *
* Prints formatted text to the monochrome device specified. *
* *
* INPUT: control -- Pointer to the buffer to print to. *
* *
* text -- Pointer to the text to display. *
* *
* ... -- Any optional parameters needed by the string. *
* *
* OUTPUT: none *
* *
* WARNINGS: The final formatted string is limited to 1024 characters long. *
* *
* HISTORY: *
* 01/04/1997 JLB : Created. *
*=============================================================================================*/
void Mono_Printf(BuffControl * control, char const * text, ...)
{
if (control != NULL) {
char buf[1024];
va_list ap;
va_start(ap, text);
vsprintf(buf, text, ap);
Mono_Print(control, buf, strlen(buf));
va_end(ap);
}
}
/***********************************************************************************************
* Mono_Set_View_Pos -- Set the mono display ram view offset. *
* *
* Set the CRTC register for the monochrome display to the offset specified. The card *
* defaults to viewing offset 0 (i.e. $B0000 absolute RAM address). *
* *
* INPUT: device -- The monochrome device global data. *
* *
* pos -- The offset position to set the view to. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 01/04/1997 JLB : Created. *
*=============================================================================================*/
void Mono_Set_View_Pos(MonoGlobals * device, int pos)
{
if (device != NULL) {
WRITE_PORT_UCHAR(device->CRTCRegisters, 0x0C);
WRITE_PORT_UCHAR(device->CRTCRegisters+1, (unsigned char)(pos >> 8));
WRITE_PORT_UCHAR(device->CRTCRegisters, 0x0D);
WRITE_PORT_UCHAR(device->CRTCRegisters+1, (unsigned char)(pos & 0xFF));
}
}
void Mono_Bring_To_Top(MonoGlobals * device, int index)
{
if (index == -1 || index == device->CurrentVisible) return;
Mono_Set_View_Pos(device, index * 100);
// Mono_Set_View_Pos(device, index * MONO_WIDTH * MONO_HEIGHT);
device->CurrentVisible = index;
Mono_Update_Cursor(device);
}
void Display_Signon_Banner(BuffControl * control)
{
Mono_Printf(control,
"\fMono Display Driver [mono.sys] -- NT Kernel Mode Device Driver\n"
"Version: 1.0 -- (" __DATE__ " " __TIME__ ")\n"
"Device Name: " A_DEVICE_NAME "\n"
"Symbolic Link: " A_SYMBOLIC_NAME " (\"\\\\.\\MONO\")\n\n");
Mono_Printf(control, "Supporting IOCTL Services:\n");
Mono_Printf(control, "--------------------------\n");
Mono_Printf(control, " [%08X] IOCTL_MONO_PRINT_RAW(char * text, int length)\n", IOCTL_MONO_PRINT_RAW);
Mono_Printf(control, " [%08X] IOCTL_MONO_CLEAR_SCREEN(void)\n", IOCTL_MONO_CLEAR_SCREEN);
Mono_Printf(control, " [%08X] IOCTL_MONO_SET_CURSOR(int x, int y)\n", IOCTL_MONO_SET_CURSOR);
Mono_Printf(control, " [%08X] IOCTL_MONO_SCROLL(void)\n", IOCTL_MONO_SCROLL);
Mono_Printf(control, " [%08X] IOCTL_MONO_BRING_TO_TOP(void)\n", IOCTL_MONO_BRING_TO_TOP);
Mono_Printf(control, " [%08X] IOCTL_MONO_SET_ATTRIBUTE(char attrib)\n", IOCTL_MONO_SET_ATTRIBUTE);
Mono_Printf(control, " [%08X] IOCTL_MONO_PAN(void)\n", IOCTL_MONO_PAN);
Mono_Printf(control, " [%08X] IOCTL_MONO_LOCK(void) [returns mono memory address]\n", IOCTL_MONO_LOCK);
Mono_Printf(control, " [%08X] IOCTL_MONO_UNLOCK(void)\n", IOCTL_MONO_UNLOCK);
}
/*++
Routine Description:
Given a physical address, maps this address into a user mode process's
address space
Arguments:
DeviceObject - pointer to a device object
IoBuffer - pointer to the I/O buffer
InputBufferLength - input buffer length
OutputBufferLength - output buffer length
Return Value:
STATUS_SUCCESS if sucessful, otherwise
STATUS_UNSUCCESSFUL,
STATUS_INSUFFICIENT_RESOURCES,
(other STATUS_* as returned by kernel APIs)
--*/
void * Mono_Fetch_Ptr(PDEVICE_OBJECT DeviceObject)
{
UNICODE_STRING memory_unicode_string;
OBJECT_ATTRIBUTES object_attribute;
HANDLE section_handle = NULL;
NTSTATUS error;
void * retval = NULL;
/*
** Try to open the PhysicalMemory section. This will be needed when mapping the
** physical memory 'file' to an accessable address range. First create a physical
** memory object and then convert that object into a handle value.
*/
RtlInitUnicodeString(&memory_unicode_string, L"\\Device\\PhysicalMemory");
InitializeObjectAttributes(&object_attribute, &memory_unicode_string, OBJ_CASE_INSENSITIVE, (HANDLE)NULL, (PSECURITY_DESCRIPTOR)NULL);
error = ZwOpenSection(&section_handle, SECTION_ALL_ACCESS, &object_attribute);
if (NT_SUCCESS(error)) {
PHYSICAL_ADDRESS logical_base_address;
PHYSICAL_ADDRESS physical_address;
ULONG in_io_space = 0;
physical_address.HighPart = 0;
physical_address.LowPart = MONO_MEMORY;
//
// Translate the physical addresses.
//
if (HalTranslateBusAddress(Isa, 0, physical_address, &in_io_space, &logical_base_address)) {
PVOID virtual_address = NULL;
ULONG viewlength = MONO_MEM_LENGTH;
PHYSICAL_ADDRESS view_base = logical_base_address;
//
// Map the section
//
error = ZwMapViewOfSection(section_handle, (HANDLE) -1, &virtual_address, 0L, viewlength, &view_base, &viewlength, ViewShare, 0, PAGE_READWRITE | PAGE_NOCACHE);
if (NT_SUCCESS(error)) {
//
// Mapping the section above rounded the physical address down to the
// nearest 64 K boundary. Now return a virtual address that sits where
// we want by adding in the offset from the beginning of the section.
//
(ULONG) virtual_address += (ULONG)logical_base_address.LowPart - (ULONG)view_base.LowPart;
retval = virtual_address;
}
}
/*
** Close the zone handle before exiting.
*/
ZwClose(section_handle);
}
return(retval);
}