reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.c

878 lines
26 KiB
C

/*
* COPYRIGHT: GPLv2+ - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.c
* PURPOSE: DOS EMS Driver
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*
* DOCUMENTATION: Official specification:
* LIM EMS v4.0: http://www.phatcode.net/res/218/files/limems40.txt
*/
/* INCLUDES *******************************************************************/
#include "ntvdm.h"
#define NDEBUG
#include <debug.h>
#include "emulator.h"
#include "../../memory.h"
#include "bios/umamgr.h"
#include "dos.h"
#include "dos/dem.h"
#include "device.h"
#include "emsdrv.h"
#define EMS_DEVICE_NAME "EMMXXXX0"
#define EMS_SEGMENT_SIZE ((EMS_PHYSICAL_PAGES * EMS_PAGE_SIZE) >> 4)
#define EMS_SYSTEM_HANDLE 0
/* PRIVATE VARIABLES **********************************************************/
static PDOS_DEVICE_NODE Node;
static RTL_BITMAP AllocBitmap;
static PULONG BitmapBuffer = NULL;
static PEMS_PAGE PageTable = NULL;
static EMS_HANDLE HandleTable[EMS_MAX_HANDLES];
static PVOID Mapping[EMS_PHYSICAL_PAGES] = { NULL };
static PVOID MappingBackup[EMS_PHYSICAL_PAGES] = { NULL };
static ULONG EmsTotalPages = 0;
static PVOID EmsMemory = NULL;
static USHORT EmsSegment = EMS_SEGMENT;
/* PRIVATE FUNCTIONS **********************************************************/
static VOID InitHandlesTable(VOID)
{
USHORT i;
for (i = 0; i < ARRAYSIZE(HandleTable); i++)
{
HandleTable[i].Allocated = FALSE;
HandleTable[i].PageCount = 0;
RtlZeroMemory(HandleTable[i].Name, sizeof(HandleTable[i].Name));
InitializeListHead(&HandleTable[i].PageList);
}
}
static PEMS_HANDLE CreateHandle(PUSHORT Handle)
{
PEMS_HANDLE HandleEntry;
USHORT i;
/* Handle 0 is reserved (system handle) */
for (i = 1; i < ARRAYSIZE(HandleTable); i++)
{
HandleEntry = &HandleTable[i];
if (!HandleEntry->Allocated)
{
*Handle = i;
HandleEntry->Allocated = TRUE;
return HandleEntry;
}
}
return NULL;
}
static VOID FreeHandle(PEMS_HANDLE HandleEntry)
{
HandleEntry->Allocated = FALSE;
HandleEntry->PageCount = 0;
RtlZeroMemory(HandleEntry->Name, sizeof(HandleEntry->Name));
// InitializeListHead(&HandleEntry->PageList);
}
static inline PEMS_HANDLE GetHandleRecord(USHORT Handle)
{
if (Handle >= ARRAYSIZE(HandleTable)) return NULL;
return &HandleTable[Handle];
}
static inline BOOLEAN ValidateHandle(PEMS_HANDLE HandleEntry)
{
return (HandleEntry != NULL && HandleEntry->Allocated);
}
static UCHAR EmsFree(USHORT Handle)
{
PLIST_ENTRY Entry;
PEMS_HANDLE HandleEntry = GetHandleRecord(Handle);
if (!ValidateHandle(HandleEntry))
return EMS_STATUS_INVALID_HANDLE;
for (Entry = HandleEntry->PageList.Flink;
Entry != &HandleEntry->PageList;
Entry = Entry->Flink)
{
PEMS_PAGE PageEntry = (PEMS_PAGE)CONTAINING_RECORD(Entry, EMS_PAGE, Entry);
ULONG PageNumber = ARRAY_INDEX(PageEntry, PageTable);
/* Free the page */
RtlClearBits(&AllocBitmap, PageNumber, 1);
}
InitializeListHead(&HandleEntry->PageList);
if (Handle != EMS_SYSTEM_HANDLE)
FreeHandle(HandleEntry);
return EMS_STATUS_SUCCESS;
}
static UCHAR EmsAlloc(USHORT NumPages, PUSHORT Handle)
{
ULONG i, CurrentIndex = 0;
PEMS_HANDLE HandleEntry;
if (NumPages == 0) return EMS_STATUS_ZERO_PAGES;
HandleEntry = CreateHandle(Handle);
if (!HandleEntry) return EMS_STATUS_NO_MORE_HANDLES;
while (HandleEntry->PageCount < NumPages)
{
ULONG RunStart;
ULONG RunSize = RtlFindNextForwardRunClear(&AllocBitmap, CurrentIndex, &RunStart);
if (RunSize == 0)
{
/* Free what's been allocated already and report failure */
EmsFree(*Handle);
return EMS_STATUS_INSUFFICIENT_PAGES;
}
else if ((HandleEntry->PageCount + RunSize) > NumPages)
{
/* We don't need the entire run */
RunSize = NumPages - HandleEntry->PageCount;
}
CurrentIndex = RunStart + RunSize;
HandleEntry->PageCount += RunSize;
RtlSetBits(&AllocBitmap, RunStart, RunSize);
for (i = 0; i < RunSize; i++)
{
PageTable[RunStart + i].Handle = *Handle;
InsertTailList(&HandleEntry->PageList, &PageTable[RunStart + i].Entry);
}
}
return EMS_STATUS_SUCCESS;
}
static UCHAR InitSystemHandle(USHORT NumPages)
{
//
// FIXME: This is an adapted copy of EmsAlloc!!
//
ULONG i, CurrentIndex = 0;
PEMS_HANDLE HandleEntry = &HandleTable[EMS_SYSTEM_HANDLE];
/* The system handle must never have been initialized before */
ASSERT(!HandleEntry->Allocated);
/* Now allocate it */
HandleEntry->Allocated = TRUE;
while (HandleEntry->PageCount < NumPages)
{
ULONG RunStart;
ULONG RunSize = RtlFindNextForwardRunClear(&AllocBitmap, CurrentIndex, &RunStart);
if (RunSize == 0)
{
/* Free what's been allocated already and report failure */
EmsFree(EMS_SYSTEM_HANDLE);
// FIXME: For this function (and EmsAlloc as well),
// use instead an internal function that just uses
// PEMS_HANDLE pointers instead. It's only in the
// EMS interrupt handler that we should do the
// unfolding.
return EMS_STATUS_INSUFFICIENT_PAGES;
}
else if ((HandleEntry->PageCount + RunSize) > NumPages)
{
/* We don't need the entire run */
RunSize = NumPages - HandleEntry->PageCount;
}
CurrentIndex = RunStart + RunSize;
HandleEntry->PageCount += RunSize;
RtlSetBits(&AllocBitmap, RunStart, RunSize);
for (i = 0; i < RunSize; i++)
{
PageTable[RunStart + i].Handle = EMS_SYSTEM_HANDLE;
InsertTailList(&HandleEntry->PageList, &PageTable[RunStart + i].Entry);
}
}
return EMS_STATUS_SUCCESS;
}
static PEMS_PAGE GetLogicalPage(PEMS_HANDLE HandleEntry, USHORT LogicalPage)
{
PLIST_ENTRY Entry = HandleEntry->PageList.Flink;
while (LogicalPage)
{
if (Entry == &HandleEntry->PageList) return NULL;
LogicalPage--;
Entry = Entry->Flink;
}
return (PEMS_PAGE)CONTAINING_RECORD(Entry, EMS_PAGE, Entry);
}
static UCHAR EmsMap(USHORT Handle, UCHAR PhysicalPage, USHORT LogicalPage)
{
PEMS_PAGE PageEntry;
PEMS_HANDLE HandleEntry = GetHandleRecord(Handle);
if (!ValidateHandle(HandleEntry))
return EMS_STATUS_INVALID_HANDLE;
if (PhysicalPage >= EMS_PHYSICAL_PAGES)
return EMS_STATUS_INV_PHYSICAL_PAGE;
if (LogicalPage == 0xFFFF)
{
/* Unmap */
Mapping[PhysicalPage] = NULL;
return EMS_STATUS_SUCCESS;
}
PageEntry = GetLogicalPage(HandleEntry, LogicalPage);
if (!PageEntry) return EMS_STATUS_INV_LOGICAL_PAGE;
Mapping[PhysicalPage] = (PVOID)((ULONG_PTR)EmsMemory
+ ARRAY_INDEX(PageEntry, PageTable) * EMS_PAGE_SIZE);
return EMS_STATUS_SUCCESS;
}
static VOID WINAPI EmsIntHandler(LPWORD Stack)
{
switch (getAH())
{
/* Get Manager Status */
case 0x40:
{
setAH(EMS_STATUS_SUCCESS);
break;
}
/* Get Page Frame Segment */
case 0x41:
{
setAH(EMS_STATUS_SUCCESS);
setBX(EmsSegment);
break;
}
/* Get Number of Unallocated Pages */
case 0x42:
{
setAH(EMS_STATUS_SUCCESS);
setBX(RtlNumberOfClearBits(&AllocBitmap));
setDX(EmsTotalPages);
break;
}
/* Get Handle and Allocate Memory */
case 0x43:
{
USHORT Handle;
UCHAR Status = EmsAlloc(getBX(), &Handle);
if (Status == EMS_STATUS_SUCCESS)
setDX(Handle);
setAH(Status);
break;
}
/* Map Memory */
case 0x44:
{
setAH(EmsMap(getDX(), getAL(), getBX()));
break;
}
/* Release Handle and Memory */
case 0x45:
{
setAH(EmsFree(getDX()));
break;
}
/* Get EMM Version */
case 0x46:
{
setAH(EMS_STATUS_SUCCESS);
setAL(EMS_VERSION_NUM);
break;
}
/* Save Page Map */
case 0x47:
{
// FIXME: This depends on an EMS handle given in DX
RtlCopyMemory(MappingBackup, Mapping, sizeof(Mapping));
setAH(EMS_STATUS_SUCCESS);
break;
}
/* Restore Page Map */
case 0x48:
{
// FIXME: This depends on an EMS handle given in DX
RtlCopyMemory(Mapping, MappingBackup, sizeof(Mapping));
setAH(EMS_STATUS_SUCCESS);
break;
}
/* Get Number of Opened Handles */
case 0x4B:
{
USHORT NumOpenHandles = 0;
USHORT i;
for (i = 0; i < ARRAYSIZE(HandleTable); i++)
{
if (HandleTable[i].Allocated)
++NumOpenHandles;
}
setAH(EMS_STATUS_SUCCESS);
setBX(NumOpenHandles);
break;
}
/* Get Handle Number of Pages */
case 0x4C:
{
PEMS_HANDLE HandleEntry = GetHandleRecord(getDX());
if (!ValidateHandle(HandleEntry))
{
setAH(EMS_STATUS_INVALID_HANDLE);
break;
}
setAH(EMS_STATUS_SUCCESS);
setBX(HandleEntry->PageCount);
break;
}
/* Get All Handles Number of Pages */
case 0x4D:
{
PEMS_HANDLE_PAGE_INFO HandlePageInfo = (PEMS_HANDLE_PAGE_INFO)SEG_OFF_TO_PTR(getES(), getDI());
USHORT NumOpenHandles = 0;
USHORT i;
for (i = 0; i < ARRAYSIZE(HandleTable); i++)
{
if (HandleTable[i].Allocated)
{
HandlePageInfo->Handle = i;
HandlePageInfo->PageCount = HandleTable[i].PageCount;
++HandlePageInfo;
++NumOpenHandles;
}
}
setAH(EMS_STATUS_SUCCESS);
setBX(NumOpenHandles);
break;
}
/* Get or Set Page Map */
case 0x4E:
{
switch (getAL())
{
/* Get Mapping Registers */
// case 0x00: // TODO: NOT IMPLEMENTED
/* Set Mapping Registers */
// case 0x01: // TODO: NOT IMPLEMENTED
/* Get and Set Mapping Registers At Once */
// case 0x02: // TODO: NOT IMPLEMENTED
/* Get Size of Page-Mapping Array */
case 0x03:
{
setAH(EMS_STATUS_SUCCESS);
setAL(sizeof(Mapping));
break;
}
default:
{
DPRINT1("EMS function AH = 0x4E, subfunction AL = %02X NOT IMPLEMENTED\n", getAL());
setAH(EMS_STATUS_UNKNOWN_FUNCTION);
break;
}
}
break;
}
/* Get/Set Handle Name */
case 0x53:
{
PEMS_HANDLE HandleEntry = GetHandleRecord(getDX());
if (!ValidateHandle(HandleEntry))
{
setAH(EMS_STATUS_INVALID_HANDLE);
break;
}
if (getAL() == 0x00)
{
/* Retrieve the name */
RtlCopyMemory(SEG_OFF_TO_PTR(getES(), getDI()),
HandleEntry->Name,
sizeof(HandleEntry->Name));
setAH(EMS_STATUS_SUCCESS);
}
else if (getAL() == 0x01)
{
/* Store the name */
RtlCopyMemory(HandleEntry->Name,
SEG_OFF_TO_PTR(getDS(), getSI()),
sizeof(HandleEntry->Name));
setAH(EMS_STATUS_SUCCESS);
}
else
{
DPRINT1("Invalid subfunction %02X for EMS function AH = 53h\n", getAL());
setAH(EMS_STATUS_INVALID_SUBFUNCTION);
}
break;
}
/* Handle Directory functions */
case 0x54:
{
if (getAL() == 0x00)
{
/* Get Handle Directory */
PEMS_HANDLE_DIR_ENTRY HandleDir = (PEMS_HANDLE_DIR_ENTRY)SEG_OFF_TO_PTR(getES(), getDI());
USHORT NumOpenHandles = 0;
USHORT i;
for (i = 0; i < ARRAYSIZE(HandleTable); i++)
{
if (HandleTable[i].Allocated)
{
HandleDir->Handle = i;
RtlCopyMemory(HandleDir->Name,
HandleTable[i].Name,
sizeof(HandleDir->Name));
++HandleDir;
++NumOpenHandles;
}
}
setAH(EMS_STATUS_SUCCESS);
setAL((UCHAR)NumOpenHandles);
}
else if (getAL() == 0x01)
{
/* Search for Named Handle */
PUCHAR HandleName = (PUCHAR)SEG_OFF_TO_PTR(getDS(), getSI());
PEMS_HANDLE HandleFound = NULL;
USHORT i;
for (i = 0; i < ARRAYSIZE(HandleTable); i++)
{
if (HandleTable[i].Allocated &&
RtlCompareMemory(HandleName,
HandleTable[i].Name,
sizeof(HandleTable[i].Name)) == sizeof(HandleTable[i].Name))
{
HandleFound = &HandleTable[i];
break;
}
}
/* Bail out if no handle was found */
if (i >= ARRAYSIZE(HandleTable)) // HandleFound == NULL
{
setAH(EMS_STATUS_HANDLE_NOT_FOUND);
break;
}
/* Return the handle number */
setDX(i);
/* Sanity check: Check whether the handle was unnamed */
i = 0;
while ((i < sizeof(HandleFound->Name)) && (HandleFound->Name[i] == '\0'))
++i;
if (i >= sizeof(HandleFound->Name))
{
setAH(EMS_STATUS_UNNAMED_HANDLE);
}
else
{
setAH(EMS_STATUS_SUCCESS);
}
}
else if (getAL() == 0x02)
{
/*
* Get Total Number of Handles
*
* This function retrieves the maximum number of handles
* (allocated or not) the memory manager supports, which
* a program may request.
*/
setAH(EMS_STATUS_SUCCESS);
setBX(ARRAYSIZE(HandleTable));
}
else
{
DPRINT1("Invalid subfunction %02X for EMS function AH = 54h\n", getAL());
setAH(EMS_STATUS_INVALID_SUBFUNCTION);
}
break;
}
/* Move/Exchange Memory */
case 0x57:
{
PUCHAR SourcePtr, DestPtr;
PEMS_HANDLE HandleEntry;
PEMS_PAGE PageEntry;
BOOLEAN Exchange = getAL();
PEMS_COPY_DATA Data = (PEMS_COPY_DATA)SEG_OFF_TO_PTR(getDS(), getSI());
if (Data->SourceType)
{
/* Expanded memory */
HandleEntry = GetHandleRecord(Data->SourceHandle);
if (!ValidateHandle(HandleEntry))
{
setAH(EMS_STATUS_INVALID_HANDLE);
break;
}
PageEntry = GetLogicalPage(HandleEntry, Data->SourceSegment);
if (!PageEntry)
{
setAH(EMS_STATUS_INV_LOGICAL_PAGE);
break;
}
SourcePtr = (PUCHAR)((ULONG_PTR)EmsMemory
+ ARRAY_INDEX(PageEntry, PageTable) * EMS_PAGE_SIZE
+ Data->SourceOffset);
}
else
{
/* Conventional memory */
SourcePtr = (PUCHAR)SEG_OFF_TO_PTR(Data->SourceSegment, Data->SourceOffset);
}
if (Data->DestType)
{
/* Expanded memory */
HandleEntry = GetHandleRecord(Data->DestHandle);
if (!ValidateHandle(HandleEntry))
{
setAH(EMS_STATUS_INVALID_HANDLE);
break;
}
PageEntry = GetLogicalPage(HandleEntry, Data->DestSegment);
if (!PageEntry)
{
setAH(EMS_STATUS_INV_LOGICAL_PAGE);
break;
}
DestPtr = (PUCHAR)((ULONG_PTR)EmsMemory
+ ARRAY_INDEX(PageEntry, PageTable) * EMS_PAGE_SIZE
+ Data->DestOffset);
}
else
{
/* Conventional memory */
DestPtr = (PUCHAR)SEG_OFF_TO_PTR(Data->DestSegment, Data->DestOffset);
}
if (Exchange)
{
ULONG i;
/* Exchange */
for (i = 0; i < Data->RegionLength; i++)
{
UCHAR Temp = DestPtr[i];
DestPtr[i] = SourcePtr[i];
SourcePtr[i] = Temp;
}
}
else
{
/* Move */
RtlMoveMemory(DestPtr, SourcePtr, Data->RegionLength);
}
setAH(EMS_STATUS_SUCCESS);
break;
}
/* Get Mappable Physical Address Array */
case 0x58:
{
if (getAL() == 0x00)
{
PEMS_MAPPABLE_PHYS_PAGE PageArray = (PEMS_MAPPABLE_PHYS_PAGE)SEG_OFF_TO_PTR(getES(), getDI());
ULONG i;
for (i = 0; i < EMS_PHYSICAL_PAGES; i++)
{
PageArray->PageSegment = EMS_SEGMENT + i * (EMS_PAGE_SIZE >> 4);
PageArray->PageNumber = i;
++PageArray;
}
setAH(EMS_STATUS_SUCCESS);
setCX(EMS_PHYSICAL_PAGES);
}
else if (getAL() == 0x01)
{
setAH(EMS_STATUS_SUCCESS);
setCX(EMS_PHYSICAL_PAGES);
}
else
{
DPRINT1("Invalid subfunction %02X for EMS function AH = 58h\n", getAL());
setAH(EMS_STATUS_INVALID_SUBFUNCTION);
}
break;
}
/* Get Expanded Memory Hardware Information */
case 0x59:
{
if (getAL() == 0x00)
{
PEMS_HARDWARE_INFO HardwareInfo = (PEMS_HARDWARE_INFO)SEG_OFF_TO_PTR(getES(), getDI());
/* Return the hardware information */
HardwareInfo->RawPageSize = EMS_PAGE_SIZE >> 4;
HardwareInfo->AlternateRegSets = 0;
HardwareInfo->ContextAreaSize = sizeof(Mapping);
HardwareInfo->DmaRegisterSets = 0;
HardwareInfo->DmaChannelOperation = 0;
setAH(EMS_STATUS_SUCCESS);
}
else if (getAL() == 0x01)
{
/* Same as function AH = 42h */
setAH(EMS_STATUS_SUCCESS);
setBX(RtlNumberOfClearBits(&AllocBitmap));
setDX(EmsTotalPages);
}
else
{
DPRINT1("Invalid subfunction %02X for EMS function AH = 59h\n", getAL());
setAH(EMS_STATUS_INVALID_SUBFUNCTION);
}
break;
}
default:
{
DPRINT1("EMS function AH = %02X NOT IMPLEMENTED\n", getAH());
setAH(EMS_STATUS_UNKNOWN_FUNCTION);
break;
}
}
}
static VOID FASTCALL EmsReadMemory(ULONG Address, PVOID Buffer, ULONG Size)
{
ULONG i;
ULONG RelativeAddress = Address - TO_LINEAR(EmsSegment, 0);
ULONG FirstPage = RelativeAddress / EMS_PAGE_SIZE;
ULONG LastPage = (RelativeAddress + Size - 1) / EMS_PAGE_SIZE;
ULONG Offset, Length;
for (i = FirstPage; i <= LastPage; i++)
{
Offset = (i == FirstPage) ? RelativeAddress & (EMS_PAGE_SIZE - 1) : 0;
Length = ((i == LastPage)
? (RelativeAddress + Size - (LastPage << EMS_PAGE_BITS))
: EMS_PAGE_SIZE) - Offset;
if (Mapping[i]) RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)Mapping[i] + Offset), Length);
Buffer = (PVOID)((ULONG_PTR)Buffer + Length);
}
}
static BOOLEAN FASTCALL EmsWriteMemory(ULONG Address, PVOID Buffer, ULONG Size)
{
ULONG i;
ULONG RelativeAddress = Address - TO_LINEAR(EmsSegment, 0);
ULONG FirstPage = RelativeAddress / EMS_PAGE_SIZE;
ULONG LastPage = (RelativeAddress + Size - 1) / EMS_PAGE_SIZE;
ULONG Offset, Length;
for (i = FirstPage; i <= LastPage; i++)
{
Offset = (i == FirstPage) ? RelativeAddress & (EMS_PAGE_SIZE - 1) : 0;
Length = ((i == LastPage)
? (RelativeAddress + Size - (LastPage << EMS_PAGE_BITS))
: EMS_PAGE_SIZE) - Offset;
if (Mapping[i]) RtlCopyMemory((PVOID)((ULONG_PTR)Mapping[i] + Offset), Buffer, Length);
Buffer = (PVOID)((ULONG_PTR)Buffer + Length);
}
return TRUE;
}
static WORD NTAPI EmsDrvDispatchIoctlRead(PDOS_DEVICE_NODE Device, DWORD Buffer, PWORD Length)
{
// TODO: NOT IMPLEMENTED
UNIMPLEMENTED;
return DOS_DEVSTAT_DONE;
}
/* PUBLIC FUNCTIONS ***********************************************************/
BOOLEAN EmsDrvInitialize(USHORT Segment, ULONG TotalPages)
{
USHORT Size;
/* Try to allocate our page table in UMA at the given segment */
EmsSegment = (Segment != 0 ? Segment : EMS_SEGMENT);
Size = EMS_SEGMENT_SIZE; // Size in paragraphs
if (!UmaDescReserve(&EmsSegment, &Size)) return FALSE;
EmsTotalPages = TotalPages;
BitmapBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
((TotalPages + 31) / 32) * sizeof(ULONG));
if (BitmapBuffer == NULL)
{
UmaDescRelease(EmsSegment);
return FALSE;
}
RtlInitializeBitMap(&AllocBitmap, BitmapBuffer, TotalPages);
PageTable = (PEMS_PAGE)RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
TotalPages * sizeof(EMS_PAGE));
if (PageTable == NULL)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, BitmapBuffer);
BitmapBuffer = NULL;
UmaDescRelease(EmsSegment);
return FALSE;
}
EmsMemory = (PVOID)RtlAllocateHeap(RtlGetProcessHeap(), 0, TotalPages * EMS_PAGE_SIZE);
if (EmsMemory == NULL)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, PageTable);
PageTable = NULL;
RtlFreeHeap(RtlGetProcessHeap(), 0, BitmapBuffer);
BitmapBuffer = NULL;
UmaDescRelease(EmsSegment);
return FALSE;
}
InitHandlesTable();
/*
* FIXME: We should ensure that the system handle is associated
* with mapped pages from conventional memory. DosEmu seems to do
* it correctly. 384kB of memory mapped.
*/
if (InitSystemHandle(384/16) != EMS_STATUS_SUCCESS)
{
DPRINT1("Impossible to allocate pages for the system handle!\n");
RtlFreeHeap(RtlGetProcessHeap(), 0, EmsMemory);
EmsMemory = NULL;
RtlFreeHeap(RtlGetProcessHeap(), 0, PageTable);
PageTable = NULL;
RtlFreeHeap(RtlGetProcessHeap(), 0, BitmapBuffer);
BitmapBuffer = NULL;
UmaDescRelease(EmsSegment);
return FALSE;
}
MemInstallFastMemoryHook((PVOID)TO_LINEAR(EmsSegment, 0),
EMS_PHYSICAL_PAGES * EMS_PAGE_SIZE,
EmsReadMemory,
EmsWriteMemory);
/* Create the device */
Node = DosCreateDeviceEx(DOS_DEVATTR_IOCTL | DOS_DEVATTR_CHARACTER,
EMS_DEVICE_NAME,
Int16To32StubSize);
Node->IoctlReadRoutine = EmsDrvDispatchIoctlRead;
RegisterInt32(DEVICE_PRIVATE_AREA(Node->Driver),
EMS_INTERRUPT_NUM, EmsIntHandler, NULL);
return TRUE;
}
VOID EmsDrvCleanup(VOID)
{
/* Delete the device */
DosDeleteDevice(Node);
MemRemoveFastMemoryHook((PVOID)TO_LINEAR(EmsSegment, 0),
EMS_PHYSICAL_PAGES * EMS_PAGE_SIZE);
if (EmsMemory)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, EmsMemory);
EmsMemory = NULL;
}
if (PageTable)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, PageTable);
PageTable = NULL;
}
if (BitmapBuffer)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, BitmapBuffer);
BitmapBuffer = NULL;
}
UmaDescRelease(EmsSegment);
}