;
; jmemdosa.asm
;
; Copyright (C) 1992, Thomas G. Lane.
; This file is part of the Independent JPEG Group's software.
; For conditions of distribution and use, see the accompanying README file.
;
; This file contains low-level interface routines to support the MS-DOS
; backing store manager (jmemdos.c).  Routines are provided to access disk
; files through direct DOS calls, and to access XMS and EMS drivers.
;
; This file should assemble with Microsoft's MASM or any compatible
; assembler (including Borland's Turbo Assembler).  If you haven't got
; a compatible assembler, better fall back to jmemansi.c or jmemname.c.
;
; To minimize dependence on the C compiler's register usage conventions,
; we save and restore all 8086 registers, even though most compilers only
; require SI,DI,DS to be preserved.  Also, we use only 16-bit-wide return
; values, which everybody returns in AX.
;
; Based on code contributed by Ge' Weijers.
;

JMEMDOSA_TXT    segment byte public 'CODE'

        assume    cs:JMEMDOSA_TXT

        public    _jdos_open
        public    _jdos_close
        public    _jdos_seek
        public    _jdos_read
        public    _jdos_write
        public    _jxms_getdriver
        public    _jxms_calldriver
        public    _jems_available
        public    _jems_calldriver

;
; short far jdos_open (short far * handle, char far * filename)
;
; Create and open a temporary file
;
_jdos_open    proc    far
        push    bp            ; linkage
        mov     bp,sp
        push    si            ; save all registers for safety
        push    di
        push    bx
        push    cx
        push    dx
        push    es
        push    ds
        mov    cx,0            ; normal file attributes
        lds    dx,dword ptr [bp+10]    ; get filename pointer
        mov    ah,3ch            ; create file
        int    21h
        jc    open_err        ; if failed, return error code
        lds    bx,dword ptr [bp+6]    ; get handle pointer
        mov    word ptr [bx],ax    ; save the handle
        xor    ax,ax            ; return zero for OK
open_err:    pop    ds            ; restore registers and exit
        pop    es
        pop    dx
        pop    cx
        pop    bx
        pop    di
        pop    si
        pop     bp
        ret
_jdos_open    endp


;
; short far jdos_close (short handle)
;
; Close the file handle
;
_jdos_close    proc    far
        push    bp            ; linkage
        mov     bp,sp
        push    si            ; save all registers for safety
        push    di
        push    bx
        push    cx
        push    dx
        push    es
        push    ds
        mov    bx,word ptr [bp+6]    ; file handle
        mov    ah,3eh            ; close file
        int    21h
        jc    close_err        ; if failed, return error code
        xor    ax,ax            ; return zero for OK
close_err:    pop    ds            ; restore registers and exit
        pop    es
        pop    dx
        pop    cx
        pop    bx
        pop    di
        pop    si
        pop     bp
        ret
_jdos_close    endp


;
; short far jdos_seek (short handle, long offset)
;
; Set file position
;
_jdos_seek    proc    far
        push    bp            ; linkage
        mov     bp,sp
        push    si            ; save all registers for safety
        push    di
        push    bx
        push    cx
        push    dx
        push    es
        push    ds
        mov    bx,word ptr [bp+6]    ; file handle
        mov    dx,word ptr [bp+8]    ; LS offset
        mov    cx,word ptr [bp+10]    ; MS offset
        mov    ax,4200h        ; absolute seek
        int    21h
        jc    seek_err        ; if failed, return error code
        xor    ax,ax            ; return zero for OK
seek_err:    pop    ds            ; restore registers and exit
        pop    es
        pop    dx
        pop    cx
        pop    bx
        pop    di
        pop    si
        pop     bp
        ret
_jdos_seek    endp


;
; short far jdos_read (short handle, void far * buffer, unsigned short count)
;
; Read from file
;
_jdos_read    proc    far
        push    bp            ; linkage
        mov     bp,sp
        push    si            ; save all registers for safety
        push    di
        push    bx
        push    cx
        push    dx
        push    es
        push    ds
        mov    bx,word ptr [bp+6]    ; file handle
        lds    dx,dword ptr [bp+8]    ; buffer address
        mov    cx,word ptr [bp+12]    ; number of bytes
        mov    ah,3fh            ; read file
        int    21h
        jc    read_err        ; if failed, return error code
        cmp    ax,word ptr [bp+12]    ; make sure all bytes were read
        je    read_ok
        mov    ax,1            ; else return 1 for not OK
        jmp    short read_err
read_ok:    xor    ax,ax            ; return zero for OK
read_err:    pop    ds            ; restore registers and exit
        pop    es
        pop    dx
        pop    cx
        pop    bx
        pop    di
        pop    si
        pop     bp
        ret
_jdos_read    endp


;
; short far jdos_write (short handle, void far * buffer, unsigned short count)
;
; Write to file
;
_jdos_write    proc    far
        push    bp            ; linkage
        mov     bp,sp
        push    si            ; save all registers for safety
        push    di
        push    bx
        push    cx
        push    dx
        push    es
        push    ds
        mov    bx,word ptr [bp+6]    ; file handle
        lds    dx,dword ptr [bp+8]    ; buffer address
        mov    cx,word ptr [bp+12]    ; number of bytes
        mov    ah,40h            ; write file
        int    21h
        jc    write_err        ; if failed, return error code
        cmp    ax,word ptr [bp+12]    ; make sure all bytes written
        je    write_ok
        mov    ax,1            ; else return 1 for not OK
        jmp    short write_err
write_ok:    xor    ax,ax            ; return zero for OK
write_err:    pop    ds            ; restore registers and exit
        pop    es
        pop    dx
        pop    cx
        pop    bx
        pop    di
        pop    si
        pop     bp
        ret
_jdos_write    endp


;
; void far jxms_getdriver (XMSDRIVER far *)
;
; Get the address of the XMS driver, or NULL if not available
;
_jxms_getdriver    proc    far
        push    bp            ; linkage
        mov     bp,sp
        push    si            ; save all registers for safety
        push    di
        push    bx
        push    cx
        push    dx
        push    es
        push    ds
        mov     ax,4300h        ; call multiplex interrupt with
        int    2fh            ; a magic cookie, hex 4300
        cmp     al,80h            ; AL should contain hex 80
        je    xmsavail
        xor     dx,dx            ; no XMS driver available
        xor     ax,ax            ; return a nil pointer
        jmp    short xmsavail_done
xmsavail:    mov     ax,4310h        ; fetch driver address with
        int    2fh            ; another magic cookie
        mov     dx,es            ; copy address to dx:ax
        mov     ax,bx
xmsavail_done:    les     bx,dword ptr [bp+6]    ; get pointer to return value
        mov    word ptr es:[bx],ax
        mov    word ptr es:[bx+2],dx
        pop    ds            ; restore registers and exit
        pop    es
        pop    dx
        pop    cx
        pop    bx
        pop    di
        pop    si
        pop    bp
        ret
_jxms_getdriver    endp


;
; void far jxms_calldriver (XMSDRIVER, XMScontext far *)
;
; The XMScontext structure contains values for the AX,DX,BX,SI,DS registers.
; These are loaded, the XMS call is performed, and the new values of the
; AX,DX,BX registers are written back to the context structure.
;
_jxms_calldriver     proc    far
        push    bp            ; linkage
        mov     bp,sp
        push    si            ; save all registers for safety
        push    di
        push    bx
        push    cx
        push    dx
        push    es
        push    ds
        les     bx,dword ptr [bp+10]    ; get XMScontext pointer
        mov     ax,word ptr es:[bx]    ; load registers
        mov     dx,word ptr es:[bx+2]
        mov     si,word ptr es:[bx+6]
        mov     ds,word ptr es:[bx+8]
        mov     bx,word ptr es:[bx+4]
        call    dword ptr [bp+6]    ; call the driver
        mov    cx,bx            ; save returned BX for a sec
        les     bx,dword ptr [bp+10]    ; get XMScontext pointer
        mov     word ptr es:[bx],ax    ; put back ax,dx,bx
        mov     word ptr es:[bx+2],dx
        mov     word ptr es:[bx+4],cx
        pop    ds            ; restore registers and exit
        pop    es
        pop    dx
        pop    cx
        pop    bx
        pop    di
        pop    si
        pop     bp
        ret
_jxms_calldriver     endp


;
; short far jems_available (void)
;
; Have we got an EMS driver? (this comes straight from the EMS 4.0 specs)
;
_jems_available    proc    far
        push    si            ; save all registers for safety
        push    di
        push    bx
        push    cx
        push    dx
        push    es
        push    ds
        mov    ax,3567h        ; get interrupt vector 67h
        int    21h
        push    cs
        pop    ds
        mov    di,000ah        ; check offs 10 in returned seg
        lea    si,ASCII_device_name    ; against literal string
        mov    cx,8
        cld
        repe cmpsb
        jne    no_ems
        mov    ax,1            ; match, it's there
        jmp    short avail_done
no_ems:        xor    ax,ax            ; it's not there
avail_done:    pop    ds            ; restore registers and exit
        pop    es
        pop    dx
        pop    cx
        pop    bx
        pop    di
        pop    si
        ret

ASCII_device_name    db    "EMMXXXX0"

_jems_available    endp


;
; void far jems_calldriver (EMScontext far *)
;
; The EMScontext structure contains values for the AX,DX,BX,SI,DS registers.
; These are loaded, the EMS trap is performed, and the new values of the
; AX,DX,BX registers are written back to the context structure.
;
_jems_calldriver    proc far
        push    bp            ; linkage
        mov     bp,sp
        push    si            ; save all registers for safety
        push    di
        push    bx
        push    cx
        push    dx
        push    es
        push    ds
        les     bx,dword ptr [bp+6]    ; get EMScontext pointer
        mov     ax,word ptr es:[bx]    ; load registers
        mov     dx,word ptr es:[bx+2]
        mov     si,word ptr es:[bx+6]
        mov     ds,word ptr es:[bx+8]
        mov     bx,word ptr es:[bx+4]
        int    67h            ; call the EMS driver
        mov    cx,bx            ; save returned BX for a sec
        les     bx,dword ptr [bp+6]    ; get EMScontext pointer
        mov     word ptr es:[bx],ax    ; put back ax,dx,bx
        mov     word ptr es:[bx+2],dx
        mov     word ptr es:[bx+4],cx
        pop    ds            ; restore registers and exit
        pop    es
        pop    dx
        pop    cx
        pop    bx
        pop    di
        pop    si
        pop     bp
        ret
_jems_calldriver    endp

JMEMDOSA_TXT    ends

        end
