home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 19 / CD_ASCQ_19_010295.iso / dos / prg / midas / ems.asm < prev    next >
Assembly Source File  |  1994-08-06  |  24KB  |  907 lines

  1. ;*    EMS.ASM
  2. ;*
  3. ;* EMS heap manager, v1.00
  4. ;*
  5. ;* Copyright 1994 Petteri Kangaslampi and Jarno Paananen
  6. ;*
  7. ;* This file is part of the MIDAS Sound System, and may only be
  8. ;* used, modified and distributed under the terms of the MIDAS
  9. ;* Sound System license, LICENSE.TXT. By continuing to use,
  10. ;* modify or distribute this file you indicate that you have
  11. ;* read the license and understand and accept it fully.
  12. ;*
  13.  
  14.  
  15. P386
  16. IDEAL
  17. JUMPS
  18.  
  19.  
  20. INCLUDE "lang.inc"
  21. INCLUDE "errors.inc"
  22. INCLUDE "ems.inc"
  23. INCLUDE "mmem.inc"
  24.  
  25.  
  26.  
  27. DATASEG
  28.  
  29. emsHandles    DD    ?        ; pointer to first EMS handle
  30. emsSaveArray    DD    ?        ; EMS Page Map Save Array pointer
  31. emsPageFrame    DW    ?        ; EMS Page Frame segment
  32. emsIsSafe    DW    ?        ; emsSafe flag
  33. emsMapped    DW    4 dup (?)    ; from which handle are pages
  34.                     ; mapped
  35. emsMemPtr       DD      ?               ; temporary pointer used by EMS
  36.                                         ; Heap Manager functions
  37.  
  38. IDATASEG
  39. EMMname     DB    "EMMXXXX0"      ; EMM device name
  40. EMMNAMELEN = 8                ; length of EMM device name
  41.  
  42.  
  43.  
  44.  
  45.  
  46. CODESEG
  47.  
  48.  
  49. ;/***************************************************************************\
  50. ;*
  51. ;* Function:     int emsInit(int *emmOK);
  52. ;*
  53. ;* Description:  Initializes EMS heap. Must be called before other EMS heap
  54. ;*               manager functions.
  55. ;*
  56. ;* Input:        int *emmOK              pointer to variable containing EMM
  57. ;*                                       status
  58. ;*
  59. ;* Returns:      MIDAS error code.
  60. ;*               *emmOK contains 1 if Expanded Memory Manager was found (EMS
  61. ;*               initialized succesfully) or 0 if not. Note that the lack
  62. ;*               of Expanded Memory Manager is _not_ an error.
  63. ;*
  64. ;\***************************************************************************/
  65.  
  66. PROC    emsInit         FAR     emmOK : dword
  67. USES    si,di
  68.  
  69.     cld
  70.  
  71.     mov    ax,3567h        ; get EMM interrupt vector
  72.     int    21h
  73.  
  74.     mov    bx,0Ah
  75.     mov    cx,EMMNAMELEN        ; offset 0Ah of the interrupt vector
  76.         xor     si,si                   ; si = offset to EMM driver name str
  77.  
  78.         ; offset 0Ah in the EMM interrupt vector segment should contain the
  79.         ; driver name, or else it does not point to a valid EMM
  80.  
  81. @@cmp:
  82.         mov     al,[EMMname+si]         ; get character from string
  83.         inc     si
  84.  
  85.         cmp     [es:bx],al              ; compare it to EMM driver string
  86.         jne     @@noemm                 ; if different, there is no EMM
  87.     inc    bx
  88.     loop    @@cmp
  89.  
  90.     mov    ah,40h            ; EMS Get Status function
  91.     int    67h
  92.         test    ah,ah                   ; non-zero status means error
  93.         jnz     @@emmerr
  94.  
  95.     mov    ah,41h            ; EMS Get Page Frame function
  96.     int    67h
  97.         test    ah,ah                   ; non-zero status means error
  98.         jnz     @@emmerr
  99.     mov    [emsPageFrame],bx    ; save Page Frame segment address
  100.  
  101.     mov    ax,4E03h        ; EMS Get Size of Page Map Save Array
  102.     int    67h
  103.         test    ah,ah                   ; non-zero status means error
  104.         jnz     @@emmerr
  105.  
  106.         ; allocate memory for EMS Save Array:
  107.         call    memAlloc LANG, ax, seg emsSaveArray offset emsSaveArray
  108.         test    ax,ax
  109.         jnz     @@err
  110.  
  111.     mov    [emsHandles],0        ; no EMS handles allocated
  112.     mov    [emsIsSafe],0
  113.  
  114.         les     bx,[emmOK]              ; store 1 in *emmOK to mark that EMS
  115.         mov     [word es:bx],1          ; can be used
  116.  
  117.         xor     ax,ax                   ; success
  118.     jmp    @@done
  119.  
  120. @@noemm:
  121.         les     bx,[emmOK]              ; store 0 in *emmOK to mark that EMS
  122.         mov     [word es:bx],0          ; can not be used
  123.  
  124.         xor     ax,ax                   ; success
  125.         jmp     @@done
  126.  
  127. @@emmerr:
  128.         ; Expanded Memory Manager internal error:
  129.         mov     ax,errEMMFailure
  130.  
  131. @@err:
  132.         ERROR   ID_emsInit
  133.  
  134. @@done:
  135.     ret
  136. ENDP
  137.  
  138.  
  139.  
  140.  
  141. ;/***************************************************************************\
  142. ;*
  143. ;* Function:     int emsClose(void);
  144. ;*
  145. ;* Description:  Uninitializes EMS heap freeing all allocated blocks. Must be
  146. ;*               called before program exits if emsInit() has been called.
  147. ;*
  148. ;* Returns:      MIDAS error code
  149. ;*
  150. ;\***************************************************************************/
  151.  
  152. PROC    emsClose    FAR
  153. USES    si
  154.  
  155. @@free:
  156.     cmp    [emsHandles],0        ; any EMS handles allocated?
  157.     je    @@empty
  158.  
  159.     les    bx,[emsHandles]
  160.     lgs    si,[es:bx+emsHandle.block]    ; point gs:si to first block
  161.  
  162. @@fblk: cmp    [gs:si+emsBlock.used],1     ; is block used?
  163.     je    @@dealloc            ; if is, deallocate it
  164.     cmp    [gs:si+emsBlock.next],0     ; is there a next block?
  165.     je    @@err                ; if not, heap is corrupted
  166.     lgs    si,[gs:si+emsBlock.next]    ; point gs:si to next block
  167.     jmp    @@fblk
  168.  
  169. @@dealloc:
  170.         push    gs
  171.     call    emsFree LANG, gs si    ; free this block
  172.         pop     gs
  173.         test    ax,ax
  174.         jnz     @@err
  175.  
  176.     jmp    @@free            ; continue deallocating blocks
  177.  
  178.  
  179. @@empty:
  180.         ; deallocate Page Map Save Array:
  181.     call    memFree LANG, [emsSaveArray]
  182.         test    ax,ax
  183.         jnz     @@err
  184.  
  185.         xor     ax,ax                   ; success
  186.         jmp     @@done
  187.  
  188. @@err:
  189.         ERROR   ID_emsClose
  190.  
  191. @@done:
  192.     ret
  193. ENDP
  194.  
  195.  
  196.  
  197.  
  198. ;/***************************************************************************\
  199. ;*
  200. ;* Function:     int emsAlloc(ushort bytes, emsBlock **ems);
  201. ;*
  202. ;* Description:  Allocates an EMS memory block
  203. ;*
  204. ;* Input:        ushort bytes            number of bytes to be allocated
  205. ;*               emsBlock **ems          Pointer to EMS Block pointer
  206. ;*
  207. ;* Returns:      MIDAS error code.
  208. ;*               EMS block pointer stored in *ems, NULL if failure
  209. ;*
  210. ;\***************************************************************************/
  211.  
  212. PROC    emsAlloc        FAR     bytes : word, ems : dword
  213. USES    si, di
  214. LOCAL   handle : dword
  215.  
  216.     cmp    [emsHandles],0        ; are there any EMS handles allocated?
  217.     je    @@newhandle        ; if not, allocate
  218.  
  219.     mov    cx,[bytes]
  220.  
  221.     lgs    si,[emsHandles]     ; point gs:si to first handle
  222. @@hlp:
  223.     les    bx,[gs:si+emsHandle.block]    ; point es:bx to first block
  224.                         ; in handle
  225. @@blp:
  226.     cmp    [es:bx+emsBlock.used],0     ; is current block in use?
  227.     je    @@unused
  228. @@nextblk:
  229.     cmp    [es:bx+emsBlock.next],0     ; is there a next block?
  230.     je    @@lastblk
  231.     les    bx,[es:bx+emsBlock.next]    ; point es:bx to next block
  232.     jmp    @@blp                ; and continue searching
  233.  
  234. @@unused:
  235.     cmp    [es:bx+emsBlock.bytes],cx    ; is this unused block long
  236.     jb    @@nextblk            ; long enough?
  237.     je    @@blksame            ; if same length, don't alloc
  238.                         ; a new block
  239.         ; allocate memory for new block:
  240.     push    cx bx es
  241.         call    memAlloc LANG, SIZE emsBlock, seg emsMemPtr offset emsMemPtr
  242.     pop    es bx cx
  243.         test    ax,ax
  244.         jnz     @@err
  245.  
  246.     push    ds
  247.  
  248.         lds     di,[emsMemPtr]                  ; point ds:di to new block
  249.  
  250.     mov    eax,[es:bx+emsBlock.next]    ; add this new block after
  251.     mov    [ds:di+emsBlock.next],eax    ; the current empty block
  252.     lgs    si,[es:bx+emsBlock.next]
  253.     mov    [word gs:si+emsBlock.prev],di
  254.     mov    [word gs:si+2+emsBlock.prev],ds
  255.     mov    [word es:bx+emsBlock.next],di
  256.     mov    [word es:bx+2+emsBlock.next],ds
  257.     mov    [word ds:di+emsBlock.prev],bx
  258.     mov    [word ds:di+2+emsBlock.prev],es
  259.  
  260.     mov    eax,[es:bx+emsBlock.handle]    ; copy EMS handle pointer
  261.     mov    [ds:di+emsBlock.handle],eax
  262.     mov    [ds:di+emsBlock.used],0     ; new block is not used
  263.  
  264.     mov    ax,[es:bx+emsBlock.addr]    ; address of this block is
  265.     add    ax,cx                ; address of the previous
  266.     mov    [ds:di+emsBlock.addr],ax    ; + bytes
  267.  
  268.     mov    ax,[es:bx+emsBlock.bytes]
  269.     sub    ax,cx                ; decrease number of bytes
  270.     mov    [ds:di+emsBlock.bytes],ax
  271.  
  272.     mov    [es:bx+emsBlock.bytes],cx    ; size of current block is
  273.     mov    [es:bx+emsBlock.used],1     ; [bytes] and it is in use
  274.  
  275.     pop    ds
  276.     jmp    @@ok                ; block allocated
  277.  
  278. @@blksame:
  279.     mov    [es:bx+emsBlock.used],1     ; block sizes are the same
  280.     jmp    @@ok                ; - only used status needs
  281.                         ; to be changed.
  282.  
  283.  
  284.  
  285. @@lastblk:
  286.     mov    ax,[es:bx+emsBlock.addr]    ; address in handle
  287.     add    ax,[es:bx+emsBlock.bytes]    ; plus number of bytes
  288.     neg    ax                ; negated == bytes free
  289.     cmp    ax,cx                ; enough space after this blk?
  290.     jae    @@addblk            ; if is, add new block here
  291.  
  292.     cmp    [gs:si+emsHandle.next],0    ; is there a next handle?
  293.     je    @@newhandle            ; if not, allocate new
  294.  
  295.     lgs    si,[gs:si+emsHandle.next]    ; continue searching for space
  296.     jmp    @@hlp                ; from next handle
  297.  
  298.  
  299. @@addblk:
  300.         ; allocate memory for new block:
  301.     push    cx bx es
  302.         call    memAlloc LANG, SIZE emsBlock, seg emsMemPtr offset emsMemPtr
  303.     pop    es bx cx
  304.         test    ax,ax
  305.         jnz     @@err
  306.  
  307.         push    ds
  308.  
  309.         lds     di,[emsMemPtr]                  ; point ds:di to new block
  310.  
  311.     mov    ax,[es:bx+emsBlock.addr]    ; address of new block
  312.     add    ax,[es:bx+emsBlock.bytes]
  313.     mov    [ds:di+emsBlock.addr],ax
  314.     mov    [ds:di+emsBlock.bytes],cx    ; number of bytes in new block
  315.  
  316.     mov    [ds:di+emsBlock.next],0     ; this is the last block
  317.     mov    [word ds:di+emsBlock.prev],bx    ; previous block is the
  318.     mov    [word ds:di+2+emsBlock.prev],es ; current one
  319.     mov    [word es:bx+emsBlock.next],di    ; next block to current one is
  320.     mov    [word es:bx+2+emsBlock.next],ds ; the new one
  321.  
  322.     mov    [ds:di+emsBlock.used],1     ; new block is in use
  323.     mov    eax,[es:bx+emsBlock.handle]    ; new block has the same
  324.     mov    [ds:di+emsBlock.handle],eax    ; handle as the current one
  325.  
  326.     mov    bx,di
  327.     mov    ax,ds                ; return block pointer in
  328.     mov    es,ax                ; es:bx
  329.  
  330.     pop    ds
  331.     jmp    @@ok
  332.  
  333.  
  334. @@newhandle:
  335.         ; allocate EMS pages:
  336.         call    emsAllocPages LANG, seg emsMemPtr offset emsMemPtr
  337.         test    ax,ax
  338.         jnz     @@err
  339.  
  340.         mov     eax,[emsMemPtr]
  341.         mov     [handle],eax
  342.  
  343.         ; allocate memory for EMS block:
  344.         call    memAlloc LANG, SIZE emsBlock, seg emsMemPtr offset emsMemPtr
  345.         test    ax,ax
  346.         jnz     @@err
  347.  
  348.         les     bx,[emsMemPtr]          ; point es:bx to new block
  349.  
  350.     mov    [es:bx+emsBlock.addr],0 ; in the beginning of handle area
  351.     mov    ax,[bytes]
  352.     mov    [es:bx+emsBlock.bytes],ax
  353.     mov    [es:bx+emsBlock.next],0     ; no next block
  354.     mov    [es:bx+emsBlock.prev],0     ; no previous block
  355.     mov    [es:bx+emsBlock.used],1     ; block is in use
  356.     mov    eax,[handle]
  357.     mov    [es:bx+emsBlock.handle],eax
  358.  
  359.     lgs    si,[handle]
  360.     mov    [word gs:si+emsHandle.block],bx     ; add block to handle
  361.     mov    [word gs:si+2+emsHandle.block],es
  362.  
  363.  
  364. @@ok:   ; es:bx points to allocated EMS block
  365.  
  366.         lgs     si,[ems]
  367.         mov     [word gs:si],bx         ; store EMS block pointer to *ems
  368.         mov     [word gs:si+2],es
  369.  
  370.         xor     ax,ax                   ; success
  371.         jmp     @@done
  372.  
  373. @@err:
  374.         les     bx,[ems]
  375.         mov     [dword es:bx],0         ; store NULL to *ems
  376.  
  377.         ERROR   ID_emsAlloc
  378.  
  379. @@done:
  380.     ret
  381. ENDP
  382.  
  383.  
  384.  
  385.  
  386.  
  387. ;/***************************************************************************\
  388. ;*
  389. ;* Function:     int emsFree(emsBlock *ems);
  390. ;*
  391. ;* Description:  Deallocates an EMS block allocated with emsAlloc
  392. ;*
  393. ;* Input:        emsBlock *ems           pointer to block to be deallocated
  394. ;*
  395. ;* Returns:      MIDAS error code
  396. ;*
  397. ;\***************************************************************************/
  398.  
  399. PROC    emsFree     FAR    ems : dword
  400. LOCAL    handle : dword
  401. USES    si,di
  402.  
  403.     les    bx,[ems]
  404.     mov    eax,[es:bx+emsBlock.handle]    ; save handle pointer
  405.     mov    [handle],eax
  406.     cmp    [es:bx+emsBlock.next],0     ; the last block of handle?
  407.     je    @@last
  408.  
  409.     mov    [es:bx+emsBlock.used],0     ; current block is not in use
  410.  
  411.     ; now combine all unused blocks that are after another
  412.  
  413. @@combfree:
  414.     lgs    si,[handle]            ; point gs:si to handle
  415.     les    bx,[gs:si+emsHandle.block]    ; point es:bx to first block
  416.  
  417. @@cunused:
  418.     cmp    [es:bx+emsBlock.used],0     ; is block unused?
  419.     jne    @@nextb
  420.  
  421.     lgs    si,[es:bx+emsBlock.next]    ; point gs:si to next block
  422.     cmp    [gs:si+emsBlock.used],0     ; is next block unused?
  423.     jne    @@nextb             ; if not, move on
  424.  
  425. @@comb:
  426.     ; block pointed by es:bx is free and so is the next one, gs:si
  427.  
  428.     mov    ax,[gs:si+emsBlock.bytes]    ; increase the length of
  429.     add    [es:bx+emsBlock.bytes],ax    ; current block
  430.  
  431.     mov    eax,[gs:si+emsBlock.next]
  432.     mov    [es:bx+emsBlock.next],eax
  433.     or    eax,eax
  434.     jz    @@nonext
  435.     push    ds                ; remove block pointed by
  436.     lds    di,[gs:si+emsBlock.next]    ; gs:si from list
  437.     mov    [word ds:di+emsBlock.prev],bx
  438.     mov    [word ds:di+2+emsBlock.prev],es
  439.     pop    ds
  440.  
  441. @@nonext:
  442.         push    gs es bx
  443.     call    memFree LANG, gs si        ; deallocate block
  444.         pop     bx es gs
  445.         test    ax,ax
  446.         jnz     @@err
  447.  
  448.     cmp    [es:bx+emsBlock.next],0     ; is there a next block?
  449.     je    @@chkfree
  450.     lgs    si,[es:bx+emsBlock.next]    ; point gs:si to next block
  451.     cmp    [gs:si+emsBlock.used],0     ; is next block used?
  452.     je    @@comb                ; if not, combine to this one
  453.  
  454. @@nextb:
  455.     cmp    [es:bx+emsBlock.next],0     ; is there a next block?
  456.     je    @@chkfree            ; if not, we are finished
  457.     les    bx,[es:bx+emsBlock.next]    ; point es:bx to next block
  458.     jmp    @@cunused            ; and continue
  459.  
  460.  
  461. @@chkfree:
  462.     ; all free blocks combined. Now check if there is only one free
  463.     ; block in the handle
  464.     lgs    si,[handle]            ; point gs:si to handle
  465.     les    bx,[gs:si+emsHandle.block]    ; point es:bx to first block
  466.     cmp    [es:bx+emsBlock.next],0     ; is this the last block?
  467.     jne    @@ok
  468.     cmp    [es:bx+emsBlock.used],0     ; is this block unused?
  469.     jne    @@ok
  470.  
  471.     ; only one unused block in the handle - deallocate it.
  472.  
  473.     push    es bx
  474.     call    emsFreePages LANG, gs si    ; deallocate handle
  475.     pop    bx es
  476.         test    ax,ax
  477.         jnz     @@err
  478.  
  479.     call    memFree LANG, es bx        ; deallocate block structure
  480.         test    ax,ax
  481.         jnz     @@err
  482.  
  483.     jmp    @@ok
  484.  
  485.  
  486. @@last:
  487.     cmp    [es:bx+emsBlock.prev],0     ; the only block of handle?
  488.     je    @@only
  489.  
  490.     les    bx,[es:bx+emsBlock.prev]    ; point es:bx to prev block
  491.     mov    [es:bx+emsBlock.next],0     ; no next block
  492.     call    memFree LANG, [ems]        ; deallocate block
  493.         test    ax,ax
  494.         jnz     @@err
  495.  
  496.     jmp    @@chkfree            ; check if handle should be
  497.                         ; deallocated
  498.  
  499.  
  500. @@only:
  501.         call    emsFreePages LANG, [es:bx+emsBlock.handle]      ; free handle
  502.         test    ax,ax
  503.         jnz     @@err
  504.  
  505.     call    memFree LANG, [ems]        ; free current block
  506.         test    ax,ax
  507.         jnz     @@err
  508.  
  509. @@ok:
  510.         xor     ax,ax                   ; success
  511.     jmp    @@done
  512.  
  513. @@err:
  514.         ERROR   ID_emsFree
  515.  
  516. @@done:
  517.     ret
  518. ENDP
  519.  
  520.  
  521.  
  522.  
  523.  
  524. ;/***************************************************************************\
  525. ;*
  526. ;* Function:     int emsMap(emsBlock *ems, void **memPtr);
  527. ;*
  528. ;* Description:  Maps an EMS block to conventional memory.
  529. ;*
  530. ;* Input:        emsBlock *ems           pointer to block to be mapped
  531. ;*               void **memPtr           pointer to conventional memory ptr
  532. ;*
  533. ;* Returns:      MIDAS error code.
  534. ;*               Pointer to the conventional memory area where the block
  535. ;*               was mapped is stored in **memPtr, NULL if failure.
  536. ;*
  537. ;\***************************************************************************/
  538.  
  539. PROC    emsMap          FAR     ems : dword, memPtr : dword
  540. USES    si,di
  541.  
  542.     les    di,[ems]            ; point es:di to EMS block
  543.     lgs    si,[es:di+emsBlock.handle]    ; point gs:si to EMS handle
  544.     mov    dx,[gs:si+emsHandle.handle]    ; handle number
  545.  
  546.     mov    cx,[es:di+emsBlock.addr]    ; cx = first page to map
  547.     shr    cx,14
  548.  
  549.     mov    si,[es:di+emsBlock.addr]
  550.     add    si,[es:di+emsBlock.bytes]    ; si = last page to map
  551.     shr    si,14
  552.  
  553. @@mlp:    cmp    [emsIsSafe],1            ; is safety-flag on?
  554.     jne    @@map                ; if not, always map the page
  555.  
  556.     mov    bx,cx                ; if is, check if this page
  557.     shl    bx,1                ; is already mapped
  558.     cmp    [emsMapped+bx],dx
  559.     je    @@mapped
  560.  
  561.     mov    [emsMapped+bx],dx        ; if not, map it normally and
  562.                         ; mark mapped
  563. @@map:
  564.     mov    al,cl                ; al = physical page number
  565.     mov    bx,cx                ; bx = logical page number
  566.     mov    ah,44h                ; EMS Map Handle Pages funct
  567.     int    67h
  568.     or    ah,ah
  569.         jnz     @@emmerr
  570.  
  571. @@mapped:
  572.     inc    cx                ; map next page
  573.     cmp    cx,si                ; should next page still be
  574.     jbe    @@mlp                ; mapped?
  575.  
  576.         mov     ax,[es:di+emsBlock.addr]
  577.         les     bx,[memPtr]             ; store pointer to the conventional
  578.         mov     [es:bx],ax              ; memory area to *memPtr
  579.         mov     ax,[emsPageFrame]
  580.         mov     [es:bx+2],ax
  581.  
  582.         xor     ax,ax                   ; success
  583.         jmp     @@done
  584.  
  585. @@emmerr:
  586.         ; EMM mapping function failed
  587.         mov     ax,errEMMFailure
  588.  
  589. @@err:
  590.         ERROR   ID_emsMap
  591.  
  592. @@done:
  593.     ret
  594. ENDP
  595.  
  596.  
  597.  
  598.  
  599. ;/***************************************************************************\
  600. ;*
  601. ;* Function:     int emsSave(void);
  602. ;*
  603. ;* Description:  Saves the EMS status. To be used by TempoTimer. Can only be
  604. ;*               called once.
  605. ;*
  606. ;* Returns:      MIDAS error code
  607. ;*
  608. ;\***************************************************************************/
  609.  
  610. PROC    emsSave     FAR
  611. USES    di
  612.  
  613.     mov    ax,4E00h        ; EMS Get Page Map subfunction
  614.     les    di,[emsSaveArray]    ; pointer to Page Map Save Array
  615.     int    67h
  616.     or    ah,ah            ; nonzero status means error
  617.         jnz     @@emmerr
  618.  
  619.         xor     ax,ax                   ; success
  620.         jmp     @@done
  621.  
  622. @@emmerr:
  623.         ; EMM Save function failed
  624.         mov     ax,errEMMFailure
  625.  
  626. @@err:
  627.         ERROR   ID_emsSave
  628.  
  629. @@done:
  630.     ret
  631. ENDP
  632.  
  633.  
  634.  
  635.  
  636.  
  637. ;/***************************************************************************\
  638. ;*
  639. ;* Function:     int emsRestore(void);
  640. ;*
  641. ;* Description:  Restores EMS status saved with emsSave(). To be used by
  642. ;*               TempoTimer. Can only be called once.
  643. ;*
  644. ;* Returns:      MIDAS error code
  645. ;*
  646. ;\***************************************************************************/
  647.  
  648. PROC    emsRestore    FAR
  649. USES    ds, si
  650.  
  651.     mov    ax,4E01h        ; EMS Set Page Map subfunction
  652.     lds    si,[emsSaveArray]    ; point ds:si to Page Map Save Array
  653.     int    67h
  654.     or    ah,ah            ; nonzero status means error
  655.         jnz     @@emmerr
  656.  
  657.         xor     ax,ax                   ; success
  658.     jmp    @@done
  659.  
  660. @@emmerr:
  661.         ; EMM Restore function failed
  662.         mov     ax,errEMMFailure
  663.  
  664. @@err:
  665.         ERROR   ID_emsRestore
  666.  
  667. @@done:
  668.     ret
  669. ENDP
  670.  
  671.  
  672.  
  673.  
  674.  
  675. ;/***************************************************************************\
  676. ;*
  677. ;* Function:     int emsAllocPages(emsHandle **emsh);
  678. ;*
  679. ;* Description:  Allocate 4 pages of EMS memory to a handle. Used internally
  680. ;*               by EMS heap manager.
  681. ;*
  682. ;* Returns:      MIDAS error code.
  683. ;*               Pointer to a emsHandle structure for the pages stored in
  684. ;*               *emsh, NULL if failure.
  685. ;*
  686. ;\***************************************************************************/
  687.  
  688. PROC    emsAllocPages   FAR     emsh : dword
  689. USES    si
  690. LOCAL    handle : dword
  691.  
  692.         ; allocate memory for handle structure:
  693.         call    memAlloc LANG, size emsHandle, seg emsMemPtr offset emsMemPtr
  694.         test    ax,ax
  695.         jnz     @@err
  696.  
  697.         les     bx,[emsMemPtr]          ; point es:bx to handle structure
  698.         mov     [word handle],bx        ; store handle pointer in handle
  699.         mov     [word handle+2],es
  700.  
  701.  
  702.     mov    [es:bx+emsHandle.handle],0
  703.     mov    [es:bx+emsHandle.block],0
  704.     mov    [es:bx+emsHandle.next],0
  705.  
  706.     push    bx
  707.     mov    ah,43h            ; EMS Allocate Pages function
  708.     mov    bx,4            ; allocate 4 pages (64k)
  709.     int    67h
  710.         pop     bx
  711.         or      ah,ah                   ; successful if status is zero
  712.         jz      @@allocok
  713.  
  714.         ; check if the cause of the error was lack of EMS. If so, return
  715.         ; errOutOfEMS, otherwise errEMMFailure
  716.         cmp     ah,85h                  ; out of EMS handles?
  717.         je      @@outofems
  718.         cmp     ah,87h                  ; not enough EMS pages?
  719.         je      @@outofems
  720.         cmp     ah,88h                  ; not enough unallocated pages?
  721.         je      @@outofems
  722.         jmp     @@emmerr
  723.  
  724. @@outofems:
  725.         mov     ax,errOutOfEMS          ; out of EMS memory
  726.         jmp     @@err
  727.  
  728.  
  729. @@allocok:
  730.     mov    [es:bx+emsHandle.handle],dx    ; store EMS handle number
  731.  
  732.     cmp    [emsHandles],0        ; first EMS handle?
  733.     jne    @@notfirst
  734.  
  735.     mov    [word emsHandles],bx    ; point emsHandles to this page as
  736.     mov    [word emsHandles+2],es    ; it is the first
  737.     mov    [es:bx+emsHandle.prev],0    ; no previous handle (first)
  738.     jmp    @@prevset
  739.  
  740. @@notfirst:
  741.     push    ds
  742.  
  743.     lds    si,[emsHandles]     ; start searching for last handle
  744. @@flast:
  745.     cmp    [ds:si+emsHandle.next],0    ; is this the last handle?
  746.     je    @@last
  747.     lds    si,[ds:si+emsHandle.next]    ; next handle
  748.     jmp    @@flast
  749.  
  750. @@last:
  751.     mov    [word ds:si+emsHandle.next],bx        ; ds:si now points to
  752.     mov    [word ds:si+2+emsHandle.next],es    ; last handle which
  753.     mov    [word es:bx+emsHandle.prev],si        ; is the previous for
  754.     mov    [word es:bx+2+emsHandle.prev],ds    ; this one
  755.     pop    ds
  756.  
  757. @@prevset:
  758.         les     bx,[emsh]
  759.         mov     eax,[handle]            ; store handle pointer in *emsh
  760.         mov     [es:bx],eax
  761.  
  762.         xor     ax,ax                   ; success
  763.         jmp     @@done
  764.  
  765.  
  766. @@emmerr:
  767.         mov     ax,errEMMFailure        ; Expanded Memory Manager failure
  768.  
  769. @@err:
  770.         ERROR   ID_emsAllocPages
  771.  
  772. @@done:
  773.     ret
  774. ENDP
  775.  
  776.  
  777.  
  778.  
  779. ;/***************************************************************************\
  780. ;*
  781. ;* Function:     int emsFreePages(emsHandle *handle);
  782. ;*
  783. ;* Description:  Deallocates an EMS handle allocated by emsAllocPages(). Used
  784. ;*               internally by EMS heap manager.
  785. ;*
  786. ;* Input:        emsHandle *handle       pointer to handle to be deallocated.
  787. ;*
  788. ;* Returns:      MIDAS error code
  789. ;*
  790. ;\***************************************************************************/
  791.  
  792. PROC    emsFreePages    FAR    handle : dword
  793. USES    si
  794.  
  795.     les    bx,[handle]        ; point es:bx to handle structure
  796.     cmp    [es:bx+emsHandle.prev],0    ; first handle?
  797.     je    @@first
  798.  
  799.     push    ds
  800.     mov    eax,[es:bx+emsHandle.next]    ; eax = pointer to next handle
  801.     lds    si,[es:bx+emsHandle.prev]    ; point ds:si to prev handle
  802.     mov    [ds:si+emsHandle.next],eax    ; prev->next = this->next
  803.     pop    ds
  804.  
  805.     or    eax,eax         ; is this the last handle?
  806.     jz    @@dealloc
  807.  
  808.     push    ds
  809.     mov    eax,[es:bx+emsHandle.prev]    ; eax = pointer to prev handle
  810.     lds    si,[es:bx+emsHandle.next]    ; point ds:si to next handle
  811.     mov    [ds:si+emsHandle.prev],eax    ; next->prev = this->prev
  812.     pop    ds
  813.     jmp    @@dealloc
  814.  
  815. @@first:
  816.     mov    eax,[es:bx+emsHandle.next]    ; set emsHandles to next
  817.     mov    [emsHandles],eax        ; handle (might be 0)
  818.     or    eax,eax             ; is there a next handle?
  819.     jz    @@fnn
  820.     lgs    si,[es:bx+emsHandle.next]    ; if is, its previous handle
  821.     mov    [gs:si+emsHandle.prev],0    ; is now zero (it's the first)
  822. @@fnn:
  823.  
  824. @@dealloc:
  825.     mov    ah,45h            ; EMS Deallocate Pages function
  826.     mov    dx,[es:bx+emsHandle.handle]    ; EMS handle number
  827.     int    67h
  828.         test    ah,ah                   ; failure if nonzero status
  829.         jnz     @@emmerr
  830.  
  831.     call    memFree LANG, es bx    ; deallocate handle structure memory
  832.         test    ax,ax
  833.         jnz     @@err
  834.  
  835.         xor     ax,ax                   ; success
  836.         jmp     @@done
  837.  
  838. @@emmerr:
  839.         mov     ax,errEMMFailure        ; Expanded Memory Manager failure
  840.  
  841. @@err:
  842.         ERROR   ID_emsFreePages
  843.  
  844. @@done:
  845.     ret
  846. ENDP
  847.  
  848.  
  849.  
  850.  
  851. ;/***************************************************************************\
  852. ;*
  853. ;* Function:     int emsSafe(void);
  854. ;*
  855. ;* Description:  Sets the EMS safety flag on so that the EMS heap manager
  856. ;*               can optimize page mappings. Until emsStopSafe() is restored,
  857. ;*               no other routine than emsMap() must touch the EMS page
  858. ;*               mappings
  859. ;*
  860. ;* Returns:      MIDAS error code
  861. ;*
  862. ;\***************************************************************************/
  863.  
  864. PROC    emsSafe         FAR
  865.  
  866.     mov    [emsIsSafe],1        ; it is now safe to assume that EMS
  867.     xor    bx,bx            ; mappings remain untouched by other
  868.     mov    cx,4            ; routines.
  869.     mov    ax,-1
  870.  
  871. @@lp:    mov    [emsMapped+bx],ax    ; clear mapping status table to
  872.     add    bx,2            ; indicate that no pages are mapped
  873.     loop    @@lp
  874.  
  875.         xor     ax,ax                   ; always successful
  876.  
  877.     ret
  878. ENDP
  879.  
  880.  
  881.  
  882.  
  883. ;/***************************************************************************\
  884. ;*
  885. ;* Function:     int emsStopSafe(void);
  886. ;*
  887. ;* Description:  Sets the EMS safety flag off.
  888. ;*
  889. ;* Returns:      MIDAS error code
  890. ;*
  891. ;\***************************************************************************/
  892.  
  893. PROC    emsStopSafe     FAR
  894.  
  895.     mov    [emsIsSafe],0        ; it is no longer safe to assume that
  896.                     ; EMS mappings remain untouched
  897.         xor     ax,ax                   ; always successful
  898.  
  899.     ret
  900. ENDP
  901.  
  902.  
  903.  
  904.  
  905.  
  906. END
  907.