;
; 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
