;--------------------------------
; Test4ems.Asm - James Vahn
; Displays the significant EMS driver data.

cseg segment
assume cs:cseg, ds:cseg
org 100h                                ;COM format

Begin:
        call    Detect                  ;Look for a driver.
        jc      Error                   ;No driver found.
        mov     dx,offset Msg           ;Inform that it was found.
        mov     ah,09h
        int     21h
        call    ShowVersion             ;Show which version.
        jc      error2                  ;function disabled.
        call    GetEMSdata              ;Get EMS info data.
        jc      error2
        call    ShowData                ;Display it onscreen.
        call    GetMEM                  ;Show memory available.
        mov     ax,4C00h                ;Exit.
        int     21h
Error:
        mov     dx,offset Msg2          ;No driver found, exit.
        jmp     E1
Error2:
        mov     dx,offset Msg1          ;Driver found, but not enabled.

  E1:   mov     ah,09h                  ;Exit.
        int     21h
        mov     ax,4C01h
        int     21h

_EmsH struc
        EmmRawPageSize                  dw ?
        NumberAlternateRegisterSets     dw ?
        SizeMappingContextSaveArea      dw ?
        NumberDMARegisterSets           dw ?
        DMAOperationType                dw ?
_EmsH ends

 EmsH           db size _EmsH dup (?)
 CRLF           db 13,10,36
 Msg            db 'EMS driver detected, version ',36
 Msg1           db 'Function not enabled.',13,10,36
 Msg2           db 'Error, Driver Not Found.',13,10,36
 Msg3           db '             Emm Raw Page Size $'
 Msg4           db 'Number Alternate Register Sets $'
 Msg5           db 'Size Mapping Context Save Area $'
 Msg6           db '      Number DMA Register Sets $'
 Msg7           db '            DMA Operation Type $'
 Msg8           db 13,10,'Total EMS memory $'
 Msg9           db 'Total EMS memory available $'
 Msg10          db 'k',13,10,36

;************************************************
 Detect  proc   NEAR
  ; Tests if an EMS driver is present. Carry set on Error.
  ; Note: DR-DOS uses EMMQXXX0

        mov     ax,3567h                ;Get driver address into ES:BX
        int     21h
        cld
        mov     si, offset driver1      ;Look for EMMXXXX0.
        mov     di,0Ah                  ;Offset into driver.
        mov     cx,8                    ;Check 8 bytes.
        repe cmpsb                      ;Compare DS:SI to ES:DI
        jcxz    Dp1                     ;Found it, exit.
        mov     si,offset driver2       ;Look for DR-DOS driver.
        mov     di,0Ah
        mov     cx,8
        repe cmpsb
        jcxz    Dp1
        stc                             ;Set carry on fail.
 Dp1:   ret

 driver1 db 'EMMXXXX0'
 driver2 db 'EMMQXXX0'

ENDP
;*********************************************
 ShowVersion    proc    NEAR
  ; Get version of Driver.
        mov     ah,46h
        int     67h                     ;Call Get Version function.
        or      ah,ah
        jne     NoVersion               ;AH=0 if enabled.

        push    ax                      ;Save it.
        mov     cl,4
        shr     ax,cl                   ;Version in BCD, shift right
        xor     ah,ah                   ;four places for high nibble.
        call    Bin2Dec

        mov     dl,'.'
        mov     ah,02h
        int     21h                     ;Print '.'

        pop     ax
        and     ax,00001111b            ;Mask off upper nibble.
        call    Bin2DEC

        mov     dx,offset CRLF
        mov     ah,09h
        int     21h
        int     21h                     ;Double line feed.
        ret

 NoVersion:
        stc                             ;Set carry on error.
        ret
ENDP
;*********************************************
 GetEMSdata     proc    NEAR
  ; Put the EMS data info into the buffer.

        mov     di,offset EmsH
        push    ds
        pop     es
        mov     ax,5900h
        int     67h
        or      ah,ah
        ret
ENDP

;********************************************
 ShowData       proc    NEAR
  ; This procedure prints out the EMS data info.

        mov     dx,offset Msg3
        mov     bx,offset EmsH
        mov     cx,5                    ;5 data fields.
  Show:
        mov     ah,09h
        int     21h

        mov     ax,[bx]
        call    Bin2DEC
        push    dx
        mov     dx,offset CRLF
        mov     ah,09h
        int     21h
        pop     dx

        add     dx,32                   ;Get next line of text.
        add     bx,2                    ;Get next word of data.
        loop show
        ret
ENDP

;*****************************************
 GetMEM         proc    NEAR
  ; Show how much EMS memory, total and available.

        mov     ax,4200h                ;Find EMS memory.
        int     67h
        push    bx
        push    dx

        mov     dx,offset Msg8          ;Show Total EMS Memory.
        mov     ah,09h
        int     21h
        pop     ax
        mov     bx,16
        mul     bx
        call    Bin2DEC
        mov     dx,offset Msg10
        mov     ah,09h
        int     21h

        mov     dx,offset Msg9          ;Show Free EMS Memory.
        mov     ah,09h
        int     21h
        pop     ax
        mov     bx,16
        mul     bx
        call    Bin2DEC
        mov     dx,offset Msg10
        mov     ah,09h
        int     21h
        ret
ENDP

;******************************************
 Bin2DEC        proc    Near
  ; Convert AX to unsigned decimal ASCII output

        push    dx                      ;Save everything.
        push    cx
        push    bx
        push    ax
        mov     ax,0A30h                ;Print a '0'
        mov     bh,0
        mov     cx,1
        int     10h
        pop     ax
bin2as: mov     cx,5                    ;maximum of 5 decimal digits
        mov     bx,10d
bin2a1: xor     dx,dx
        div     bx
        add     dl,'0'                  ;Convert remainder to ASCII.
        push    dx
        loop    bin2a1
        mov     cx,5
        mov     bl,'0'                  ;Suppress leading zeros.
bin2a2: pop     ax
        or      bl,al
        test    bl,0Fh
        jz      bin2a4
        mov     dl,al                   ;Output ASCII digit in AL.
        mov     ah,02h
        int     21h
bin2a4: loop    bin2a2
        pop     bx                      ;Restore registers and return.
        pop     cx
        pop     dx
        ret
ENDP

cseg ends
end Begin
