home *** CD-ROM | disk | FTP | other *** search
/ Multimedia & CD-ROM 3 / mmcd03-jun1995-cd.iso / utils / various / utils-1 / ems40.asm < prev    next >
Assembly Source File  |  1991-06-24  |  121KB  |  2,201 lines

  1. ;============================================================================
  2. ;EMS40.SYS an Expanded Memory Simulator for the IBM AT
  3. ;
  4. ; Revision History:
  5. ;
  6. ;   Version 1.0         Initial Release              PC Mag Vol 8, Num 12
  7. ;
  8. ;   Version 1.1         Enlarged internal save       July 18, 1989
  9. ;                       area for functions 8 & 9.
  10. ;
  11. ;                       Reduced default number of
  12. ;                       possible from 255 to 127.
  13. ;
  14. ;                       Bug fixes:
  15. ;                        Fun 23. Preserve CX on call.
  16. ;                        Fun 2500. Return size in CX.
  17. ;
  18. ;============================================================================
  19.                 PAGE    ,132
  20. CODE            SEGMENT PUBLIC'code'
  21.                 ASSUME  CS:CODE
  22. ;-----------------------------------------------------------------------------
  23. ;Structure of the device driver request header
  24. ;-----------------------------------------------------------------------------
  25. REQ_STRUC       STRUC
  26. LEN             DB      ?
  27. UNIT            DB      ?                       ;unit number
  28. COMMAND         DB      ?                       ;command code
  29. STATUS          DW      ?                       ;return status
  30. RESERVE         DB      8 DUP (?)
  31. MEDIA           DB      ?
  32. ADDRESS         DD      ?                       ;Transfer address
  33. CONFIG_PTR      DD      ?                       ;Pointer to line in config
  34. REQ_STRUC       ENDS
  35. ;-----------------------------------------------------------------------------
  36. ;Segment descriptor structure
  37. ;-----------------------------------------------------------------------------
  38. DAT_SEG_DES     STRUC                           ;data segment descriptor
  39. SEG_LIM         DW      0                       ;length of segment
  40. BASE_ADRL       DW      0                       ;base address of segment
  41. BASE_ADRH       DB      0
  42.                 DB      0                       ;access rights byte
  43.                 DW      0                       ;reserved
  44. DAT_SEG_DES     ENDS
  45. ;=============================================================================
  46. ;Device header begin
  47. ;=============================================================================
  48.                 ORG     0                       ;drivers start at offset 0
  49. HEADER          DD      -1                      ;Pointer to next driver
  50.                 DW      8000H                   ;device attribute word
  51.                 DW      OFFSET STRATEGY         ;pointer to strategy routine
  52.                 DW      OFFSET INTERRUPT        ;pointer to interrupt routine
  53.                 DB      'EMMXXXX0'              ;name of driver
  54. ;Device header end
  55. SWAP_POINTER    DW      OFFSET EMS_EXCH_PAG
  56. PROGRAM         DB      "EMS 4.0 Simulator, Ver. 1.1"
  57. COPYRIGHT       DB      " (C) 1989 Ziff Communications",13,10
  58. PROGRAMMER      DB      "PC Magazine ",254," Douglas Boling",13,10,"$",26
  59. REQ_HEADADR     DD      ?                       ;Far pointer to request header
  60. ;-----------------------------------------------------------------------------
  61. ;Global Descriptor table needed for moves to and from extended memory.
  62. ;-----------------------------------------------------------------------------
  63. GDT             LABEL   BYTE
  64.                 DAT_SEG_DES <>                  ;Dummy
  65.                 DAT_SEG_DES <>                  ;GDT descriptor
  66. SOURCE          DAT_SEG_DES <4000H,,,93H,>      ;source descriptor
  67. DEST            DAT_SEG_DES <4000H,,,93H,>      ;destination descriptor
  68.                 DAT_SEG_DES <>                  ;bios code descriptor
  69.                 DAT_SEG_DES <>                  ;stack segment descriptor
  70. ;=============================================================================
  71. ;Strategy routine. This routine stores the address of the request header
  72. ;=============================================================================
  73. STRATEGY        PROC    FAR
  74.                 ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING
  75.                 MOV     WORD PTR CS:[REQ_HEADADR],BX    ;save offset
  76.                 MOV     WORD PTR CS:[REQ_HEADADR+2],ES  ;save segment
  77.                 RET
  78. STRATEGY        ENDP
  79. ;=============================================================================
  80. ;Interrupt routine. This routine executes the command code in the req header.
  81. ;=============================================================================
  82. INTERRUPT       PROC    FAR
  83.                 ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING
  84.                 PUSHF
  85.                 PUSH    AX                      ;save every register used
  86.                 PUSH    BX
  87.                 PUSH    CX
  88.                 PUSH    DX
  89.                 PUSH    DI
  90.                 PUSH    SI
  91.                 PUSH    DS
  92.                 PUSH    ES
  93.                 PUSH    CS                      ;Set DS
  94.                 POP     DS
  95.                 ASSUME  DS:CODE
  96.                 CLD                             ;any string operations move up.
  97. ;Get command from request header
  98.                 LES     DI,[REQ_HEADADR]        ;load address of req header
  99.                 ASSUME  ES:NOTHING
  100.                 MOV     BL,ES:[DI.COMMAND]
  101.                 CMP     BL,0
  102.                 JNE     PROCESS1
  103.                 CALL    INITIALIZE
  104.                 JMP     SHORT DONE
  105. PROCESS1:       CMP     BL,16                   ;see if command out of range
  106.                 JBE     DONE
  107.                 MOV     AX,8003H                ;unknown command error code
  108. DONE:           OR      AX,0100H                ;set the 'done' bit
  109.                 MOV     ES:[DI.STATUS],AX
  110.                 POP     ES                      ;restore registers before exit
  111.                 POP     DS
  112.                 POP     SI
  113.                 POP     DI
  114.                 POP     DX
  115.                 POP     CX
  116.                 POP     BX
  117.                 POP     AX
  118.                 POPF
  119.                 RET
  120. INTERRUPT       ENDP
  121. DRIVER_END      =       $                       ;Last part of driver code
  122. ;======================================================================
  123. ;EMS Driver code starts here.
  124. ;======================================================================
  125. OLD_INT15H      LABEL DWORD
  126. OLD_INT15HO     DW      ?                       ;offset of old interrupt vector
  127. OLD_INT15HS     DW      ?                       ;segment
  128. EXT_MEM_LIMIT   DW      0                       ;adjusted top of avail memory
  129. OS_ENABLED      DB      1                       ;Enable os functions 1=enabled
  130. OS_PASS_LOW     DW      0                       ;Operating system password.
  131. OS_PASS_HIGH    DW      0
  132. ALT_MAP_PTRS    DW      0                       ;Mapping pointer for funct 28
  133. ALT_MAP_PTRO    DW      0
  134. WINDOW_SEG      DW      ?                       ;starting segment of ems win
  135. WINDOW_ADDR_BASE        DD      4 DUP(0)        ;address of each page
  136. EXTEND_ADRL     DW      ?                       ;base of extended memory used
  137. EXTEND_ADRH     DB      ?
  138. TOTAL_PAGES     DW      24                      ;default to 384k of exp mem.
  139. TOTAL_HANDLES   DW      127                     ;Default number of handles
  140. INT_SAVE_SIZE   DW      15                      ;Number of save areas for 8/9
  141. PAG_OWNER_TBL   DW      ?                       ;Pointer to page table
  142. HANDLE_ARRAY    DW      ?                       ;Pointer to handle table
  143. MAP_ARRAY_PTR   DW      ?                       ;Pointer to map array
  144. MOVE_BUSY_FLAG  DB      0                       ;Indicates blk move active
  145. SAVED_ADDR_LOW  DW      0                       ;Saved address of block
  146. SAVED_ADDR_HIGH DB      0                       ;  being moved.
  147. ;======================================================================
  148. ;Interrupt 15h routine. Intercept extended memory size determine.
  149. ;======================================================================
  150. INT_15H         PROC    FAR
  151.                 ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING
  152.                 CMP     AH,88H
  153.                 JE      INT15_F88
  154.                 JMP     CS:[OLD_INT15H]
  155. INT15_F88:      MOV     AX,CS:EXT_MEM_LIMIT             ;provide new limit
  156.                 CLC                                     ;clear error flag
  157.                 RET     2
  158. INT_15H         ENDP
  159. ;-----------------------------------------------------------------------------
  160. ;Jump table for EMS driver commands
  161. ;-----------------------------------------------------------------------------
  162. EMS_CMDS        DW      OFFSET EMS_01           ;Get status
  163.                 DW      OFFSET EMS_02           ;Get page frame seg address
  164.                 DW      OFFSET EMS_03           ;Get unallocated page count
  165.                 DW      OFFSET EMS_04           ;Allocate pages
  166.                 DW      OFFSET EMS_05           ;Map/unmap handle pages
  167.                 DW      OFFSET EMS_06           ;Deallocate pages
  168.                 DW      OFFSET EMS_07           ;Get version
  169.                 DW      OFFSET EMS_08           ;Save page map
  170.                 DW      OFFSET EMS_09           ;Restore page map
  171.                 DW      OFFSET EMS_UNSP         ;reserved
  172.                 DW      OFFSET EMS_UNSP         ;reserved
  173.                 DW      OFFSET EMS_12           ;Get handle count
  174.                 DW      OFFSET EMS_13           ;Get handle pages
  175.                 DW      OFFSET EMS_14           ;Get all handle pages
  176.                 DW      OFFSET EMS_15           ;Page map functions
  177.                 DW      OFFSET EMS_16           ;Partial page map functions
  178.                 DW      OFFSET EMS_17           ;Map/unmap multiple hndl pages
  179.                 DW      OFFSET EMS_18           ;Reallocate pages
  180.                 DW      OFFSET EMS_19           ;Handle attribute
  181.                 DW      OFFSET EMS_20           ;Handle name
  182.                 DW      OFFSET EMS_21           ;Handle directory
  183.                 DW      OFFSET EMS_22           ;Alter page map and jump
  184.                 DW      OFFSET EMS_23           ;Alter page map and call
  185.                 DW      OFFSET EMS_24           ;move/exchange memory region
  186.                 DW      OFFSET EMS_25           ;Get mappable phys addr array
  187.                 DW      OFFSET EMS_26           ;Hardware configuration
  188.                 DW      OFFSET EMS_27           ;Allocate standard pages
  189.                 DW      OFFSET EMS_28           ;Alternate map register set
  190.                 DW      OFFSET EMS_UNSP         ;Warmboot preparation
  191.                 DW      OFFSET EMS_30           ;OS/E functions
  192. ;======================================================================
  193. ;Interrupt 67h routine. EMS driver function dispatcher.
  194. ;======================================================================
  195. INT_67H         PROC    FAR
  196.                 ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING
  197.                 PUSH    BP
  198.                 MOV     BP,SP                   ;set up stack addressing
  199.                 CLD                             ;any string operations move up.
  200.                 PUSH    CX                      ;Save registers
  201.                 PUSH    DI                      ;NOTE: Don't change the
  202.                 PUSH    SI                      ;  order of the register save.
  203.                 PUSH    DS                      ;  Many of the routines depend
  204.                 PUSH    ES                      ;  on the correct order.
  205.                 PUSH    CS                      ;point ds to code segment
  206.                 POP     DS
  207.                 ASSUME  DS:CODE
  208.                 CMP     AH,5DH                  ;Check for a cmd out of range
  209.                 JA      EMS_CMD_ERR
  210.                 CMP     AH,40H
  211.                 JL      EMS_CMD_ERR
  212.                 MOV     DI,OFFSET RETURN_ADDR   ;Push return address onto
  213.                 PUSH    DI                      ;  stack.
  214.                 PUSH    AX                      ;save AX
  215.                 SUB     AH,40H                  ;Convert command code in AX
  216.                 MOV     AL,AH                   ;  into a jump address.
  217.                 XOR     AH,AH                   ;Clear upper byte
  218.                 SAL     AX,1                    ;Convert to word offset
  219.                 ADD     AX,OFFSET EMS_CMDS      ;add offset of jump table
  220.                 MOV     DI,AX                   ;Copy to DI
  221.                 POP     AX                      ;restore AX
  222.                 PUSH    [DI]                    ;Put offset of routine on stk
  223.                 MOV     DI,[BP-4]               ;Restore DI
  224.                 CALL    EMS_CHECK_HDL           ;check for valid handle in DX
  225.                 DB      0C3h                    ;RETN opcode to call function.
  226. RETURN_ADDR:    POP     ES                      ;  The RETN instruction is
  227.                 POP     DS                      ;  hand assembled to force a
  228.                 POP     SI                      ;  near return in a far proc.
  229.                 POP     DI                      ;  For MASM 5.0, the RETN can
  230.                 POP     CX                      ;  be specified as an opcode.
  231.                 POP     BP
  232.                 IRET
  233. EMS_CMD_ERR:    MOV     AH,84H                  ;EMS command out of range
  234.                 JMP     SHORT RETURN_ADDR
  235. INT_67H         ENDP
  236. ;======================================================================
  237. ;Function 1.  Get status.
  238. ;======================================================================
  239. EMS_01          PROC    NEAR
  240.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  241.                 XOR     AX,AX
  242.                 RET
  243. EMS_01          ENDP
  244. ;======================================================================
  245. ;Function 2.  Get segment address of EMS window
  246. ;======================================================================
  247. EMS_02          PROC    NEAR
  248.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  249.                 MOV     BX,WINDOW_SEG           ;store starting seg of window
  250.                 XOR     AX,AX
  251.                 RET
  252. EMS_02          ENDP
  253. ;======================================================================
  254. ;Function 3.  Get count of unallocated pages
  255. ;======================================================================
  256. EMS_03          PROC    NEAR
  257.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  258.                 XOR     DX,DX                   ;search for hndl =-1 (unaloc)
  259.                 DEC     DX
  260.                 CLC                             ;fake 'handle ok' flag
  261.                 CALL    EMS_13
  262.                 MOV     DX,TOTAL_PAGES          ;Load total pages
  263.                 XOR     AX,AX                   ;Clear return code
  264.                 RET
  265. EMS_03          ENDP
  266. ;======================================================================
  267. ;Function 4.  Get handle and allocate pages
  268. ;======================================================================
  269. EMS_04          PROC    NEAR
  270.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  271.                 OR      BX,BX                   ;Check for 0 page request
  272.                 JE      EMS_04_ERR              ;If so, error
  273.                 CALL    EMS_27                  ;Let function 27 do the work
  274. EMS_04_EXIT:    RET
  275. EMS_04_ERR:     MOV     AH,89H                  ;attempt to allocate 0 pages
  276.                 JMP     SHORT EMS_04_EXIT
  277. EMS_04          ENDP
  278. ;======================================================================
  279. ;Function 5,  Map / Unmap pages.
  280. ;======================================================================
  281. EMS_05          PROC    NEAR
  282.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  283.                 PUSH    BX
  284.                 PUSH    DX
  285.                 JC      EMS_05_EXIT             ;carry set, invalid handle
  286.                 CMP     AL,3                    ;Check for physical page out
  287.                 JA      EMS_05_ERR0             ;  of range
  288.                 CMP     BX,0FFFFH               ;See if unmap page. If so,
  289.                 JNE     EMS_05_S1               ;  save current mapped page
  290.                 MOV     BL,AL                   ;  but don't map new page.
  291.                 XOR     AX,AX
  292.                 XOR     DX,DX                   ;DL:AX=0 indicates no map
  293.                 JMP     SHORT EMS_05_S2
  294. EMS_05_S1:      PUSH    AX                      ;Save physical page to map
  295.                 CALL    EMS_LOG2PHY             ;Convert page into an address
  296.                 POP     BX                      ;Put phy page into BX for call
  297.                 JC      EMS_05_EXIT             ;If error, exit
  298. EMS_05_S2:      CALL    EMS_EXCH_PAG            ;Map the page
  299.                 XOR     AX,AX                   ;Clear return code
  300. EMS_05_EXIT:    POP     DX                      ;Restore registers.
  301.                 POP     BX
  302.                 RET
  303. EMS_05_ERR0:    MOV     AH,8BH                  ;Physical page out of range
  304.                 JMP     SHORT EMS_05_EXIT
  305. EMS_05          ENDP
  306. ;======================================================================
  307. ;Function 6,  Deallocate pages.
  308. ;======================================================================
  309. EMS_06          PROC    NEAR
  310.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  311.                 PUSH    BX
  312.                 PUSH    DX
  313.                 JC      EMS_06_EXIT             ;carry set, invalid handle
  314.                 MOV     BL,0FFH                 ;clear all pages
  315.                 CALL    EMS_DEALLOC             ;Deallocate memory
  316.                 OR      DL,DL                   ;handle zero cannot be
  317.                 JE      EMS_06_GOOD             ;  deallocated
  318.                 PUSH    CS                      ;Deallocate handle
  319.                 POP     ES
  320.                 ASSUME  ES:CODE
  321.                 MOV     DI,HANDLE_ARRAY
  322.                 MOV     AX,DX                   ;copy handle
  323.                 MOV     CX,9                    ;convert handle to an index into
  324.                 MUL     CX                      ;  the handle array.
  325.                 ADD     DI,AX
  326.                 XOR     AL,AL                   ;Erase handle flag and name.
  327.                 REP     STOSB
  328. EMS_06_GOOD:    XOR     AX,AX                   ;clear return code
  329. EMS_06_EXIT:    POP     DX
  330.                 POP     BX
  331.                 RET
  332. EMS_06          ENDP
  333. ;======================================================================
  334. ;Function 7.  Get version number
  335. ;======================================================================
  336. EMS_07          PROC    NEAR
  337.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  338.                 MOV     AX,0040H                ;store ver num and ret code
  339.                 RET
  340. EMS_07          ENDP
  341. ;======================================================================
  342. ;Function 8. Save page map.
  343. ;======================================================================
  344. EMS_08          PROC    NEAR
  345.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  346.                 PUSH    BX
  347.                 PUSH    DX
  348.                 JC      EMS_08_EXIT             ;Carry set, invalid handle
  349. ;Search the mapping arrays to find an array that is empty.  At the same
  350. ;   time, make sure that the handle doesn't have an array currently saved.
  351.                 MOV     SI,MAP_ARRAY_PTR        ;Start search of map arr lbls
  352.                 MOV     CX,INT_SAVE_SIZE        ;Search all save map arrays
  353.                 XOR     BX,BX                   ;Initialize free pointer
  354. EMS_08_L1:      ADD     SI,18                   ;Look at next map array
  355.                 CMP     WORD PTR [SI],0FFFFh    ;See if free
  356.                 JNE     EMS_08_S1
  357.                 MOV     DI,SI                   ;If so, copy address
  358.                 JMP     SHORT EMS_08_S3
  359. EMS_08_S1:      CMP     [SI],DX                 ;See if curr hndl used before
  360.                 JNE     EMS_08_S2
  361.                 MOV     AH,8DH                  ;Handle already used for save
  362.                 JMP     SHORT EMS_08_EXIT
  363. EMS_08_S2:      LOOP    EMS_08_L1               ;Loop back
  364.                 MOV     AH,8CH                  ;No room to store page map
  365.                 JMP     SHORT EMS_08_EXIT
  366. EMS_08_S3:      PUSH    CS                      ;Point ds:si to page array
  367.                 POP     ES
  368.                 ASSUME ES:CODE                  ;Point es:di to save array
  369.                 MOV     SI,MAP_ARRAY_PTR
  370.                 MOV     [SI],DX                 ;Label arrays with handle
  371.                 MOV     CX,9
  372.                 REP     MOVSW
  373.                 XOR     AX,AX                   ;Clear return code
  374. EMS_08_EXIT:    POP     DX
  375.                 POP     BX
  376.                 RET
  377. EMS_08          ENDP
  378. ;======================================================================
  379. ;Function 9. Restore page map
  380. ;======================================================================
  381. EMS_09          PROC    NEAR
  382.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  383.                 PUSH    BX
  384.                 PUSH    DX
  385.                 JC      EMS_09_EXIT             ;carry set, invalid handle
  386. ;find the saved page map in the save array.
  387.                 MOV     SI,MAP_ARRAY_PTR
  388.                 MOV     CX,INT_SAVE_SIZE
  389. EMS_09_L1:      ADD     SI,18                   ;look at next map array
  390.                 CMP     [SI],DX                 ;See if array label matches
  391.                 JE      EMS_09_S1               ;  the handle.
  392.                 LOOP    EMS_09_L1
  393.                 MOV     AH,8EH                  ;no saved page map found
  394.                 JMP     SHORT EMS_09_EXIT
  395. ;Now that the saved array has been found, call restore map routine.
  396. EMS_09_S1:      CALL    EMS_15_1                ;restore map
  397.                 MOV     WORD PTR [SI],0FFFFh    ;mark saved array as free
  398.                 XOR     AX,AX                   ;clear return code
  399. EMS_09_EXIT:    POP     DX
  400.                 POP     BX
  401.                 RET
  402. EMS_09          ENDP
  403. ;======================================================================
  404. ;Function 12, Get Handle Count
  405. ;======================================================================
  406. EMS_12          PROC    NEAR
  407.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  408.                 MOV     DI,HANDLE_ARRAY         ;point to handle array
  409.                 XOR     BX,BX                   ;clear count and compare regs
  410.                 MOV     CX,TOTAL_HANDLES        ;look at all handles 0 - feh
  411. EMS_12_L1:      CMP     BH,[DI]                 ;if handle id = 0 then that
  412.                 JE      EMS_12_S1               ;  handle has not been allocated.
  413.                 INC     BL                      ;Add one to open handle count
  414. EMS_12_S1:      ADD     DI,9                    ;Move di to point to next id.
  415.                 LOOP    SHORT EMS_12_L1
  416.                 XOR     AX,AX                   ;clear return code
  417. EMS_12_EXIT:    RET
  418. EMS_12          ENDP
  419. ;======================================================================
  420. ;Function 13 Get Handle pages
  421. ;Entry: dx = handle to search for
  422. ;Exit:  ax = return code.      bx = number of matches found.
  423. ;======================================================================
  424. EMS_13          PROC    NEAR
  425.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  426.                 PUSH    DI
  427.                 JC      EMS_13_EXIT             ;carry set, invalid handle
  428.                 MOV     DI,PAG_OWNER_TBL        ;point to owner table
  429.                 MOV     CX,TOTAL_PAGES
  430.                 XOR     BX,BX                   ;Clear page count
  431. EMS_13_LOOP:    CMP     DL,[DI]                 ;Compare handle to table
  432.                 JNE     EMS_13_SKIP
  433.                 INC     BX                      ;Inc count of pages
  434. EMS_13_SKIP:    ADD     DI,3                    ;Point to next entry
  435.                 LOOP    EMS_13_LOOP
  436.                 XOR     AX,AX                   ;Clear return code.
  437. EMS_13_EXIT:    POP     DI
  438.                 RET
  439. EMS_13          ENDP
  440. ;======================================================================
  441. ;Function 14. Get All Handle Pages
  442. ;======================================================================
  443. EMS_14          PROC    NEAR
  444.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  445.                 PUSH    DX
  446.                 XOR     DX,DX                   ;Handle currently being checked
  447.                 XOR     SI,SI                   ;SI total open handles counter
  448. EMS_14_L1:      CALL    EMS_CHECK_HDL           ;See if handle active
  449.                 CALL    EMS_13                  ;Count pages for handle
  450.                 JC      EMS_14_S1               ;If bad handle, skip
  451.                 INC     SI                      ;Add to handle count
  452.                 MOV     ES:[DI],DX              ;Write results to the array
  453.                 MOV     ES:2[DI],BX
  454. EMS_14_S1:      INC     DX                      ;Point to next handle
  455.                 ADD     DI,4                    ;Incriment array pointer
  456.                 CMP     DX,TOTAL_HANDLES        ;Have we check all handles?
  457.                 JL      EMS_14_L1               ;No, loop back.
  458.                 MOV     BX,SI                   ;Get number of active handles
  459.                 XOR     AX,AX                   ;Clear return code
  460. EMS_14_EXIT:    POP     DX
  461.                 RET
  462. EMS_14          ENDP
  463. ;======================================================================
  464. ;Function 15.  Get/Set Page Map
  465. ;======================================================================
  466. EMS_15_TBL      DB      3               ;Max value of subfunction
  467.                 DW      OFFSET EMS_15_0 ;Jump table for subfunctions
  468.                 DW      OFFSET EMS_15_1
  469.                 DW      OFFSET EMS_15_2
  470.                 DW      OFFSET EMS_15_3
  471. EMS_15          PROC    NEAR
  472.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  473.                 PUSH    BX
  474.                 PUSH    DX
  475.                 MOV     DS,SS:[BP-8]            ;Get original DS
  476.                 ASSUME  DS:NOTHING
  477.                 MOV     DI,OFFSET EMS_15_TBL    ;Point to jump table structure
  478.                 CALL    EMS_DISPATCHER          ;Dispatch routine calls
  479. EMS_15_EXIT:    POP     DX                      ;  subfunction routine.
  480.                 POP     BX
  481.                 RET
  482. EMS_15          ENDP
  483. ;----------------------------------------------------------------------
  484. ;Function 15.0  Get mapping array
  485. ;----------------------------------------------------------------------
  486. EMS_15_0        PROC    NEAR
  487.                 ASSUME  DS:NOTHING,ES:NOTHING
  488.                 PUSH    SI
  489.                 PUSH    DS
  490.                 PUSH    CS
  491.                 POP     DS
  492.                 ASSUME  DS:CODE
  493.                 MOV     SI,MAP_ARRAY_PTR        ;DS:SI points to page array
  494.                 MOV     CX,9                    ;ES:DI points to destination
  495.                 REP     MOVSW                   ;Copy mapping array
  496.                 XOR     AH,AH
  497.                 POP     DS
  498.                 POP     SI
  499.                 RET
  500. EMS_15_0        ENDP
  501. ;----------------------------------------------------------------------
  502. ;Function 15.1  Set mapping array
  503. ;----------------------------------------------------------------------
  504. EMS_15_1        PROC    NEAR
  505.                 ASSUME  DS:NOTHING,ES:NOTHING
  506.                 PUSH    SI
  507.                 XOR     BX,BX                   ;start with logical page 0
  508.                 ADD     SI,2                    ;move si past the handle ptr
  509. EMS_15_1_L1:    MOV     AX,DS:[SI]              ;get current page address
  510.                 MOV     DX,DS:[SI+2]
  511.                 PUSH    BX
  512.                 CALL    EMS_EXCH_PAG            ;Exchange current window page
  513.                 POP     BX                      ;Point si to next address
  514.                 ADD     SI,4
  515.                 INC     BX
  516.                 CMP     BL,3                    ;Have we done all 4 pages?
  517.                 JLE     EMS_15_1_L1             ;No, loop back
  518.                 XOR     AH,AH
  519. EMS_15_1_EXIT:  POP     SI
  520.                 RET
  521. EMS_15_1        ENDP
  522. ;----------------------------------------------------------------------
  523. ;Function 15.2  Get & Set mapping array
  524. ;----------------------------------------------------------------------
  525. EMS_15_2        PROC    NEAR
  526.                 ASSUME  DS:NOTHING,ES:NOTHING
  527.                 PUSH    DI
  528.                 CALL    EMS_15_0                ;Save current mapping array
  529.                 POP     DI
  530.                 CALL    EMS_15_1                ;Set new mapping context
  531.                 XOR     AH,AH
  532.                 RET
  533. EMS_15_2        ENDP
  534. ;----------------------------------------------------------------------
  535. ;Function 15.3  Get mapping array size
  536. ;----------------------------------------------------------------------
  537. EMS_15_3        PROC    NEAR
  538.                 ASSUME  DS:NOTHING,ES:NOTHING
  539.                 MOV     AX,0012H                ;18 bytes in the page array
  540.                 RET
  541. EMS_15_3        ENDP
  542. ;======================================================================
  543. ;Function 16.  Get/Set Partial Page Map
  544. ;======================================================================
  545. EMS_16_TBL      DB      2                       ;Max value of subfunction
  546.                 DW      OFFSET EMS_16_0         ;Jump table for subfunctions
  547.                 DW      OFFSET EMS_16_1
  548.                 DW      OFFSET EMS_16_2
  549. EMS_16          PROC    NEAR
  550.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  551.                 PUSH    BX
  552.                 PUSH    DX
  553.                 MOV     DS,SS:[BP-8]            ;Get original DS from stack
  554.                 ASSUME  DS:NOTHING
  555.                 MOV     DI,OFFSET EMS_16_TBL    ;Point to jump table structure
  556.                 CALL    EMS_DISPATCHER          ;Dispatch routine calls
  557. EMS_16_EXIT:    POP     DX                      ;  subfunction routine.
  558.                 POP     BX
  559.                 RET
  560. EMS_16          ENDP
  561. ;----------------------------------------------------------------------
  562. ;Function 16.0  Get mapping array
  563. ;----------------------------------------------------------------------
  564. EMS_16_0        PROC    NEAR
  565.                 ASSUME  DS:NOTHING,ES:NOTHING
  566.                 MOV     CX,DS:[SI]              ;get count of mappable segs.
  567.                 MOV     ES:[DI],CX              ;save count
  568. EMS_16_0_L1:    MOV     AX,DS:2[SI]             ;Get segment to convert
  569.                 CALL    EMS_SEG2LOG             ;convert segment onto page #
  570.                 JC      EMS_16_0_EXIT
  571.                 MOV     ES:2[DI],BX             ;save physical page number
  572.                 SAL     BX,1                    ;Convert page number
  573.                 SAL     BX,1                    ;  into offset
  574.                 ADD     BX,CS:MAP_ARRAY_PTR
  575.                 MOV     AX,CS:2[BX]
  576.                 MOV     ES:4[DI],AX             ;save address low
  577.                 MOV     AX,CS:4[BX]
  578.                 MOV     ES:6[DI],AX             ;save address high
  579.                 ADD     DI,6
  580.                 INC     SI                      ;point to next seg to save
  581.                 INC     SI
  582.                 LOOP    EMS_16_0_L1
  583.                 XOR     AX,AX
  584. EMS_16_0_EXIT:  RET
  585. EMS_16_0        ENDP
  586. ;----------------------------------------------------------------------
  587. ;Function 16.1  Set mapping array
  588. ;----------------------------------------------------------------------
  589. EMS_16_1        PROC    NEAR
  590.                 ASSUME  DS:NOTHING,ES:NOTHING
  591.                 MOV     CX,DS:[SI]              ;get count of pages
  592. EMS_16_1_L1:    MOV     BX,2[SI]                ;get logical page
  593.                 MOV     AX,4[SI]                ;get address of page to
  594.                 MOV     DX,6[SI]                ;  restore
  595.                 CALL    EMS_EXCH_PAG            ;Exchange current window page
  596.                 ADD     SI,6                    ;Point si to next page
  597.                 LOOP    EMS_16_1_L1             ;No, loop back
  598.                 XOR     AX,AX                   ;Clear error code
  599. EMS_16_1_EXIT:  RET
  600. EMS_16_1        ENDP
  601. ;----------------------------------------------------------------------
  602. ;Function 16.2  Get partial mapping array size
  603. ;----------------------------------------------------------------------
  604. EMS_16_2        PROC    NEAR
  605.                 ASSUME  DS:NOTHING,ES:NOTHING
  606.                 MOV     AX,BX                   ;get number of pages
  607.                 MOV     AH,6                    ;6 bytes per page
  608.                 MUL     AH
  609.                 ADD     AX,2                    ;add room for count
  610.                 XOR     AH,AH                   ;zero return code
  611.                 RET
  612. EMS_16_2        ENDP
  613. ;======================================================================
  614. ;Function 17.  Map Multiple Handle Pages
  615. ;======================================================================
  616. EMS_17          PROC    NEAR
  617.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  618.                 MOV     ES,SS:[BP-8]            ;get pointer to map structure
  619.                 CALL    EMS_17_INTERNAL
  620.                 RET
  621. EMS_17          ENDP
  622. ;----------------------------------------------------------------------
  623. ;Function 17 (internal).  Used by jump and call routines to map pages.
  624. ;----------------------------------------------------------------------
  625. EMS_17_INTERNAL PROC    NEAR
  626.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  627.                 PUSH    BX
  628.                 PUSH    DX
  629.                 JC      EMS_17_EXIT             ;carry set, invalid handle
  630.                 CMP     AL,1                    ;no subfunction > 1.
  631.                 JA      EMS_17_ERR1
  632.                 CMP     CX,4                    ;Make sure count < number of
  633.                 JA      EMS_17_ERR2             ;  mappable pages.
  634.                 MOV     CH,AL                   ;save subfunction
  635. EMS_17_L1:      MOV     AX,ES:[SI+2]            ;get physical page number/seg
  636.                 OR      CH,CH
  637.                 JE      EMS_17_S3               ;if seg address mapping,
  638.                 CALL    EMS_SEG2LOG             ;  convert seg addr to number
  639.                 JC      EMS_17_EXIT             ;check for error on conversion
  640.                 MOV     AL,BL
  641. EMS_17_S3:      MOV     BX,ES:[SI]              ;get logical page number
  642.                 CLC                             ;handle valid
  643.                 PUSH    CX                      ;save count
  644.                 CALL    EMS_05                  ;map page
  645.                 POP     CX                      ;restore count
  646.                 OR      AH,AH                   ;check for error
  647.                 JNE     EMS_17_EXIT
  648.                 ADD     SI,4                    ;Move pointers to next
  649.                 DEC     CL                      ;  mapping structure.
  650.                 JNZ     EMS_17_L1
  651.                 XOR     AX,AX                   ;clear return code
  652. EMS_17_EXIT:    POP     DX
  653.                 POP     BX
  654.                 RET
  655. EMS_17_ERR1:    MOV     AH,8FH                  ;invalid subfunction
  656.                 JMP     SHORT EMS_17_EXIT
  657. EMS_17_ERR2:    MOV     AH,8BH                  ;Number exceeds mappable pages
  658.                 JMP     SHORT EMS_17_EXIT       ;  in the system
  659. EMS_17_INTERNAL ENDP
  660. ;======================================================================
  661. ;Function 18.  Reallocate Pages
  662. ;======================================================================
  663. EMS_18          PROC    NEAR
  664.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  665.                 PUSH    BX
  666.                 PUSH    DX
  667.                 JC      EMS_18_EXIT             ;carry set, invalid handle
  668.                 MOV     DI,BX                   ;save reallocation count
  669.                 PUSH    BX
  670.                 CALL    EMS_13                  ;get current count
  671.                 MOV     CX,BX
  672.                 POP     BX                      ;get back new count
  673.                 SUB     BX,CX
  674.                 JG      EMS_18_INCREASE
  675.                 JL      EMS_18_REDUCE
  676.                 XOR     AH,AH                   ;clear return code
  677. EMS_18_EXIT:    POP     DX
  678.                 POP     BX
  679.                 RET
  680. EMS_18_INCREASE:
  681.                 CALL    EMS_ASSIGN
  682.                 JMP     SHORT EMS_18_EXIT
  683. EMS_18_REDUCE:  NEG     BX                      ;turn into positive number
  684.                 CALL    EMS_DEALLOC
  685.                 JMP     SHORT EMS_18_EXIT
  686. EMS_18          ENDP
  687. ;======================================================================
  688. ;Function 19. Get/Set Handle Attribute (Not Supported)
  689. ;======================================================================
  690. EMS_19          PROC    NEAR
  691.                 ASSUME  CS:CODE,DS:CODE
  692.                 CMP     AL,1
  693.                 JE      EMS_19_1                ;Set handle attribute.
  694.                 CMP     AL,2                    ;For subfunctions 0 and 2,
  695.                 JG      EMS_19_ERR1             ;  return volatile handle,
  696. EMS_19_GOOD_EXIT:
  697.                 XOR     AX,AX                   ;  non-volatile not supp
  698. EMS_19_EXIT:    RET
  699. EMS_19_1:       CALL    EMS_CHECK_HDL           ;See if good handle
  700.                 JC      EMS_19_ERR2
  701.                 CMP     BL,1                    ;See if legal attribute type
  702.                 JG      EMS_19_ERR3             ;  or if non-volatile.
  703.                 JL      EMS_19_GOOD_EXIT
  704.                 MOV     AH,91H                  ;function not supported
  705.                 JMP     SHORT EMS_19_EXIT
  706. EMS_19_ERR1:    MOV     AH,8FH                  ;subfunction invalid
  707.                 JMP     SHORT EMS_19_EXIT
  708. EMS_19_ERR2:    MOV     AH,83H                  ;invalid handle
  709.                 JMP     SHORT EMS_19_EXIT
  710. EMS_19_ERR3:    MOV     AH,90H                  ;attribute type not defined.
  711.                 JMP     SHORT EMS_19_EXIT
  712. EMS_19          ENDP
  713. ;======================================================================
  714. ;Function 20. Get/Set Handle Name
  715. ;======================================================================
  716. EMS_20          PROC    NEAR
  717.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  718.                 PUSH    BX
  719.                 PUSH    DX
  720.                 JC      EMS_20_EXIT             ;carry set, invalid handle
  721.                 PUSH    AX                      ;find spot for handle
  722.                 MOV     BX,CS                   ;get code segment
  723.                 MOV     AX,DX                   ;Compute offset by multipling
  724.                 MOV     AH,9                    ;  the handle number by the
  725.                 MUL     AH                      ;  size of each entry (9).
  726.                 MOV     DX,AX
  727.                 ADD     DX,HANDLE_ARRAY
  728.                 INC     DX                      ;point dx past the handle used
  729.                 POP     AX                      ;  flag.
  730.                 OR      AL,AL                   ;Check for get or set subfun.
  731.                 JNE     EMS_20_S1
  732. ;Get Handle Name
  733.                 MOV     SI,DX                   ;load pointer to handle name
  734.                 JMP     SHORT EMS_20_MOV
  735. ;Set Handle Name
  736. EMS_20_S1:      CMP     AL,1                    ;Make sure that subfunction
  737.                 JNE     EMS_20_ERR1             ;  = 1.
  738.                 MOV     DS,SS:[BP-8]            ;Get original DS
  739.                 ASSUME  DS:NOTHING
  740.                 PUSH    SI
  741.                 PUSH    DX
  742.                 CALL    EMS_21_1                ;First, search for handle
  743.                 POP     DX                      ;  with this name. The
  744.                 POP     SI                      ;  return code must be a0h.
  745.                 AND     AH,0FEH                 ;  or a1h.
  746.                 CMP     AH,0A0H
  747.                 JNE     EMS_20_ERR2
  748.                 MOV     DI,DX                   ;Get back name pointer
  749.                 PUSH    CS
  750.                 POP     ES
  751.                 ASSUME  ES:CODE
  752. EMS_20_MOV:     MOV     CX,8                    ;copy name. move 8 bytes
  753.                 REP     MOVSB
  754.                 XOR     AX,AX                   ;clear return code
  755. EMS_20_EXIT:    POP     DX
  756.                 POP     BX
  757.                 RET
  758. EMS_20_ERR1:    MOV     AH,8FH                  ;Invalid subfunction
  759.                 JMP     SHORT EMS_20_EXIT
  760. EMS_20_ERR2:    MOV     AH,0A1H                 ;Handle already used
  761.                 JMP     SHORT EMS_20_EXIT
  762. EMS_20          ENDP
  763. ;======================================================================
  764. ;Function 21. Get Handle directory
  765. ;======================================================================
  766. EMS_21_TBL      DB      2               ;Max value of subfunction
  767.                 DW      OFFSET EMS_21_0 ;Jump table for subfunctions
  768.                 DW      OFFSET EMS_21_1
  769.                 DW      OFFSET EMS_21_2
  770. EMS_21          PROC    NEAR
  771.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  772.                 MOV     DS,SS:[BP-8]            ;Get original DS
  773.                 ASSUME  DS:NOTHING
  774.                 MOV     DI,OFFSET EMS_21_TBL
  775.                 CALL    EMS_DISPATCHER
  776. EMS_21_EXIT:    RET
  777. EMS_21          ENDP
  778. ;----------------------------------------------------------------------
  779. ;Function 21.0  Get Handle Directory
  780. ;----------------------------------------------------------------------
  781. EMS_21_0        PROC    NEAR
  782.                 ASSUME  DS:NOTHING,ES:NOTHING
  783.                 PUSH    DX
  784.                 PUSH    CS
  785.                 POP     DS
  786.                 ASSUME  DS:CODE
  787.                 MOV     SI,HANDLE_ARRAY
  788.                 XOR     AX,AX                   ;Clear RC and hndl counter
  789.                 MOV     DX,AX                   ;Start with handle 0
  790. EMS_21_0_L1:    CMP     BYTE PTR [SI],0         ;Check flag to see if handle
  791.                 JE      EMS_21_0_S1             ;  is used.
  792.                 MOV     ES:[DI],DX              ;Store handle value
  793.                 INC     SI                      ;move SI past handle flag
  794.                 ADD     DI,2                    ;move DI past handle
  795.                 MOV     CX,8                    ;8 char per handle name
  796.                 REP     MOVSB
  797.                 INC     AL                      ;add to handle count
  798.                 JMP     SHORT EMS_21_0_S2
  799. EMS_21_0_S1:    ADD     SI,9                    ;move to the next handle
  800. EMS_21_0_S2:    INC     DX                      ;check next handle
  801.                 CMP     DX,TOTAL_HANDLES        ;last handle?
  802.                 JB      EMS_21_0_L1             ;no, loop back
  803.                 POP     DX
  804.                 RET
  805. EMS_21_0        ENDP
  806. ;----------------------------------------------------------------------
  807. ;Function 21.1  Search for Named Handle
  808. ;----------------------------------------------------------------------
  809. EMS_21_1        PROC    NEAR
  810.                 ASSUME  DS:NOTHING
  811.                 PUSH    BX
  812.                 PUSH    DS                      ;copy segment of name
  813.                 POP     ES
  814.                 ASSUME ES:NOTHING
  815.                 MOV     DI,SI
  816.                 MOV     CX,8                    ;Check for null string. If
  817.                 XOR     AL,AL                   ;  null, skip scan for dup
  818.                 REPE    SCASB                   ;  strings.
  819.                 JE      EMS_21_1_ERR1
  820.                 MOV     CX,CS:TOTAL_HANDLES     ;look at all handles
  821.                 PUSH    CS                      ;ES:DI -> handle array
  822.                 POP     ES                      ;DS:SI -> handle name
  823.                 ASSUME  ES:CODE
  824.                 MOV     BX,SI                   ;bx holds handle name ptr
  825.                 MOV     AX,CS:HANDLE_ARRAY      ;ax holds handle array ptr
  826.                 INC     AX                      ;move ax past handle flag
  827.                 XOR     DX,DX                   ;start handle count at 0
  828. EMS_21_1_L1:    MOV     DI,AX                   ;Compare each of the handle
  829.                 MOV     SI,BX                   ;  names with the new handle
  830.                 PUSH    CX
  831.                 MOV     CX,8
  832.                 REPE    CMPSB
  833.                 POP     CX
  834.                 JE      EMS_21_1_EXIT           ;If match found print err msg.
  835.                 ADD     AX,9                    ;move AX to next handle
  836.                 INC     DX
  837.                 LOOP    EMS_21_1_L1
  838.                 MOV     AH,0A0H                 ;handle not found
  839.                 JMP     SHORT EMS_21_1_EXIT1
  840. EMS_21_1_EXIT:  XOR     AH,AH
  841. EMS_21_1_EXIT1: POP     BX
  842.                 RET
  843. EMS_21_1_ERR1:  MOV     AH,0A1H                 ;null handle found
  844.                 JMP     SHORT EMS_21_1_EXIT1
  845. EMS_21_1        ENDP
  846. ;----------------------------------------------------------------------
  847. ;Function 21.2  Get Total Handles
  848. ;----------------------------------------------------------------------
  849. EMS_21_2        PROC    NEAR
  850.                 ASSUME  DS:NOTHING
  851.                 MOV     BX,CS:TOTAL_HANDLES     ;Get number of allowed hdls
  852.                 XOR     AX,AX                   ;Clear return code.
  853.                 RET
  854. EMS_21_2        ENDP
  855. ;======================================================================
  856. ;Function 22. Alter Page Map and Jump
  857. ;======================================================================
  858. EMS_22          PROC    NEAR
  859.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  860.                 JC      EMS_22_EXIT             ;carry set, invalid handle
  861. ;Map new pages into window
  862.                 MOV     DI,SI                   ; ES:DI = pointer to map and
  863.                 MOV     ES,SS:[BP-8]            ;  jump data
  864.                 MOV     SI,ES:[DI]              ;Modify return address on
  865.                 MOV     SS:[BP+2],SI            ;  the stack to the address
  866.                 MOV     SI,ES:[DI+2]            ;  in the jump structure.
  867.                 MOV     SS:[BP+4],SI
  868.                 MOV     SI,ES:[DI+5]            ;Get pointer to mapping
  869.                 MOV     ES,ES:[DI+7]            ;   structure.
  870.                 MOV     CL,ES:[DI+4]            ;get mapping count
  871.                 XOR     CH,CH
  872.                 CALL    EMS_17_INTERNAL         ;alter page map
  873. EMS_22_EXIT:    RET
  874. EMS_22          ENDP
  875. ;======================================================================
  876. ;Function 23. Alter Page Map and Call
  877. ;======================================================================
  878. EMS_23          PROC    NEAR
  879.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  880.                 JC      EMS_23_JMP_END          ;carry set, invalid handle
  881.                 CMP     AL,2                    ;Check for stack size function
  882.                 JNE     EMS_23_S1
  883.                 MOV     BX,28                   ;Say we need 28 bytes
  884.                 XOR     AH,AH
  885. EMS_23_JMP_END: JMP     EMS_23_EXIT
  886. EMS_23_S1:      PUSH    AX                      ;Save subfunction
  887. ;Map new pages into window
  888.                 MOV     DI,SI                   ;get pointer to map and
  889.                 MOV     ES,SS:[BP-8]            ;  jump data
  890.                 PUSH    ES                      ;Save pointer to structure
  891.                 PUSH    DI
  892.                 XOR     CH,CH
  893.                 MOV     CL,ES:[DI+4]            ;get mapping count
  894.                 MOV     SI,ES:[DI+5]            ;get pointer to mapping
  895.                 MOV     ES,ES:[DI+7]            ;   structure
  896.                 PUSH    AX
  897.                 CLC                             ;indicate good handle
  898.                 CALL    EMS_17_INTERNAL         ;alter page map
  899.                 OR      AH,AH
  900.                 POP     AX                      ;Restore AX
  901.                 JNE     EMS_23_EXIT
  902. ;Restore values in the registers and call.
  903.                 MOV     AX,SS:[BP+6]            ;get flags
  904.                 PUSH    AX
  905.                 POPF                            ;load flags
  906.                 MOV     ES,SS:[BP-10]           ;restore ES
  907.                 MOV     DS,SS:[BP-8]            ;Restore DS
  908.                 MOV     SI,SS:[BP-6]            ;Restore SI
  909.                 MOV     DI,SS:[BP-4]            ;Restore DI
  910.                 MOV     CX,SS:[BP-2]            ;Restore CX
  911.                 ASSUME  DS:NOTHING
  912.                 PUSH    BP                      ;Save my base pointer
  913.                 MOV     BP,SS:[BP]              ;Restore BP
  914.                 MOV     AX,0000                 ;Clear return code
  915.                 CALL    DWORD PTR DS:[SI]       ;Call.
  916.                 POP     AX                      ;Get back pointer to stack
  917.                 PUSH    BP                      ;Save returned BP
  918.                 MOV     BP,AX                   ;Restore my base pointer
  919.                 POP     AX                      ;Get back returned BP
  920.                 PUSHF                           ;Save returned flags
  921.                 MOV     [BP-10],ES
  922.                 MOV     [BP-8],DS               ;Put reg values on stack
  923.                 MOV     [BP-6],SI               ;  to be restored on return
  924.                 MOV     [BP-4],DI
  925.                 MOV     [BP-2],CX
  926.                 POP     CX                      ;Get back returned flags
  927.                 MOV     SS:[BP+6],CX
  928.                 MOV     SS:[BP],AX              ;Save returned BP
  929.                 PUSH    CS
  930.                 POP     DS
  931.                 ASSUME  DS:CODE
  932. ;Map old pages into window
  933.                 POP     DI                      ;Get back pointer to structure
  934.                 POP     ES
  935.                 XOR     CH,CH
  936.                 MOV     CL,ES:[DI+9]            ;get mapping count
  937.                 MOV     SI,ES:[DI+10]           ;get pointer to mapping
  938.                 MOV     ES,ES:[DI+12]           ;   structure
  939.                 CLC                             ;indicate good handle
  940.                 POP     AX                      ;Restore subfunction
  941.                 CALL    EMS_17_INTERNAL         ;alter page map
  942. EMS_23_EXIT:    RET
  943. EMS_23          ENDP
  944. ;======================================================================
  945. ;Function 24.  Move/Exchange Memory Region
  946. ;======================================================================
  947. EMS_24_SUBFUN   EQU     [BP-1]                  ;Saved subfunction
  948. EMS_24_DIR      EQU     [BP-2]                  ;Direction flag for move
  949. EMS_24_COUNT    EQU     [BP-6]                  ;Amount of memory to move
  950. EMS_24_SRC_PTR  EQU     [BP-10]                 ;Source move pointer
  951. EMS_24_DEST_PTR EQU     [BP-14]                 ;Destination move pointer
  952. EMS_24_RET_CODE EQU     [BP-15]                 ;RC for non-fatal error codes
  953. EMS_24          PROC    NEAR
  954.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  955.                 PUSH    BX                      ;Save registers
  956.                 PUSH    DX
  957.                 MOV     ES,SS:[BP-8]            ;Get DS off original stack
  958.                 PUSH    ES                      ;Push for local addressability
  959.                 PUSH    SI
  960.                 PUSH    BP
  961.                 MOV     BP,SP                   ;Set up pointer to local data
  962.                 SUB     SP,18                   ;Make room on stack for data
  963.                 MOV     EMS_24_SUBFUN,AL        ;Save subfunction
  964.                 MOV     BYTE PTR EMS_24_RET_CODE,0
  965.                 MOV     AX,ES:[SI]              ;Get count from move struc
  966.                 MOV     DX,ES:[SI+2]
  967.                 CMP     DX,10H                  ;see if region size > 1M
  968.                 JB      EMS_24_S0
  969.                 MOV     AH,96H                  ;region > 1M byte
  970.                 JMP     EMS_24_EXIT
  971. EMS_24_S0:      MOV     WORD PTR [EMS_24_COUNT],AX      ;Save count. Compute
  972.                 MOV     WORD PTR [EMS_24_COUNT+2],DX    ;  the number of
  973.                 MOV     CX,16384                        ;  16K pages needed.
  974.                 DIV     CX
  975.                 MOV     CH,AL                   ;Save number of pages
  976.                 MOV     CL,DL                   ;save remainder
  977. ;Verify handles have the pages assigned. (If Expanded memory.)
  978.                 ADD     SI,4                    ;move pointer to source descr
  979.                 MOV     DI,-10                  ;Pointer to src local store
  980.                 CALL    EMS_CHECK_MOV
  981.                 JC      EMS_24_JMP_EXIT
  982.                 PUSH    AX                      ;Save source end address
  983.                 PUSH    DX
  984.                 ADD     SI,7                    ;Point to destination block
  985.                 MOV     DI,-14                  ;Pointer to dest local store
  986.                 CALL    EMS_CHECK_MOV
  987.                 POP     DI                      ;Recover source end address
  988.                 POP     BX
  989.                 JNC     EMS_24_S01              ;If error flag set, exit
  990. EMS_24_JMP_EXIT:
  991.                 JMP     EMS_24_EXIT
  992. EMS_24_S01:     MOV     BYTE PTR EMS_24_DIR,0   ;Set direction flag bottom up
  993. ;Check and adjust for overlap if necessary. If exchange, don't allow overlap.
  994.                 MOV     CL,BYTE PTR ES:[SI]     ;Get destination memory type
  995.                 ADD     CL,BYTE PTR ES:[SI-7]   ;Compare to source memory type
  996.                 CMP     CL,1                    ;0 = both conv, 1 = diff types,
  997.                 JE      EMS_24_MOVEDATA         ;  2 = both expanded.
  998.                 JB      EMS_24_S2               ;0, check conv overlap.
  999.                 MOV     CX,ES:[SI+1]            ;Get dest handle
  1000.                 CMP     CX,ES:[SI-6]            ;Compare to source handle
  1001.                 JNE     EMS_24_MOVEDATA         ;Not the same, no overlap
  1002.                 MOV     CX,ES:[SI-2]            ;Get source starting page
  1003.                 CMP     CX,ES:[SI+5]            ;Compare dest starting page
  1004.                 JB      EMS_24_S1               ;If source starts first,
  1005.                 JA      EMS_24_S02              ;  bottom up move.
  1006.                 MOV     CX,ES:[SI-4]            ;Get source starting offset
  1007.                 CMP     CX,ES:[SI+3]            ;Get source starting offset
  1008.                 JB      EMS_24_S1               ;Source lower, bottom up move
  1009. EMS_24_S02:     MOV     BX,AX                   ;Copy from top down.
  1010.                 MOV     DI,DX                   ;Put end addr of Dest in DI,BX
  1011.                 SUB     SI,7                    ;Point to source descriptor
  1012.                 MOV     BYTE PTR EMS_24_DIR,1   ;Set direction top down
  1013. EMS_24_S1:      CMP     DI,ES:[SI+5]            ;Compare end with start addr
  1014.                 JB      EMS_24_MOVEDATA         ;No overlap
  1015.                 JA      EMS_24_OVERLAP          ;Overlap
  1016.                 CMP     BX,ES:[SI+3]            ;Same pages, check offsets
  1017.                 JB      EMS_24_MOVEDATA         ;If less, no overlap
  1018.                 JMP     SHORT EMS_24_OVERLAP
  1019. ;Check for overlap of conventional memory regions.
  1020. EMS_24_S2:      CMP     DX,DI                   ;Compare high word
  1021.                 JB      EMS_24_S3               ;dest higher, top down
  1022.                 JA      EMS_24_S21              ;Less, bottom up.
  1023.                 CMP     AX,BX                   ;Compare low word of address
  1024.                 JB      EMS_24_S3               ;Jmp if dest addr higher
  1025. EMS_24_S21:     MOV     SI,-14                  ;Point to dest descriptor
  1026.                 CALL    EMS_24_ADR_CNV
  1027.                 XCHG    DI,DX                   ;Exchange starting addresses
  1028.                 XCHG    BX,AX
  1029.                 MOV     SI,-10                  ;Point to source descriptor
  1030.                 CALL    EMS_24_ADR_CNV
  1031.                 MOV     BYTE PTR EMS_24_DIR,1   ;Set direction flag top down
  1032. EMS_24_S3:      SUB     BX,WORD PTR [EMS_24_COUNT]      ;Generate start addr
  1033.                 SBB     DI,WORD PTR [EMS_24_COUNT+2]
  1034.                 CMP     DX,DI                   ;Compare starting addr with
  1035.                 JB      EMS_24_MOVEDATA         ;  end of other block
  1036.                 CMP     AX,BX
  1037.                 JBE     EMS_24_MOVEDATA
  1038. EMS_24_OVERLAP: MOV     BYTE PTR EMS_24_RET_CODE,92H    ;Indicate overlap
  1039.                 CMP     BYTE PTR EMS_24_SUBFUN,0        ;If exch. don't allow
  1040.                 JE      EMS_24_MOVEDATA                 ;  overlap.
  1041.                 MOV     AH,97H                          ;Error, no overlap
  1042.                 JMP     EMS_24_EXIT                     ;  on exchange.
  1043. ;Move/Exchange the data
  1044. EMS_24_MOVEDATA:
  1045.                 MOV     BX,MAP_ARRAY_PTR        ;Save context of pages 0 & 1
  1046.                 PUSH    [BX+8]                  ;Save address for page 1
  1047.                 PUSH    [BX+6]
  1048.                 PUSH    [BX+4]                  ;Save address for page 0
  1049.                 PUSH    [BX+2]
  1050.                 STD
  1051.                 CMP     BYTE PTR EMS_24_DIR,0   ;If moving from top to bottom
  1052.                 JNE     EMS_24_MOVE0            ;  set direction flag for move
  1053.                 CLD
  1054.                 MOV     AX,ES:[SI-4]            ;If move from bottom to top,
  1055.                 MOV     DX,ES:[SI-2]                    ;  initialize the
  1056.                 MOV     WORD PTR [EMS_24_SRC_PTR],AX    ;  pointers back to
  1057.                 MOV     WORD PTR [EMS_24_SRC_PTR+2],DX  ;  the starting
  1058.                 MOV     AX,ES:[SI+3]                    ;  addresses.
  1059.                 MOV     DX,ES:[SI+5]
  1060.                 MOV     WORD PTR [EMS_24_DEST_PTR],AX
  1061.                 MOV     WORD PTR [EMS_24_DEST_PTR+2],DX
  1062. EMS_24_MOVE0:   XOR     CX,CX                   ;Clear last move count
  1063. EMS_24_MOVELOOP:
  1064.                 MOV     ES,[BP+4]               ;Restore move structure
  1065.                 MOV     BX,[BP+2]               ;  pointer to ES:BX
  1066.                 MOV     DX,ES                   ;Save ES
  1067.                 MOV     AX,CX                   ;Save last count
  1068.                 ADD     BX,4                    ;Point to source descriptor
  1069.                 XOR     SI,SI                   ;Indicate source
  1070.                 CALL    EMS_24_MOV_SET
  1071.                 PUSH    ES                      ;Save source pointer
  1072.                 PUSH    DI
  1073.                 XCHG    CX,AX                   ;save count, restore last cnt
  1074.                 MOV     ES,DX                   ;Restore ES
  1075.                 ADD     BX,7                    ;Point to dest mem descriptor
  1076.                 MOV     SI,1
  1077.                 CALL    EMS_24_MOV_SET          ;Map extended mem if needed
  1078.                 POP     SI                      ;Get back source pointer
  1079.                 POP     BX                      ;Save segment in BX
  1080.                 CMP     AX,CX                   ;Get lower count
  1081.                 JA      EMS_24_MOVE1
  1082.                 MOV     CX,AX
  1083. EMS_24_MOVE1:   MOV     AX,WORD PTR [EMS_24_COUNT]      ;Get move count
  1084.                 MOV     DX,WORD PTR [EMS_24_COUNT+2]
  1085.                 OR      DX,DX                           ;See if at end of
  1086.                 JNE     EMS_24_MOVE2                    ;  count. If so,
  1087.                 CMP     AX,CX                           ;  copy only to end
  1088.                 JA      EMS_24_MOVE2                    ;  of count.
  1089.                 MOV     CX,AX
  1090. EMS_24_MOVE2:   SUB     AX,CX                   ;Subtract from count
  1091.                 SBB     DX,0
  1092.                 PUSH    CX
  1093.                 PUSH    AX                      ;Save count
  1094.                 PUSH    DX
  1095.                 CMP     BYTE PTR EMS_24_SUBFUN,1        ;See if move or exch
  1096.                 MOV     DS,BX                   ;Time to set DS
  1097.                 ASSUME  DS:NOTHING
  1098.                 JE      EMS_24_EXCH
  1099.                 REP     MOVSB                   ;Move that data
  1100.                 JMP     SHORT EMS_24_MOVE3
  1101. EMS_24_EXCH:    MOV     BL,ES:[DI]              ;Get dest byte
  1102.                 MOVSB
  1103.                 CMP     BYTE PTR EMS_24_DIR,0   ;Check direction flag to
  1104.                 JNE     EMS_24_EXCH1            ;  make sure of pointers
  1105.                 MOV     DS:[SI-1],BL            ;Move dest byte to source
  1106.                 JMP     SHORT EMS_24_EXCH2
  1107. EMS_24_EXCH1:   MOV     DS:[SI+1],BL            ;Move dest byte to source
  1108. EMS_24_EXCH2:   LOOP    EMS_24_EXCH             ;Loop until block exchanged.
  1109. EMS_24_MOVE3:   PUSH    CS                      ;Restore DS altered by move
  1110.                 POP     DS
  1111.                 ASSUME  DS:CODE
  1112.                 POP     DX                      ;Get back count
  1113.                 POP     AX
  1114.                 POP     CX
  1115.                 MOV     WORD PTR [EMS_24_COUNT],AX      ;Restore count
  1116.                 MOV     WORD PTR [EMS_24_COUNT+2],DX
  1117.                 OR      DX,DX
  1118.                 JNE     EMS_24_MOVE4            ;See if count has expired.
  1119.                 OR      AX,AX
  1120.                 JLE     EMS_24_LOOP_DONE
  1121. EMS_24_MOVE4:   JMP     EMS_24_MOVELOOP
  1122. EMS_24_LOOP_DONE:                               ;Restore pages 0 and 1.
  1123.                 XOR     BX,BX                   ;set physical page = 0
  1124.                 POP     AX                      ;get address of page to
  1125.                 POP     DX                      ;  restore
  1126.                 CALL    EMS_EXCH_PAG            ;Exchange current window page
  1127.                 MOV     BX,1                    ;set physical page = 1
  1128.                 POP     AX                      ;get address of page to
  1129.                 POP     DX                      ;  restore
  1130.                 CALL    EMS_EXCH_PAG            ;Exchange current window page
  1131.                 MOV     AH,BYTE PTR EMS_24_RET_CODE     ;Get return code
  1132. EMS_24_EXIT:    ADD     SP,18                   ;Deallocate local storage
  1133.                 POP     BP
  1134.                 POP     SI
  1135.                 POP     ES
  1136.                 POP     DX
  1137.                 POP     BX
  1138.                 RET
  1139. EMS_24          ENDP
  1140. ;----------------------------------------------------------------------
  1141. ;Convert address to segment offset form
  1142. ;Entry: dx ax - address
  1143. ;          si - pointer to local memory descriptor
  1144. ;----------------------------------------------------------------------
  1145. EMS_24_ADR_CNV  PROC    NEAR
  1146.                 PUSH    AX
  1147.                 PUSH    DX
  1148.                 MOV     CX,16384                ;Convert address to seg:offset
  1149.                 DIV     CX
  1150.                 MOV     WORD PTR [BP+SI],DX     ;Save offset
  1151.                 MOV     CL,10
  1152.                 SAL     AX,CL
  1153.                 MOV     WORD PTR [BP+SI+2],AX   ;Save segment
  1154.                 POP     DX
  1155.                 POP     AX
  1156.                 RET
  1157. EMS_24_ADR_CNV  ENDP
  1158. ;----------------------------------------------------------------------
  1159. ;Setup ems page for move.
  1160. ;Entry:    al - 0 = source page, 1 = destination page.
  1161. ;       es:bx - pointer to external memory descriptor
  1162. ;          cx - Count used on last move
  1163. ;Exit:  ES:DI - pointer to data to move
  1164. ;          cx - max count before crossing boundry.
  1165. ;----------------------------------------------------------------------
  1166. EMS_24_MOV_SET  PROC    NEAR
  1167.                 ASSUME  DS:CODE
  1168.                 PUSH    AX
  1169.                 PUSH    BX
  1170.                 PUSH    DX
  1171.                 MOV     DX,SI
  1172.                 MOV     SI,-10                  ;Use SI as offset to src_ptr
  1173.                 OR      DX,DX
  1174.                 JE      EMS_24_MOV_SET_S0
  1175.                 SUB     SI,4                    ;Point SI to dest_ptr
  1176. EMS_24_MOV_SET_S0:
  1177.                 MOV     DH,BYTE PTR ES:[BX]     ;Get memory type
  1178.                 MOV     AX,16383                ;Load constants for EMS mem
  1179.                 MOV     DI,1
  1180.                 OR      DH,DH                   ;Check type of number
  1181.                 JNE     EMS_24_MOV_SET_S1       ;1 = EMS memory
  1182.                 MOV     DI,1024                 ;Load constants for
  1183.                                                 ;  conventional memory.
  1184. EMS_24_MOV_SET_S1:
  1185.                 CMP     BYTE PTR EMS_24_DIR,0   ;If bottom up move, skip
  1186.                 JE      EMS_24_MOV_SET_S3
  1187. ;Top down.
  1188.                 SUB     WORD PTR [BP+SI],CX     ;Sub last move from offset
  1189.                 JAE     EMS_24_MOV_SET_S2       ;See if end of page
  1190.                 MOV     WORD PTR [BP+SI],AX     ;Start at top of next page
  1191.                 SUB     WORD PTR [BP+SI+2],DI   ;Point to next page
  1192. EMS_24_MOV_SET_S2:
  1193.                 MOV     CX,WORD PTR [BP+SI]     ;Get offset for count
  1194.                 INC     CX
  1195.                 JMP     EMS_24_MOV_SET_S5
  1196. ;Bottom up
  1197. EMS_24_MOV_SET_S3:
  1198.                 ADD     WORD PTR [BP+SI],CX     ;Add last move to offset
  1199.                 CMP     WORD PTR [BP+SI],AX     ;See if end of page
  1200.                 JBE     EMS_24_MOV_SET_S4
  1201. EMS_24_MOV_SET_S31:
  1202.                 MOV     WORD PTR [BP+SI],0      ;Start at bottom of page
  1203.                 ADD     WORD PTR [BP+SI+2],DI   ;Point to next page
  1204. EMS_24_MOV_SET_S4:
  1205.                 MOV     CX,AX                   ;Compute count to end of page
  1206.                 SUB     CX,WORD PTR [BP+SI]
  1207.                 INC     CX
  1208. EMS_24_MOV_SET_S5:
  1209.                 OR      DH,DH                   ;Check type of number
  1210.                 JE      EMS_24_MOV_SET_CONV1    ;If conventional, don't map
  1211.                 PUSH    CX                      ;Save new count
  1212.                 PUSH    DX
  1213.                 MOV     AL,DL                   ;Pass proper phyical page
  1214.                 MOV     DX,WORD PTR ES:[BX+1]   ;Get handle
  1215.                 MOV     BX,WORD PTR [BP+SI+2]   ;Put page in proper register
  1216.                 PUSHF                           ;Save direction flag state
  1217.                 CLD                             ;Set assumed direction flag
  1218.                 CLC                             ;Set handle good flag
  1219.                 CALL    EMS_05                  ;Map page
  1220.                 POPF                            ;Get back flags
  1221.                 POP     DX
  1222.                 POP     CX                      ;Get count back
  1223.                 MOV     AX,WINDOW_SEG           ;Get window segment
  1224.                 OR      DL,DL                   ;See if source or dest
  1225.                 JE      EMS_24_MOV_SET_S6       ;If destination, point to
  1226.                 ADD     AX,1024                 ;  2nd page. 1024 paragraphs
  1227. EMS_24_MOV_SET_S6:
  1228.                 MOV     ES,AX                   ;Set pointer to data
  1229. EMS_24_MOV_SET_EXIT:
  1230.                 MOV     DI,WORD PTR [BP+SI]     ;Load offset
  1231.                 POP     DX
  1232.                 POP     BX
  1233.                 POP     AX
  1234.                 RET
  1235. EMS_24_MOV_SET_CONV1:
  1236.                 MOV     DI,WORD PTR [BP+SI+2]
  1237.                 MOV     ES,DI
  1238.                 JMP     SHORT EMS_24_MOV_SET_EXIT
  1239. EMS_24_MOV_SET  ENDP
  1240. ;----------------------------------------------------------------------
  1241. ;Check parameters for move or exchange
  1242. ;Entry: es:si - pointer to memory descriptor
  1243. ;       bp+di - pointer to local store descriptor
  1244. ;          ch - number of extended pages needed
  1245. ;          cl - number of bytes into last extended page
  1246. ;Exit:  dx,ax - ending address if conventional
  1247. ;          ax - ending page if expanded
  1248. ;          dx - ending offset if expanded
  1249. ;----------------------------------------------------------------------
  1250. EMS_CHECK_MOV   PROC    NEAR
  1251.                 ASSUME  DS:CODE,ES:NOTHING
  1252.                 PUSH    BX
  1253.                 PUSH    CX
  1254.                 PUSH    DI
  1255.                 XOR     AX,AX
  1256.                 MOV     AL,CH                   ;Get number of pages needed
  1257.                 MOV     DI,AX                   ;Save number of pages in DI
  1258.                 XOR     CH,CH
  1259.                 MOV     AX,ES:[SI+5]            ;Get segment/page
  1260.                 MOV     BX,ES:[SI+3]            ;get offset
  1261.                 MOV     DL,ES:[SI]              ;Get memory type
  1262.                 OR      DL,DL                   ;See if EMS or low memory
  1263.                 JE      EMS_CHECK_MOV_CONV      ;jump if low memory
  1264.                 CMP     DL,1                    ;If not low mem make sure
  1265.                 JE      EMS_CHECK_MOV_S1        ;  EMS memory.
  1266.                 MOV     AH,98H                  ;Invalid memory type
  1267.                 JMP     EMS_CHECK_MOV_SET_ERR
  1268. EMS_CHECK_MOV_S1:
  1269.                 CMP     BX,3FFFH                ;Check for offset < 16K
  1270.                 JA      EMS_CHECK_MOV_ERR1
  1271. ;See if the handle owns enough pages to hold the region.
  1272.                 MOV     DX,ES:[SI+1]            ;Get handle
  1273.                 PUSH    CX
  1274.                 CALL    EMS_CHECK_HDL           ;Verify handle.
  1275.                 CALL    EMS_13                  ;Get number of pages owned
  1276.                 POP     CX                      ;  by handle
  1277.                 OR      AH,AH                   ;If error, set carry and
  1278.                 JNE     EMS_CHECK_MOV_SET_ERR   ;  return.
  1279.                 MOV     DX,BX                   ;save number of pages
  1280.                 MOV     BX,ES:[SI+5]            ;Get logical page number
  1281.                 MOV     AX,DI                   ;Copy number of pages needed
  1282.                 ADD     AX,BX                   ;Add starting page.
  1283.                 ADD     CX,ES:[SI+3]            ;Add start offset to remainder
  1284.                 DEC     CX                      ;  of the num of pages needed.
  1285.                 CMP     CX,16384
  1286.                 JL      EMS_CHECK_MOV_S4        ;If rem+offset > 16K add a
  1287.                 INC     AX                      ;  page to the num needed.
  1288.                 SUB     CX,16384
  1289. EMS_CHECK_MOV_S4:
  1290.                 CMP     AX,DX                   ;Compare to total number of
  1291.                 JG      EMS_CHECK_MOV_ERR3      ;  pages.
  1292.                 MOV     DX,CX                   ;Copy ending offset
  1293.                 XCHG    AX,DX                   ;Exchange offset and segment
  1294. EMS_CHECK_MOV_EXIT:
  1295.                 CLC                             ;Clear error flag
  1296. EMS_CHECK_MOV_EXIT1:
  1297.                 POP     DI                      ;Restore registers
  1298.                 MOV     [BP+DI],AX              ;Save offset
  1299.                 MOV     [BP+DI+2],DX            ;Save segnent/page
  1300.                 POP     CX
  1301.                 POP     BX
  1302.                 RET
  1303. EMS_CHECK_MOV_CONV:
  1304.                 MOV     CX,16                   ;convert segment into address
  1305.                 MUL     CX
  1306.                 ADD     AX,BX                   ;Add offset
  1307.                 ADC     DX,0
  1308.                 ADD     AX,WORD PTR [EMS_24_COUNT]      ;Add len to start addr
  1309.                 ADC     DX,WORD PTR [EMS_24_COUNT+2]
  1310.                 SUB     AX,1                    ;Decriment count
  1311.                 SBB     DX,0
  1312.                 JMP     SHORT EMS_CHECK_MOV_EXIT
  1313. EMS_CHECK_MOV_ERR1:
  1314.                 MOV     AH,95H                  ;offset too large
  1315. EMS_CHECK_MOV_SET_ERR:
  1316.                 STC                             ;Indicate error
  1317.                 JMP     SHORT EMS_CHECK_MOV_EXIT1
  1318. EMS_CHECK_MOV_ERR3:
  1319.                 MOV     AH,93H                  ;Not enough pages
  1320.                 JMP     SHORT EMS_CHECK_MOV_SET_ERR
  1321. EMS_CHECK_MOV ENDP
  1322. ;======================================================================
  1323. ;Function 25. Get Mappable Physical Address Array
  1324. ;======================================================================
  1325. EMS_25          PROC    NEAR
  1326.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  1327.                 CMP     AL,1                    ;assure subfunction 0 or 1.
  1328.                 JB      EMS_25_S1
  1329.                 JE      EMS_25_EXIT
  1330.                 MOV     AH,8FH                  ;Unknown subfunction
  1331.                 JMP     SHORT EMS_25_EXIT1
  1332. EMS_25_S1:      MOV     AX,WINDOW_SEG
  1333.                 XOR     CX,CX
  1334. EMS_25_L1:      MOV     ES:[DI],AX              ;write segment
  1335.                 MOV     ES:2[DI],CX             ;write segment number
  1336.                 ADD     AX,1024                 ;Point to next segment
  1337.                 ADD     DI,4
  1338.                 INC     CX                      ;Indicate next page
  1339.                 CMP     CX,3
  1340.                 JLE     EMS_25_L1
  1341. EMS_25_EXIT:    MOV     WORD PTR SS:[BP-2],4    ;replace saved CX with 4
  1342.                 XOR     AX,AX                   ;clear return code
  1343. EMS_25_EXIT1:   RET
  1344. EMS_25          ENDP
  1345. ;======================================================================
  1346. ;Function 26.  Get Expanded Memory Hardware Information
  1347. ;======================================================================
  1348. EMS_26          PROC    NEAR
  1349.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  1350.                 CMP     OS_ENABLED,1            ;Are OS funcctions enabled?
  1351.                 JNE     EMS_26_ERR1             ;No, exit
  1352.                 CMP     AL,1                    ;Subfunction 1, get page cnt
  1353.                 JB      EMS_26_0                ;Jmp to subfunction 0
  1354.                 JA      EMS_26_ERR2             ;If > 1, invalid subfunction.
  1355. EMS_26_1:       CALL    EMS_03                  ;Since raw page = normal page,
  1356.                 JMP     SHORT EMS_26_EXIT       ;  get normal page count.
  1357. EMS_26_0:       XOR     CX,CX
  1358.                 MOV     WORD PTR ES:[DI],1024   ;16K pages (1024 paragraphs)
  1359.                 MOV     ES:2[DI],CX             ;No alternate register sets
  1360.                 CALL    EMS_15_3                ;Get context area size
  1361.                 MOV     ES:4[DI],AX
  1362.                 MOV     ES:6[DI],CX             ;No DMA channels
  1363.                 MOV     ES:8[DI],CX             ;DMA channel operation
  1364.                 XOR     AX,AX                   ;clear return code
  1365. EMS_26_EXIT:    RET
  1366. EMS_26_ERR1:    MOV     AH,0A4H                 ;operating system denied
  1367.                 JMP     SHORT EMS_26_EXIT       ;  access.
  1368. EMS_26_ERR2:    MOV     AH,8FH                  ;Invalid subfunction
  1369.                 JMP     SHORT EMS_26_EXIT
  1370. EMS_26          ENDP
  1371. ;======================================================================
  1372. ;Function 27.  Get handle and allocate pages
  1373. ;======================================================================
  1374. EMS_27          PROC    NEAR
  1375.                 ASSUME  DS:CODE,ES:NOTHING
  1376.                 PUSH    BX                      ;Save register
  1377.                 CMP     BX,TOTAL_PAGES          ;Make sure request is not out
  1378.                 JLE     EMS_27_S1               ;  of range.
  1379.                 MOV     AH,87H                  ;Not enough pages in system
  1380.                 JMP     SHORT EMS_27_EXIT
  1381. EMS_27_S1:      PUSH    BX                      ;save num. of pages to alloc
  1382.                 XOR     DX,DX                   ;search for handle =-1 (unaloc)
  1383.                 DEC     DX
  1384.                 CLC
  1385.                 CALL    EMS_13                  ;get unallocated page count.
  1386.                 POP     CX
  1387.                 CMP     BX,CX                   ;check for enough free pages
  1388.                 JL      EMS_27_ERR1
  1389.                 MOV     DI,HANDLE_ARRAY         ;Assign handle
  1390.                 XOR     AX,AX                   ;search for free handles
  1391.                 MOV     DX,AX                   ;dx=0 at start of hndl search
  1392. EMS_27_L1:      CMP     AL,[DI]                 ;if handle id = 0 then that
  1393.                 JE      EMS_27_S2               ;  hndl has not been allocated.
  1394.                 ADD     DI,9                    ;Move di to point to next id.
  1395.                 INC     DX
  1396.                 CMP     DX,TOTAL_HANDLES        ;have we searched all handles?
  1397.                 JB      EMS_27_L1
  1398.                 MOV     AH,85H                  ;no free handles
  1399.                 JMP     SHORT EMS_27_EXIT
  1400. EMS_27_S2:      DEC     BYTE PTR [DI]           ;indicate that handle is used
  1401.                 MOV     BX,CX
  1402.                 CALL    EMS_ASSIGN              ;alloc pages, dx = new handle
  1403. EMS_27_EXIT:    POP     BX                      ;Restore register
  1404.                 RET
  1405. EMS_27_ERR1:    MOV     AH,88H
  1406.                 JMP     SHORT EMS_27_EXIT
  1407. EMS_27          ENDP
  1408. ;======================================================================
  1409. ;Function 28. Alternate Map Register Set
  1410. ;======================================================================
  1411. EMS_28_TBL      DB      8               ;Subfunction limit
  1412.                 DW      OFFSET EMS_28_0 ;Jump table for subfunctions
  1413.                 DW      OFFSET EMS_28_1
  1414.                 DW      OFFSET EMS_28_2
  1415.                 DW      OFFSET EMS_28_3
  1416.                 DW      OFFSET EMS_28_4
  1417.                 DW      OFFSET EMS_28_3
  1418.                 DW      OFFSET EMS_28_6
  1419.                 DW      OFFSET EMS_28_6
  1420.                 DW      OFFSET EMS_28_6
  1421. EMS_28          PROC    NEAR
  1422.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  1423.                 CMP     OS_ENABLED,1            ;See if function enabled
  1424.                 JNE     EMS_28_ERR1
  1425.                 MOV     DI,OFFSET EMS_28_TBL
  1426.                 CALL    EMS_DISPATCHER
  1427. EMS_28_EXIT:    RET
  1428. EMS_28_ERR1:    MOV     AH,0A4H                 ;operating system denied
  1429.                 JMP     SHORT EMS_28_EXIT       ;  access.
  1430. EMS_28          ENDP
  1431. ;----------------------------------------------------------------------
  1432. ;Function 28.0  Get Alternate Map Register Set
  1433. ;----------------------------------------------------------------------
  1434. EMS_28_0        PROC    NEAR
  1435.                 PUSH    DX
  1436.                 MOV     ES,ALT_MAP_PTRS         ;Get pointer
  1437.                 MOV     DI,ALT_MAP_PTRO
  1438.                 MOV     SS:[BP-10],ES
  1439.                 OR      DI,DI                   ;See if it is zero
  1440.                 JNE     EMS_28_0_S1
  1441.                 MOV     CX,ES                   ;If so, exit without saving
  1442.                 OR      CX,CX                   ;  page map array.
  1443.                 XOR     AX,AX                   ;Clear return code
  1444.                 JE      EMS_28_0_EXIT
  1445. EMS_28_0_S1:    PUSH    DI                      ;save original pointer
  1446.                 CALL    EMS_15_0                ;copy page map
  1447.                 POP     DI                      ;The return code will be
  1448. EMS_28_0_EXIT:  XOR     BL,BL                   ;  set by Function 15.0
  1449.                 POP     DX                      ;Indicate non-support for
  1450.                 RET                             ;  alternate mapping regs.
  1451. EMS_28_0        ENDP
  1452. ;----------------------------------------------------------------------
  1453. ;Function 28.1  Set Alternate Map Register Set
  1454. ;----------------------------------------------------------------------
  1455. EMS_28_1        PROC    NEAR
  1456.                 PUSH    BX
  1457.                 PUSH    DX
  1458.                 OR      BL,BL                   ;check bl = 0
  1459.                 JNE     EMS_28_1_ERR
  1460.                 MOV     ALT_MAP_PTRS,ES         ;Save mapping pointer
  1461.                 MOV     ALT_MAP_PTRO,DI
  1462.                 OR      DI,DI                   ;See if it is zero
  1463.                 JNE     EMS_28_1_S1
  1464.                 MOV     CX,ES                   ;If so, exit without restoring
  1465.                 OR      CX,CX                   ;  page map array.
  1466.                 JE      EMS_28_1_EXIT
  1467. EMS_28_1_S1:    PUSH    DS
  1468.                 MOV     SI,ES                   ;Put pointer into ds:si for
  1469.                 MOV     DS,SI                   ;  function 15.1 call.
  1470.                 ASSUME  DS:NOTHING
  1471.                 MOV     SI,DI                   ;DS:SI = ES:DI
  1472.                 CALL    EMS_15_1                ;Restore page map
  1473.                 POP     DS
  1474.                 ASSUME  DS:CODE
  1475. EMS_28_1_EXIT:  POP     DX
  1476.                 POP     BX
  1477.                 RET
  1478. EMS_28_1_ERR:   MOV     AH,9CH                  ;Alternate map register
  1479.                 JMP     SHORT EMS_28_EXIT       ;  sets not supported.
  1480. EMS_28_1        ENDP
  1481. ;----------------------------------------------------------------------
  1482. ;Function 28.2  Get Alternate Map Save Array Size
  1483. ;----------------------------------------------------------------------
  1484. EMS_28_2        PROC    NEAR
  1485.                 CALL    EMS_15_3                ;Get save array size.
  1486.                 MOV     DX,AX
  1487.                 RET
  1488. EMS_28_2        ENDP
  1489. ;----------------------------------------------------------------------
  1490. ;Function 28.3 and 28.5  Deallocate Map Register Set
  1491. ;----------------------------------------------------------------------
  1492. EMS_28_3        PROC    NEAR
  1493.                 XOR     BL,BL                   ;set bl = 0
  1494.                 XOR     AX,AX
  1495.                 RET
  1496. EMS_28_3        ENDP
  1497. ;----------------------------------------------------------------------
  1498. ;Function 28.4  Deallocate Alternate Map Register Set
  1499. ;----------------------------------------------------------------------
  1500. EMS_28_4        PROC    NEAR
  1501.                 OR      BL,BL                   ;See if zero page indicated
  1502.                 JNE     EMS_28_4_ERR1           ;  if not, error
  1503.                 XOR     AX,AX                   ;Clear return code.
  1504.                 MOV     ALT_MAP_PTRS,AX         ;Clear mapping pointer
  1505.                 MOV     ALT_MAP_PTRO,AX
  1506. EMS_28_4_EXIT:  RET
  1507. EMS_28_4_ERR1:  MOV     AH,9CH                  ;Alt register sets not
  1508.                 JMP     SHORT EMS_28_4_EXIT     ;  supported
  1509. EMS_28_4        ENDP
  1510. ;----------------------------------------------------------------------
  1511. ;Function 28.6-28.8  Unsupported Subfunctions
  1512. ;----------------------------------------------------------------------
  1513. EMS_28_6        PROC    NEAR
  1514.                 OR      BL,BL                   ;see if zero page indicated
  1515.                 JNE     EMS_28_6_ERR1           ;if not, error
  1516.                 XOR     AX,AX                   ;clear return code.
  1517. EMS_28_6_EXIT:  RET
  1518. EMS_28_6_ERR1:  MOV     AH,9CH                  ;Alt register sets not
  1519.                 JMP     SHORT EMS_28_6_EXIT     ;  supported
  1520. EMS_28_6        ENDP
  1521. ;======================================================================
  1522. ;Function 30.  OS/E Functions
  1523. ;======================================================================
  1524. EMS_30          PROC    NEAR
  1525.                 PUSH    DX
  1526.                 CMP     OS_PASS_LOW,0
  1527.                 JNE     EMS_30_S1
  1528.                 CMP     OS_PASS_HIGH,0
  1529.                 JE      EMS_30_S2               ;first call, create password.
  1530. EMS_30_S1:      CMP     OS_PASS_LOW,BX          ;Check password
  1531.                 JNE     EMS_30_ERR1
  1532.                 CMP     OS_PASS_HIGH,CX
  1533.                 JNE     EMS_30_ERR1
  1534.                 JMP     SHORT EMS_30_S3
  1535. EMS_30_S2:      PUSH    AX                      ;Read the system time using
  1536.                 XOR     AH,AH                   ;  bios int 1A function 00.
  1537.                 INT     1AH
  1538.                 MOV     AX,DX                   ;copy low word of time
  1539.                 INC     CX                      ;multiply by high word. Inc
  1540.                 MUL     CX                      ;to assure count <> 0.
  1541.                 MOV     OS_PASS_LOW,AX
  1542.                 MOV     OS_PASS_HIGH,DX
  1543.                 MOV     BX,AX                   ;Return password in BX,CX
  1544.                 MOV     SS:[BP-2],DX            ;Update CX on stack
  1545.                 POP     AX                      ;get back subfunction
  1546. EMS_30_S3:      CMP     AL,2                    ;return key function
  1547.                 JNE     EMS_30_S4
  1548.                 XOR     AX,AX                   ;Clear return code
  1549.                 MOV     OS_PASS_LOW,AX          ;Clear password
  1550.                 MOV     OS_PASS_HIGH,AX
  1551.                 MOV     OS_ENABLED,1            ;set op system flag
  1552.                 JMP     SHORT EMS_30_EXIT
  1553. EMS_30_S4:      CMP     AL,1                    ;Disable op system functions
  1554.                 JNE     EMS_30_S5
  1555.                 MOV     OS_ENABLED,0            ;Clear flag
  1556.                 JMP     SHORT EMS_30_EXIT
  1557. EMS_30_S5:      OR      AL,AL                   ;Enable op system functions
  1558.                 JNE     EMS_30_ERR2
  1559.                 MOV     OS_ENABLED,1            ;Set flag
  1560. EMS_30_EXIT:    XOR     AX,AX
  1561. EMS_30_EXIT1:   POP     DX
  1562.                 RET
  1563. EMS_30_ERR1:    MOV     AH,0A4H                 ;Access denied
  1564.                 JMP     SHORT EMS_30_EXIT1
  1565. EMS_30_ERR2:    MOV     AH,8FH                  ;Subfunction not defined
  1566.                 JMP     SHORT EMS_30_EXIT1
  1567. EMS_30          ENDP
  1568. ;======================================================================
  1569. ;Unsupported Function
  1570. ;======================================================================
  1571. EMS_UNSP        PROC    NEAR
  1572.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  1573.                 MOV     AH,91H                  ;Feature not supported.
  1574.                 RET
  1575. EMS_UNSP        ENDP
  1576. ;-----------------------------------------------------------------------------
  1577. ;Convert segment address into logical page number
  1578. ;Entry: ax - segment address to convert  EXIT: bl - logical page number
  1579. ;-----------------------------------------------------------------------------
  1580. EMS_SEG2LOG     PROC    NEAR
  1581.                 ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING
  1582.                 PUSH    CX
  1583.                 PUSH    DX
  1584.                 XOR     BX,BX                   ;clear logical sector number
  1585.                 MOV     DX,CS:WINDOW_SEG
  1586.                 MOV     CX,4
  1587. EMS_SEG2_L1:    CMP     AX,DX
  1588.                 JE      EMS_SEG2_FND
  1589.                 ADD     DX,400H
  1590.                 INC     BX
  1591.                 LOOP    EMS_SEG2_L1
  1592.                 MOV     AH,8BH                  ;segment not valid
  1593.                 STC
  1594.                 JMP     SHORT EMS_SEG2_EXIT
  1595. EMS_SEG2_FND:   CLC
  1596. EMS_SEG2_EXIT:  POP     DX
  1597.                 POP     CX
  1598.                 RET
  1599. EMS_SEG2LOG     ENDP
  1600. ;------------------------------------------------------------------------
  1601. ;EMS convert logical page to address
  1602. ;Entry: bx = logical page  dx = handle of page owner
  1603. ;Exit: dx,ax - absolute address of page. carry set - page not found
  1604. ;------------------------------------------------------------------------
  1605. EMS_LOG2PHY     PROC    NEAR
  1606.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  1607.                 PUSH    DI
  1608.                 MOV     DI,PAG_OWNER_TBL        ;Point to page owner table
  1609.                 MOV     CX,TOTAL_PAGES          ;Check entry for each page
  1610. EMS_LOG2P_L1:   CMP     BYTE PTR [DI],DL        ;See if owned by handle
  1611.                 JNE     EMS_LOG2P_S1
  1612.                 CMP     WORD PTR [DI+1],BX      ;See if this is the page
  1613.                 JE      EMS_LOG2P_S2            ;  we have been looking for.
  1614. EMS_LOG2P_S1:   ADD     DI,3
  1615.                 LOOP    SHORT EMS_LOG2P_L1
  1616.                 MOV     AH,8AH                  ;page out of range for handle
  1617.                 STC
  1618.                 JMP     SHORT EMS_LOG2PHY_EXIT
  1619. EMS_LOG2P_S2:   SUB     DI,PAG_OWNER_TBL        ;compute the phy page address
  1620.                 MOV     AX,DI
  1621.                 XOR     DX,DX                   ;Clear high word
  1622.                 MOV     CX,3                    ;Divide by size of each entry
  1623.                 DIV     CX
  1624.                 MOV     CX,16384                ;Mul page number by size of
  1625.                 MUL     CX                      ;  page.
  1626.                 ADD     AX,EXTEND_ADRL          ;Add starting address
  1627.                 ADC     DL,EXTEND_ADRH
  1628.                 XOR     DH,DH
  1629.                 CLC                             ;clear error flag
  1630. EMS_LOG2PHY_EXIT:
  1631.                 POP     DI
  1632.                 RET
  1633. EMS_LOG2PHY     ENDP
  1634. ;------------------------------------------------------------------------
  1635. ;EMS Assign pages  bx = number of pages needed  dx = handle to assign pages.
  1636. ;------------------------------------------------------------------------
  1637. EMS_ASSIGN      PROC    NEAR
  1638.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  1639.                 CMP     AX,TOTAL_PAGES          ;see if enough total pages
  1640.                 JG      EMS_ASSIGN_ERR2
  1641.                 PUSH    DX                      ;save handle
  1642.                 PUSH    BX                      ;save pages to add
  1643.                 MOV     DX,0FFFFH               ;load unassigned handle
  1644.                 CLC                             ;Get number of unassigned
  1645.                 CALL    EMS_13                  ;  pages.
  1646.                 POP     AX                      ;Get back number of pages
  1647.                 POP     DX                      ;Get back handle
  1648.                 CMP     BX,AX                   ;are there enough pages?
  1649.                 JL      EMS_ASSIGN_ERR1         ;No, return error code.
  1650.                 PUSH    AX                      ;Save number of pages to alloc
  1651.                 CLC                             ;Set handle found flag
  1652.                 CALL    EMS_13                  ;Get number of pages assigned
  1653.                 POP     AX                      ;Get back num pages requested
  1654.                 MOV     DI,PAG_OWNER_TBL        ;point to page owner table
  1655.                 MOV     CX,TOTAL_PAGES          ;Get size of the array
  1656.                 INC     CX                      ;Make sure loop complete
  1657. EMS_ASSIGN_L1:  OR      AX,AX                   ;See if we have assigned
  1658.                 JE      EMS_ASSIGN_S2           ;  enough pages.
  1659.                 CMP     BYTE PTR [DI],0FFH      ;see if page is unowned
  1660.                 JNE     EMS_ASSIGN_S1           ;Page owned, try another.
  1661.                 MOV     [DI],DL                 ;if so, assign it to the hndl
  1662.                 MOV     [DI+1],BX               ;Assign page number
  1663.                 INC     BX                      ;inc page number to assign
  1664.                 DEC     AX                      ;one less page needed.
  1665. EMS_ASSIGN_S1:  ADD     DI,3                    ;point to the next page entry
  1666.                 LOOP    EMS_ASSIGN_L1
  1667. EMS_ASSIGN_ERR1:
  1668.                 MOV     AH,88H                  ;not enough unallocated pages
  1669.                 STC                             ;set error flag
  1670.                 JMP     SHORT EMS_ASSIGN_EXIT
  1671. EMS_ASSIGN_ERR2:
  1672.                 MOV     AH,87H                  ;not enough pages in system
  1673.                 STC                             ;set error flag
  1674.                 JMP     SHORT EMS_ASSIGN_EXIT
  1675. EMS_ASSIGN_S2:  CLC
  1676.                 XOR     AX,AX                   ;Clear return code.
  1677. EMS_ASSIGN_EXIT:
  1678.                 RET
  1679. EMS_ASSIGN      ENDP
  1680. ;------------------------------------------------------------------------
  1681. ;EMS Deallocate pages
  1682. ;Entry: dx = handle
  1683. ;       bl = number of pages to deallocate
  1684. ;------------------------------------------------------------------------
  1685. EMS_DEALLOC     PROC    NEAR
  1686.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  1687.                 CMP     BL,0FFH                 ;See if clear all
  1688.                 JNE     EMS_DEALLOC_S0
  1689.                 XOR     BX,BX
  1690.                 JMP     SHORT EMS_DEALLOC_S1
  1691. EMS_DEALLOC_S0: XOR     BH,BH
  1692.                 PUSH    BX                      ;Save num of pages to dealloc
  1693.                 CLC
  1694.                 CALL    EMS_13                  ;Get num of pages owned
  1695.                 POP     AX                      ;Get back num pages to dealloc
  1696.                 SUB     BX,AX                   ;Sub dealloc from total
  1697. EMS_DEALLOC_S1: MOV     DI,PAG_OWNER_TBL        ;Point to the page owner table
  1698.                 MOV     CX,TOTAL_PAGES
  1699. EMS_DEALLOC_L1: CMP     [DI],DL                 ;compare handle
  1700.                 JNE     EMS_DEALLOC_S2          ;if not, keep looking
  1701.                 CMP     [DI+1],BX               ;compare page number if above
  1702.                 JB      EMS_DEALLOC_S2          ;  new limit, erase.  Else,
  1703.                 MOV     BYTE PTR [DI],0FFH      ;  keep looking
  1704.                 MOV     WORD PTR [DI+1],0FFFFH
  1705. EMS_DEALLOC_S2: ADD     DI,3                    ;Point to next entry
  1706.                 LOOP    EMS_DEALLOC_L1
  1707. EMS_DEALLOC_EXIT:
  1708.                 XOR     AH,AH                   ;Clear return code.
  1709.                 RET
  1710. EMS_DEALLOC     ENDP
  1711. ;-----------------------------------------------------------------------------
  1712. ;EMS Subfunction dispatcher
  1713. ;Entry: DI = pointer to jump table structure
  1714. ;-----------------------------------------------------------------------------
  1715. EMS_DISPATCHER  PROC    NEAR
  1716.                 ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING
  1717.                 CMP     AL,CS:[DI]                      ;Compare subfunction to limit
  1718.                 JA      EMS_DIS_ERR1            ;If above, error.
  1719.                 PUSH    BX                      ;Save BX
  1720.                 MOV     BL,AL                   ;Convert subfunction to
  1721.                 XOR     BH,BH                   ;  jump address.
  1722.                 SHL     BX,1
  1723.                 ADD     BX,DI                   ;Add offset into jump table
  1724.                 INC     BX                      ;Skip past limit
  1725.                 MOV     DI,BX                   ;Copy jump address pointer
  1726.                 POP     BX                      ;Restore BX
  1727.                 PUSH    CS:[DI]                 ;Save jump address
  1728.                 MOV     DI,SS:[BP-4]            ;Restore DI
  1729.                 RETN                            ;Jump to subfunction code.
  1730. EMS_DIS_ERR1:   MOV     AH,8FH                  ;Illegal subfunction
  1731.                 STC                             ;Set error flag
  1732.                 RET
  1733. EMS_DISPATCHER  ENDP
  1734. ;-----------------------------------------------------------------------------
  1735. ;EMS Check Handle
  1736. ;Entry: dx = handle to check  Exit: zero flag set - handle not found, ah = 83h
  1737. ;-----------------------------------------------------------------------------
  1738. EMS_CHECK_HDL   PROC    NEAR
  1739.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  1740.                 PUSH    DX
  1741.                 PUSH    BX
  1742.                 OR      DH,DH                   ;dh must be 0 for valid handle
  1743.                 JNE     EMS_CHECK_ERROR
  1744.                 XCHG    AX,DX                   ;Save ax
  1745.                 MOV     AH,9                    ;Convert handle into an index
  1746.                 MUL     AH                      ;  into the array
  1747.                 MOV     BX,AX                   ;copy to base register
  1748.                 ADD     BX,HANDLE_ARRAY         ;add base address of array
  1749.                 MOV     AX,DX                   ;restore ax
  1750.                 CMP     BYTE PTR [BX],0         ;If byte<>0, then good handle
  1751.                 JE      EMS_CHECK_ERROR
  1752.                 CLC                             ;clear error flag
  1753. EMS_CHECK_EXIT: POP     BX
  1754.                 POP     DX
  1755.                 RET
  1756. EMS_CHECK_ERROR:
  1757.                 MOV     AH,83H                  ;load error return code in ah
  1758.                 STC                             ;set error flag
  1759.                 JMP     SHORT EMS_CHECK_EXIT
  1760. EMS_CHECK_HDL   ENDP
  1761. ;------------------------------------------------------------------------
  1762. ;EMS exchange page
  1763. ;Entry: bl = window page to map    dl,ax = absolute address of page to map.
  1764. ;------------------------------------------------------------------------
  1765. EMS_EXCH_PAG    PROC    NEAR
  1766.                 ASSUME  CS:CODE,DS:NOTHING,ES:NOTHING
  1767.                 PUSH    CX
  1768.                 PUSH    SI
  1769.                 PUSH    DS
  1770.                 PUSH    ES
  1771.                 PUSH    CS                      ;point DS, ES to code segment
  1772.                 POP     DS
  1773.                 ASSUME  DS:CODE,ES:CODE
  1774.                 PUSH    DEST.BASE_ADRL          ;Save GTD data in case a
  1775.                 PUSH    SOURCE.BASE_ADRL        ;  reentrant call is made.
  1776.                 MOV     CH,DEST.BASE_ADRH
  1777.                 MOV     CL,SOURCE.BASE_ADRH
  1778.                 PUSH    CX
  1779.                 MOV     DI,OFFSET WINDOW_ADDR_BASE      ;Point to window addr
  1780.                 MOV     SI,MAP_ARRAY_PTR        ;Point to mapping array.
  1781.                 INC     SI
  1782.                 INC     SI
  1783.                 XOR     BH,BH                   ;Clear high byte of page num
  1784. ;Check to see if previous process was interrupted. If so, complete last move.
  1785.                 PUSH    BX                      ;Save page number
  1786.                 MOV     BL,MOVE_BUSY_FLAG       ;If not 0, this flag contains
  1787.                 OR      BL,BL                   ;  the page that was being
  1788.                 JE      EMS_EXCH_NOT_BUSY       ;  moved when the driver was
  1789.                 DEC     BL                      ;  interrupted.
  1790.                 PUSH    AX                      ;Save new address for a moment
  1791.                 PUSH    DX
  1792.                 MOV     AX,[DI+BX]              ;Load window address into
  1793.                 MOV     DL,[DI+BX+2]            ;  destination registers.
  1794.                 MOV     CX,SAVED_ADDR_LOW       ;Load physical page address
  1795.                 MOV     DH,SAVED_ADDR_HIGH      ;  into source registers.
  1796.                 CALL    EMS_MOVE_DATA           ;Move memory
  1797.                 MOV     MOVE_BUSY_FLAG,0        ;  busy flag.
  1798.                 POP     DX                      ;Get back new address
  1799.                 POP     AX
  1800. EMS_EXCH_NOT_BUSY:
  1801.                 POP     BX                      ;Get back page number
  1802.                 SAL     BX,1                    ;Convert page number into
  1803.                 SAL     BX,1                    ;  array index.
  1804.                 MOV     DH,1
  1805.                 CMP     AX,[SI+BX]              ;Check to see if page to be
  1806.                 JNE     EMS_EXCH_S1             ;  is already mapped in the
  1807.                 CMP     DX,[SI+BX+2]            ;  page.
  1808.                 JE      EMS_EXCH_EXIT           ;If so, exit.
  1809. EMS_EXCH_S1:    PUSH    AX                      ;Save new page address
  1810.                 PUSH    DX
  1811. ;Check to see if the address requested has already been mapped.
  1812.                 MOV     AX,[SI+BX]              ;Load address of current page
  1813.                 MOV     DX,[SI+BX+2]            ;  into destination registers.
  1814.                 OR      DH,DH                   ;See if this is the primary
  1815.                 JE      LOAD_PAGE               ;  page. No, don't save.
  1816.                 XOR     DH,DH                   ;Search for secondary pages
  1817.                 CALL    EMS_CHK_LOCAL           ;Check for same page locally
  1818.                 JC      LOAD_PAGE
  1819. ;Save page currently mapped.
  1820. STORE_PAGE:     MOV     CX,[DI+BX]              ;Load address of window
  1821.                 MOV     DH,[DI+BX+2]            ;  into source registers.
  1822.                 CALL    EMS_MOVE_DATA
  1823. ;Load in page from extended memory.
  1824. LOAD_PAGE:      POP     DX                      ;Pop new page address
  1825.                 POP     AX
  1826.                 MOV     DH,1                    ;Search for primary page.
  1827.                 CALL    EMS_CHK_LOCAL           ;See if page mapped elsewhere
  1828.                 MOV     CX,BX                   ;Copy page array index
  1829.                 INC     CX                      ;Make non-zero number
  1830.                 MOV     MOVE_BUSY_FLAG,CL       ;Busy = page being loaded
  1831.                 MOV     DH,1                    ;Set primary flag
  1832.                 MOV     [SI+BX+2],DX            ;Load new address into the
  1833.                 MOV     [SI+BX],AX              ;  page map array.
  1834.                 MOV     SAVED_ADDR_LOW,AX       ;Save address of page to be
  1835.                 MOV     SAVED_ADDR_HIGH,DL      ;  loaded.
  1836.                 JC      EMS_EXCH_EXIT           ;If map local, exit
  1837.                 MOV     CX,[DI+BX]              ;Load window address
  1838.                 MOV     DH,[DI+BX+2]
  1839.                 XCHG    AX,CX                   ;Put source and destination
  1840.                 XCHG    DL,DH                   ;  addresses in proper place.
  1841.                 CALL    EMS_MOVE_DATA           ;Move memory
  1842. EMS_EXCH_EXIT:  MOV     MOVE_BUSY_FLAG,0        ;Clear move busy flag
  1843.                 POP     CX                      ;Restore GDT data
  1844.                 MOV     SOURCE.BASE_ADRH,CL
  1845.                 MOV     DEST.BASE_ADRH,CH
  1846.                 POP     SOURCE.BASE_ADRL
  1847.                 POP     DEST.BASE_ADRL
  1848.                 POP     ES                      ;Restore registers
  1849.                 POP     DS
  1850.                 POP     SI
  1851.                 POP     CX
  1852.                 RET
  1853. EMS_EXCH_PAG    ENDP
  1854. ;-----------------------------------------------------------------------------
  1855. ;EMS CHK LOCAL compares address to addresses in map array.
  1856. ;  Entry:  DL,AX - address
  1857. ;          BX - Index into map array
  1858. ;-----------------------------------------------------------------------------
  1859. EMS_CHK_LOCAL   PROC    NEAR
  1860.                 PUSH    AX
  1861.                 PUSH    BX
  1862.                 PUSH    DX
  1863.                 PUSH    DI
  1864.                 OR      AX,AX                   ;If the current page is
  1865.                 JNE     EMS_CHK_LOC0            ;  unowned, don't do anything
  1866.                 OR      DL,DL                   ;  but set the local flag and
  1867.                 JE      EMS_CHK_LOC5            ;  exit.
  1868. EMS_CHK_LOC0:   MOV     DI,BX                   ;Copy page index
  1869.                 XOR     BX,BX                   ;Search the mapping table
  1870.                 MOV     CX,4                    ;  for the address to be
  1871. EMS_CHK_LOC1:   CMP     AX,[SI+BX]              ;  mapped. If found, use
  1872.                 JNE     EMS_CHK_LOC2            ;  the data from the mapped
  1873.                 CMP     DX,[SI+BX+2]            ;  page since it may be more
  1874.                 JE      EMS_CHK_LOC3            ;  accurate than the page
  1875. EMS_CHK_LOC2:   ADD     BX,4                    ;  in extended memory.
  1876.                 LOOP    EMS_CHK_LOC1
  1877.                 JMP     SHORT EMS_CHK_LOC6      ;Local page not found
  1878. ;Local page found. If not the same page, copy data from primary to secondary.
  1879. EMS_CHK_LOC3:   CMP     DI,BX                   ;Check for same page found
  1880.                 JE      EMS_CHK_LOC5            ;Same page, do nothing
  1881.                 OR      DH,DH                   ;See if found primary
  1882.                 JE      EMS_CHK_LOC4
  1883.                 XCHG    DI,BX
  1884. EMS_CHK_LOC4:   MOV     BYTE PTR [SI+BX+3],1    ;Set primary flag
  1885.                 XCHG    DI,BX
  1886.                 MOV     BYTE PTR [SI+BX+3],0    ;Reset primary flag
  1887.                 MOV     CL,12                   ;Convert indices to offsets
  1888.                 SAL     BX,CL                   ;  within page frame.
  1889.                 SAL     DI,CL
  1890.                 PUSH    SI                      ;Save map array pointer
  1891.                 MOV     SI,BX                   ;Put source offset into SI
  1892.                 PUSH    DS
  1893.                 MOV     AX,WINDOW_SEG
  1894.                 MOV     DS,AX                   ;Set the segments to the
  1895.                 MOV     ES,AX                   ;  page frame.
  1896.                 MOV     CX,8192                 ;8192 words or 16384 bytes
  1897.                 CLD                             ;Set direction
  1898.                 REP     MOVSW                   ;Move it
  1899.                 POP     DS
  1900.                 POP     SI
  1901. EMS_CHK_LOC5:   STC                             ;Indicate local page found
  1902. EMS_CHK_LOC_EXIT:
  1903.                 POP     DI
  1904.                 POP     DX
  1905.                 POP     BX
  1906.                 POP     AX
  1907.                 RET
  1908. EMS_CHK_LOC6:   CLC                             ;Indicate local page not fnd
  1909.                 JMP     SHORT EMS_CHK_LOC_EXIT
  1910. EMS_CHK_LOCAL   ENDP
  1911. ;-----------------------------------------------------------------------------
  1912. ;EMS MOVE DATA moves blocks of data using BIOS move block function.
  1913. ;  Entry:  DL,AX - destination address  CX,DH - source address.
  1914. ;-----------------------------------------------------------------------------
  1915. EMS_MOVE_DATA   PROC    NEAR
  1916.                 PUSH    CX
  1917.                 PUSH    SI
  1918.                 MOV     SI,CS
  1919.                 MOV     ES,SI
  1920.                 MOV     SI,OFFSET GDT           ;ES:SI point to GDT
  1921.                 MOV     DEST.BASE_ADRL,AX       ;store source address
  1922.                 MOV     DEST.BASE_ADRH,DL
  1923.                 MOV     SOURCE.BASE_ADRL,CX     ;store destination address
  1924.                 MOV     SOURCE.BASE_ADRH,DH
  1925.                 MOV     AH,87H                  ;BIOS move extended block
  1926.                 MOV     CX,2000H                ;move 8192 words
  1927.                 INT     15H                     ;call BIOS
  1928.                 POP     SI
  1929.                 POP     CX
  1930.                 RET
  1931. EMS_MOVE_DATA   ENDP
  1932. ;-----------------------------------------------------------------------------
  1933. ;Init1. code initializes memory below this address then returns.
  1934. ;-----------------------------------------------------------------------------
  1935. INITIALIZE1     PROC    NEAR
  1936. INIT1:          ASSUME  CS:CODE,DS:CODE,ES:CODE
  1937.                 MOV     DI,PAG_OWNER_TBL
  1938.                 MOV     AX,TOTAL_PAGES          ;Compute size of page owner
  1939.                 MOV     DX,3                    ;  table.
  1940.                 MUL     DX
  1941.                 MOV     CX,AX
  1942.                 XOR     AX,AX                   ;load ff's into page owner tbl
  1943.                 DEC     AX                      ;  because ff is invalid hndl.
  1944.                 REP     STOSB
  1945.                 MOV     AX,TOTAL_HANDLES        ;Compute size of handle array
  1946.                 MOV     AH,9                    ;9 bytes / handle
  1947.                 MUL     AH
  1948.                 MOV     CX,AX
  1949.                 XOR     AX,AX
  1950.                 REP     STOSW
  1951.                 MOV     DI,HANDLE_ARRAY         ;activate system handle
  1952.                 DEC     BYTE PTR [DI]
  1953.                 MOV     DI,MAP_ARRAY_PTR
  1954.                 MOV     CX,INT_SAVE_SIZE        ;Get number of save areas
  1955.                 INC     CX                      ;Add 1 for active map
  1956. EMS_INIT_L2:
  1957.                 MOV     WORD PTR [DI],0FFFFH    ;Mark space as free
  1958.                 INC     DI                      ;Move pointer past free flag
  1959.                 INC     DI
  1960.                 PUSH    CX
  1961.                 MOV     CX,8                    ;Clear save area
  1962.                 REP     STOSW
  1963.                 POP     CX
  1964.                 LOOP    EMS_INIT_L2
  1965.                 RET
  1966. INITIALIZE1     ENDP
  1967. ;======================  End of resident Code  =============================
  1968. DATA_START      =       $
  1969. VDISK_HEADER    DB      'VDISK  V'
  1970. ERRMSG          DB      'Not enough memory',13,10,'$'
  1971. ;===========================================================================
  1972. ;Initialize. This routine sets up the EMS driver.
  1973. ;===========================================================================
  1974. INITIALIZE      PROC    NEAR
  1975.                 ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  1976.                 PUSH    CS                      ;Parse command line
  1977.                 POP     ES
  1978.                 LDS     SI,[REQ_HEADADR]        ;get back addr of hdr
  1979.                 ASSUME  DS:NOTHING,ES:CODE
  1980.                 LDS     SI,DS:[SI.CONFIG_PTR]   ;Get pointer to config line
  1981.                 MOV     BH,1                    ;Look for first non-character
  1982.                 MOV     CX,80                   ;80 characters in line
  1983.                 CALL    SCAN_FOR                ;Scan for non-character.
  1984.                 OR      AH,AH                   ;see if found
  1985.                 JNE     CHK_FOR_VDISK           ;not found, skip remainder
  1986.                 XOR     BH,BH                   ;Look for next character
  1987.                 CALL    SCAN_FOR                ;Scan for character
  1988.                 OR      AH,AH                   ;see if found
  1989.                 JNE     CHK_FOR_VDISK           ;not found, skip remainder
  1990. ;-----------------------------------------------------------------------------
  1991. ;Non-blank line after driver name. Attempt to convert to memory size in Kbytes
  1992. ;-----------------------------------------------------------------------------
  1993.                 DEC     SI                      ;backup to 1st number
  1994.                 MOV     CX,5                    ;Max 5 numbers.
  1995.                 XOR     AX,AX                   ;Clear running total
  1996.                 MOV     DI,10                   ;Decimal conversion constant
  1997. INIT_LOOP1:     MOV     BL,DS:[SI]              ;Get number
  1998.                 INC     SI                      ;Point to next number.
  1999.                 SUB     BL,'0'                  ;Convert to number and see
  2000.                 JB      INIT_SKIP1              ;  if in range for a number.
  2001.                 CMP     BL,9
  2002.                 JA      INIT_SKIP1
  2003.                 XOR     BH,BH
  2004.                 MUL     DI                      ;Mul by 16 to convert to hex
  2005.                 ADD     AX,BX                   ;add to current total
  2006.                 LOOP    INIT_LOOP1
  2007. ;-----------------------------------------------------------------------------
  2008. ;Compute number of pages available for allocated memory.
  2009. ;-----------------------------------------------------------------------------
  2010. INIT_SKIP1:     XOR     DX,DX                   ;Clear high word for divide
  2011.                 MOV     DI,16                   ;Divide number of Kbytes
  2012.                 DIV     DI                      ;  by 16 Kbytes / page.
  2013.                 OR      AX,AX                   ;if number less than 1 page
  2014.                 JE      CHK_FOR_VDISK           ;  use default 24 pages.
  2015.                 MOV     CS:TOTAL_PAGES,AX       ;Save number of pages.
  2016. ;-----------------------------------------------------------------------------
  2017. ;Check for vdisk driver by reading int 19 vector.
  2018. ;-----------------------------------------------------------------------------
  2019. CHK_FOR_VDISK:  PUSH    CS                      ;Set DS = CS
  2020.                 POP     DS
  2021.                 ASSUME  DS:CODE
  2022.                 MOV     AX,3519H                ;Get interrupt vector 19
  2023.                 INT     21H                     ;ES points to VDISK segment
  2024.                 MOV     DI,12H                  ;VDISK header at offset 12h
  2025.                 MOV     SI,OFFSET VDISK_HEADER
  2026.                 MOV     CX,8                    ;8 characters in header
  2027.                 XOR     BX,BX                   ;assume no memory used by vdisk
  2028.                 REPE    CMPSB                   ;Compare header
  2029.                 JNE     CHK_EXT_MEM
  2030. ;-----------------------------------------------------------------------------
  2031. ;If VDISK present, read top of available memory from inside VDISK driver.
  2032. ;-----------------------------------------------------------------------------
  2033.                 MOV     SI,2CH                  ;load offset of memory used
  2034.                 MOV     AX,ES:[SI]              ;Get amount of memory used by
  2035.                 MOV     DL,ES:[SI+2]            ;  vdisk
  2036.                 SUB     DL,10H                  ;Subtract 1 Mbyte starting adr
  2037.                 XOR     DH,DH
  2038.                 MOV     BX,16384                ;Convert to 16k pages
  2039.                 DIV     BX
  2040.                 MOV     BX,AX                   ;save result in BX
  2041. ;-----------------------------------------------------------------------------
  2042. ;Find upper limit of extended memory.
  2043. ;-----------------------------------------------------------------------------
  2044. CHK_EXT_MEM:    PUSH    CS                      ;ES = CS
  2045.                 POP     ES
  2046.                 ASSUME  ES:CODE
  2047.                 MOV     AH,88H                  ;Get extended memory function
  2048.                 CLC                             ;clr err flag. (fix IBMCACHE)
  2049.                 INT     15H                     ;Returns extended memory in
  2050.                 JC      EXTEND_ERROR            ;  1k pages.
  2051.                 MOV     CL,4                    ;Convert number of 1k pages
  2052.                 SAR     AX,CL                   ;  into number of 16k pages.
  2053.                 SUB     AX,TOTAL_PAGES          ;See if there is enough room.
  2054.                 JL      EXTEND_ERROR
  2055.                 CMP     AX,BX                   ;Subtract memory used by vdisk
  2056.                 JGE     EXTEND_MEM_OK1
  2057. EXTEND_ERROR:   JMP     DISP_ERR                ;Error, abort instalation.
  2058. ;-----------------------------------------------------------------------------
  2059. ;Compute the starting address of the extended memory area for int 15.
  2060. ;-----------------------------------------------------------------------------
  2061. EXTEND_MEM_OK1: PUSH    CS                      ;  ES = CS
  2062.                 POP     ES                      ;Convert memory req. to 1k
  2063.                 ASSUME  ES:CODE                 ;  pages then store this
  2064.                 MOV     CL,4                    ;  value for use as the new
  2065.                 SAL     AX,CL                   ;  extended memory limit.
  2066.                 MOV     EXT_MEM_LIMIT,AX
  2067.                 MOV     CX,1024                 ;Convert number of 1024
  2068.                 MUL     CX                      ;  byte pages to absolute adr
  2069.                 ADD     DL,10H                  ;Add starting address of
  2070.                 MOV     EXTEND_ADRL,AX          ;  extended memory and
  2071.                 MOV     EXTEND_ADRH,DL          ;  save.
  2072. ;-----------------------------------------------------------------------------
  2073. ;Initialize the variables and pointers needed to emulate the EMS spec.
  2074. ;-----------------------------------------------------------------------------
  2075.                 MOV     CX,OFFSET DATA_START    ;Get end of installed code.
  2076.                 MOV     PAG_OWNER_TBL,CX        ;Save pointer to page table
  2077.                 MOV     AX,TOTAL_PAGES          ;Get number of pages
  2078.                 MOV     AH,3                    ;Compute the size of the
  2079.                 MUL     AH                      ;  page frame.
  2080.                 ADD     CX,AX                   ;Add to current pointer
  2081.                 MOV     HANDLE_ARRAY,CX         ;Save pointer to handle array
  2082.                 MOV     AX,TOTAL_HANDLES        ;compute size of handle
  2083.                 MOV     AH,9                    ;  array using 9 bytes / hdl.
  2084.                 MUL     AH
  2085.                 ADD     CX,AX
  2086.                 MOV     MAP_ARRAY_PTR,CX        ;map array 18 bytes. 4 arrays.
  2087.                 MOV     AX,INT_SAVE_SIZE        ;Get number of save areas
  2088.                 INC     AX                      ;Add 1 for active map
  2089.                 MOV     AH,18                   ;Compute size of internal
  2090.                 MUL     AH                      ;  save array using 18 bytes
  2091.                 ADD     AX,CX                   ;  per save area
  2092. ;-----------------------------------------------------------------------------
  2093. ;Compute the segment address of the page frame
  2094. ;-----------------------------------------------------------------------------
  2095.                 ADD     AX,15                   ;Add 15 to round to next seg
  2096.                 MOV     CL,4                    ;convert offset into a
  2097.                 SHR     AX,CL                   ;segment value
  2098.                 MOV     BX,CS                   ;get code segment
  2099.                 ADD     AX,BX                   ;add code seg to current ptr
  2100.                 MOV     WINDOW_SEG,AX           ;store starting segment of ems
  2101.                 PUSH    AX                      ;  page frame.
  2102. ;-----------------------------------------------------------------------------
  2103. ;Generate and store abolute addresses of window pages.
  2104. ;-----------------------------------------------------------------------------
  2105.                 MOV     DX,16                   ;Convert segment into
  2106.                 MUL     DX                      ;  absolute address.
  2107.                 MOV     DI,OFFSET WINDOW_ADDR_BASE
  2108.                 MOV     CX,4
  2109. EMS_INIT_L3:    MOV     [DI],AX                 ;Save absolute address
  2110.                 MOV     [DI+2],DX
  2111.                 ADD     AX,16384                ;point to next page address
  2112.                 ADC     DX,0
  2113.                 ADD     DI,4                    ;point to next save address
  2114.                 LOOP    EMS_INIT_L3
  2115. ;-----------------------------------------------------------------------------
  2116. ;Write the memory requirments to the device driver header
  2117. ;-----------------------------------------------------------------------------
  2118.                 POP     BX                      ;Get back seg start of window
  2119.                 ADD     BX,1000H                ;Add 64 Kbytes.
  2120.                 XOR     AX,AX                   ;Start at offset 0
  2121.                 PUSH    ES
  2122.                 CALL    LOAD_HEADER             ;Load memory requirments into
  2123.                 POP     ES                      ;  request header.
  2124.                 MOV     DX,OFFSET PROGRAM       ;Print copyright
  2125.                 MOV     AH,9
  2126.                 INT     21H
  2127. ;-----------------------------------------------------------------------------
  2128. ;Vector interrupt 15h to reserve the extended memory.
  2129. ;-----------------------------------------------------------------------------
  2130.                 PUSH    ES
  2131.                 MOV     AX,3515H                ;Get interrupt vector 15
  2132.                 INT     21H
  2133.                 MOV     OLD_INT15HO,BX          ;save vector
  2134.                 MOV     OLD_INT15HS,ES
  2135.                 POP     ES
  2136.                 MOV     AX,2515H                ;Set interrupt vector 15
  2137.                 MOV     DX,OFFSET INT_15H
  2138.                 INT     21H                     ;Call DOS
  2139. ;-----------------------------------------------------------------------------
  2140. ;Vector the 67h interrupt to the driver. Jump to final installation code.
  2141. ;-----------------------------------------------------------------------------
  2142.                 MOV     AX,2567H                ;Set interrupt vector 67
  2143.                 MOV     DX,OFFSET INT_67H
  2144.                 INT     21H                     ;Call DOS
  2145.                 JMP     INIT1                   ;jump to final init. code.
  2146. ;-----------------------------------------------------------------------------
  2147. ;error routine to abort instalation.
  2148. ;-----------------------------------------------------------------------------
  2149. DISP_ERR:       MOV     DX,OFFSET ERRMSG        ;Tell user that the driver is
  2150.                 MOV     AH,9                    ;  not loaded.
  2151.                 INT     21H
  2152.                 MOV     AX,3000H                ;Get DOS version
  2153.                 INT     21H
  2154.                 XCHG    AL,AH                   ;Put number in proper order
  2155.                 CMP     AX,31EH                 ;See if DOS 3.3
  2156.                 MOV     AX,OFFSET DRIVER_END    ;Offset of device driver code
  2157.                 MOV     BX,CS                   ;If >3.3, abort install with
  2158.                 JB      ERROR_ABORT_SKIP        ; 0 memory. Otherwise leave
  2159.                 XOR     AX,AX                   ;  driver stub installed.
  2160. ERROR_ABORT_SKIP:
  2161.                 CALL    LOAD_HEADER             ;Load into request header
  2162.                 MOV     AX,8002                 ;Indicate error in the
  2163.                 RET                             ;  driver return code.
  2164. ;-----------------------------------------------------------------------------
  2165. ;LOADHEADER loads the amount of memory needed into the request header.
  2166. ;-----------------------------------------------------------------------------
  2167. LOAD_HEADER     PROC    NEAR
  2168.                 LES     DI,[REQ_HEADADR]                ;get addr of req hdr
  2169.                 MOV     WORD PTR ES:[DI.ADDRESS],AX     ;Store offset and
  2170.                 MOV     WORD PTR ES:[DI.ADDRESS+2],BX   ;  code segment.
  2171.                 RET
  2172. LOAD_HEADER     ENDP
  2173. ;-----------------------------------------------------------------------------
  2174. ;ScanFor - scans for first (non)occurance of character in line.
  2175. ; Entry -  BH - 0 = scan for non character, 1 = scan for character.
  2176. ;          DS:SI - string to scan.   CX - length of string
  2177. ; Exit  -  AH - 1 = end of line found.
  2178. ;-----------------------------------------------------------------------------
  2179. SCAN_FOR        PROC    NEAR
  2180.                 XOR     AH,AH                   ;Clear found flag
  2181. SCAN_LOOP1:     LODSB                           ;Get character
  2182.                 OR      BH,BH                   ;see if first match or
  2183.                 JE      SCAN_SKIP1              ;  mismatch. 0 = match
  2184.                 CMP     AL,20H                  ;Check for noncharacter.
  2185.                 JLE     SCAN_SKIP4
  2186.                 JMP     SHORT SCAN_SKIP2
  2187. SCAN_SKIP1:     CMP     AL,20H                  ;Check for character
  2188.                 JG      SCAN_SKIP4
  2189. SCAN_SKIP2:     CMP     AL,13                   ;Check for CR
  2190.                 JE      SCAN_SKIP3
  2191.                 CMP     AL,10                   ;Check for LF
  2192.                 JE      SCAN_SKIP3
  2193.                 LOOP    SCAN_LOOP1
  2194. SCAN_SKIP3:     INC     AH                      ;character not found
  2195. SCAN_SKIP4:     RET
  2196. SCAN_FOR        ENDP
  2197. END_OF_CODE     =       $
  2198. INITIALIZE      ENDP
  2199. CODE            ENDS
  2200.                 END
  2201.