;-----------------------------------------------------------------------
; MODULE XDETECT
;
; Hardware detection module
;
; Compile with Tasm.
; C callable.
;
;
; ****** XLIB - Mode X graphics library                ****************
; ******                                               ****************
; ****** Written By Themie Gouthas                     ****************
;
; egg@dstos3.dsto.gov.au
; teg@bart.dsto.gov.au
;-----------------------------------------------------------------------
LOCALS
.286

include model.inc
include xdetect.inc

	.data

_MouseButtonCount dw 0
_MouseVersion     dw 0
_MouseType        db 0
_MouseIRQ         db 0

	.code


i86       equ 0
i186      equ 1
i286      equ 2
i386sx    equ 3
i386dx    equ 4
i486      equ 5


NONE      equ 0
MDA       equ 1
CGA       equ 2
EGAMono   equ 3
EGAColor  equ 4
VGAMono   equ 5
VGAColor  equ 6
MCGAMono  equ 7
MCGAColor equ 8

PS2_CARDS db  0,1,2,2,4,3,2,5,6,2,8,7,8


;-----------------------------------------------------------------------
; PC Graphics detection routine. Returns graphics card type
;
; C callable as:
;    unsigned int x_graphics_card();
;
;

proc _x_graphics_card
	push bp                  ; Preserve caller's stack frame
	mov  bp,sp
	mov  ax,1A00h            ; Try calling VGA Identity Adapter function
	int  10h
	cmp  al,1Ah              ; Do we have PS/2 video bios ?
	jne  @@not_PS2           ; No!

	cmp  bl,0Ch              ; bl > 0Ch => CGA hardware
	jg   @@is_CGA            ; Jump if we have CGA
	xor  bh,bh
	xor  ah,ah
	mov  al,cs:PS2_CARDS[bx] ; Load ax from PS/2 hardware table
	jmp  short @@done        ; return ax
@@is_CGA:
	mov  ax,CGA              ; Have detected CGA, return id
	jmp  short @@done
@@not_PS2:                       ; OK We don't have PS/2 Video bios
	mov  ah,12h              ; Set alternate function service
	mov  bx,10h              ; Set to return EGA information
	int  10h                 ; call video service
	cmp  bx,10h              ; Is EGA there ?
	je   @@simple_adapter    ; Nop!
	mov  ah,12h              ; Since we have EGA bios, get details
	mov  bl,10h
	int  10h
	or   bh,bh               ; Do we have colour EGA ?
	jz   @@ega_color         ; Yes
	mov  ax,EGAMono          ; Otherwise we have Mono EGA
	jmp  short @@done
@@ega_color:
	mov  ax,EGAColor         ; Have detected EGA Color, return id
	jmp  short @@done
@@simple_adapter:
	int  11h                 ; Lets try equipment determination service
	and  al,30h
	shr  al,4
	xor  ah,ah
	or   al,al               ; Do we have any graphics card at all ?
	jz   @@done              ; No ? This is a stupid machine!
	cmp  al,3                ; Do We have a Mono adapter
	jne  @@is_CGA            ; No
	mov  ax,MDA              ; Have detected MDA, return id
@@done:
	pop  bp                  ;restore caller's stack frame
	ret
_x_graphics_card endp


;-----------------------------------------------------------------------
; PC Processor detection routine
;
; C callable as:
;    unsigned int x_processor();
;
;
proc _x_processor
	push bp
	mov  bp,sp
	pushf                    ; Save flags
	xor  ax,ax		 ; Clear AX
	push ax                  ; Push it on the stack
	popf                     ; Zero the flags
	pushf                    ; Try to zero bits 12-15
	pop  ax                  ; Recover flags
        and  ax,0F000h           ; If bits 12-15 are 1 => i86 or i286
        cmp  ax,0F000h
        jne  @@1

        push cx                  ; save CX
        mov  ax,0FFFFh           ; Set all AX bits
        mov  cl,33               ; Will shift once on 80186
        shl  ax,cl               ; or 33 x on 8086
        pop  cx
        mov  ax,i186
        jnz  @@done
        mov  ax,i86              ; 0 => 8086/8088
        jmp  short @@done

@@1:
        mov  ax,07000h           ; Try to set bits 12-14
        push ax
        popf
        pushf
        pop  ax
        and  ax,07000h           ; If bits 12-14 are 0 => i286
        mov  ax,i286
        jz   @@done

        ;; 386/486 resolution code taken from WHATCPU.ASM by
        ;; Dave M. Walker


        P386
        mov  eax,cr0
        mov  ebx,eax                 ;Original CR0 into EBX
        or   al,10h                  ;Set bit
        mov  cr0,eax                 ;Store it
        mov  eax,cr0                 ;Read it back
        mov  cr0,ebx                 ;Restore CR0
        test al,10h                  ;Did it set?
        mov  ax,i386sx
        jz   @@done                  ;Jump if 386SX

       ;*** Test AC bit in EFLAGS (386DX won't change)
        mov     ecx,esp                 ;Original ESP in ECX
        pushfd                          ;Original EFLAGS in EBX
        pop     ebx
        and     esp,not 3               ;Align stack to prevent 486
                                        ;  fault when AC is flipped
        mov     eax,ebx                 ;EFLAGS => EAX
        xor     eax,40000h              ;Flip AC flag
        push    eax                     ;Store it
        popfd
        pushfd                          ;Read it back
        pop     eax
        push    ebx                     ;Restore EFLAGS
        popfd
        mov     esp,ecx                 ;Restore ESP
        cmp     eax,ebx                 ;Compare old/new AC bits
        mov     ax,i386dx
        je      @@done
is_486:                                 ;Until the Pentium appears...
        mov   ax,i486
@@done:
	popf
        .286
	pop  bp
	ret
_x_processor endp

.8086
;-----------------------------------------------------------------------
; PC Numeric coprocessor detection routine
;
; C callable as:
;    unsigned int x_coprocessor();
;
;  Based on an article in PC Tech Journal, Aug 87 by Ted Forgeron
;
;  Returns 1 if coprocessor found, zero otherwise

_x_coprocessor   proc
ARG     control:word=StkSize
	push   bp
	mov    bp,sp
	sub    sp,StkSize

	fninit                          ; try to initialize the copro.
	mov    [control],0              ; clear control word variable
        fnstcw control                  ; put control word in memory
	mov    ax,[control]             ;
	cmp    ah,03h                   ; do we have a coprocessor ?
	je     @@HaveCopro              ; jump if yes!
	xor    ax,ax                    ; return 0 since nothing found
	jmp    short @@done
@@HaveCopro:
	mov    ax,1
@@done:
	mov    sp,bp
	pop    bp
	ret
_x_coprocessor   endp


;-----------------------------------------------------------------------
; PC Mouse Driver detection routine
;
; C callable as:
;    unsigned int x_mousedriver();
;
;
;  Returns 1 if mouse driver found, zero otherwise
_x_mousedriver proc
	       push bp
	       mov  bp,sp
	       mov  ax,3533h        ; Get int 33 interrupt vector
	       int  21h             ; Call dos
	       xor  cx,cx           ; Clear "found" flag
	       mov  ax,es           ; Is the vector null (ES==0 && BX==0) ?
	       or   bx,ax
	       jz   @@NoMouseDriver ; Yes! No mouse driver installed - Jump

	       ; Just make absolutely sure the vector points to the mouse
	       ; driver (just in case)

	       xor  ax,ax           ; FUNC 0: Mouse Initialization
	       int   33h
	       or    ax,ax          ; Do we have an installed mouse driver ?
	       jz    @@NoMouseDriver; No ?
	       mov   [_MouseButtonCount],bx

	       mov   ax,24h
	       int   33h
	       mov   [_MouseVersion],bx
	       mov   [_MouseType],ch
	       mov   [_MouseIRQ],cl

	       mov  cx,1            ; Yes! set flag

@@NoMouseDriver:
	       mov  ax,cx           ; Return "found" flag
	       pop  bp
	       ret
_x_mousedriver endp


end