;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; 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    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = 8514FONT.ASM
;*
;* DESCRIPTIVE NAME = 
;*
;*
;* VERSION      V2.0
;*
;* DATE         09/14/88
;*
;* DESCRIPTION  This module contains the functions that handle the font caching
;*              for the 8514.                                                   
;*
;* FUNCTIONS    cache_font  
;*              invalidate_font_cache  
;*              invalidate_cache
;*              invalidate_cache
;*              copy_font_bits
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   09/14/88                     Author:  Mike Harrington [mikehar]
;*    8/27/90                     rajivg Adapted and fitted this code into                          
;*                                OS/2 2.0 8514 font driver.
;*****************************************************************************/

        .286p

        .xlist

        include cmacros.inc
INCL_FONTFILEFORMAT     equ 1
        include pmgre.inc
        include driver.inc
        include 8514.inc
        include fontseg.inc
        include strblt8.inc
        include 8514mem.inc
        include njmp.mac
        include assert.mac
        .list

        ??_out  8514font

        externFP DosReAllocSeg


FONT_FREE  struc
ff_y        dw      ?        ; starting Y
ff_lines    dw      ?        ; number of free lines
ff_plane    db      ?
FONT_FREE  ends

sBegin  Data

font_buf_head dw    1       ; Initial size of font cache seg
font_free DB SIZE FONT_FREE DUP(?)
        externD hLocalHeap              ;Handle to our local heap
        externW selFont_list
        externW selCache_list
        externW OffScreenYMIN           ; start y of offscreen font cache.
        externW OffScreenYMAX           ; start y of offscreen font cache.
        externW OffScreenValid          ; Offscreen font cache validity flag

sEnd

sBegin  Code
        assumes cs,Code

        externW  CodeData
        externW  CacheData

;/***************************************************************************
;*
;* FUNCTION NAME = cache_font
;*
;* DESCRIPTION   = This function caches a font to 8514 VRAM. 
;*
;* INPUT         = selFont = font selector 
;* OUTPUT        = excel flag 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;* PSEUDO-CODE   =
;*
;*              {
;*                Is the font already cached?
;*                    yes - return success.
;*             
;*                Is there room for the font in VRAM?
;*                    no - return failure
;*             
;*                alloc room
;*             
;*                cache
;*             
;*                return
;*              }
;**************************************************************************/


define_frame chfont                  ; defining the stack frame.

cBegin  <nogen>
cEnd    <nogen>

CacheYMAX    equ   159

no_room_for_font_pop:
        pop     ax              ;clean up saved di
no_room_for_font:
        cCall   invalidate_cache
        mov     ax,dx
        and     excel,not CACHED_FONT
        errn$   cache_font

        public  cache_font              ; Temporary
cache_font  proc    far

        mov     ax,selFont               ;save  selector
        mov     dx,ax
        mov     es,CodeData
        assumes es,Data

        cmp     es:OffScreenValid,OFFSCREEN_VALID
        jz      @F
        cCall   invalidate_cache

@@:     cmp     lfd.font_height,CacheYMAX
        jbe     @F
        jmp     cf_font_too_large

@@:     lea     di,selFont_list
        mov     bx,di
        mov     cx,MAX_CACHED_FONTS
        mov     si,cx
;/*
;** now si = selFont_list + (MAX_CACHED_FONTS*2), or the end of the list.
;**       cx = MAX_CACHED_FONTS
;**       ax = our current font
;**       dir is set for backwards scan
;*/


        repne   scasw                           ;find the font selector
        jnz     @F
        sub     di,DataOFFSET selFont_list+2    ; because di had got updated by 2
        add     di,DataOFFSET selCache_list
        mov     ax,es:[di]                      ; save pointer to info list

;/*
;** From this point on, we store in offFont the offset to cacheData segment
;*/
        mov     offFont,ax
        jmp     font_is_cached
@@:

        mov     di,bx               ;it's not cached so lets find an empty slot
        mov     cx,si
        xor     ax,ax
        repne   scasw               ;find a free slot
        jnz     no_room_for_font
        sub     di,2                ;move pointer back to previous entry
        push    di                  ;save pointer to empty thing


        mov     ds,dx
        assumes ds,FontSeg

;/*
;**  Now we're going to run though the width tables to see how many lines
;**  we'll need to store the font. We do this by adding each width to the
;**  current X until we get to the end of the line, then we increment the
;**  line count. When we're done, we multiply our line count by the font
;**  width and we have our inital guess at the number of lines needed by
;**  the font.
;*/

        mov     cx,fsMetrics.foca_usLastChar    ; first char(zero) relative!!!
        inc     cx
        mov     si,6               ; 'normal' font increment
        cmp     fsDef.fdChardef,FONTDEFCHAR3
        jne     @f
        mov     si,8
@@:     mov     di,1
        xor     ax,ax
        lea     bx,fsDef.fdCellBaseOffset  ;set pointer to char offsets
        add     bx,2            ; 2 to get to the char table
total_lines:
        mov     dx,[bx]         ; compare if offset zero
        or      dx,[bx][2]      ; if yes then skip this char
        jz      nextchar
        cmp     si,8
        jne     @F
        add     bx,2            ; because we want to access 'b' width
@@:
        mov     dx,[bx][4]
        add     dx,7            ; round up to next byte
        and     dx,(NOT 7)
        add     ax,dx
        cmp     ax,1024
        jl      nextchar
        inc     di
        mov     ax,[bx][4]
nextchar:
        add     bx,si
        loop    total_lines
        mov     ax,di
        mul     fsDef.fdCellHeight
        mov     dx,ds
        lea     di,font_free
        cmp     es:[di].ff_lines,ax
        njc     no_room_for_font_pop

        mov     cx,ax
        mov     ax,fsMetrics.foca_usLastChar
        inc     ax
        mov     bx,(size HW_FONT_ENTRIES)
        cmp     fsDef.fdChardef,FONTDEFCHAR3
        jne     @f
        mov     bx,(size HW_ABC_FONT_ENTRIES)
@@:
        mul     bx
        mov     dx,CacheData
        lsl     bx,dx
        mov     dx,bx
        sub     bx,font_buf_head    ;top of seg - top of buf = room left
        cmp     ax,bx
        jle     cf_room_in_seg
        push    ax
        sub     ax,bx               ;total needed - what we have
        add     ax,dx               ;what we need + current seg limit
        cmp     ax,dx               ; make sure that unsigned overflow didn't occur
        jg      @F
        pop     ax
        jmp     no_room_for_font_pop
@@:
        push    cx
        mov     dx,CacheData
        cCall   DosReAllocSeg,<ax,dx>
        mov     dx,ax
        pop     cx
        pop     ax
        or      dx,dx
        njnz    no_room_for_font_pop
cf_room_in_seg:
        add     ax,font_buf_head
        xchg    ax,font_buf_head
cf_save_sel:
        pop     si                     ; restore pointer
        mov     es:[si],ds             ;save selector in list
        sub     si,DataOFFSET selFont_list
        add     si,DataOFFSET selCache_list
        mov     es:[si],ax             ; save pointer to info list
;/*
;** From this point on, we store in offFont the offset to cacheData segment
;*/
        mov     offFont,ax

        mov     bx,es:[di].ff_y
        mov     dx,1024
        sub     dx,bx
        cmp     dx,fsDef.fdCellHeight
        jg      @f
        inc     es:[di].ff_plane
        mov     bx,es:OffScreenYMIN
        mov     es:[di].ff_y,bx
        sub     es:[di].ff_lines,dx
        jns     @f
        mov     dx,ds
        jmp     no_room_for_font
@@:
        add     bx,cx
        mov     dl,es:[di].ff_plane
        cmp     bx,1024
        jl      fits_in_one_plane
check_it_again_sam:
        sub     bx,1024
        add     bx,es:OffScreenYMIN
        inc     es:[di].ff_plane
        cmp     bx,1024
        jge     check_it_again_sam
fits_in_one_plane:
        xchg    bx,es:[di].ff_y
        sub     es:[di].ff_lines,cx
        mov     cl,dl
        push    di

;/*
;** now ds:si (and es:si) point to the selCache_list struct. It's time
;** to copy our font bits to display ram.
;*/
        mov     di,bx
        mov     si,ax   ;????????

        push    es:OffScreenYMIN
        mov     es,CacheData
        assumes es,Cache
        cCall   copy_font_bits
        pop     di
        mov     ds,CodeData
        assumes ds,Data

        or      ax,ax
        jz      restart_relay
;/*
;**Let's see where we ended. First let's check the final Y
;*/
        cmp     bx,[di].ff_y
        je      @f                  ;y's ok
        mov     ax,[di].ff_y
        sub     ax,bx
        mov     [di].ff_y,bx        ;adjust cur y and line count
        add     [di].ff_lines,ax
        jns     @f
        jmp     no_room_for_font
@@:     mov     [di].ff_plane,dl    ;save real plane number
        or      ch,ch               ;did we run out of planes?
        jz      font_is_cached
restart_relay:
        jmp     no_room_for_font
font_is_cached:
        or      excel,CACHED_FONT    ; flag that the font is cached
        mov     ax,CACHED_FONT
        jmp     short cf_exit

cf_font_too_large:
        and     excel,not CACHED_FONT
        xor     ax,ax

cf_exit:
        ret
cache_font  endp


;/***************************************************************************
;*
;* FUNCTION NAME = invalidate_font_cache
;*
;* DESCRIPTION   = If the given font selector is in the font cache, and this  
;*                 is a display dc, the cache is marked as invalid.  We expect
;*                 the caller to not call this routine with the default       
;*                 character or marker font since they can never be unloaded  
;*                 (thus their z selector cannot be reused).
;*
;*                 Registers Destroyed:
;*                       BX,CX,DI,ES,FLags
;*
;* INPUT         = AX = Font selector 
;*                 BX = ddc
;*                 DS = Data
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

        public  invalidate_font_cache
invalidate_font_cache   proc    near
        mov     bx,[bx].ddc_npsd        ;  is the device and not an IC
        mov     bl,[bx].sd_fb
        and     bl,SD_DEVICE or SD_NONNULL
        cmp     bl,SD_DEVICE or SD_NONNULL
        jne     cache_invalidated

;/*
;** This is the physical device.  We will have to walk the list of fonts
;** currently cached to see if this selector is in the list.
;*/

;/*
;** Search the identifier list for the selector belonging to the current font
;*/


        mov     cx,MAX_CACHED_FONTS     ;Search this many cache structures
        mov     di,DataOFFSET selFont_list
        mov     es,CodeData
        assumes es,Data
        repnz   scasw
        jne     not_found_in_cache

;/*
;** We found the entry, so we need to mark the cache as invalid.
;*/
        dec     di                  ; because it gets updated by 2
        dec     di
        mov     es:[di],0ffffh      ; mark this entry as invalid
        sub     di,DataOFFSET selFont_list
        add     di,DataOFFSET selCache_list
        mov     es:[di],0ffffh      ; mark this entry as invalid

not_found_in_cache:
cache_invalidated:
        ret

invalidate_font_cache   endp

;/***************************************************************************
;*
;* FUNCTION NAME = invalidate_cache
;*
;* DESCRIPTION   = invalidates font cache list by restoring the free list to its
;*                 initial state and clearing the font selector list.           
;*
;*                 Registers Preserved:
;*                       DX
;*
;* INPUT         = ES = CodeData 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

cProc   far_invalidate_cache,<FAR,PUBLIC,NODATA>
cBegin
        call    invalidate_cache
cEnd

cProc   invalidate_cache,<PUBLIC,NEAR>,<ax,bx,dx>
cBegin
        mov     es,CodeData
        assumes es,Data

        lea     di,selFont_list  ;Wipe out fontsel list
        xor     ax,ax
        mov     cx,MAX_CACHED_FONTS
        rep     stosw

        mov     bx,es:OffScreenYMIN
        mov     ax,1024
        mov     es:font_free.ff_y,bx
        sub     ax,bx
        shl     ax,3
        mov     es:font_free.ff_lines,ax
        xor     ax,ax
        mov     es:font_free.ff_plane,al
        mov     es:font_buf_head,0

        mov     es:OffScreenValid,OFFSCREEN_VALID

cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = copy_font_bits
;*
;* DESCRIPTION   = Copies font bits to display adapter 
;*
;* INPUT         = es:si-> cached font table 
;*                 ds: fontseg               
;*                 di: starting Y            
;*                 cx: starting plane        
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

cProc   copy_font_bits,<PUBLIC,NEAR>
        parmW   OffsetY
        localW  fontheight
        localW  char_cols
        localW  count
        localW  cur_y
        localW  plane
        localW  plane_nomodify
cBegin

        assumes es,Cache
        assumes ds,FontSeg

        mov     plane,cx
        mov     plane_nomodify,cx
        mov     cur_y,di
        mov     di,si
        xor     si,si
        mov     dx,fsDef.fdCellHeight
        mov     fontheight,dx
        mov     bx,fsMetrics.foca_usLastChar
        inc     bx
        mov     count,bx
        mov     bx,dx

        lea     si,fsDef.fdCellBaseOffset  ;set pointer to char offsets
        add     si,2;!!!

;/*
;** 8514/a initalization
;*/

        WaitQ   3                      ;trashes ax,cx,dx
        mov     ax,bx
        dec     ax
        .errnz  LY_2DECODE
        outwQ   MISC_REG
        mov     ax,7
        outwQ   MAJ_AXIS_PCNT
        mov     cx,plane
        mov     ax,1
        shl     ax,cl
        mov     plane,ax
        outwQ   WRITE_MASK_REG,
        WaitQ   7
        outwQ   MISC_REG,(MODE_2DECODE+MD_PS_VAR+0)
        outwQ    BKGD_MIX_REG,(FUNC_ZEROS)
        outwQ    FRGD_MIX_REG,(FUNC_ONES)
        outwQ    MISC_REG,YMIN_2DECODE
        outwQ    MISC_REG,XMIN_2DECODE
        outwQ    MISC_REG,(XMAX_2DECODE+3ffh)
        outwQ    MISC_REG,(YMAX_2DECODE+3ffh)
        xor     bx,bx
        cmp     fsDef.fdChardef,FONTDEFCHAR3
        jne     cfb_do_char
        jmp     do_abc_font

cfb_do_char:
        mov     ax,1024
        sub     ax,bx
        mov     dx,[si]
        or      dx,[si][2]              ; compare if char offset zero
        jz      cfb_room_left
        mov     dx,[si][4]
        or      dx,dx
        jz      cfb_room_left
        add     dx,7
        shr     dx,3                    ;bx=# rows/char=(width+7)/8
        mov     char_cols,dx
        shl     dx,3
        cmp     dx,ax
        jle     cfb_room_left
        xor     bx,bx
        mov     ax,cur_y
        mov     cx,fontheight
        add     ax,cx
        mov     dx,1024
        sub     dx,cx
        cmp     ax,dx
        jl      @f
        inc     plane_nomodify
        mov     ax,plane
        add     al,al                   ; increment plane
        mov     plane,ax
        njc     cfb_exit_bad            ; no planes left
        WaitQ   1
        mov     ax,plane
        outwQ   WRITE_MASK_REG,
        mov     ax,OffsetY
@@:
        mov     cur_y,ax
cfb_room_left:

        mov     ax,bx
        stosw
        mov     ax,cur_y
        stosw
        mov     ax,[si][4]

        stosw
        mov     ax,plane
        rol     al,1
        stosw

        mov     ax,[si]
        or      ax,[si][2]          ; if offset zero, go to new char
        jz      next_char
        mov     ax,[si][4]          ; if width zero, go to new char
        or      ax,ax
        jz      next_char
        push    si
        mov     si,[si].lo

cfb_do_col:

        WaitQ   3
        WaitCMD
        outwQ    Y0,cur_y
        outwQ    X0,bx
        outwQ    COMMAND_REG,41b3h+CMD_BYTE
        mov     cx,fontheight
        mov     dx,PIXEL_TRANS_REG

cfb_outbits:
        lodsb
        mov     ah,al          ;copy backwards byte into al
        shr     ah,3           ; move bits to current position
        shl     al,1
        out     dx,ax
        loop    cfb_outbits

        add     bx,8
        dec     char_cols      ;Are we finished with this character?
        jnz     cfb_do_col

;/*
;**at this point, we're done with a character.
;*/
        pop     si
next_char:
        dec     count
        jz      cfb_exit
        add     si,6    ;!!!
        jmp     cfb_do_char

cfb_exit:
        mov     ax,1
        push    ax
cfb_leave:
        ;restore 8514 to the default state
        WaitQ   8
        outwQ    MISC_REG,<XMIN_2DECODE>
        outwQ    ,<XMAX_2DECODE or 03ffh>
        outwQ    ,<YMIN_2DECODE>
        outwQ    ,<YMAX_2DECODE or 03ffh>
        outwQ    ,MODE_2DECODE                 ;Graphics Mode Register
        outwQ    WRITE_MASK_REG,0ffffh
        outwQ    BKGD_MIX_REG,FUNC_ZEROS       ;For performance purposes
        outwQ    FRGD_MIX_REG,FUNC_ZEROS

        mov     bx,cur_y
        add     bx,fontheight
        mov     cx,plane
        mov     dx,plane_nomodify
        pop     ax

cEnd

cfb_exit_bad:
        xor     ax,ax
        push    ax
        jmp     short cfb_leave

do_abc_font:
        mov     ax,1024
        sub     ax,bx
        mov     dx,[si]
        or      dx,[si][2]              ; if char offset zero, skip this char
        jz      abc_cfb_room_left
        mov     dx,[si][6]
        add     dx,7
        shr     dx,3                    ;bx=# rows/char=(width+7)/8
        mov     char_cols,dx
        shl     dx,3
        cmp     dx,ax
        jle     abc_cfb_room_left
        xor     bx,bx
        mov     ax,cur_y
        add     ax,fontheight
        cmp     ax,1024
        jl      @f
        inc     plane_nomodify
        mov     ax,plane
        add     al,al
        mov     plane,ax
        njc     cfb_exit_bad
        WaitQ   1
        mov     ax,plane
        outwQ   WRITE_MASK_REG,
        mov     ax,OffsetY
@@:
        mov     cur_y,ax
abc_cfb_room_left:

        mov     ax,bx
        stosw
        mov     ax,cur_y
        stosw
        mov     ax,[si][4]
        stosw
        mov     ax,[si][6]
        stosw
        mov     ax,[si][8]
        stosw
        mov     ax,plane
        rol     al,1
        stosw

        mov     ax,[si]
        or      ax,[si][2]          ; if offset zero, go to new char
        jz      next_char1
        push    si
        mov     si,[si].lo

abc_cfb_do_col:

        WaitQ   3
        WaitCMD
        outwQ    Y0,cur_y
        outwQ    X0,bx
        outwQ    COMMAND_REG,41b3h+CMD_BYTE
        mov     cx,fontheight
        mov     dx,PIXEL_TRANS_REG

abc_cfb_outbits:
        lodsb
        mov     ah,al          ;copy backwards byte into al
        shr     ah,3           ; move bits to current position
        shl     al,1
        out     dx,ax
        loop    abc_cfb_outbits

        add     bx,8
        dec     char_cols      ;Are we finished with this character?
        jnz     abc_cfb_do_col

;/*
;**at this point, we're done with a character.
;*/
        pop     si
next_char1:
        dec     count
        jz      abc_cfb_exit
        add     si,10   ;!!!
        jmp     do_abc_font

abc_cfb_exit:
        jmp     cfb_exit

sEnd    Code



        end
