;*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.;
;*****************************************************************************/
;***********************************************************************
;
;   Module          = SEAMLESS.ASM
;
;   Description     = Thunked entry points for seamless VDMs calling PM driver
;
;
;***********************************************************************

.386p

INCL_GPIBITMAPS EQU     1
INCL_PM EQU     1
INCL_SUB EQU 1
include os2.inc
include eddinclt.inc
include cursor.inc
include eddconse.inc

IFDEF SEAMLESS

ifdef DCAF                                                                ;@DCAF
extrn _pscaStart         :dword                                           ;@DCAF
endif ;DCAF                                                               ;@DCAF
extrn _cursor_data       :dword
extrn _SeamlessAddresses :dword
extrn _SeamlessStack     :dword
extrn DOS32FLATTOSEL     :proc

SM_PMDISP               struc
flOptions               dd      ?
ulLength                dd      ?
pointer                 dd      ?
SM_PMDISP               ends

SM_ADDRESS_32BIT        equ 0008h
SM_PASSTHRU             equ 0010h
SEAMLESS_STACK_SIZE     equ 0400h
DOS32FLATDS             equ 53



_DATA           segment dword use32 public 'DATA'
_DATA           ends

_TEXT           segment use32 dword public 'CODE'
ifdef   _8514
PUBLIC  _Vio32SetMode
endif
_TEXT           ends

; 16 bit code segment that         driver will call into.
CODE16         segment word use16 public 'CODE'
               assume CS:CODE16
               assume FS:FLAT

extrn   Vio16SetMode       :FAR

public  SEAMLESSINITIALIZE
public  SEAMLESSTERMINATE
public  _SeamlessExcludeCursor
public  _SeamlessDisableCursor
public  _SeamlessEnableCursor

public  SeamlessVDMCreated32
public  SeamlessVDMDestroyed32
public  SeamlessExcludeCursor32
public  SeamlessDisableCursor32
public  SeamlessEnableCursor32

public _start_of_seamless_thunks
_start_of_seamless_thunks:

;-----------------------------------------------------------------------
;
; SeamlessTouchPages touches all of the pages that the VDM has access
; too as specified in the SeamlessAddresses structure. This function assumes
; that ds has already been set up to be the flat selector.
;
;-----------------------------------------------------------------------
        align   4
SeamlessTouchPages     proc near

        ; Save the registers we will use in this routine.
        push    es
        push    ax
        push    esi
        push    edi
        push    ecx

        mov     edi, offset FLAT:_SeamlessAddresses

do_next_block:
        ; The pass through element is always last in the SeamlessAddresses
        ; data structure so we can use this to exit our loop correctly.
        test    [edi].flOptions, SM_PASSTHRU
        jnz     short done_all_blocks

        ; Get the length of the block in bytes.
        mov     ecx, [edi].ulLength

        ; Check if the pointer field of this block is 32 bit or 16 bit.
        test    [edi].flOptions, SM_ADDRESS_32BIT
        jnz     short block_32bit

block_16bit:
        ; Load es:si with the 16:16 address and ensure top half of esi is zero
        ; so that we can use ds:esi later.
        xor     esi, esi
        les     si, [edi].pointer
        jmp     short do_next_page

block_32bit:
        ; Load ds:esi with the flat:32 address.
        push    ds
        pop     es
        mov     esi, [edi].pointer

do_next_page:
        ; Touch this page.
        mov     al, es:[esi]

        ; See if there is another page in this block.
        add     esi, 1000h
        sub     ecx, 1000h
        jg      do_next_page

        ; Loop back and do the next block.
        add     edi, size SM_PMDISP
        jmp     short do_next_block

done_all_blocks:

        ; Restore the registers that we saved earlier.
        pop     ecx
        pop     edi
        pop     esi
        pop     ax
        pop     es
        ret

SeamlessTouchPages     endp


;-----------------------------------------------------------------------
;
; SeamlessInitialise is the thunked entry point to SeamlessVDMCreated.
;
;-----------------------------------------------------------------------
        align   4
SEAMLESSINITIALIZE     proc far

        ; Save ds and es on the 16 bit stack.
        push    ds
        push    es

        ; Get the FLAT selector into ds and es.
        mov     ax, SEG FLAT:_DATA
        mov     ds, ax
        mov     es, ax

        ; Save ss:sp (ie 16 bit stack) in ebx.
        mov     bx, ss
        rol     ebx, 16
        mov     bx, sp

        ; Set up the 32 bit stack.
        mov     ss, ax
        mov     esp, offset FLAT:_SeamlessStack+SEAMLESS_STACK_SIZE

        ; Now on 32-bit stack

        ; Save the 16 bit ss:sp on the 32 bit stack.
        push    ebx

        ; Jump into the 32 bit code which will call the 32 bit init code.
        jmp     far ptr FLAT:SeamlessVDMCreated32

ret_from_created32:
        pop     eax
        mov     dx,ax
        rol     eax,16
        mov     ss,ax
        movzx   esp,dx

        ; Now on 16-bit stack
        pop     es
        pop     ds

        ; Return and unstack the ULONG parameter.
        retf    4

SEAMLESSINITIALIZE endp


;-----------------------------------------------------------------------
;
; SeamlessInitialise is the thunked entry point to SeamlessVDMTerminated
;
;-----------------------------------------------------------------------
        align   4
SEAMLESSTERMINATE      proc far

        ; Save ds and es on the 16 bit stack.
        push    ds
        push    es

        ; Get the FLAT selector into ds and es.
        mov     ax, SEG FLAT:_DATA
        mov     ds, ax
        mov     es, ax

        ; Save ss:sp (ie 16 bit stack) in ebx.
        mov     bx, ss
        rol     ebx, 16
        mov     bx, sp

        ; Set up the 32 bit stack.
        mov     ss, ax
        mov     esp, offset FLAT:_SeamlessStack+SEAMLESS_STACK_SIZE

        ; Now on 32-bit stack

        ; Save the 16 bit ss:sp on the 32 bit stack.
        push    ebx

        ; Jump into the 32 bit code which will call the 32 bit terminate code.
        jmp     far ptr FLAT:SeamlessVDMDestroyed32

ret_from_destroyed32:
        pop     eax
        mov     dx,ax
        rol     eax,16
        mov     ss,ax
        movzx   esp,dx

        ; Now on 16-bit stack
        pop     es
        pop     ds


        ; Return and unstack the ULONG parameter.
        retf    4

SEAMLESSTERMINATE endp

;-----------------------------------------------------------------------
;
; SeamlessExcludeCursor is the thunked entry point to eddm_ExcludeCursor.
; When calling on to eddm_ExcludeCursor CALLED_FROM_BLT | COORD_AI is passed
; as the coordinate type.  This ensures that the code does not try to look
; at the pdc to see if the destination is the screen.
; The exclusion rectangle is passed in the following regisers in AI coords
; (ie 0,0 is top left of screen).
;
;       left    top     right   bottom
;       cx      dx      si      di
;
;-----------------------------------------------------------------------
        align   4
_SeamlessExcludeCursor   proc far

ifdef DCAF                                                                ;@DCAF
        ; See whether we need to accumulate the bounds for DCAF           ;@DCAF
        ; We know that the         driver always has fs set up            ;@DCAF
        ; to be the flat selector so we use it here to access our         ;@DCAF
        ; 32-bit data.                                                    ;@DCAF
ifdef   _8514
        ; Defect 74324. The S3 driver doesn't have the fs register set up
        ; as stated above.  @EKF
        push    ds
        mov     ax,SEG FLAT:_DATA
        mov     ds,ax
        mov     eax, offset FLAT:_pscaStart                               ;@DCAF
        cmp     dword ptr [eax],0                                         ;@DCAF
        pop     ds
else    ;~8514
        mov     eax, offset FLAT:_pscaStart                               ;@DCAF
        cmp     dword ptr fs:[eax],0                                      ;@DCAF
endif   ;~8514
        jnz     short no_fast_exit                                        ;@DCAF
endif ;DCAF                                                               ;@DCAF

IFNDEF _8514
        ; If we are not using a software cursor then we can go for a
        ; fast exit.  We know that the         driver always has
        ; fs set up to be the flat selector so we use it here to
        ; access our 32 bit data.
        mov     eax, offset FLAT:_cursor_data.cd_cursor_status
        test    byte ptr fs:[eax], CURSOR_SOFTWARE
        jz      short SEC_exit
ENDIF

ifdef DCAF                                                                ;@DCAF
no_fast_exit:                                                             ;@DCAF
endif ;DCAF                                                               ;@DCAF
                                                                          ;@DCAF
        ; Save ds and es on the 16 bit stack.
        push    ds
        push    es

        ; Get the FLAT selector into ds and es.
        mov     ax, SEG FLAT:_DATA
        mov     ds, ax
        mov     es, ax

        ; Before we start using esp and eip we must disable interrupts
        ; because an interupt can corrupt the top half of the registers
        ; because it thinks we are 16 bit. Touch all the pages we might
        ; access before disabling interrupts (a page fault is non-maskable
        ; and will reenable interrupts).
        call    SeamlessTouchPages
        cli

        ; Save ss:sp (ie 16 bit stack) in ebx.
        mov     bx, ss
        rol     ebx, 16
        mov     bx, sp

        ; Set up the 32 bit stack.
        mov     ax, SEG FLAT:_DATA
        mov     ss, ax
        mov     esp, offset FLAT:_SeamlessStack+SEAMLESS_STACK_SIZE

        ; Now on 32-bit stack

        ; Save the 16 bit ss:sp on the 32 bit stack.
        push    ebx

        ; Jump into the 32 bit code which will call the 32 bit exculsion code.
        jmp     far ptr FLAT:SeamlessExcludeCursor32

ret_from_exclude32:
        pop     eax
        mov     dx,ax
        rol     eax,16
        mov     ss,ax
        movzx   esp,dx

        ; Now on 16-bit stack

        sti

        pop     es
        pop     ds

SEC_exit:
        retf


_SeamlessExcludeCursor endp



;-----------------------------------------------------------------------
;
; SeamlessDisableCursor is the thunked entry point to disable_cursor.
; This function should only be called if a software cursor is in use.
;
;-----------------------------------------------------------------------
        align   4
_SeamlessDisableCursor   proc far

        ; Save ds and es on the 16 bit stack.
        push    ds
        push    es

        ; Get the FLAT selector into ds and es.
        mov     ax, SEG FLAT:_DATA
        mov     ds, ax
        mov     es, ax

        ; Before we start using esp and eip we must disable interrupts
        ; because an interupt can corrupt the top half of the registers
        ; because it thinks we are 16 bit. Touch all the pages we might
        ; access before disabling interrupts (a page fault is non-maskable
        ; and will reenable interrupts).
        call    SeamlessTouchPages
        cli

        ; Save ss:sp (ie 16 bit stack) in ebx.
        mov     bx, ss
        rol     ebx, 16
        mov     bx, sp

        ; Set up the 32 bit stack.
        mov     ax, SEG FLAT:_DATA
        mov     ss, ax
        mov     esp, offset FLAT:_SeamlessStack+SEAMLESS_STACK_SIZE

        ; Now on 32-bit stack

        ; Save the 16 bit ss:sp on the 32 bit stack.
        push    ebx

        ; Jump into the 32 bit code which will call the 32 bit disable code.
        jmp     far ptr FLAT:SeamlessDisableCursor32

ret_from_disable32:
        pop     eax
        mov     dx,ax
        rol     eax,16
        mov     ss,ax
        movzx   esp,dx

        ; Now on 16-bit stack

        sti

        pop     es
        pop     ds

        retf

_SeamlessDisableCursor endp


;-----------------------------------------------------------------------
;
; SeamlessEnableCursor is the thunked entry point to reenable_cursor.
; This function should only be called if a software cursor is in use.
;
;-----------------------------------------------------------------------
        align   4
_SeamlessEnableCursor   proc far

        ; Save ds and es on the 16 bit stack.
        push    ds
        push    es

        ; Get the FLAT selector into ds and es.
        mov     ax, SEG FLAT:_DATA
        mov     ds, ax
        mov     es, ax

        ; Before we start using esp and eip we must disable interrupts
        ; because an interupt can corrupt the top half of the registers
        ; because it thinks we are 16 bit. Touch all the pages we might
        ; access before disabling interrupts (a page fault is non-maskable
        ; and will reenable interrupts).
        call    SeamlessTouchPages
        cli

        ; Save ss:sp (ie 16 bit stack) in ebx.
        mov     bx, ss
        rol     ebx, 16
        mov     bx, sp

        ; Set up the 32 bit stack.
        mov     ax, SEG FLAT:_DATA
        mov     ss, ax
        mov     esp, offset FLAT:_SeamlessStack+SEAMLESS_STACK_SIZE

        ; Now on 32-bit stack

        ; Save the 16 bit ss:sp on the 32 bit stack.
        push    ebx

        ; Jump into the 32 bit code which will call the 32 bit exculsion code.
        jmp     far ptr FLAT:SeamlessEnableCursor32

ret_from_enable32:
        pop     eax
        mov     dx,ax
        rol     eax,16
        mov     ss,ax
        movzx   esp,dx

        ; Now on 16-bit stack

        sti

        pop     es
        pop     ds

        retf
_SeamlessEnableCursor endp

public _end_of_seamless_thunks
_end_of_seamless_thunks:

CODE16   ends


; 32 bit code that 16 bit code JUMPs to in order to change from 16 bit mode
; to 32 bit mode.

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

ifdef DCAF                                                                ;@DCAF
extrn   _AccumulateSeamlessBounds  :proc                                  ;@DCAF
endif ;DCAF                                                               ;@DCAF
extrn   _eddm_ExcludeCursor     :proc
extrn   _disable_cursor         :proc
extrn   _reenable_cursor        :proc
extrn   _SeamlessVDMCreated     :proc
extrn   _SeamlessVDMDestroyed   :proc

        align   4

SeamlessExcludeCursor32 proc far

        ; The exclude cursor function expects the following parameters:
        ; 
        ; eddm_ExcludeCursor(pDevPoint  ArgExclusionRect,
        ;                    USHORT     CoordsType)
        ; 
        ; We must pass CoordsType of (COORD_AI | CALLED_FROM_BLT) to ensure
        ; that the correct code path is taken without ever trying to access
        ; the DC structure through pdc.

        ; top left| right bottom
        ; x, y    | x,  y
        ; cx,dx   | si, di
        ; 
        ; 0,0 is top left.

        ; First make a DevPoint structure on the stack.
        push    di      ; bottom
        push    si      ; right
        push    dx      ; top
        push    cx      ; left

        mov     eax, esp

ifdef  DCAF                                                               ;@DCAF
        ; Call the DCAF bounds accumulation if required                   ;@DCAF
        cmp     _pscaStart,0                                              ;@DCAF
        je      short no_DCAF_accumulation                                ;@DCAF
        push    eax                                                       ;@DCAF
        call    _AccumulateSeamlessBounds                                 ;@DCAF
        add     esp, 04h        ; Remove parameter                        ;@DCAF
                                                                          ;@DCAF
        ; C calling convention has kindly left all of the parameters      ;@DCAF
        ; on the stack, so we will leave them there for the cursor        ;@DCAF
        ; exclusion call to use.                                          ;@DCAF
        ; All we need to do is make eax point to them.                    ;@DCAF
        mov     eax, esp                                                  ;@DCAF
                                                                          ;@DCAF
no_DCAF_accumulation:                                                     ;@DCAF
                                                                          ;@DCAF
        ; See whether cursor exclusion is required                        ;@DCAF
        test    byte ptr _cursor_data.cd_cursor_status, CURSOR_SOFTWARE   ;@DCAF
        jz      short no_cursor_exclusion                                 ;@DCAF
                                                                          ;@DCAF
endif ;DCAF                                                               ;@DCAF

        ; Now push the parameters (note that we push dword CoordsType
        ; even though it is a USHORT).
        push    dword ptr (COORD_AI or CALLED_FROM_BLT) ; CoordsType
        push    eax                                     ; pDevPoint

        call    _eddm_ExcludeCursor

ifdef DCAF                                                                ;@DCAF
        ; Remove the ExcludeCursor parameters from the stack              ;@DCAF
        add     esp, 08h                                                  ;@DCAF
                                                                          ;@DCAF
no_cursor_exclusion:                                                      ;@DCAF
        ; Remove the DevPoint structure that we created earlier           ;@DCAF
        add     esp, 08h                                                  ;@DCAF
else  ;not DCAF                                                           ;@DCAF

        ; The parameters have been removed from the stack by the
        ; _eddm_ExcludeCursor function itself. Now we must remove the
        ; DevPoint structure we created earlier.
        add     esp, 10h
endif ;DCAF                                                               ;@DCAF

        ; Return to the 16 bit code.
        jmp     far ptr CODE16:ret_from_exclude32

SeamlessExcludeCursor32 endp




        align   4
SeamlessDisableCursor32 proc far

        ; The disable cursor function expects no parameters.
        call    _disable_cursor

        ; Return to the 16 bit code.
        jmp     far ptr CODE16:ret_from_disable32

SeamlessDisableCursor32 endp


        align   4
SeamlessEnableCursor32 proc far

        ; The reenable cursor function expects no parameters.
        call    _reenable_cursor

        ; Return to the 16 bit code.
        jmp     far ptr CODE16:ret_from_enable32

SeamlessEnableCursor32 endp


        align   4
SeamlessVDMCreated32 proc far

        ; The VDM created function expects no parameters.
        call    _SeamlessVDMCreated

        ; Return to the 16 bit code.
        jmp     far ptr CODE16:ret_from_created32

SeamlessVDMCreated32 endp


        align   4
SeamlessVDMDestroyed32 proc far

        ; The VDM destroyed cursor function expects no parameters.
        call    _SeamlessVDMDestroyed

        ; Return to the 16 bit code.
        jmp     far ptr CODE16:ret_from_destroyed32

SeamlessVDMDestroyed32 endp

_TEXT   ENDS


ENDIF ; IFDEF SEAMLESS

ifdef _8514

_TEXT   SEGMENT

ALIGN 4
_Vio32SetMode PROC

        push    ebp
        mov     ebp,esp


        cld                     ;Assume direction flag clear
        xor     eax,eax
        push    eax             ; temp storage for return value
        push    esi
        push    edi
        push    eax             ; temp storage
        push    eax             ;Error flag for cleanup
        push    eax             ; temp storage for Stack Allocation Flags
        push    eax             ; temp storage for BMP Flags
        push    eax             ; temp storage for Alias Flags
        push    eax             ; temp storage for ptr param #1

;* Compare stack selector against FLAT:R3DSB
;* If the selector is not equal, then don't bump stack.

        mov     eax,ss
        cmp     ax,DOS32FLATDS          ;32 bit stack?
        jne     short L28               ; if not, skip bumping code

;* Bump the stack down if too near 64K boundary.

        mov     eax,esp
        cmp     ax,1024
        jae     short L28
        xor     ax,ax
        mov     esp,eax         ; bump the stack down


;Insure that 1 DWORD exists on stack
        push    eax
L28:


; ****> BEGIN Pointer/Structure Section



        mov     esi,[ebp+8]             ;pviomi base address

;Pointer pviomi --> pviomi
        or      esi,esi
        jz      L29

        mov     [ebp-36],esi

;Structures are Identical
;Structures don't have pointers

;Treat structure same as buffer

;Check Boundary Crossing - fixed size item
        cmp     si,65524
        jbe     L29                     ;Enough room

; Allocate space on stack
        sub     esp,12                  ;Alloc Mem
        and     esp,0FFFFFFFCh          ;DWORD align
        mov     edi,esp                 ;Points to new data area
        mov     [ebp-36],edi

;Transfer 12 bytes

        mov     ecx,3
        rep     movsd

L29:

; ****> END Pointer/Structure Section

;* Create new call frame, using 16-bit semantics.

        push    es
        push    ebx
        push    ebp                     ; save ebp
        mov     eax,esp                 ; save current esp
        push    ss
        push    eax


        mov     edx,ss                  ; get cpl bits to use as dpl bits
        and     edx,3                   ; mask off rest of register

        or      dl,4                    ;Force LDT bit on


        ;From Name: pviomi  Type: struct VIOMODEINFO
        mov     eax,DWORD PTR [ebp-36]
        or      eax,eax
        jz      short L32               ;NULL pointer

        call    DOS32FLATTOSEL          ;Convert in packed region

L32:    push    eax



        ;From Name: hVio  Type: unsigned short
        push    WORD PTR [ebp+12]       ; To: unsigned short

;* Convert SS:ESP to 16-bit SS:SP.

        mov     eax,esp                 ; use CRMA on ESP to get SS
        ror     eax,16
        shl     eax,3
        or      al,dl
        mov     ss,eax

;* Jump to 16-bit segment to issue call (so that 16-bit API can RETF).
;* The following two lines are the same as:
        jmp     FAR PTR T_VIO16SETMODE
ALIGN 4



NOMEM_Vio32SetMode:
        push    8
        pop     eax

ERR_Vio32SetMode:
        mov     BYTE PTR [ebp-20],1             ;Set flag
        jmp     short L33
ALIGN 4

R_VIO16SETMODE::                                ; label defining return jmp location


;* Restore 32-bit SS:ESP - it is on top of stack.

        movzx   esp,sp                  ; make sure that esp is correct
        lss     esp,[esp]
        pop     ebp
        pop     ebx
        pop     es


;Convert Return Code
;USHORT --> ULONG
        movzx   eax,ax
L33:
;Functions contain pointers, save return code
        mov     [ebp-4],eax             ;Save return code

; ****> BEGIN Pointer/Structure Unpack Section


;Undo Pointer pviomi --> pviomi


        mov     esi,[ebp-36]            ;pviomi temp address
        or      esi,esi
        jz      L34



        mov     edi,[ebp+8]             ;pviomi original address

;Structures are Identical
;Structures don't have pointers
;Structure doesn't have output semantics
;Treat structure same as buffer
;Types are identical and no imbedded pointers exist
;This means that we treated the pointer as a buffer
;If temp address == original address then no work required
        cmp     esi,edi
        je      L34

;Item is fixed size
;stack deallocated implicitly

L34:            ;No action required

; ****> END Pointer/Structure Unpack Section

;* 32-bit return code.

        lea     esp,[ebp-12]
        pop     edi
        pop     esi
        pop     eax             ;Pop saved return code
        leave
        ret                             ; Remove parameters

_Vio32SetMode endp

_TEXT   ENDS

CODE16 SEGMENT
ALIGN 4
T_VIO16SETMODE  PROC FAR
        call    FAR PTR Vio16SetMode            ; call 16-bit version
        jmp     FAR PTR FLAT:R_VIO16SETMODE             ; jump back
ALIGN 4

T_VIO16SETMODE  ENDP
CODE16 ENDS

endif ;_8514

end



