;*DDK*************************************************************************/
;
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
PAGE 80,132
;/**********************************************************************
;/*
;/* Module:         XGA ring0 initialization code
;/*
;/* Description:    OS/2 kernel device driver support for XGA hardware.
;/*                 Init code is thrown away when finished with so place
;/*                  it in a separate module
;/*
;/**********************************************************************

.386p                                           ;Protect mode 386 code

HARD_DRAW       equ     1               ; get the real XGA register defns
RING0           equ     1               ; get special ring0 versions
INCL_GPIBITMAPS EQU     1
include os2.inc
include xgaadapt.inc
include eddhcone.inc
include eddhmacr.inc

include xgaring0.inc

include edd0extf.inc                    ; C functions, in edd0code.c

extrn Device_Help       : DWORD
extrn drvError          : WORD
extrn GDTselectors      : WORD
extrn GDTCount          : WORD

extrn FlatPageList      : DWORD
extrn PageList          : DWORD
extrn FlatLockHandle    : DWORD
extrn LockHandle        : DWORD
extrn XGARegPointer     : DWORD
extrn FlatXGARegPointer : DWORD


;/**********************************************************************
;
; Data Segment
;
;/**********************************************************************

AKDATA SEGMENT USE16 WORD PUBLIC 'FAR_DATA'

        public  deviceNum
deviceNum       DW      0               ;number of XGA adapters found

; The GDT selectors which the ring 2 code uses is mapped directly to
; each one of these instances.

public  instances
instances       XGAINSTANCE <>
                XGAINSTANCE <>
                XGAINSTANCE <>
                XGAINSTANCE <>
                XGAINSTANCE <>
                XGAINSTANCE <>
                XGAINSTANCE <>
                XGAINSTANCE <>

NUMOFINSTANCES          EQU     8


        ; Define the end of the resident data area. This will move backwards
        ; over some of the instances above) when we find out how many instances
        ; are required (how many XGA adapters there are in the system).

; All of the following data can be discarded
; (NB. this assumes that this file is the last in the link order)
END_OF_DATA     DW      $


InstancePtr     DW      0               ;temp pointer to an XGAINSTANCE
GDTptr          DW      0               ;temp pointer to our GDTs



;
; Command line parsing table and vars
;
; Each parse block has the switch char, followed by the option byte,
; followed by the OFFSET (address) of the WORD where the result is stored.
; If the option byte == pNUMBER then an integer is read in and stored at
; OFFSET, otherwise the option byte is stored at OFFSET.
; Whitespace and colons are ignored in the command line. All switch chars
; are uppercased on input.
;

EXTRN vRamSpace :WORD

parseTab        parseBlock <'W', pNUMBER, OFFSET workSpace>
                parseBlock <'V', pNUMBER, OFFSET vRamSpace>

pTABLEN         EQU (($ - OFFSET parseTab) / TYPE parseBlock)
pNUMBER         EQU 080H


workSpace       DW 0
toGo            DW 80

;
; Messages
;

CR              EQU <13, 10>

IFDEF PUT_UP_MESSAGE
StartMsg        DB  CR, ' Version 3.00 (C) Copyright IBM Corp. 1986 - 1989', CR
StartMsgLen     EQU ($ - OFFSET StartMsg)
ENDIF

noXGAMsg        DB  '  No graphics adapter present.', CR
noXGAMsgLen     EQU ($ - OFFSET noXGAMsg)

ErrorMsg        DB  '  Installation Failed.', CR
ErrorMsgLen     EQU ($ - OFFSET ErrorMsg)

badFlagMsg      DB  '  Invalid parameter /', CR
badFlagLen      EQU ($ - OFFSET badFlagMsg)

flagBuff        DB 0

ifndef REAL_CRUISER
GDTreg          DF      0               ;Global Descriptor Table register
endif ; ndef REAL_CRUISER

AKDATA  ENDS


PUBLIC  Init
public  Set_DMA
public  Setup_On
public  Setup_Off

_TEXT           SEGMENT USE16 WORD PUBLIC 'CODE'
                assume  cs:_TEXT, ds:AKDATA, es:NOTHING, ss:NOTHING


; All of the following code can be discarded
; (NB. this assumes that this file is the last in the link order)
END_OF_CODE     equ     $

;/******************************************************************************
;/*
;/* Function:   Init
;/*
;/* Purpose:    Initialise the driver.
;/*
;/******************************************************************************

Init    PROC NEAR

        ; break for debugging
;       int     3

; Get the DevHlp address
        mov     eax, es:[bx].InitpEnd
        mov     Device_Help,eax

        push    es                                      ;save packet pointer
        push    bx

; We need some flat model pointers for the 2.0 specific calls we make
        ; first we will need a flat pointer to our pagelist structure
        ; a flat model pointer is basically a linear address, so lets
        ; convert our Virtual pagelist address to linear

        mov     ax, ds
        lea     esi, PageList           ; virtual address in ax:esi
        mov     dl, DevHlp_VirtToLin    ; convert it to linear
        call    Device_Help             ; eax = linear addr

        mov     FlatPageList, eax

        ; now get a linear address for the lock handle return array

        mov     ax, ds
        lea     esi, LockHandle         ; virtual address in ax:esi
        mov     dl, DevHlp_VirtToLin    ; convert it to linear
        call    Device_Help             ; eax = linear addr

        mov     FlatLockHandle, eax

        ; now get a linear address for the memory mapped register pointer

        mov     ax, ds
        lea     esi, XGARegPointer      ; virtual address in ax:esi
        mov     dl, DevHlp_VirtToLin    ; convert it to linear
        call    Device_Help             ; eax = linear addr

        mov     FlatXGARegPointer, eax

; Call PARSE to get the command line options
        call    parse                                   ;get command line opts

        call    Set_DMA

; just use the planar for the moment. (assumes xga is on planar).
        mov instances[0].slot_number, 0
        mov deviceNum, 1


; Shrink back end-of-memory over unused XGAINSTANCEs
        mov     ax, NUMOFINSTANCES
        sub     ax, deviceNum                           ;how many required
        imul    ax, SIZEOFXGAINSTANCE                   ;change to bytes
        sub     END_OF_DATA, ax                         ;adjust data limit

        lea     ax, END_OF_CODE                         ;tell OS/2 where ...
        mov     cx, END_OF_DATA                         ; the segs end

; Set command error = NO_Error
        mov     drvError, No_Error
        jmp     short iexit

; Set segment ends in packet
Iexit:
        pop     bx
        pop     es
        mov     WORD PTR es: [bx].initpEnd,   ax
        mov     WORD PTR es: [bx].initpEnd+2, cx

        ret

; Set command error = general failure
        mov     drvError, General_Failure               ;tell OS/2 we failed

        xor     ax, ax                                  ;(set CS & DS seg ..
        xor     cx, cx                                  ; .. length to zero)
        jmp     IExit

Init    ENDP








;/******************************************************************************
;/*
;/*     parse
;/*
;/*     Scan the command-line looking for flags and/or numbers as specified
;/*     in the parse table parseTab. The only switch indicator supported is
;/*     the '/' char, and only short positive integer numbers are allowed.
;/*     Whitespace in the command-line is ignored.
;/*
;/******************************************************************************

parse   PROC NEAR

        push    es                              ;save request block ptr
        push    bx

        les     di, DWORD PTR es: [bx].InitpEnd+4 ;get cmd line ptr

        push    di                              ;save cmd line ptr
        mov     al, 0                           ;locate end of string
        call    locate                          ;do it ...
        jc      pEnd                            ;can't find end of string
        mov     toGo, 80                        ;adjust toGo to be LOS
        sub     toGo, cx                        ; "      "      "
        pop     di                              ;restore cmd line ptr

flag:   mov     al, '/'                         ;locate backslash
        call    locate                          ;do it ...
        jc      pEnd                            ;can't find it; end of string

        mov     cx, pTABLEN                     ;get count of supported flags
        mov     si, OFFSET parseTab             ;address parse table
        call    getchar                         ;get switch char
        cmp     ax, 96                          ;is char lowercase ?
        jb      upChar                          ;nope .. skip
        sub     ax, 32                          ;yep  .. ASCII adjust
upChar: mov     bl, al                          ;keep a copy of it

lFlag:  lodsd                                   ;get parse table info
        cmp     al, bl                          ;match this switch char ?
        je      flagOk                          ;skip if so ...
        loop    lFlag                           ;check with next entry

        call    badflag                         ;display 'invalid flag' msg
        jmp     short flag                      ;look for more flags

flagOk: xor     bx, bx                          ;clear accumulator
        mov     bl, ah                          ;AH has parse table flags
        sar     eax, 16                         ;upper 16 has dest addr
        mov     si, ax                          ;get dest offset into SI
        test    bl, pNUMBER                     ;switch expect a number ?
        jz      notnum                          ;skip if not ...

        xor     bx, bx                          ;clear accumulator
num:    call    getchar                         ;get next digit
        sub     ax, 48                          ;ASCII adjust
        jc      notnum                          ;not a digit
        cmp     ax, 9
        ja      notnum                          ;not a digit
        imul    bx, 10                          ;bump decimal number
        add     bx, ax                          ;add digit to accumulator
        jmp     short num                       ;get another digit

notnum: mov     [si], bx                        ;save accumulator in dest
        jmp     short flag                      ;go get another switch

pEnd:   pop     bx                              ;restore request packet ptr
        pop     es

        ret                                     ;and go home ...

parse   ENDP

;
; Get next char from input buffer, stripping whitespace & colons.
;

TAB     EQU     8
SPACE   EQU     32
COLON   EQU     58

getchar PROC NEAR

        movzx   ax, BYTE PTR es: [di]           ;get next char
        inc     di                              ;bump to next ...
        dec     toGo                            ;one less char to go
        cmp     ax, SPACE                       ;ignore whitespace
        je      getchar
        cmp     ax, TAB                         ;ignore whitespace
        je      getchar
        cmp     ax, COLON                       ;ignore colons
        je      getchar
        ret                                     ;return char in AX

getchar ENDP

;
; Locate next instance in the input buffer of char passed in AL.
; Returns pointing at the char after the next instance.
;

locate  PROC NEAR

        mov     cx, toGo                        ;get count of chars to go
        jcxz    lBad                            ;oops ! internal error
        cld                                     ;(murphy's law)
        repne   scasb                           ;locate char passed in AL
        mov     toGo, cx                        ;reset chars to go
        clc                                     ;set default return state
        jz      lOk                             ;found the char ?
lBad:   stc                                     ;set error flag if not
lOk:    ret

locate  ENDP

;
; Display 'invalid flag' message. BL has flag char.
;

badflag PROC NEAR

;       mov     BYTE PTR [flagBuff], bl                 ;load flag char
;
;       push    STDIO                                   ;push STDIO handle
;       push    badFlagLen                              ;push message length
;       push    ds                                      ;push 32 bit addr
;       push    OFFSET badFlagMsg
;       call    DosPutMessage                           ;display text
;
;       push    STDIO                                   ;push STDIO handle
;       push    1                                       ;push message length
;       push    ds                                      ;push 32 bit addr
;       push    OFFSET flagBuff
;       call    DosPutMessage                           ;display text
        ret

badflag ENDP

;-----------------------------------------------------------------------;
;  Start of the SetDMA code
;-----------------------------------------------------------------------;

;-----------------------------------------------------------------------;
;  Equates
;-----------------------------------------------------------------------;
Max_Slots       equ     8               ; Maximum number of slots in system
DMA_Mask        equ     0D4h            ; DMA mask register
DMA_Mode        equ     0D6h            ; DMA mode register
XGA_ID          equ     8FD8h           ; XGA POS ID's 8FD8-8FDB
POS_Base        equ     100h            ; POS base address
Adapter_En      equ     108h            ; Adapter setup register for slot 0
ERROR_ABIOS_NOT_PRESENT         EQU     3


;-----------------------------------------------------------------------;
;  Initialize DMA for bus mastership.  Assumes the XGA adapter POST     ;
;  has already set up the DMA bits in POS.  Also assumes that nothing   ;
;  is in setup mode (planar nor adapters).                              ;
;-----------------------------------------------------------------------;
Set_DMA proc near

;-------------- Determine if this could be an ISA system

   pusha

   ; Get Logical ID request block for POS data
   mov     al, 010H                     ; device id (POS regs)
   mov     bl, 0                        ; get first free LID
   mov     dh, 1                        ; dma, pos
   mov     dl, DevHlp_GetLidEntry       ; call OS2
   call    Device_Help
   jnc     Set_DMA_01                   ; This is a micro-channel.

   cmp     ax, Error_ABIOS_Not_Present
   je      Set_DMA1
   jmp     Set_DMA_Done


Set_DMA_01:
; Free Logical ID request block
   mov     dl, DevHlp_FreeLIDEntry      ; free up our LID
   call    Device_Help                  ; do it
   jmp     Set_DMA_Done

;-------------- Search for an XGA in the system slots
Set_DMA1:
        mov     bl,1                    ; Start w/ slot 1
Set_DMA_Loop:
        call    Setup_On                ; Put slot in setup mode
        mov     dx,POS_Base+1           ; Read POS byte 1
        in      al,dx                   ; 
        mov     ah,al                   ; 
        dec     dx                      ; Read POS byte 0
        in      al,dx                   ; 
        and     al,11111100b            ; Look for any of 4 possible POS ID's
        cmp     ax,XGA_ID               ; Is it an XGA?
        jne     Set_DMA_Next            ; No - go check next slot

;-------------- Found XGA, now check if DMA bits in POS are set

        mov     dx,POS_Base+3           ; Read POS byte 3
        in      al,dx                   ; 
        and     al,00011000b            ; Is DMA enabled?
        jz      Set_DMA_Next            ; No - go check next slot

;-------------- Set up DMA channel for cascade mode

        shr     al,3                    ; Move DMA channel bits to lsb
        mov     ah,al                   ; Save in AH
        or      al,0D0h                 ; Set for cascade mode
        out     DMA_Mode,al             ; DMA mode reg
;       IO_Delay                        ;
        jmp     $+2
        jmp     $+2
        jmp     $+2
        mov     al,ah                   ; Restore DMA channel
        out     DMA_Mask,al             ; Set DMA mask reg
;       IO_Delay                        ;
        jmp     $+2
        jmp     $+2
        jmp     $+2

;-------------- Continue checking slots
Set_DMA_Next:
        call    Setup_Off               ; Take slot out of setup mode
        inc     bl                      ; Next slot
        cmp     bl,Max_Slots            ; More slots left?
        jbe     Set_DMA_Loop            ; Yes - continue searching

;-------------- All done
Set_DMA_Done:
        popa
        ret

Set_DMA endp

;-----------------------------------------------------------------------;
;  Setup_On                                                             ;
;                                                                       ;
;  Put selected slot into setup mode.  Slot number not value checked!   ;
;-----------------------------------------------------------------------;
;  On entry:  BL = 1-8 = Slot to put in setup mode                      ;
;                                                                       ;
;  On exit:   Selected slot in setup mode                               ;
;-----------------------------------------------------------------------;
;  Registers modified:  AL, DX, Flags                                   ;
;-----------------------------------------------------------------------;
Setup_On        proc    near

        mov     dx,Adapter_En           ; Adapter setup register for slot 0
        mov     al,bl                   ; Get slot number
        dec     al                      ; Adjust for base 0
        add     dl,al                   ; Offset to selected slot
        or      al,00001000b            ; Turn on setup bit
        out     dx,al                   ; Put slot in setup mode
        ret                             ; 

Setup_On        endp

;-----------------------------------------------------------------------;
;  Setup_Off                                                            ;
;                                                                       ;
;  Take selected slot out of setup mode.  Slot number not value checked!;
;-----------------------------------------------------------------------;
;  On entry:  BL = 1-8 = Slot to take out of setup mode                 ;
;                                                                       ;
;  On exit:   Selected slot out of setup mode.                          ;
;-----------------------------------------------------------------------;
;  Registers modified:  AL, DX, Flags                                   ;
;-----------------------------------------------------------------------;
Setup_Off       proc    near

        mov     dx,Adapter_En           ; Adapter setup register for slot 0
        mov     al,bl                   ; Get slot number
        dec     al                      ; Adjust for base 0
        add     dl,al                   ; Offset to selected slot
        and     al,11110111b            ; Turn off setup bit
        out     dx,al                   ; Take slot out of setup mode
        ret                             ; 

Setup_Off       endp

;-----------------------------------------------------------------------;
;  End of the SetDMA code
;-----------------------------------------------------------------------;

_TEXT   ENDS
        END
