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