2 * COPYRIGHT: GPLv2+ - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.c
5 * PURPOSE: DOS EMS Driver
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
8 * DOCUMENTATION: Official specification:
9 * LIM EMS v4.0: http://www.phatcode.net/res/218/files/limems40.txt
12 /* INCLUDES *******************************************************************/
18 #include "../../memory.h"
19 #include "bios/umamgr.h"
27 #define EMS_DEVICE_NAME "EMMXXXX0"
29 #define EMS_SEGMENT_SIZE ((EMS_PHYSICAL_PAGES * EMS_PAGE_SIZE) >> 4)
30 #define EMS_SYSTEM_HANDLE 0
32 /* PRIVATE VARIABLES **********************************************************/
34 static PDOS_DEVICE_NODE Node
;
35 static RTL_BITMAP AllocBitmap
;
36 static PULONG BitmapBuffer
= NULL
;
37 static PEMS_PAGE PageTable
= NULL
;
38 static EMS_HANDLE HandleTable
[EMS_MAX_HANDLES
];
39 static PVOID Mapping
[EMS_PHYSICAL_PAGES
] = { NULL
};
40 static PVOID MappingBackup
[EMS_PHYSICAL_PAGES
] = { NULL
};
41 static ULONG EmsTotalPages
= 0;
42 static PVOID EmsMemory
= NULL
;
43 static USHORT EmsSegment
= EMS_SEGMENT
;
45 /* PRIVATE FUNCTIONS **********************************************************/
47 static VOID
InitHandlesTable(VOID
)
51 for (i
= 0; i
< ARRAYSIZE(HandleTable
); i
++)
53 HandleTable
[i
].Allocated
= FALSE
;
54 HandleTable
[i
].PageCount
= 0;
55 RtlZeroMemory(HandleTable
[i
].Name
, sizeof(HandleTable
[i
].Name
));
56 InitializeListHead(&HandleTable
[i
].PageList
);
60 static PEMS_HANDLE
CreateHandle(PUSHORT Handle
)
62 PEMS_HANDLE HandleEntry
;
65 /* Handle 0 is reserved (system handle) */
66 for (i
= 1; i
< ARRAYSIZE(HandleTable
); i
++)
68 HandleEntry
= &HandleTable
[i
];
69 if (!HandleEntry
->Allocated
)
72 HandleEntry
->Allocated
= TRUE
;
80 static VOID
FreeHandle(PEMS_HANDLE HandleEntry
)
82 HandleEntry
->Allocated
= FALSE
;
83 HandleEntry
->PageCount
= 0;
84 RtlZeroMemory(HandleEntry
->Name
, sizeof(HandleEntry
->Name
));
85 // InitializeListHead(&HandleEntry->PageList);
88 static inline PEMS_HANDLE
GetHandleRecord(USHORT Handle
)
90 if (Handle
>= ARRAYSIZE(HandleTable
)) return NULL
;
91 return &HandleTable
[Handle
];
94 static inline BOOLEAN
ValidateHandle(PEMS_HANDLE HandleEntry
)
96 return (HandleEntry
!= NULL
&& HandleEntry
->Allocated
);
99 static UCHAR
EmsFree(USHORT Handle
)
102 PEMS_HANDLE HandleEntry
= GetHandleRecord(Handle
);
104 if (!ValidateHandle(HandleEntry
))
105 return EMS_STATUS_INVALID_HANDLE
;
107 for (Entry
= HandleEntry
->PageList
.Flink
;
108 Entry
!= &HandleEntry
->PageList
;
109 Entry
= Entry
->Flink
)
111 PEMS_PAGE PageEntry
= (PEMS_PAGE
)CONTAINING_RECORD(Entry
, EMS_PAGE
, Entry
);
112 ULONG PageNumber
= ARRAY_INDEX(PageEntry
, PageTable
);
115 RtlClearBits(&AllocBitmap
, PageNumber
, 1);
118 InitializeListHead(&HandleEntry
->PageList
);
120 if (Handle
!= EMS_SYSTEM_HANDLE
)
121 FreeHandle(HandleEntry
);
123 return EMS_STATUS_SUCCESS
;
126 static UCHAR
EmsAlloc(USHORT NumPages
, PUSHORT Handle
)
128 ULONG i
, CurrentIndex
= 0;
129 PEMS_HANDLE HandleEntry
;
131 if (NumPages
== 0) return EMS_STATUS_ZERO_PAGES
;
133 HandleEntry
= CreateHandle(Handle
);
134 if (!HandleEntry
) return EMS_STATUS_NO_MORE_HANDLES
;
136 while (HandleEntry
->PageCount
< NumPages
)
139 ULONG RunSize
= RtlFindNextForwardRunClear(&AllocBitmap
, CurrentIndex
, &RunStart
);
143 /* Free what's been allocated already and report failure */
145 return EMS_STATUS_INSUFFICIENT_PAGES
;
147 else if ((HandleEntry
->PageCount
+ RunSize
) > NumPages
)
149 /* We don't need the entire run */
150 RunSize
= NumPages
- HandleEntry
->PageCount
;
153 CurrentIndex
= RunStart
+ RunSize
;
154 HandleEntry
->PageCount
+= RunSize
;
155 RtlSetBits(&AllocBitmap
, RunStart
, RunSize
);
157 for (i
= 0; i
< RunSize
; i
++)
159 PageTable
[RunStart
+ i
].Handle
= *Handle
;
160 InsertTailList(&HandleEntry
->PageList
, &PageTable
[RunStart
+ i
].Entry
);
164 return EMS_STATUS_SUCCESS
;
167 static UCHAR
InitSystemHandle(USHORT NumPages
)
170 // FIXME: This is an adapted copy of EmsAlloc!!
173 ULONG i
, CurrentIndex
= 0;
174 PEMS_HANDLE HandleEntry
= &HandleTable
[EMS_SYSTEM_HANDLE
];
176 /* The system handle must never have been initialized before */
177 ASSERT(!HandleEntry
->Allocated
);
179 /* Now allocate it */
180 HandleEntry
->Allocated
= TRUE
;
182 while (HandleEntry
->PageCount
< NumPages
)
185 ULONG RunSize
= RtlFindNextForwardRunClear(&AllocBitmap
, CurrentIndex
, &RunStart
);
189 /* Free what's been allocated already and report failure */
190 EmsFree(EMS_SYSTEM_HANDLE
);
191 // FIXME: For this function (and EmsAlloc as well),
192 // use instead an internal function that just uses
193 // PEMS_HANDLE pointers instead. It's only in the
194 // EMS interrupt handler that we should do the
196 return EMS_STATUS_INSUFFICIENT_PAGES
;
198 else if ((HandleEntry
->PageCount
+ RunSize
) > NumPages
)
200 /* We don't need the entire run */
201 RunSize
= NumPages
- HandleEntry
->PageCount
;
204 CurrentIndex
= RunStart
+ RunSize
;
205 HandleEntry
->PageCount
+= RunSize
;
206 RtlSetBits(&AllocBitmap
, RunStart
, RunSize
);
208 for (i
= 0; i
< RunSize
; i
++)
210 PageTable
[RunStart
+ i
].Handle
= EMS_SYSTEM_HANDLE
;
211 InsertTailList(&HandleEntry
->PageList
, &PageTable
[RunStart
+ i
].Entry
);
215 return EMS_STATUS_SUCCESS
;
218 static PEMS_PAGE
GetLogicalPage(PEMS_HANDLE HandleEntry
, USHORT LogicalPage
)
220 PLIST_ENTRY Entry
= HandleEntry
->PageList
.Flink
;
224 if (Entry
== &HandleEntry
->PageList
) return NULL
;
226 Entry
= Entry
->Flink
;
229 return (PEMS_PAGE
)CONTAINING_RECORD(Entry
, EMS_PAGE
, Entry
);
232 static UCHAR
EmsMap(USHORT Handle
, UCHAR PhysicalPage
, USHORT LogicalPage
)
235 PEMS_HANDLE HandleEntry
= GetHandleRecord(Handle
);
237 if (!ValidateHandle(HandleEntry
))
238 return EMS_STATUS_INVALID_HANDLE
;
240 if (PhysicalPage
>= EMS_PHYSICAL_PAGES
)
241 return EMS_STATUS_INV_PHYSICAL_PAGE
;
243 if (LogicalPage
== 0xFFFF)
246 Mapping
[PhysicalPage
] = NULL
;
247 return EMS_STATUS_SUCCESS
;
250 PageEntry
= GetLogicalPage(HandleEntry
, LogicalPage
);
251 if (!PageEntry
) return EMS_STATUS_INV_LOGICAL_PAGE
;
253 Mapping
[PhysicalPage
] = (PVOID
)((ULONG_PTR
)EmsMemory
254 + ARRAY_INDEX(PageEntry
, PageTable
) * EMS_PAGE_SIZE
);
255 return EMS_STATUS_SUCCESS
;
258 static VOID WINAPI
EmsIntHandler(LPWORD Stack
)
262 /* Get Manager Status */
265 setAH(EMS_STATUS_SUCCESS
);
269 /* Get Page Frame Segment */
272 setAH(EMS_STATUS_SUCCESS
);
277 /* Get Number of Unallocated Pages */
280 setAH(EMS_STATUS_SUCCESS
);
281 setBX(RtlNumberOfClearBits(&AllocBitmap
));
282 setDX(EmsTotalPages
);
286 /* Get Handle and Allocate Memory */
290 UCHAR Status
= EmsAlloc(getBX(), &Handle
);
292 if (Status
== EMS_STATUS_SUCCESS
)
302 setAH(EmsMap(getDX(), getAL(), getBX()));
306 /* Release Handle and Memory */
309 setAH(EmsFree(getDX()));
313 /* Get EMM Version */
316 setAH(EMS_STATUS_SUCCESS
);
317 setAL(EMS_VERSION_NUM
);
324 // FIXME: This depends on an EMS handle given in DX
325 RtlCopyMemory(MappingBackup
, Mapping
, sizeof(Mapping
));
326 setAH(EMS_STATUS_SUCCESS
);
330 /* Restore Page Map */
333 // FIXME: This depends on an EMS handle given in DX
334 RtlCopyMemory(Mapping
, MappingBackup
, sizeof(Mapping
));
335 setAH(EMS_STATUS_SUCCESS
);
339 /* Get Number of Opened Handles */
342 USHORT NumOpenHandles
= 0;
345 for (i
= 0; i
< ARRAYSIZE(HandleTable
); i
++)
347 if (HandleTable
[i
].Allocated
)
351 setAH(EMS_STATUS_SUCCESS
);
352 setBX(NumOpenHandles
);
356 /* Get Handle Number of Pages */
359 PEMS_HANDLE HandleEntry
= GetHandleRecord(getDX());
361 if (!ValidateHandle(HandleEntry
))
363 setAH(EMS_STATUS_INVALID_HANDLE
);
367 setAH(EMS_STATUS_SUCCESS
);
368 setBX(HandleEntry
->PageCount
);
372 /* Get All Handles Number of Pages */
375 PEMS_HANDLE_PAGE_INFO HandlePageInfo
= (PEMS_HANDLE_PAGE_INFO
)SEG_OFF_TO_PTR(getES(), getDI());
376 USHORT NumOpenHandles
= 0;
379 for (i
= 0; i
< ARRAYSIZE(HandleTable
); i
++)
381 if (HandleTable
[i
].Allocated
)
383 HandlePageInfo
->Handle
= i
;
384 HandlePageInfo
->PageCount
= HandleTable
[i
].PageCount
;
390 setAH(EMS_STATUS_SUCCESS
);
391 setBX(NumOpenHandles
);
395 /* Get/Set Handle Name */
398 PEMS_HANDLE HandleEntry
= GetHandleRecord(getDX());
400 if (!ValidateHandle(HandleEntry
))
402 setAH(EMS_STATUS_INVALID_HANDLE
);
408 /* Retrieve the name */
409 RtlCopyMemory(SEG_OFF_TO_PTR(getES(), getDI()),
411 sizeof(HandleEntry
->Name
));
412 setAH(EMS_STATUS_SUCCESS
);
414 else if (getAL() == 0x01)
417 RtlCopyMemory(HandleEntry
->Name
,
418 SEG_OFF_TO_PTR(getDS(), getSI()),
419 sizeof(HandleEntry
->Name
));
420 setAH(EMS_STATUS_SUCCESS
);
424 DPRINT1("Invalid subfunction %02X for EMS function AH = 53h\n", getAL());
425 setAH(EMS_STATUS_INVALID_SUBFUNCTION
);
431 /* Handle Directory functions */
436 /* Get Handle Directory */
438 PEMS_HANDLE_DIR_ENTRY HandleDir
= (PEMS_HANDLE_DIR_ENTRY
)SEG_OFF_TO_PTR(getES(), getDI());
439 USHORT NumOpenHandles
= 0;
442 for (i
= 0; i
< ARRAYSIZE(HandleTable
); i
++)
444 if (HandleTable
[i
].Allocated
)
446 HandleDir
->Handle
= i
;
447 RtlCopyMemory(HandleDir
->Name
,
449 sizeof(HandleDir
->Name
));
455 setAH(EMS_STATUS_SUCCESS
);
456 setAL((UCHAR
)NumOpenHandles
);
458 else if (getAL() == 0x01)
460 /* Search for Named Handle */
462 PUCHAR HandleName
= (PUCHAR
)SEG_OFF_TO_PTR(getDS(), getSI());
463 PEMS_HANDLE HandleFound
= NULL
;
466 for (i
= 0; i
< ARRAYSIZE(HandleTable
); i
++)
468 if (HandleTable
[i
].Allocated
&&
469 RtlCompareMemory(HandleName
,
471 sizeof(HandleTable
[i
].Name
)) == sizeof(HandleTable
[i
].Name
))
473 HandleFound
= &HandleTable
[i
];
478 /* Bail out if no handle was found */
479 if (i
>= ARRAYSIZE(HandleTable
)) // HandleFound == NULL
481 setAH(EMS_STATUS_HANDLE_NOT_FOUND
);
485 /* Return the handle number */
488 /* Sanity check: Check whether the handle was unnamed */
490 while ((i
< sizeof(HandleFound
->Name
)) && (HandleFound
->Name
[i
] == '\0'))
493 if (i
>= sizeof(HandleFound
->Name
))
495 setAH(EMS_STATUS_UNNAMED_HANDLE
);
499 setAH(EMS_STATUS_SUCCESS
);
502 else if (getAL() == 0x02)
505 * Get Total Number of Handles
507 * This function retrieves the maximum number of handles
508 * (allocated or not) the memory manager supports, which
509 * a program may request.
511 setAH(EMS_STATUS_SUCCESS
);
512 setBX(ARRAYSIZE(HandleTable
));
516 DPRINT1("Invalid subfunction %02X for EMS function AH = 54h\n", getAL());
517 setAH(EMS_STATUS_INVALID_SUBFUNCTION
);
523 /* Move/Exchange Memory */
526 PUCHAR SourcePtr
, DestPtr
;
527 PEMS_HANDLE HandleEntry
;
529 BOOLEAN Exchange
= getAL();
530 PEMS_COPY_DATA Data
= (PEMS_COPY_DATA
)SEG_OFF_TO_PTR(getDS(), getSI());
532 if (Data
->SourceType
)
534 /* Expanded memory */
535 HandleEntry
= GetHandleRecord(Data
->SourceHandle
);
536 if (!ValidateHandle(HandleEntry
))
538 setAH(EMS_STATUS_INVALID_HANDLE
);
542 PageEntry
= GetLogicalPage(HandleEntry
, Data
->SourceSegment
);
545 setAH(EMS_STATUS_INV_LOGICAL_PAGE
);
549 SourcePtr
= (PUCHAR
)((ULONG_PTR
)EmsMemory
550 + ARRAY_INDEX(PageEntry
, PageTable
) * EMS_PAGE_SIZE
551 + Data
->SourceOffset
);
555 /* Conventional memory */
556 SourcePtr
= (PUCHAR
)SEG_OFF_TO_PTR(Data
->SourceSegment
, Data
->SourceOffset
);
561 /* Expanded memory */
562 HandleEntry
= GetHandleRecord(Data
->DestHandle
);
563 if (!ValidateHandle(HandleEntry
))
565 setAH(EMS_STATUS_INVALID_HANDLE
);
569 PageEntry
= GetLogicalPage(HandleEntry
, Data
->DestSegment
);
572 setAH(EMS_STATUS_INV_LOGICAL_PAGE
);
576 DestPtr
= (PUCHAR
)((ULONG_PTR
)EmsMemory
577 + ARRAY_INDEX(PageEntry
, PageTable
) * EMS_PAGE_SIZE
582 /* Conventional memory */
583 DestPtr
= (PUCHAR
)SEG_OFF_TO_PTR(Data
->DestSegment
, Data
->DestOffset
);
591 for (i
= 0; i
< Data
->RegionLength
; i
++)
593 UCHAR Temp
= DestPtr
[i
];
594 DestPtr
[i
] = SourcePtr
[i
];
601 RtlMoveMemory(DestPtr
, SourcePtr
, Data
->RegionLength
);
604 setAH(EMS_STATUS_SUCCESS
);
608 /* Get Mappable Physical Address Array */
613 PEMS_MAPPABLE_PHYS_PAGE PageArray
= (PEMS_MAPPABLE_PHYS_PAGE
)SEG_OFF_TO_PTR(getES(), getDI());
616 for (i
= 0; i
< EMS_PHYSICAL_PAGES
; i
++)
618 PageArray
->PageSegment
= EMS_SEGMENT
+ i
* (EMS_PAGE_SIZE
>> 4);
619 PageArray
->PageNumber
= i
;
623 setAH(EMS_STATUS_SUCCESS
);
624 setCX(EMS_PHYSICAL_PAGES
);
626 else if (getAL() == 0x01)
628 setAH(EMS_STATUS_SUCCESS
);
629 setCX(EMS_PHYSICAL_PAGES
);
633 DPRINT1("Invalid subfunction %02X for EMS function AH = 58h\n", getAL());
634 setAH(EMS_STATUS_INVALID_SUBFUNCTION
);
640 /* Get Expanded Memory Hardware Information */
645 PEMS_HARDWARE_INFO HardwareInfo
= (PEMS_HARDWARE_INFO
)SEG_OFF_TO_PTR(getES(), getDI());
647 /* Return the hardware information */
648 HardwareInfo
->RawPageSize
= EMS_PAGE_SIZE
>> 4;
649 HardwareInfo
->AlternateRegSets
= 0;
650 HardwareInfo
->ContextAreaSize
= sizeof(Mapping
);
651 HardwareInfo
->DmaRegisterSets
= 0;
652 HardwareInfo
->DmaChannelOperation
= 0;
654 setAH(EMS_STATUS_SUCCESS
);
656 else if (getAL() == 0x01)
658 /* Same as function AH = 42h */
659 setAH(EMS_STATUS_SUCCESS
);
660 setBX(RtlNumberOfClearBits(&AllocBitmap
));
661 setDX(EmsTotalPages
);
665 DPRINT1("Invalid subfunction %02X for EMS function AH = 59h\n", getAL());
666 setAH(EMS_STATUS_INVALID_SUBFUNCTION
);
674 DPRINT1("EMS function AH = %02X NOT IMPLEMENTED\n", getAH());
675 setAH(EMS_STATUS_UNKNOWN_FUNCTION
);
681 static VOID FASTCALL
EmsReadMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
684 ULONG RelativeAddress
= Address
- TO_LINEAR(EmsSegment
, 0);
685 ULONG FirstPage
= RelativeAddress
/ EMS_PAGE_SIZE
;
686 ULONG LastPage
= (RelativeAddress
+ Size
- 1) / EMS_PAGE_SIZE
;
687 ULONG Offset
, Length
;
689 for (i
= FirstPage
; i
<= LastPage
; i
++)
691 Offset
= (i
== FirstPage
) ? RelativeAddress
& (EMS_PAGE_SIZE
- 1) : 0;
692 Length
= ((i
== LastPage
)
693 ? (RelativeAddress
+ Size
- (LastPage
<< EMS_PAGE_BITS
))
694 : EMS_PAGE_SIZE
) - Offset
;
696 if (Mapping
[i
]) RtlCopyMemory(Buffer
, (PVOID
)((ULONG_PTR
)Mapping
[i
] + Offset
), Length
);
697 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Length
);
701 static BOOLEAN FASTCALL
EmsWriteMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
704 ULONG RelativeAddress
= Address
- TO_LINEAR(EmsSegment
, 0);
705 ULONG FirstPage
= RelativeAddress
/ EMS_PAGE_SIZE
;
706 ULONG LastPage
= (RelativeAddress
+ Size
- 1) / EMS_PAGE_SIZE
;
707 ULONG Offset
, Length
;
709 for (i
= FirstPage
; i
<= LastPage
; i
++)
711 Offset
= (i
== FirstPage
) ? RelativeAddress
& (EMS_PAGE_SIZE
- 1) : 0;
712 Length
= ((i
== LastPage
)
713 ? (RelativeAddress
+ Size
- (LastPage
<< EMS_PAGE_BITS
))
714 : EMS_PAGE_SIZE
) - Offset
;
716 if (Mapping
[i
]) RtlCopyMemory((PVOID
)((ULONG_PTR
)Mapping
[i
] + Offset
), Buffer
, Length
);
717 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Length
);
723 static WORD NTAPI
EmsDrvDispatchIoctlRead(PDOS_DEVICE_NODE Device
, DWORD Buffer
, PWORD Length
)
725 // TODO: NOT IMPLEMENTED
727 return DOS_DEVSTAT_DONE
;
730 /* PUBLIC FUNCTIONS ***********************************************************/
732 BOOLEAN
EmsDrvInitialize(USHORT Segment
, ULONG TotalPages
)
736 /* Try to allocate our page table in UMA at the given segment */
737 EmsSegment
= (Segment
!= 0 ? Segment
: EMS_SEGMENT
);
738 Size
= EMS_SEGMENT_SIZE
; // Size in paragraphs
739 if (!UmaDescReserve(&EmsSegment
, &Size
)) return FALSE
;
741 EmsTotalPages
= TotalPages
;
742 BitmapBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
744 ((TotalPages
+ 31) / 32) * sizeof(ULONG
));
745 if (BitmapBuffer
== NULL
)
747 UmaDescRelease(EmsSegment
);
751 RtlInitializeBitMap(&AllocBitmap
, BitmapBuffer
, TotalPages
);
753 PageTable
= (PEMS_PAGE
)RtlAllocateHeap(RtlGetProcessHeap(),
755 TotalPages
* sizeof(EMS_PAGE
));
756 if (PageTable
== NULL
)
758 RtlFreeHeap(RtlGetProcessHeap(), 0, BitmapBuffer
);
761 UmaDescRelease(EmsSegment
);
765 EmsMemory
= (PVOID
)RtlAllocateHeap(RtlGetProcessHeap(), 0, TotalPages
* EMS_PAGE_SIZE
);
766 if (EmsMemory
== NULL
)
768 RtlFreeHeap(RtlGetProcessHeap(), 0, PageTable
);
770 RtlFreeHeap(RtlGetProcessHeap(), 0, BitmapBuffer
);
773 UmaDescRelease(EmsSegment
);
779 * FIXME: We should ensure that the system handle is associated
780 * with mapped pages from conventional memory. DosEmu seems to do
781 * it correctly. 384kB of memory mapped.
783 if (InitSystemHandle(384/16) != EMS_STATUS_SUCCESS
)
785 DPRINT1("Impossible to allocate pages for the system handle!\n");
787 RtlFreeHeap(RtlGetProcessHeap(), 0, EmsMemory
);
789 RtlFreeHeap(RtlGetProcessHeap(), 0, PageTable
);
791 RtlFreeHeap(RtlGetProcessHeap(), 0, BitmapBuffer
);
794 UmaDescRelease(EmsSegment
);
798 MemInstallFastMemoryHook((PVOID
)TO_LINEAR(EmsSegment
, 0),
799 EMS_PHYSICAL_PAGES
* EMS_PAGE_SIZE
,
803 /* Create the device */
804 Node
= DosCreateDeviceEx(DOS_DEVATTR_IOCTL
| DOS_DEVATTR_CHARACTER
,
807 Node
->IoctlReadRoutine
= EmsDrvDispatchIoctlRead
;
809 RegisterInt32(DEVICE_PRIVATE_AREA(Node
->Driver
),
810 EMS_INTERRUPT_NUM
, EmsIntHandler
, NULL
);
815 VOID
EmsDrvCleanup(VOID
)
817 /* Delete the device */
818 DosDeleteDevice(Node
);
820 MemRemoveFastMemoryHook((PVOID
)TO_LINEAR(EmsSegment
, 0),
821 EMS_PHYSICAL_PAGES
* EMS_PAGE_SIZE
);
825 RtlFreeHeap(RtlGetProcessHeap(), 0, EmsMemory
);
831 RtlFreeHeap(RtlGetProcessHeap(), 0, PageTable
);
837 RtlFreeHeap(RtlGetProcessHeap(), 0, BitmapBuffer
);
841 UmaDescRelease(EmsSegment
);