;*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    ,132
;-----------------------------Module-Header-----------------------------;
; Module Name:  palette.asm
;
; This file contains the routines which load the palette
;
; CHANGE ACTIVITY =
;   DATE      FLAG        APAR   CHANGE DESCRIPTION
;   --------  ----------  -----  ------------------------------------
;   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;   04/04/93              63295  Cleanup stack after call to Set8514HWPalette.
;   12/06/93              ?????  Make sure the DAC Select bits of 3D4/55 are
;                                set to zero before loading palette entries.
;-----------------------------------------------------------------------;

        .386p
        .xlist
ifdef   S3
;;;DAC_8BIT EQU 1          ;Uncomment this line if DAC is in 8-bit mode
endif

DCR89 EQU 1
ifdef DCR89
INCL_GPIBITMAPS EQU 1
include os2.inc
endif ;DCR89

include eddinclt.inc

?DF     equ     1                                                       ;**
include cmacros.inc

include eddhmacr.inc
include eddhcone.inc
include eddhtype.inc
include plasma.inc


TARGET_MONO             equ 00000001b
TARGET_PLASMA_MONO      equ 00000010b
LOAD_PLASMA             equ 00000100b

; change to support the M-Motion Video Adapter hanging off the
; video extension bus. M-Motion needs XGA palette changes echoed to the
; VGA palette locations
; 10/23/1992  LeRoy A. Krueger  Atlanta Development Lab
;
MMotion EQU 1
ifdef MMotion
ECHO_VGA                equ 00001000b
endif

_DATA   segment use32 dword public 'DATA'                               ;**


extrn   _DDT                    :byte
extrn   _IOBase                 :word

ifndef  _8514
extrn   _PaletteRoutine         :byte
extrn   _plasma_type_routine    :byte
extrn   _plasma_status          :byte
else
include 8514.inc
endif

ifdef CORRECT_RGB
;   /**********************************************************************/
;   /* gamma etc correction lookup tables                                 */
;   /* this converts between the assumed linear r,g or b component of a   */
;   /* PM RGB value and the corrected value required on the non-linear    */
;   /* 8514 monitor                                                       */
;   /* (This mapping is based on dodgy theory since it assumes that all   */
;   /* 8514 monitors behave the same [and 8515 and any other 8514         */
;   /* lookalikes] and we can't really believe that everone has their     */
;   /* brightness and contrast setting in the 'ideal' position anyway)    */
;   /**********************************************************************/
;   /**********************************************************************/
;   /* this table is the linear to psychometric table given in DCR 25074  */
;   /**********************************************************************/
;   /**********************************************************************/
;   /* this function allows for the fact that only 6 msb are significant  */
;   /* basically we scale the number (mult by 63/255), add 1/2 (255/510)  */
;   /* to round up, then shift left by 2 to place in the 6 most           */
;   /* significant bits                                                   */
;   /**********************************************************************/
;   #define fn(x) ((x * 126 + 255)/510) << 2
;
;   BYTE Linear_to_6BitHW[256] = {
;           fn(  0),fn(  6),fn( 18),fn( 26),fn( 33),fn( 39),fn( 44),fn( 48),
;           fn( 52),fn( 56),fn( 60),fn( 63),fn( 66),fn( 69),fn( 72),fn( 74),
;           fn( 77),fn( 79),fn( 81),fn( 84),fn( 86),fn( 88),fn( 90),fn( 92),
;           fn( 94),fn( 96),fn( 97),fn( 99),fn(101),fn(103),fn(104),fn(106),
;           fn(107),fn(109),fn(110),fn(112),fn(113),fn(115),fn(116),fn(117),
;           fn(119),fn(120),fn(121),fn(123),fn(124),fn(125),fn(126),fn(128),
;           fn(129),fn(130),fn(131),fn(132),fn(133),fn(134),fn(136),fn(137),
;           fn(138),fn(139),fn(140),fn(141),fn(142),fn(143),fn(144),fn(145),
;           fn(146),fn(147),fn(148),fn(149),fn(150),fn(151),fn(151),fn(152),
;           fn(153),fn(154),fn(155),fn(156),fn(157),fn(158),fn(159),fn(159),
;           fn(160),fn(161),fn(162),fn(163),fn(163),fn(164),fn(165),fn(166),
;           fn(167),fn(167),fn(168),fn(169),fn(170),fn(171),fn(171),fn(172),
;           fn(173),fn(174),fn(174),fn(175),fn(176),fn(176),fn(177),fn(178),
;           fn(179),fn(179),fn(180),fn(181),fn(181),fn(182),fn(183),fn(183),
;           fn(184),fn(185),fn(185),fn(186),fn(187),fn(187),fn(188),fn(189),
;           fn(189),fn(190),fn(191),fn(191),fn(192),fn(192),fn(193),fn(194),
;           fn(194),fn(195),fn(196),fn(196),fn(197),fn(197),fn(198),fn(198),
;           fn(199),fn(200),fn(200),fn(201),fn(201),fn(202),fn(203),fn(203),
;           fn(204),fn(204),fn(205),fn(205),fn(206),fn(206),fn(207),fn(208),
;           fn(208),fn(209),fn(209),fn(210),fn(210),fn(211),fn(211),fn(212),
;           fn(212),fn(213),fn(213),fn(214),fn(215),fn(215),fn(216),fn(216),
;           fn(217),fn(217),fn(218),fn(218),fn(219),fn(219),fn(220),fn(220),
;           fn(221),fn(221),fn(222),fn(222),fn(223),fn(223),fn(224),fn(224),
;           fn(225),fn(225),fn(225),fn(226),fn(226),fn(227),fn(227),fn(228),
;           fn(228),fn(229),fn(229),fn(230),fn(230),fn(231),fn(231),fn(232),
;           fn(232),fn(232),fn(233),fn(233),fn(234),fn(234),fn(235),fn(235),
;           fn(236),fn(236),fn(236),fn(237),fn(237),fn(238),fn(238),fn(239),
;           fn(239),fn(240),fn(240),fn(240),fn(241),fn(241),fn(242),fn(242),
;           fn(242),fn(243),fn(243),fn(244),fn(244),fn(245),fn(245),fn(245),
;           fn(246),fn(246),fn(247),fn(247),fn(247),fn(248),fn(248),fn(249),
;           fn(249),fn(249),fn(250),fn(250),fn(251),fn(251),fn(251),fn(252),
;           fn(252),fn(253),fn(253),fn(253),fn(254),fn(254),fn(255),fn(255)
;         };

; The code above used to be in the C part of the driver.
; The table it generates is given below
; (moving it into the asm code makes this module more self contained)
Linear_to_6BitHW  label byte

        db      000h, 004h, 010h, 018h, 020h, 028h, 02ch, 030h
        db      034h, 038h, 03ch, 040h, 040h, 044h, 048h, 048h
        db      04ch, 050h, 050h, 054h, 054h, 058h, 058h, 05ch
        db      05ch, 060h, 060h, 060h, 064h, 064h, 068h, 068h
        db      068h, 06ch, 06ch, 070h, 070h, 070h, 074h, 074h
        db      074h, 078h, 078h, 078h, 07ch, 07ch, 07ch, 080h
        db      080h, 080h, 080h, 084h, 084h, 084h, 088h, 088h
        db      088h, 088h, 08ch, 08ch, 08ch, 08ch, 090h, 090h
        db      090h, 090h, 094h, 094h, 094h, 094h, 094h, 098h
        db      098h, 098h, 098h, 09ch, 09ch, 09ch, 09ch, 09ch
        db      0a0h, 0a0h, 0a0h, 0a0h, 0a0h, 0a4h, 0a4h, 0a4h
        db      0a4h, 0a4h, 0a8h, 0a8h, 0a8h, 0a8h, 0a8h, 0a8h
        db      0ach, 0ach, 0ach, 0ach, 0ach, 0ach, 0b0h, 0b0h
        db      0b0h, 0b0h, 0b0h, 0b4h, 0b4h, 0b4h, 0b4h, 0b4h
        db      0b4h, 0b8h, 0b8h, 0b8h, 0b8h, 0b8h, 0b8h, 0bch
        db      0bch, 0bch, 0bch, 0bch, 0bch, 0bch, 0c0h, 0c0h
        db      0c0h, 0c0h, 0c0h, 0c0h, 0c4h, 0c4h, 0c4h, 0c4h
        db      0c4h, 0c4h, 0c4h, 0c8h, 0c8h, 0c8h, 0c8h, 0c8h
        db      0c8h, 0c8h, 0cch, 0cch, 0cch, 0cch, 0cch, 0cch
        db      0cch, 0d0h, 0d0h, 0d0h, 0d0h, 0d0h, 0d0h, 0d0h
        db      0d0h, 0d4h, 0d4h, 0d4h, 0d4h, 0d4h, 0d4h, 0d4h
        db      0d8h, 0d8h, 0d8h, 0d8h, 0d8h, 0d8h, 0d8h, 0d8h
        db      0dch, 0dch, 0dch, 0dch, 0dch, 0dch, 0dch, 0dch
        db      0e0h, 0e0h, 0e0h, 0e0h, 0e0h, 0e0h, 0e0h, 0e0h
        db      0e0h, 0e4h, 0e4h, 0e4h, 0e4h, 0e4h, 0e4h, 0e4h
        db      0e4h, 0e4h, 0e8h, 0e8h, 0e8h, 0e8h, 0e8h, 0e8h
        db      0e8h, 0e8h, 0e8h, 0ech, 0ech, 0ech, 0ech, 0ech
        db      0ech, 0ech, 0ech, 0ech, 0f0h, 0f0h, 0f0h, 0f0h
        db      0f0h, 0f0h, 0f0h, 0f0h, 0f0h, 0f4h, 0f4h, 0f4h
        db      0f4h, 0f4h, 0f4h, 0f4h, 0f4h, 0f4h, 0f4h, 0f8h
        db      0f8h, 0f8h, 0f8h, 0f8h, 0f8h, 0f8h, 0f8h, 0f8h
        db      0f8h, 0fch, 0fch, 0fch, 0fch, 0fch, 0fch, 0fch
endif ; CORRECT_RGB

ifdef WAIT_FLYBACK
globalB waitfb,0
endif ; WAIT_FLYBACK

        align   4

globalD disp_mode_store,0

_DATA   ends

_IOPL   segment dword use32 public 'CODE'
        assume  cs:FLAT, ds:FLAT, es:FLAT

extrn   _disable_cursor  :proc
extrn   _reenable_cursor :proc
extrn   _foregroundSession:word

ifndef _8514

;/**********************************************************************
;/* Function:  LoadPaletteEntries
;/* Purpose:   Load palette
;/*
;/*  This routine makes the far call through the callgate which is
;/*   needed in order to run the routine with IOPL (actually at ring 0)
;/**********************************************************************

; We have to use a Masm proc, not a cMacros proc for this routine in
; order to get exactly what we want (Because this is called from C we need
; to use the _stdcall calling convention, where the called routine pops
; its parameters when returning)

        pPaletteEntries   equ   <[ebp+16]>
        count             equ   <[ebp+12]>
        start             equ   <[ebp+8] >

        align   4
        public  _LoadPaletteEntries
_LoadPaletteEntries     proc    near

        mov     ax, _foregroundSession
        or      ax, ax
        jz      lpe_dead
        push    ebp
        mov     ebp,esp
        push    ebx
        push    esi
        push    edi

        ; XGA hardware cannot have both sprite and palette updates at the
        ; same time so we must disbale the cursor.
        call    _disable_cursor

        push    pPaletteEntries
        push    count
        push    start
        call    fword ptr _PaletteRoutine.cg_offset

        call    _reenable_cursor

        pop     edi
        pop     esi
        pop     ebx
        mov     esp,ebp
        pop     ebp

lpe_dead:
        ret     ;12

_LoadPaletteEntries  endp

;/**********************************************************************
;/* Function:  LoadPaletteEntriesWorker
;/* Purpose:   Load palette
;/*
;/*  In the 2.0 driver (which implements palette manager) this is
;/*   always passed a colour palette.  The routine itself does any
;/*   colour  -> mono translations required if the monitor is mono
;/**********************************************************************
; We have to use a Masm proc, not a cMacros proc for this routine in
; order to get exactly what we want

        align   4
        public  _LoadPaletteEntriesWorker
_LoadPaletteEntriesWorker       proc far
        start           equ     <[ebp]>
        count           equ     <[ebp+4]>
        pPaletteEntries equ     <[ebp+8]>

; Even though we are 32 bit we must use si, NOT esi in the next line
; because the calling convention only passes us a stack offset in si
        movzx   ebp, si          ; this is where the parameters were placed

; set up the data segment because we currently have 0's in the selectors
        mov     ax, SEG FLAT:_IOBase
        mov     ds, ax
        mov     es, ax

; get the start of the port addresses
        mov     dx, _IOBase

; Set hardware palette sequence register = RGB
        mov     ax, palette_rgb
        iowrite index, ax

; Get the index of the first location to be modified from the parm block
        mov     ebx, start

ifdef WAIT_FLYBACK
        ; wait for an initial blanking period to start
        cCall   WaitForBlankingStart
endif ; WAIT_FLYBACK

; Write to hardware sprite/palette index write register
        mov     al, sprite_indx_write_lo  ; Write low byte
        mov     ah, bl
        iowrite index, ax
        mov     al, sprite_indx_write_hi  ; Write high byte
        mov     ah, bh
        iowrite index, ax

; Get number of entries to update from parm block
        mov     ecx, count

; we always do any colour to mono conversions needed on the fly
        xor     edi,edi         ; no flags set yet

        ; check if the monitor we
        ; are loading the palette to is colour or mono
DM_MONO equ     00000010b       ; should be in xgaadapt.inc
        test    [_DDT],DM_MONO
        jz      short is_colour

        or      edi,TARGET_MONO
is_colour:

ifdef PDP
        test    _plasma_status,PLASMA_ENABLED
ifdef MMotion
        jnz     short record_plasma     ; do the PDP stuff as written

        mov     ax,disp_mode1 OR (disp_mode1 SHL 8)     ; put in ah and al
        iowrite index,al                ; select the register to read from
        ioread  al,dataio               ; get the display mode 1 value

        test    al,000010000B           ; test for the VEB bit
        jz      short VFB_done          ; VEB not enabled, skip VGA load

        or      edi, ECHO_VGA           ; VEB enabled, echo palette to VGA
        jmp     short store_mode1       ; let the PDP code do the work for us

record_plasma:
else
        jz      short VFB_done
endif

        ; flag that we need to write to the plasma palette
        or      edi, LOAD_PLASMA


        ; keep a track of whether plasma is emulating colour or mono
        test    _plasma_status,PLASMA_COLOUR
        jnz     short not_plasma_mono

        or      edi,TARGET_PLASMA_MONO
not_plasma_mono:

        ; if the VFB bit is set then palette writes don't get through
        ; to the XGA palette
        ; hence turn off the VFB bit
        ; do this for as short a time as possible

        mov     ax,disp_mode1 OR (disp_mode1 SHL 8)     ; put in ah and al
        iowrite index,al                ; select the register to read from
        ioread  al,dataio               ; get the display mode 1 value

ifdef MMotion
store_mode1:
endif

        ror     ax,8                    ; make ah = data, al = index
        or      ah,00000011b            ; ensure normal operation
        mov     disp_mode_store,eax     ; save this value to be restored later
        and     ah,11101111b            ; turn off VFB bit
        iowrite index, ax               ; write the modified disp_mode 1 value
VFB_done:
endif ; PDP

; Get the address of the palette data from parm block
        mov     esi, pPaletteEntries      ; address in esi              ;**

        mov     al, palette_data          ; index = data register
        iowrite index, al
        cld                               ; make si increment

        ; point at the palette data register
        add     dx,dataio

        ; is the target palette mono
        test    edi,TARGET_MONO
        jz      short no_greyscaling

mono_loop:
        ; for each palette entry we must get the RGB value
        ; then calculate a mono value using the weightings
        ;       Red     0.30
        ;       Green   0.59
        ;       Blue    0.11
        ; 
        ; this value is then output to the green gun only
        ; (note that we are working in RGB ordering)

        lodsb                   ; get the blue
        mov     ah,11
        mul     ah              ; weight by 0.11
        mov     bx,ax           ; sum of the weighted values so far

        lodsb                   ; get the green
        mov     ah,59           ; weight by 0.59
        mul     ah
        add     bx,ax           ; sum of the weighted values so far

        lodsb                   ; get the red
        mov     ah,30
        mul     ah              ; weight by 0.30
        add     ax,bx           ; add back the weighted sum

        mov     bx,100          ; weights add up to 100
        div     bl
        mov     ah,al           ; save the weighted value in ah

        xor     al,al
        out     dx,al           ; output 0 for red
        mov     al,ah
ifdef CORRECT_RGB
        lea     ebx, Linear_to_6BitHW                                   ;**
        xlatb   [ebx]         ; apply psychometric correction           ;**
endif ; CORRECT_RGB
        out     dx,al           ; output mono value to green
        xor     al,al
        out     dx,al           ; output 0 for blue

        inc     si              ; discard the X source byte

        loop    mono_loop

        jmp     short palette_done

no_greyscaling:
        ; loading a colour palette is easier

ifdef CORRECT_RGB
        lea     ebx, Linear_to_6BitHW                                   ;**
endif ; CORRECT_RGB

table_output:

ifdef WAIT_FLYBACK
        ; ensure we are still in a blanking period
        cCall   EnsureInBlanking
endif ; WAIT_FLYBACK

        lodsd                   ; get the xrgb value into eax
        ror     eax,16          ; eax = gbxr
ifdef CORRECT_RGB
        xlatb   [ebx]         ; apply psychometric correction           ;**
endif ; CORRECT_RGB
        out     dx,al           ; write Red value
        ror     eax,16          ; eax = xrgb
        xchg    al,ah           ; eax = xrbg
ifdef CORRECT_RGB
        xlatb   [ebx]         ; apply psychometric correction           ;**
endif ; CORRECT_RGB
        out     dx,al           ; write Green value
        xchg    al,ah           ; ax = gb
ifdef CORRECT_RGB
        xlatb   [ebx]         ; apply psychometric correction           ;**
endif ; CORRECT_RGB
        out     dx,al           ; write Blue value
        loop    table_output

palette_done:
        sub     dx,dataio       ; restore the dx register

ifdef PDP
ifdef MMotion
        test    edi, LOAD_PLASMA OR ECHO_VGA
else
        test    edi, LOAD_PLASMA
endif
        jz      palettes_loaded         ; no need to load VGA palette
                                        ; if plasma not enabled

        ; restore the VFB bit state
        mov     eax,disp_mode_store     ; ax holds address and data !
        iowrite index, ax

        ; now program the VGA palette

        mov     ecx, count
        mov     ebx, start

        ; we need to pointer to the palette again
        mov     esi, pPaletteEntries                                    ;**

ready_to_load:

; The 1st two IN instructions will selectively reset the Attribute Controller
; Register flip-flop, 3DAh is for color mode and 3BA is for mono.  The OUT
; to the Attribute Controller Register (3C0) with a value of 14h selects the
; Color Select Register as the target, a zero value written to the Color
; Select Register enables the 1st 16 set of R,G,B values in the DAC for
; attribute mapping.  The last out to 3C0h is required to re-enable the
; video for display.

        cli
        mov     dx,VGA_BASE+FEATURE_CONTROL_1    ; Reset the attr reg
        in      al,dx
        mov     dl,FEATURE_CONTROL_2             ; Reset the attr reg
        in      al,dx

        mov     dl,ATTR_REG
        mov     al,COLOR_SELECT or PAL_ADDR_SRC
        out     dx,al            ;select "color select register"
        xor     al,al            ;set color select register to 0
        out     dx,al            ;and select palette 0

        ; now we need to loop through to ensure
        ; that entry 0 uses palette value 0 etc up to 16 using 16
        ; al is currently 0
index_loop:
        xor     al,PAL_ADDR_SRC         ; set this bit in the address so that
                                        ; we can change the palette
        out     dx,al                   ; this is the entry we are setting
        xor     al,PAL_ADDR_SRC         ; turn off this bit in the value
        out     dx,al                   ; output the value
        inc     al
        cmp     al,16
        jne     index_loop

        ; now set the actual palette entries
        mov     dl,DAC_INDEX
        mov     al,bl                   ; bx holds start parameter
        out     dx,al                   ; specify starting index
        mov     dl,DAC_DATA             ; DX --> DAC data register

        ; is the target palette mono
        test    edi,TARGET_PLASMA_MONO
        jz      short slow_outs

vga_mono_loop:
        ; for each palette entry we must get the RGB value
        ; then calculate a mono value using the weightings
        ; 
        ;       Red     0.30
        ;       Green   0.59
        ;       Blue    0.11
        ; 
        ; this value is then output to the green gun only
        ; (note that the data we are given is in RBGX order)

        lodsb                   ; get the red
        mov     ah,30
        mul     ah              ; weight by 0.30
        mov     di,ax           ; sum of the weighted values so far

        lodsb                   ; get the blue
        mov     ah,11
        mul     ah              ; weight by 0.11
        add     di,ax           ; sum of the weighted values so far

        lodsb                   ; get the green
        mov     ah,59           ; weight by 0.59
        mul     ah
        add     ax,di           ; add back the weighted sum

        mov     bx,100          ; weights add up to 100
        div     bl
        mov     ah,al           ; save the weighted value in ah
        shr     ah,2            ; move to lower 6 bits

        ; now the output to the palette
        ; which is in the proper RGB order
        xor     al,al
        out     dx,al           ; output 0 for red
        mov     al,ah
        out     dx,al           ; output mono value to green
        xor     al,al
        out     dx,al           ; output 0 for blue

        inc     esi             ; discard the X source byte             ;**

        loop    vga_mono_loop

        jmp     short palettes_loaded

slow_outs:
        lodsd                           ; eax holds XRGB
        and     eax,0fcfcfch            ; keep just top 6 bits of R,G,B
        rol     eax,14                  ; eax = G'B'X'R'
                                        ; where x' = x >> 2
                                        ; (ie moved to lower 6 bits)
                                        ; (rol 14 == ror 18)
        out     dx,al                   ; write out R'
        rol     eax,16                  ; eax holds X'R'G'B'
        xchg    al,ah                   ; ax holds B'G'
        out     dx,al                   ; write out G'
        xchg    al,ah                   ; ax holds G'B'
        out     dx,al                   ; write out B'
        loop    slow_outs

palettes_loaded:
        sti
endif ; PDP

dummy_exit:
        retf

_LoadPaletteEntriesWorker       endp



;/**********************************************************************
;/* Function:  LoadDirectPalette
;/* Purpose:   Load 16bpp palette (Direct Colour Palette)
;/*
;/*  This routine makes the far call through the callgate which is
;/*   needed in order to run the routine with IOPL (actually at ring 0)
;/**********************************************************************

        align   4
cProc   LoadDirectPalette,<PUBLIC,NODATA>,<ebx>

cBegin
        call    fword ptr _PaletteRoutine.cg_offset
cEnd

;/**********************************************************************
;/* Function:  LoadDirectPalette
;/* Purpose:   Load 16bpp palette (Direct Colour Palette)
;/*
;/*  The direct colour palette is required for 16bpp operation.
;/*  Its purpose is to supply the missing bits that the 16 colour index
;/*  does not supply.
;/*
;/*  To give future compatibility (for example when XGA uses 8 bit DACS
;/*   rather than 6 bit DACS) the red and green palette entries are
;/*   always zero, and the blue increases in steps of 8 with an upper
;/*   limit of F8, beyond which the value starts again from 0.
;/*
;/*  Only half the palette is used, and this half is the opposite half
;/*   to the value used for the border colour.
;/*
;/**********************************************************************
; We have to use a Masm proc, not a cMacros proc for this routine in
; order to get exactly what we want

        align   4
        public  _LoadDirectPaletteWorker
_LoadDirectPaletteWorker       proc far

; set up the data segment because we currently have 0's in the selectors
        mov     ax, SEG FLAT:_IOBase
        mov     ds, ax
        mov     es, ax

        ; get the start of the port addresses
        mov     dx, _IOBase

        ; Set hardware palette sequence register = RGB
        mov     ax, palette_rgb
        iowrite index, ax

ifdef WAIT_FLYBACK
        ; wait for an initial blanking period to start
        cCall   WaitForBlankingStart
endif ; WAIT_FLYBACK

        ; The direct colour palette goes in the other half of the palette
        ; to the colour used for the border colour
        mov     al,border_colour
        iowrite index,al                ; select the register to read from
        ioread  al,dataio               ; get the border index
        not     al                      ; we have to use the opposite half
        and     al,80h                  ; keep just the top bit which
                                        ; identifies which half to use
        movzx   bx,al                   ; put either 128 or 0 in bx

        ; Write to hardware sprite/palette index write register
        mov     al, sprite_indx_write_lo  ; Write low byte
        mov     ah, bl
        iowrite index, ax
        mov     al, sprite_indx_write_hi  ; Write high byte
        mov     ah, bh
        iowrite index, ax

        ; We write to 128 entries of the palette (half of the palette)
        mov     ecx,128
        xor     bl,bl                   ; the blue value starts from zero

        ; we pump all data through the dataio register, but must
        ; first set the index register to say this is palette data
        ; we are passing
        mov     al, palette_data        ; index = data register
        iowrite index, al

        ; now point at the palette data register
        add     dx,dataio

output_next_entry:

ifdef WAIT_FLYBACK
        ; ensure we are still in a blanking period
        cCall   EnsureInBlanking
endif ; WAIT_FLYBACK

        ; we first write Red and Green values of 0
        xor     ax,ax
        out     dx,ax           ; write

        ; the blue value is stored in bl
        mov     al,bl
        out     dx,al

        ; move to the next blue value
        add     bl, 8
        and     bl, 0FCh
        loop    output_next_entry

        retf

_LoadDirectPaletteWorker        endp


ifdef WAIT_FLYBACK
;/**********************************************************************/
;/* This routine is used at the start of a palette load to wait for    */
;/* a first blanking period in which to start the load.                */
;/*                                                                    */
;/* No input parameters, no registers changed.                         */
;/**********************************************************************/

        align   4
cProc   WaitForBlankingStart,<PUBLIC,NODATA>

cBegin
        cmp     waitfb,0
        je      short waitover

        ; save registers we are about to alter
        push    edx
        push    eax

        ; get the start of the port addresses
        mov     dx, _IOBase
        add     dx,int_status   ; move to the status byte

        ; clear all interrupt indications
        mov     al, 0ffh        ; clear all interrupts
        out     dx,al

        ; wait for the start of the blanking
not_started:
        in      al,dx
        test    al, 1           ; bit set if blanking started
        jz      not_started

        ; restore the original registers
        pop     eax
        pop     edx
waitover:

cEnd

;/**********************************************************************/
;/* This routine is when performing a palette load to ensure that we   */
;/* are still within a blanking period.  If the last blanking period   */
;/* has ended then the routine waits for the next one.                 */
;/*                                                                    */
;/* No input parameters, no registers changed.                         */
;/**********************************************************************/
        align   4
cProc   EnsureInBlanking,<PUBLIC,NODATA>

cBegin
        cmp     waitfb,0
        je      short inblanking

        ; save registers we are about to alter
        push    edx
        push    eax

        ; get the start of the port addresses
        mov     dx, _IOBase
        add     dx,int_status   ; move to the status byte

        ; test to see if we are still in the blanking period
        in      al, dx
        test    al, 2           ; test for end of blanking - set = ended
        jz      short still_blanking

        ; clear the interrupt status indications
        mov     al, 0ffh
        out     dx, al

        ; blanking has ended - we must wait for the next blanking to start
not_restarted:
        in      al,dx
        test    al, 1           ; bit set if blanking started
        jz      not_restarted

still_blanking:
        ; restore the original registers
        pop     eax
        pop     edx

inblanking:

cEnd
endif ; WAIT_FLYBACK

ifdef PDP
;/****************************************************************************
;/*
;/* Function:   plasma_type
;/*
;/* Purpose:    returns true if plasma is emulating colour monitor
;/*                     false if emulating mono
;/*
;/****************************************************************************


        align   4
cProc   plasma_type,<PUBLIC,NODATA>

cBegin
        call    fword ptr _plasma_type_routine.cg_offset
cEnd

        align   4
public  _plasma_type_worker
_plasma_type_worker     proc far

        ; set index 0 (ie select PDP register 0)
        xor     ax,ax           ; clear all of ax
        mov     dx,0d00h
        out     dx,al           ; we want register 0

        inc     dx              ; move to data port
        in      al,dx
        and     al,00001000b    ; keep colour/mono bit
        jz      short @f                                                ;**

        mov     ax,1
@@:
        retf

_plasma_type_worker endp

endif ; PDP

else ;  _8514

;/**********************************************************************
;/* Function:  Load8514PaletteEntries
;/* Purpose:   Load palette
;/*
;/**********************************************************************

; We have to use a Masm proc, not a cMacros proc for this routine in
; order to get exactly what we want (Because this is called from C we need
; to use the _stdcall calling convention, where the called routine pops
; its parameters when returning)

        pPaletteEntries   equ   <[ebp+16]>
        count             equ   <[ebp+12]>
        start             equ   <[ebp+8] >

        align   4
        public  _Load8514PaletteEntries
_Load8514PaletteEntries proc    near

        mov     ax, _foregroundSession
        or      ax, ax
        jz      short lpe_dead
        push    ebp
        mov     ebp,esp
        push    ebx
        push    esi
        push    edi

; Turning off the DAC causing a terrible unwanted flicker.               
;        Sub     Al,Al                   ; turn off DAC video output
;        Mov     Dx,RAMDAC_PMASK
;        Out     Dx,Al

        push    pPaletteEntries
        push    count
        push    start
        cCall   Set8514HWPalette
        add     esp,12                  ; Clean up the stack.            

; Turning off the DAC causing a terrible unwanted flicker.               
;        Mov     Al,0ffh                 ; enable DAC video output
;        Mov     Dx,RAMDAC_PMASK
;        Out     Dx,Al

        pop     edi
        pop     esi
        pop     ebx
        mov     esp,ebp
        pop     ebp

lpe_dead:
        ret     ;12

_Load8514PaletteEntries  endp

;---------------------------Public-Routine------------------------------;
; Set8514HWPalette
;
;  Set the given RGB values into the 8514's hardware palette.  The 8-bit
;  components of the input values are converted to 6-bit components by
;  shifting off the low two bits.
;
; Entry:
;       none
; Returns:
;       none
; Error Returns:
;       none
; Registers Preserved:
;       SI,DI,BP,DS,ES
; Registers Destroyed:
;       AX,BX,CX,DX,FLAGS
; Calls:
;       None
; History:
;       ported from 8514 code critsec.asm by David Scholten
;-----------------------------------------------------------------------;
        public  Set8514HWPalette
cProc Set8514HWPalette,<PUBLIC,NEAR,NODATA>,<esi,edi,ebx>
        parmW   usFirst
        parmW   crgb
        parmD   prgb

cBegin

ifdef S3
        ;--------------------------------------------------------------
        ; For those DACs that support 8-bit LUTs (ATT & Brooktree), we
        ; don't want to shift off the low two bits.  Instead, we will
        ; ensure that the DAC is set into 8-bit Operation and branch
        ; off to code that doesn't do the shift.
        ;--------------------------------------------------------------
        test    [_DDT],USE_8BITDAC
        jz      dac_change_done

        ;--------------------------------------------------------------
        ; Two differnt types of DAC access required for ATT & Brooktree.
        ;--------------------------------------------------------------
        test    [_DDT],USE_BTDAC
        jnz     brooktree_dac

att_dac:
        ;--------------------------------------------------------------
        ; Prepare the ATT DAC to access the Control Register.
        ;--------------------------------------------------------------
        mov     dx,3c8h
        in      al,dx
        mov     dx,3c6h
        in      al,dx
        in      al,dx
        in      al,dx
        in      al,dx

        ;--------------------------------------------------------------
        ; Read the current contents of the Control Register.
        ;--------------------------------------------------------------
        in      al,dx
        mov     bl,al

        ;--------------------------------------------------------------
        ; Prepare the ATT DAC to access the Control Register, Again!
        ;--------------------------------------------------------------
        mov     dx,3c8h
        in      al,dx
        mov     dx,3c6h
        in      al,dx
        in      al,dx
        in      al,dx
        in      al,dx

        ;--------------------------------------------------------------
        ; Enable 8bit color information.
        ;--------------------------------------------------------------
        mov     al,bl
        or      al,2
        out     dx,al

        jmp     dac_change_done

brooktree_dac:
        mov     dx,3d4h
        mov     ax,55h
        out     dx,al
        inc     dx
        in      al,dx
        and     al,0fch
        or      al,1            ;Set RS[3]:RS[2] to 01
        out     dx,al

        mov     dx,3c6h         ;Set RS[1]:RS[0] to 10
        in      al,dx
        or      al,2
        out     dx,al

dac_change_done:

endif ;S3

        cld                             ; work up in address
        mov     esi,prgb
        ;lea     ebx,PalFix
        movzx   ecx,crgb                ; load loop counter
        mov     di,usFirst

ifdef   S3                                                           ;          
        mov     dx,3D4h                 ; Make sure DAC select bits  ;          
        mov     al,55h                  ; are set to zero            ;          
        out     dx,al                                                ;          
        inc     dx                                                   ;          
        in      al,dx                                                ;          
        and     al,0FCh                                              ;          
        out     dx,al                                                ;          
endif                                                                ;          

ifdef   S3

        ;--------------------------------------------------------------
        ; To avoid a bunch of cmp and jumps, we'll do one check here
        ; outside the loop and jump to two separate loops to handle
        ; either the 8-bit or 6-bit palette loops.
        ;--------------------------------------------------------------
        test    [_DDT],USE_8BITDAC
        jz      LUT_64

LUT_256:

palette_load_loop2:
        mov     ax,di
        mov     dx,RAMDAC_WADDR         ; set index of next RGB to set
        cli                             ; entering critical region
        out     dx,Al
        lodsd
        mov     dx,RAMDAC_RGB           ; send RGB data to this port

        ror     eax,16
        out     dx,Al                   ; set R

        rol     eax,8
        out     dx,Al                   ; set G

        rol     eax,8
        out     dx,Al                   ; set B

        sti                             ; exit critical region
        inc     di
        Loop    palette_load_loop2       ;for all palette entries to load...

        jmp     SetPalExit

LUT_64:

endif   ;S3

palette_load_loop:
        mov     ax,di
        Mov     dx,RAMDAC_WADDR         ; set index of next RGB to set
        cli                             ; entering critical region
        out     dx,Al
        lodsd
        mov     dx,RAMDAC_RGB           ; send RGB data to this port

        ror     eax,16
        shr     al,2                    ; convert 8-bit to 6-bit
        out     dx,Al                   ; set R

        rol     eax,8
        shr     al,2                    ; convert 8-bit to 6-bit
        out     dx,Al                   ; set G

        rol     eax,8
        shr     al,2                    ; convert 8-bit to 6-bit
        out     dx,Al                   ; set B

        sti                             ; exit critical region
        inc     di
        loop    palette_load_loop       ;for all palette entries to load...

SetPalExit:

cEnd

;/**********************************************************************
;/* Function:  LoadDirectPalette
;/* Purpose:   Load 16bpp palette (Direct Colour Palette)
;/*
;/*  The direct colour palette is required for 16bpp operation.
;/*  Its purpose is to supply the missing bits that the 16 colour index
;/*  does not supply.
;/*
;/*  To give future compatibility (for example when XGA uses 8 bit DACS
;/*   rather than 6 bit DACS) the red and green palette entries are
;/*   always zero, and the blue increases in steps of 8 with an upper
;/*   limit of F8, beyond which the value starts again from 0.
;/*
;/*  Only half the palette is used, and this half is the opposite half
;/*   to the value used for the border colour.
;/*
;/**********************************************************************

        align   4
        public  Load8514DirectPalette
cProc Load8514DirectPalette,<PUBLIC,NEAR,NODATA>,<esi,edi,ebx>
cBegin


        ifdef NOT_READY
        ; The direct colour palette goes in the other half of the palette
        ; to the colour used for the border colour
        mov     al,border_colour
        not     al                      ; we have to use the opposite half
        and     al,80h                  ; keep just the top bit which
                                        ; identifies which half to use
        movzx   bx,al                   ; put either 128 or 0 in bx

        ; We write to 128 entries of the palette (half of the palette)
        mov     ecx,128
        xor     bl,bl                   ; the blue value starts from zero

        mov     dx,3c8h                 ;Color palette write mode index reg.
        out     dx,al
        inc     dx

output_next_entry:

        ; we first write Red and Green values of 0
        xor     ax,ax
        out     dx,ax           ; write

        ; the blue value is stored in bl
        mov     al,bl
        out     dx,al

        ; move to the next blue value
        add     bl, 8
        and     bl, 0FCh
        loop    output_next_entry
        endif

cEnd

ifndef  ISO_COLORS
; ISO color mapping takes the place of this !!!
;-----------------------------------------------------------------------;
; argbLinearTo8515
;
; This table maps the linear RGB color component onto a curve to
; brighten it.  The 8515 is different than the 8514.
;
;-----------------------------------------------------------------------;
        public  PalFix
PalFix  label   byte

        IFDEF _8515
        db    00h       ;00  00
        db    04h       ;01  01
        db    05h       ;02  02
        db    05h       ;03  03
        db    06h       ;04  04
        db    07h       ;05  05
        db    07h       ;06  06
        db    08h       ;07  07
        db    09h       ;08  08
        db    09h       ;09  09
        db    0Ah       ;0A  10
        db    0Bh       ;0B  11
        db    0Bh       ;0C  12
        db    0Ch       ;0D  13
        db    0Dh       ;0E  14
        db    0Eh       ;0F  15
        db    0Eh       ;10  16
        db    0Fh       ;11  17
        db    10h       ;12  18
        db    11h       ;13  19
        db    12h       ;14  20
        db    13h       ;15  21
        db    13h       ;16  22
        db    14h       ;17  23
        db    15h       ;18  24
        db    16h       ;19  25
        db    17h       ;1A  26
        db    18h       ;1B  27
        db    19h       ;1C  28
        db    1Ah       ;1D  29
        db    1Bh       ;1E  30
        db    1Ch       ;1F  31
        db    1Dh       ;20  32
        db    1Eh       ;21  33
        db    1Fh       ;22  34
        db    20h       ;23  35
        db    21h       ;24  36
        db    22h       ;25  37
        db    23h       ;26  38
        db    24h       ;27  39
        db    25h       ;28  40
        db    26h       ;29  41
        db    27h       ;2A  42
        db    28h       ;2B  43
        db    29h       ;2C  44
        db    2Ah       ;2D  45
        db    2Bh       ;2E  46
        db    2Ch       ;2F  47
        db    2Dh       ;30  48
        db    2Eh       ;31  49
        db    30h       ;32  50
        db    31h       ;33  51
        db    32h       ;34  52
        db    33h       ;35  53
        db    35h       ;36  54
        db    35h       ;37  55
        db    37h       ;38  56
        db    38h       ;39  57
        db    39h       ;3A  58
        db    3Ah       ;3B  59
        db    3Bh       ;3C  60
        db    3Dh       ;3D  61
        db    3Eh       ;3E  62
        db    3Fh       ;3F  63
        ENDIF

        db    00h       ;00  00
        db    0Dh       ;01  01
        db    0Eh       ;02  02
        db    0Eh       ;03  03
        db    0Fh       ;04  04
        db    10h       ;05  05
        db    10h       ;06  06
        db    11h       ;07  07
        db    11h       ;08  08
        db    12h       ;09  09
        db    13h       ;0A  10
        db    13h       ;0B  11
        db    14h       ;0C  12
        db    15h       ;0D  13
        db    15h       ;0E  14
        db    16h       ;0F  15
        db    17h       ;10  16
        db    18h       ;11  17
        db    18h       ;12  18
        db    19h       ;13  19
        db    1Ah       ;14  20
        db    1Bh       ;15  21
        db    1Bh       ;16  22
        db    1Ch       ;17  23
        db    1Dh       ;18  24
        db    1Eh       ;19  25
        db    1Eh       ;1A  26
        db    1Fh       ;1B  27
        db    20h       ;1C  28
        db    21h       ;1D  29
        db    22h       ;1E  30
        db    22h       ;1F  31
        db    23h       ;20  32
        db    24h       ;21  33
        db    25h       ;22  34
        db    26h       ;23  35
        db    26h       ;24  36
        db    27h       ;25  37
        db    28h       ;26  38
        db    29h       ;27  39
        db    2Ah       ;28  40
        db    2Bh       ;29  41
        db    2Ch       ;2A  42
        db    2Ch       ;2B  43
        db    2Dh       ;2C  44
        db    2Eh       ;2D  45
        db    2Fh       ;2E  46
        db    30h       ;2F  47
        db    31h       ;30  48
        db    32h       ;31  49
        db    33h       ;32  50
        db    34h       ;33  51
        db    35h       ;34  52
        db    36h       ;35  53
        db    36h       ;36  54
        db    37h       ;37  55
        db    38h       ;38  56
        db    39h       ;39  57
        db    3Ah       ;3A  58
        db    3Bh       ;3B  59
        db    3Ch       ;3C  60
        db    3Dh       ;3D  61
        db    3Eh       ;3E  62
        db    3Fh       ;3F  63

endif ; ISO_COLORS
endif ;_8514

_IOPL   ends

        end
