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 *******************************************************************/
20 #include "../../memory.h"
21 #include "bios/umamgr.h"
29 #define EMS_DEVICE_NAME "EMMXXXX0"
31 #define EMS_SEGMENT_SIZE ((EMS_PHYSICAL_PAGES * EMS_PAGE_SIZE) >> 4)
32 #define EMS_SYSTEM_HANDLE 0
34 /* PRIVATE VARIABLES **********************************************************/
36 static PDOS_DEVICE_NODE Node
;
37 static RTL_BITMAP AllocBitmap
;
38 static PULONG BitmapBuffer
= NULL
;
39 static PEMS_PAGE PageTable
= NULL
;
40 static EMS_HANDLE HandleTable
[EMS_MAX_HANDLES
];
41 static PVOID Mapping
[EMS_PHYSICAL_PAGES
] = { NULL
};
42 static PVOID MappingBackup
[EMS_PHYSICAL_PAGES
] = { NULL
};
43 static ULONG EmsTotalPages
= 0;
44 static PVOID EmsMemory
= NULL
;
45 static USHORT EmsSegment
= EMS_SEGMENT
;
47 /* PRIVATE FUNCTIONS **********************************************************/
49 static VOID
InitHandlesTable(VOID
)
53 for (i
= 0; i
< ARRAYSIZE(HandleTable
); i
++)
55 HandleTable
[i
].Allocated
= FALSE
;
56 HandleTable
[i
].PageCount
= 0;
57 RtlZeroMemory(HandleTable
[i
].Name
, sizeof(HandleTable
[i
].Name
));
58 InitializeListHead(&HandleTable
[i
].PageList
);
62 static PEMS_HANDLE
CreateHandle(PUSHORT Handle
)
64 PEMS_HANDLE HandleEntry
;
67 /* Handle 0 is reserved (system handle) */
68 for (i
= 1; i
< ARRAYSIZE(HandleTable
); i
++)
70 HandleEntry
= &HandleTable
[i
];
71 if (!HandleEntry
->Allocated
)
74 HandleEntry
->Allocated
= TRUE
;
82 static VOID
FreeHandle(PEMS_HANDLE HandleEntry
)
84 HandleEntry
->Allocated
= FALSE
;
85 HandleEntry
->PageCount
= 0;
86 RtlZeroMemory(HandleEntry
->Name
, sizeof(HandleEntry
->Name
));
87 // InitializeListHead(&HandleEntry->PageList);
90 static inline PEMS_HANDLE
GetHandleRecord(USHORT Handle
)
92 if (Handle
>= ARRAYSIZE(HandleTable
)) return NULL
;
93 return &HandleTable
[Handle
];
96 static inline BOOLEAN
ValidateHandle(PEMS_HANDLE HandleEntry
)
98 return (HandleEntry
!= NULL
&& HandleEntry
->Allocated
);
101 static UCHAR
EmsFree(USHORT Handle
)
104 PEMS_HANDLE HandleEntry
= GetHandleRecord(Handle
);
106 if (!ValidateHandle(HandleEntry
))
107 return EMS_STATUS_INVALID_HANDLE
;
109 for (Entry
= HandleEntry
->PageList
.Flink
;
110 Entry
!= &HandleEntry
->PageList
;
111 Entry
= Entry
->Flink
)
113 PEMS_PAGE PageEntry
= (PEMS_PAGE
)CONTAINING_RECORD(Entry
, EMS_PAGE
, Entry
);
114 ULONG PageNumber
= ARRAY_INDEX(PageEntry
, PageTable
);
117 RtlClearBits(&AllocBitmap
, PageNumber
, 1);
120 InitializeListHead(&HandleEntry
->PageList
);
122 if (Handle
!= EMS_SYSTEM_HANDLE
)
123 FreeHandle(HandleEntry
);
125 return EMS_STATUS_SUCCESS
;
128 static UCHAR
EmsAlloc(USHORT NumPages
, PUSHORT Handle
)
130 ULONG i
, CurrentIndex
= 0;
131 PEMS_HANDLE HandleEntry
;
133 if (NumPages
== 0) return EMS_STATUS_ZERO_PAGES
;
135 HandleEntry
= CreateHandle(Handle
);
136 if (!HandleEntry
) return EMS_STATUS_NO_MORE_HANDLES
;
138 while (HandleEntry
->PageCount
< NumPages
)
141 ULONG RunSize
= RtlFindNextForwardRunClear(&AllocBitmap
, CurrentIndex
, &RunStart
);
145 /* Free what's been allocated already and report failure */
147 return EMS_STATUS_INSUFFICIENT_PAGES
;
149 else if ((HandleEntry
->PageCount
+ RunSize
) > NumPages
)
151 /* We don't need the entire run */
152 RunSize
= NumPages
- HandleEntry
->PageCount
;
155 CurrentIndex
= RunStart
+ RunSize
;
156 HandleEntry
->PageCount
+= RunSize
;
157 RtlSetBits(&AllocBitmap
, RunStart
, RunSize
);
159 for (i
= 0; i
< RunSize
; i
++)
161 PageTable
[RunStart
+ i
].Handle
= *Handle
;
162 InsertTailList(&HandleEntry
->PageList
, &PageTable
[RunStart
+ i
].Entry
);
166 return EMS_STATUS_SUCCESS
;
169 static UCHAR
InitSystemHandle(USHORT NumPages
)
172 // FIXME: This is an adapted copy of EmsAlloc!!
175 ULONG i
, CurrentIndex
= 0;
176 PEMS_HANDLE HandleEntry
= &HandleTable
[EMS_SYSTEM_HANDLE
];
178 /* The system handle must never have been initialized before */
179 ASSERT(!HandleEntry
->Allocated
);
181 /* Now allocate it */
182 HandleEntry
->Allocated
= TRUE
;
184 while (HandleEntry
->PageCount
< NumPages
)
187 ULONG RunSize
= RtlFindNextForwardRunClear(&AllocBitmap
, CurrentIndex
, &RunStart
);
191 /* Free what's been allocated already and report failure */
192 EmsFree(EMS_SYSTEM_HANDLE
);
193 // FIXME: For this function (and EmsAlloc as well),
194 // use instead an internal function that just uses
195 // PEMS_HANDLE pointers instead. It's only in the
196 // EMS interrupt handler that we should do the
198 return EMS_STATUS_INSUFFICIENT_PAGES
;
200 else if ((HandleEntry
->PageCount
+ RunSize
) > NumPages
)
202 /* We don't need the entire run */
203 RunSize
= NumPages
- HandleEntry
->PageCount
;
206 CurrentIndex
= RunStart
+ RunSize
;
207 HandleEntry
->PageCount
+= RunSize
;
208 RtlSetBits(&AllocBitmap
, RunStart
, RunSize
);
210 for (i
= 0; i
< RunSize
; i
++)
212 PageTable
[RunStart
+ i
].Handle
= EMS_SYSTEM_HANDLE
;
213 InsertTailList(&HandleEntry
->PageList
, &PageTable
[RunStart
+ i
].Entry
);
217 return EMS_STATUS_SUCCESS
;
220 static PEMS_PAGE
GetLogicalPage(PEMS_HANDLE HandleEntry
, USHORT LogicalPage
)
222 PLIST_ENTRY Entry
= HandleEntry
->PageList
.Flink
;
226 if (Entry
== &HandleEntry
->PageList
) return NULL
;
228 Entry
= Entry
->Flink
;
231 return (PEMS_PAGE
)CONTAINING_RECORD(Entry
, EMS_PAGE
, Entry
);
234 static UCHAR
EmsMap(USHORT Handle
, UCHAR PhysicalPage
, USHORT LogicalPage
)
237 PEMS_HANDLE HandleEntry
= GetHandleRecord(Handle
);
239 if (!ValidateHandle(HandleEntry
))
240 return EMS_STATUS_INVALID_HANDLE
;
242 if (PhysicalPage
>= EMS_PHYSICAL_PAGES
)
243 return EMS_STATUS_INV_PHYSICAL_PAGE
;
245 if (LogicalPage
== 0xFFFF)
248 Mapping
[PhysicalPage
] = NULL
;
249 return EMS_STATUS_SUCCESS
;
252 PageEntry
= GetLogicalPage(HandleEntry
, LogicalPage
);
253 if (!PageEntry
) return EMS_STATUS_INV_LOGICAL_PAGE
;
255 Mapping
[PhysicalPage
] = (PVOID
)((ULONG_PTR
)EmsMemory
256 + ARRAY_INDEX(PageEntry
, PageTable
) * EMS_PAGE_SIZE
);
257 return EMS_STATUS_SUCCESS
;
260 static VOID WINAPI
EmsIntHandler(LPWORD Stack
)
264 /* Get Manager Status */
267 setAH(EMS_STATUS_SUCCESS
);
271 /* Get Page Frame Segment */
274 setAH(EMS_STATUS_SUCCESS
);
279 /* Get Number of Unallocated Pages */
282 setAH(EMS_STATUS_SUCCESS
);
283 setBX(RtlNumberOfClearBits(&AllocBitmap
));
284 setDX(EmsTotalPages
);
288 /* Get Handle and Allocate Memory */
292 UCHAR Status
= EmsAlloc(getBX(), &Handle
);
294 if (Status
== EMS_STATUS_SUCCESS
)
304 setAH(EmsMap(getDX(), getAL(), getBX()));
308 /* Release Handle and Memory */
311 setAH(EmsFree(getDX()));
315 /* Get EMM Version */
318 setAH(EMS_STATUS_SUCCESS
);
319 setAL(EMS_VERSION_NUM
);
326 // FIXME: This depends on an EMS handle given in DX
327 RtlCopyMemory(MappingBackup
, Mapping
, sizeof(Mapping
));
328 setAH(EMS_STATUS_SUCCESS
);
332 /* Restore Page Map */
335 // FIXME: This depends on an EMS handle given in DX
336 RtlCopyMemory(Mapping
, MappingBackup
, sizeof(Mapping
));
337 setAH(EMS_STATUS_SUCCESS
);
341 /* Get Number of Opened Handles */
344 USHORT NumOpenHandles
= 0;
347 for (i
= 0; i
< ARRAYSIZE(HandleTable
); i
++)
349 if (HandleTable
[i
].Allocated
)
353 setAH(EMS_STATUS_SUCCESS
);
354 setBX(NumOpenHandles
);
358 /* Get Handle Number of Pages */
361 PEMS_HANDLE HandleEntry
= GetHandleRecord(getDX());
363 if (!ValidateHandle(HandleEntry
))
365 setAH(EMS_STATUS_INVALID_HANDLE
);
369 setAH(EMS_STATUS_SUCCESS
);
370 setBX(HandleEntry
->PageCount
);
374 /* Get All Handles Number of Pages */
377 PEMS_HANDLE_PAGE_INFO HandlePageInfo
= (PEMS_HANDLE_PAGE_INFO
)SEG_OFF_TO_PTR(getES(), getDI());
378 USHORT NumOpenHandles
= 0;
381 for (i
= 0; i
< ARRAYSIZE(HandleTable
); i
++)
383 if (HandleTable
[i
].Allocated
)
385 HandlePageInfo
->Handle
= i
;
386 HandlePageInfo
->PageCount
= HandleTable
[i
].PageCount
;
392 setAH(EMS_STATUS_SUCCESS
);
393 setBX(NumOpenHandles
);
397 /* Get or Set Page Map */
402 /* Get Mapping Registers */
403 // case 0x00: // TODO: NOT IMPLEMENTED
405 /* Set Mapping Registers */
406 // case 0x01: // TODO: NOT IMPLEMENTED
408 /* Get and Set Mapping Registers At Once */
409 // case 0x02: // TODO: NOT IMPLEMENTED
411 /* Get Size of Page-Mapping Array */
414 setAH(EMS_STATUS_SUCCESS
);
415 setAL(sizeof(Mapping
));
421 DPRINT1("EMS function AH = 0x4E, subfunction AL = %02X NOT IMPLEMENTED\n", getAL());
422 setAH(EMS_STATUS_UNKNOWN_FUNCTION
);
430 /* Get/Set Handle Name */
433 PEMS_HANDLE HandleEntry
= GetHandleRecord(getDX());
435 if (!ValidateHandle(HandleEntry
))
437 setAH(EMS_STATUS_INVALID_HANDLE
);
443 /* Retrieve the name */
444 RtlCopyMemory(SEG_OFF_TO_PTR(getES(), getDI()),
446 sizeof(HandleEntry
->Name
));
447 setAH(EMS_STATUS_SUCCESS
);
449 else if (getAL() == 0x01)
452 RtlCopyMemory(HandleEntry
->Name
,
453 SEG_OFF_TO_PTR(getDS(), getSI()),
454 sizeof(HandleEntry
->Name
));
455 setAH(EMS_STATUS_SUCCESS
);
459 DPRINT1("Invalid subfunction %02X for EMS function AH = 53h\n", getAL());
460 setAH(EMS_STATUS_INVALID_SUBFUNCTION
);
466 /* Handle Directory functions */
471 /* Get Handle Directory */
473 PEMS_HANDLE_DIR_ENTRY HandleDir
= (PEMS_HANDLE_DIR_ENTRY
)SEG_OFF_TO_PTR(getES(), getDI());
474 USHORT NumOpenHandles
= 0;
477 for (i
= 0; i
< ARRAYSIZE(HandleTable
); i
++)
479 if (HandleTable
[i
].Allocated
)
481 HandleDir
->Handle
= i
;
482 RtlCopyMemory(HandleDir
->Name
,
484 sizeof(HandleDir
->Name
));
490 setAH(EMS_STATUS_SUCCESS
);
491 setAL((UCHAR
)NumOpenHandles
);
493 else if (getAL() == 0x01)
495 /* Search for Named Handle */
497 PUCHAR HandleName
= (PUCHAR
)SEG_OFF_TO_PTR(getDS(), getSI());
498 PEMS_HANDLE HandleFound
= NULL
;
501 for (i
= 0; i
< ARRAYSIZE(HandleTable
); i
++)
503 if (HandleTable
[i
].Allocated
&&
504 RtlCompareMemory(HandleName
,
506 sizeof(HandleTable
[i
].Name
)) == sizeof(HandleTable
[i
].Name
))
508 HandleFound
= &HandleTable
[i
];
513 /* Bail out if no handle was found */
514 if (i
>= ARRAYSIZE(HandleTable
)) // HandleFound == NULL
516 setAH(EMS_STATUS_HANDLE_NOT_FOUND
);
520 /* Return the handle number */
523 /* Sanity check: Check whether the handle was unnamed */
525 while ((i
< sizeof(HandleFound
->Name
)) && (HandleFound
->Name
[i
] == '\0'))
528 if (i
>= sizeof(HandleFound
->Name
))
530 setAH(EMS_STATUS_UNNAMED_HANDLE
);
534 setAH(EMS_STATUS_SUCCESS
);
537 else if (getAL() == 0x02)
540 * Get Total Number of Handles
542 * This function retrieves the maximum number of handles
543 * (allocated or not) the memory manager supports, which
544 * a program may request.
546 setAH(EMS_STATUS_SUCCESS
);
547 setBX(ARRAYSIZE(HandleTable
));
551 DPRINT1("Invalid subfunction %02X for EMS function AH = 54h\n", getAL());
552 setAH(EMS_STATUS_INVALID_SUBFUNCTION
);
558 /* Move/Exchange Memory */
561 PUCHAR SourcePtr
, DestPtr
;
562 PEMS_HANDLE HandleEntry
;
564 BOOLEAN Exchange
= getAL();
565 PEMS_COPY_DATA Data
= (PEMS_COPY_DATA
)SEG_OFF_TO_PTR(getDS(), getSI());
567 if (Data
->SourceType
)
569 /* Expanded memory */
570 HandleEntry
= GetHandleRecord(Data
->SourceHandle
);
571 if (!ValidateHandle(HandleEntry
))
573 setAH(EMS_STATUS_INVALID_HANDLE
);
577 PageEntry
= GetLogicalPage(HandleEntry
, Data
->SourceSegment
);
580 setAH(EMS_STATUS_INV_LOGICAL_PAGE
);
584 SourcePtr
= (PUCHAR
)((ULONG_PTR
)EmsMemory
585 + ARRAY_INDEX(PageEntry
, PageTable
) * EMS_PAGE_SIZE
586 + Data
->SourceOffset
);
590 /* Conventional memory */
591 SourcePtr
= (PUCHAR
)SEG_OFF_TO_PTR(Data
->SourceSegment
, Data
->SourceOffset
);
596 /* Expanded memory */
597 HandleEntry
= GetHandleRecord(Data
->DestHandle
);
598 if (!ValidateHandle(HandleEntry
))
600 setAH(EMS_STATUS_INVALID_HANDLE
);
604 PageEntry
= GetLogicalPage(HandleEntry
, Data
->DestSegment
);
607 setAH(EMS_STATUS_INV_LOGICAL_PAGE
);
611 DestPtr
= (PUCHAR
)((ULONG_PTR
)EmsMemory
612 + ARRAY_INDEX(PageEntry
, PageTable
) * EMS_PAGE_SIZE
617 /* Conventional memory */
618 DestPtr
= (PUCHAR
)SEG_OFF_TO_PTR(Data
->DestSegment
, Data
->DestOffset
);
626 for (i
= 0; i
< Data
->RegionLength
; i
++)
628 UCHAR Temp
= DestPtr
[i
];
629 DestPtr
[i
] = SourcePtr
[i
];
636 RtlMoveMemory(DestPtr
, SourcePtr
, Data
->RegionLength
);
639 setAH(EMS_STATUS_SUCCESS
);
643 /* Get Mappable Physical Address Array */
648 PEMS_MAPPABLE_PHYS_PAGE PageArray
= (PEMS_MAPPABLE_PHYS_PAGE
)SEG_OFF_TO_PTR(getES(), getDI());
651 for (i
= 0; i
< EMS_PHYSICAL_PAGES
; i
++)
653 PageArray
->PageSegment
= EMS_SEGMENT
+ i
* (EMS_PAGE_SIZE
>> 4);
654 PageArray
->PageNumber
= i
;
658 setAH(EMS_STATUS_SUCCESS
);
659 setCX(EMS_PHYSICAL_PAGES
);
661 else if (getAL() == 0x01)
663 setAH(EMS_STATUS_SUCCESS
);
664 setCX(EMS_PHYSICAL_PAGES
);
668 DPRINT1("Invalid subfunction %02X for EMS function AH = 58h\n", getAL());
669 setAH(EMS_STATUS_INVALID_SUBFUNCTION
);
675 /* Get Expanded Memory Hardware Information */
680 PEMS_HARDWARE_INFO HardwareInfo
= (PEMS_HARDWARE_INFO
)SEG_OFF_TO_PTR(getES(), getDI());
682 /* Return the hardware information */
683 HardwareInfo
->RawPageSize
= EMS_PAGE_SIZE
>> 4;
684 HardwareInfo
->AlternateRegSets
= 0;
685 HardwareInfo
->ContextAreaSize
= sizeof(Mapping
);
686 HardwareInfo
->DmaRegisterSets
= 0;
687 HardwareInfo
->DmaChannelOperation
= 0;
689 setAH(EMS_STATUS_SUCCESS
);
691 else if (getAL() == 0x01)
693 /* Same as function AH = 42h */
694 setAH(EMS_STATUS_SUCCESS
);
695 setBX(RtlNumberOfClearBits(&AllocBitmap
));
696 setDX(EmsTotalPages
);
700 DPRINT1("Invalid subfunction %02X for EMS function AH = 59h\n", getAL());
701 setAH(EMS_STATUS_INVALID_SUBFUNCTION
);
709 DPRINT1("EMS function AH = %02X NOT IMPLEMENTED\n", getAH());
710 setAH(EMS_STATUS_UNKNOWN_FUNCTION
);
716 static VOID FASTCALL
EmsReadMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
719 ULONG RelativeAddress
= Address
- TO_LINEAR(EmsSegment
, 0);
720 ULONG FirstPage
= RelativeAddress
/ EMS_PAGE_SIZE
;
721 ULONG LastPage
= (RelativeAddress
+ Size
- 1) / EMS_PAGE_SIZE
;
722 ULONG Offset
, Length
;
724 for (i
= FirstPage
; i
<= LastPage
; i
++)
726 Offset
= (i
== FirstPage
) ? RelativeAddress
& (EMS_PAGE_SIZE
- 1) : 0;
727 Length
= ((i
== LastPage
)
728 ? (RelativeAddress
+ Size
- (LastPage
<< EMS_PAGE_BITS
))
729 : EMS_PAGE_SIZE
) - Offset
;
731 if (Mapping
[i
]) RtlCopyMemory(Buffer
, (PVOID
)((ULONG_PTR
)Mapping
[i
] + Offset
), Length
);
732 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Length
);
736 static BOOLEAN FASTCALL
EmsWriteMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
739 ULONG RelativeAddress
= Address
- TO_LINEAR(EmsSegment
, 0);
740 ULONG FirstPage
= RelativeAddress
/ EMS_PAGE_SIZE
;
741 ULONG LastPage
= (RelativeAddress
+ Size
- 1) / EMS_PAGE_SIZE
;
742 ULONG Offset
, Length
;
744 for (i
= FirstPage
; i
<= LastPage
; i
++)
746 Offset
= (i
== FirstPage
) ? RelativeAddress
& (EMS_PAGE_SIZE
- 1) : 0;
747 Length
= ((i
== LastPage
)
748 ? (RelativeAddress
+ Size
- (LastPage
<< EMS_PAGE_BITS
))
749 : EMS_PAGE_SIZE
) - Offset
;
751 if (Mapping
[i
]) RtlCopyMemory((PVOID
)((ULONG_PTR
)Mapping
[i
] + Offset
), Buffer
, Length
);
752 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Length
);
758 static WORD NTAPI
EmsDrvDispatchIoctlRead(PDOS_DEVICE_NODE Device
, DWORD Buffer
, PWORD Length
)
760 // TODO: NOT IMPLEMENTED
762 return DOS_DEVSTAT_DONE
;
765 /* PUBLIC FUNCTIONS ***********************************************************/
767 BOOLEAN
EmsDrvInitialize(USHORT Segment
, ULONG TotalPages
)
771 /* Try to allocate our page table in UMA at the given segment */
772 EmsSegment
= (Segment
!= 0 ? Segment
: EMS_SEGMENT
);
773 Size
= EMS_SEGMENT_SIZE
; // Size in paragraphs
774 if (!UmaDescReserve(&EmsSegment
, &Size
)) return FALSE
;
776 EmsTotalPages
= TotalPages
;
777 BitmapBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
779 ((TotalPages
+ 31) / 32) * sizeof(ULONG
));
780 if (BitmapBuffer
== NULL
)
782 UmaDescRelease(EmsSegment
);
786 RtlInitializeBitMap(&AllocBitmap
, BitmapBuffer
, TotalPages
);
788 PageTable
= (PEMS_PAGE
)RtlAllocateHeap(RtlGetProcessHeap(),
790 TotalPages
* sizeof(EMS_PAGE
));
791 if (PageTable
== NULL
)
793 RtlFreeHeap(RtlGetProcessHeap(), 0, BitmapBuffer
);
796 UmaDescRelease(EmsSegment
);
800 EmsMemory
= (PVOID
)RtlAllocateHeap(RtlGetProcessHeap(), 0, TotalPages
* EMS_PAGE_SIZE
);
801 if (EmsMemory
== NULL
)
803 RtlFreeHeap(RtlGetProcessHeap(), 0, PageTable
);
805 RtlFreeHeap(RtlGetProcessHeap(), 0, BitmapBuffer
);
808 UmaDescRelease(EmsSegment
);
814 * FIXME: We should ensure that the system handle is associated
815 * with mapped pages from conventional memory. DosEmu seems to do
816 * it correctly. 384kB of memory mapped.
818 if (InitSystemHandle(384/16) != EMS_STATUS_SUCCESS
)
820 DPRINT1("Impossible to allocate pages for the system handle!\n");
822 RtlFreeHeap(RtlGetProcessHeap(), 0, EmsMemory
);
824 RtlFreeHeap(RtlGetProcessHeap(), 0, PageTable
);
826 RtlFreeHeap(RtlGetProcessHeap(), 0, BitmapBuffer
);
829 UmaDescRelease(EmsSegment
);
833 MemInstallFastMemoryHook((PVOID
)TO_LINEAR(EmsSegment
, 0),
834 EMS_PHYSICAL_PAGES
* EMS_PAGE_SIZE
,
838 /* Create the device */
839 Node
= DosCreateDeviceEx(DOS_DEVATTR_IOCTL
| DOS_DEVATTR_CHARACTER
,
842 Node
->IoctlReadRoutine
= EmsDrvDispatchIoctlRead
;
844 RegisterInt32(DEVICE_PRIVATE_AREA(Node
->Driver
),
845 EMS_INTERRUPT_NUM
, EmsIntHandler
, NULL
);
850 VOID
EmsDrvCleanup(VOID
)
852 /* Delete the device */
853 DosDeleteDevice(Node
);
855 MemRemoveFastMemoryHook((PVOID
)TO_LINEAR(EmsSegment
, 0),
856 EMS_PHYSICAL_PAGES
* EMS_PAGE_SIZE
);
860 RtlFreeHeap(RtlGetProcessHeap(), 0, EmsMemory
);
866 RtlFreeHeap(RtlGetProcessHeap(), 0, PageTable
);
872 RtlFreeHeap(RtlGetProcessHeap(), 0, BitmapBuffer
);
876 UmaDescRelease(EmsSegment
);