; XMS routines to get available UMB's and HMA,
; and allocate extended memory.
; Written from the XMS 3.0 specification.
; (C) 1993 Johan. K. Reinalda, WG7J
; Modified April 1995 by James Dugal, N5KNX
; In general, the XMS driver (eg, himem.sys or qemm) returns an error
;	code in BL, setting AX=0001 when successful.
; We return the BL error code in the most-significant byte of a long-int result.

include asmgloba.h

.data
XMS_Entry  dd   1

.code
public Installed_XMS
public Request_UMB,Release_UMB
public Request_HMA,Release_HMA
public Query_XMS,Total_XMS
public Alloc_XMS,Free_XMS
public Move_XMS,Query_XMS_handle

Installed_XMS proc
    mov     ax,4300h
    int     2Fh
    cmp     al,80h
    jne     NoXMSDriver
; Get the address of the driver's control function
    mov     ax,4310h
    int     2Fh
    mov     word ptr [XMS_Entry],bx      ;XMS_Entry is function entry point
    mov     word ptr [XMS_Entry+2],es
    mov     ax, 1
    ret
NoXMSDriver:
    xor     ax, ax
    ret
Installed_XMS endp


Request_UMB proc
    arg sz:word

    mov ah, 10h
    mov dx, sz
    call [XMS_Entry]
    cmp ax, 1
    jne request_failed
    mov ax, bx      ; UMB segment in bx, blk size in dx
    jmp request_done
request_failed:
    mov ax, dx      ; return biggest available size
    mov dh, bl      ; return error code (dx must never == requested blk size)
request_done:
    ret
Request_UMB endp

Release_UMB proc
    arg block:word

    mov dx, block
    mov ah, 11h
    call [XMS_Entry]
    cmp ax, 1
    jne release_failed
    xor ax, ax
    xor dx, dx
    jmp release_done
release_failed:
    mov dh, bl          ; return error in high byte
release_done:
    ret
Release_UMB endp

Request_HMA proc
    mov ah, 01h
    mov dx, 0ffffh      ; we're an application
    call [XMS_Entry]
    ret
Request_HMA endp

Release_HMA proc
    mov ah, 02h
    call    [XMS_Entry]
    ret
Release_HMA endp

Query_XMS proc
    mov ah, 8
    mov bl, 0  ; some XMS drivers don't set bl
    call    [XMS_Entry]
    xor	dx, dx
    cmp bl, 0
    jz  QLSuccess
    mov	dh, bl
QLSuccess:
    ret
Query_XMS endp

Total_XMS proc
    mov	ah, 8
    mov bl, 0  ; some XMS drivers don't set bl
    call    [XMS_Entry]
    mov ax, dx
    mov dx, 0
    cmp bl, 0
    jz QTSuccess
    mov	dh, bl
QTSuccess:
    ret
Total_XMS endp

Alloc_XMS proc
    arg sz:word

    mov	ah, 9
    mov dx, sz	; in KB
    call    [XMS_Entry]
    or ax, ax
    mov ax, dx
    mov dx, 0
    jnz AESuccess
    mov	dh, bl
AESuccess:
    ret
Alloc_XMS endp

Free_XMS proc
    arg handle:word

    mov ah, 0Ah
    mov dx, handle
    call    [XMS_Entry]
    xor	dx, dx
    dec	ax
    jz  FSuccess
    mov dh, bl
FSuccess:
    ret
Free_XMS endp

Move_XMS proc
    arg buf:dword

    push ds
    push si

    push es	; since we must change DS, we must use ES to reference [XMS_ENTRY]
    push ds
    pop  es
; DS:SI = pointer to XMS move stucture
    lds si, buf
    mov ah, 0bh
; int 3	; <<<<<< debug entry
    call    ES: [XMS_Entry]
    xor dx, dx
    dec	ax
    jz  MSuccess
    mov	dh, bl
MSuccess:
    pop es
    pop si
    pop ds
    ret
Move_XMS endp

Query_XMS_handle proc
    arg handle:word

    mov ah, 0eh
    mov dx, handle
    call    [XMS_Entry]
    mov	ax,bx	;dx has blklen in KB, bh has lock count, bl has free handle cnt
    ret
Query_XMS_handle endp
END

