DDDR/2 - Seamless Windows Support

From EDM2
(Redirected from Seamless Windows Support)
Jump to: navigation, search
Display Device Driver Reference
Chapters
  1. 16-Bit VGA Display Driver
  2. 8514/A Display Driver
  3. 32-Bit VGA Display Driver
  4. 32-Bit Super VGA Display Driver
  5. SVGA Base Video Subsystem
  6. Physical Video Device Drivers
  7. Virtual Video Device Drivers
  8. Seamless Windows Support
  9. PM Palette Management Support
  10. Distributed Console Access Facility (DCAF)
  11. DBCS Video Driver Support
  12. Installing and Configuring Display Device Drivers
  13. Graphics Test Suites
  14. Display Test Tool
  15. VIDEOCFG.DLL Exported Functions
  16. VIDEOPMI.DLL Exported Functions
  17. VIDEO Protect-Mode Interface
Appendixes
  1. Data Types
  2. S3 Display Driver

Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation

Seamless support provides the ability to execute Windows applications in one or more windows on the OS/2 Desktop. The Windows applications run side by side with OS/2 Presentation Manager (PM) applications. To provide seamless support, you must modify both the PM and Windows display drivers.

Overview

Each seamless windows session is run as a protect-mode DOS session. The seamless session runs a copy of the Windows video display driver, modified to operate seamlessly. Seamless windows drivers write directly to the video display hardware, and must be modified to coordinate and serialize hardware access. As a result, a seamless windows driver actually "owns" a piece of the PM Desktop.

In addition to modifications to the PM and Windows drivers, the IBM Operating System/2 itself has been modified to support seamless operation. A special virtual device driver (VWIN) is used to establish limited addressability to a small set of key PM routines and data, as well as to provide services permitting hardware serialization and exchange of Windows state-change information.

SeamlessWS.png

Presentation Manager Display Device Driver

To enable a seamless session, the Presentation Manager display device driver must call the special virtual device driver, VWIN, using DOSRequestVDD. The PM driver passes initialization data to enable the seamless windows driver's access to necessary PM data and the shared data and code. After initialization, the PM driver again calls VWIN to define the current video mode and cursor size.

The PM display driver is responsible for initializing a fast safe RAM semaphore. (FSRamSemaphore) for synchronizing access to the video hardware. Both the PM and the seamless windows drivers must use the FSRamSemaphore to coordinate video access. The PM driver can force release of this semaphore when necessary, for example, if the seamless DOS session stops with the Windows driver owning the semaphore. To avoid forcing an inappropriate semaphore release, heartbeat processing has been incorporated into VWIN. The PM driver requests VWIN to initiate heartbeat processing when a timeout occurs on the PM driver's request for the FSRamSemaphore.

The PM Shield component, shown in the diagram in the previous figure, communicates with the PM driver, sending notifications whenever a seamless DOS session is created or destroyed. This enables the PM driver to modify its processing logic to be compatible with the seamless environment.

There are several other calls the PM video driver can issue to VWIN. At PM death and resurrection (that is, on a switch to a full-screen DOS or WIN-OS/2 session), the driver calls VWIN to broadcast suspend/resume drawing messages to the seamless DOS sessions. These messages are transmitted to the DOS session's drivers by way of INT 2Fh.

Seamless Windows Display Device Driver

The seamless windows display device driver is usually derived from the standard Windows driver by conditional compilation. It must always start in the disabled state to establish all necessary addressability and data before beginning seamless operation. To start in a disabled state, the driver must simulate an INT 2Fh, Function 4001h, at startup. The seamless windows driver hooks INT 2Fh to receive all notifications of foreground-background switching. The Win Shield component, diagrammed in the previous figure, enables the seamless windows driver, using INT 2Fh, Function 4002h, when synchronized with the Presentation Manager Desktop.

Because the virtual display driver and the Win Shield have the ability to disable video output from the Windows driver (through INT 2FhH), a cumulative disable count must be kept in the driver. When a Disable occurs (INT 2Fh, AX=4001h), the count is incremented. On the first increment (count = 1), output from the driver is disabled. Alternately, when an Enable occurs (INT 2Fh, AX=4002h), the count is decremented. When the count is 0, driver output can be enabled.

Most seamless processing and message handling is asynchronous; therefore, it is possible for multiple Disables to be received before any Enables take place. Events are posted to the DOS session and retained until a time slice occurs and they can be processed. As stated previously, a cumulative disable count is required.

At seamless windows driver startup, the driver must begin with a Disable count of 1 (in effect, forcing an INT 2Fh Disable on itself) to permit all the window shadows from the desktop to be reflected to the DOS session's Win Shield. When this process is complete, the Win Shield enables the seamless windows driver by way of INT 2Fh.

When the first Enable() call is received, the seamless windows display driver must call VWIN, passing it a pointer to a WINDD_INIT structure. (The WINDD_INIT structure is described in detail later in the text.) VWIN completes this structure for the Windows driver.

It is critical for the seamless windows driver to coordinate all hardware access, using the video FSRamSemaphore, and it must always reset the video hardware to a default state upon release of the semaphore.

The seamless windows driver need not perform any cursor drawing operations, nor does it need to save and restore hardware registers when switched to the background. These functions are performed by the Presentation Manager driver. However, the seamless driver must call the PM cursor-exclusion routines when outputting to the screen, to protect the mouse pointer and prevent its erasure.

Presentation Manager Shield

The PM Shield maintains Workplace Shell windowing-state information, including that related to the seamless DOS sessions.

Upon creation of a seamless DOS session, the PM Shield notifies the virtual video device driver (for example, VVGA or VSVGA) to permit direct hardware access. Normally, the virtual video drivers control and intercept attempts to access the hardware. In a seamless DOS session, however, virtual video is modified to permit this hardware I/O.

As windowing-related events occur in the seamless DOS sessions, the PM Shield duplicates these events in the Workplace Shell to track the seamless DOS sessions. Examples of windowing events are:

Create
Destroy
Move
Resize

In addition to monitoring the seamless DOS sessions, the PM Shield registers with PMWIN to be posted whenever events occur that alter the state of the desktop. (Again, events such as Create and Destroy are monitored.) These events are forwarded to VWIN, which broadcasts them to the Win Shield in each seamless DOS session.

Windows Shield

The Windows (Win) Shield is the Windows counterpart of the PM Shield. It is both an executable file and a dynamic link library (WINSHELD.EXE and WINSMSG.DLL, respectively). Win Shield serves a complementary purpose, maintaining Workplace Shell windowing-state information for its DOS session.

Initial state information for the desktop is received when the Win Shield registers with VWIN. Subsequently, VWIN notifies the Win Shield whenever changes on the desktop occur. All the desktop information is received from the PM Shield and passed on by VWIN.

Additionally, the Win Shield registers with the Windows User component to obtain notification of internal Windows events. This information is then forwarded to VWIN to update the PM Shield.

VWIN Virtual Device Driver

VWIN is the special virtual device driver that lies at the heart of seamless operation. VWIN shares all Windows and PM Desktop windowing-state information, permits addressability to seamless data and code shared between the PM and Windows display drivers, and sends INT 2Fh notification to each seamless DOS session at PM death and resurrection, as described previously.

Interface to VWIN is achieved using the following two mechanisms:

PM services are requested using DOSRequestVDD.
Windows services are requested through INT 66h.

Note: The Windows services must be requested by an interrupt because VWIN executes at Ring 0 (the highest privilege level) and the seamless windows drivers do not.

Distributed Console Access Facility (DCAF)

Seamless Windows support is provided in DCAF for installations that require remote console functions between programmable workstations.

In OS/2 2.1, Seamless Windows is supported by allowing the Windows display driver to draw directly on the Presentation Manager (PM) screen. This means that Seamless Windows updates do not go through the PM drawing functions and, therefore, will not update the active screen change area (SCA) in the usual way. As a result, Seamless Windows requires special treatment.

Prior to drawing on the PM screen, the Seamless Windows driver calls the PM driver through an exported entry point, SeamlessExcludeCursor. This call excludes the PM cursor from the area in which the Seamless Driver is about to draw. The modified XGA display driver intercepts this call and passes the rectangle coordinates to AccumulateScreenBounds.

Under DCAF, during PM display driver initialization, Seamless Windows must be granted addressability to all data and code that it will access during the call to SeamlessExcludeCursor. In order to add the supplied rectangle to all active SCAs, which can reside anywhere in the display driver heap, there is a single, static SSA (Seamless Screen Area called scaSeamless) used for this purpose. All Seamless bounding rectangles will be accumulated in scaSeamless; then, this SCA is merged with the other active SCAs when a query is issued via GreGetScreenChangeArea.

As a result, at initialization (in InitializeSeamless), the Seamless Windows driver is given access to AccumulateScreenBounds, to scaSeamless and to the DDT display driver control block, in order to retrieve the screen dimension at seamless time. The addresses of this data are stored in the SeamlessAddresses control block, owned by the Windows driver.

Before writing to the PM screen, the Seamless Windows driver will call SeamlessExcludeCursor. The exclusion rectangle will be passed in the following registers in so-called AI coordinates (i.e., 16-bit inclusive; 0, 0 is top left of screen):

Left cx
Top dx
Right si
Bottom di

The display driver will determine whether the new bounds accumulation is needed by checking the value of the pStartSCA pointer and, in SeamlessExcludeCursor32, will call AccumulateSeamlessBounds to initiate the bounds accumulation. AccumulateSeamlessBounds converts the passed rectangle to EXCLUSIVE SCREEN coordinates, clips the rectangle to the screen dimensions and calls AccumulateScreenBounds. This causes the rectangle supplied to SeamlessExcludeCursor to be added to only scaSeamless. When an SCA is queried using GreGetScreenChangeArea, the Seamless SCA is merged with the active SCAs and then reset to NULL.

Seamless Design Issues

There are multiple design issues in the seamless environment. The critical issues (those generating the most questions), are documented in the following sections:

  • Determination of code and data to be shared between the PM and Windows display drivers
  • Coordination of off-screen video RAM
  • Save/restore processing of the video hardware registers/environment
  • Implementation of semaphore and heartbeat processing
  • Conversion of Windows cursors and icons in the PM environment
  • Palette handling
  • Sharing of cursor exclusion and Enable/Disable code, including problems to be avoided
  • Setup and sharing of a pointer to video RAM.

Shared Data and Code between PM Drivers and Windows Drivers

Each design of seamless PM and Windows driver pairs requires its own shared data/code structure, because each driver implementation and its underlying video hardware are unique. The contents of the structure varies across implementations. The shared data/code structure for seamless XGA is included in the following example:

  PMDD_IO_STRUC  struc
   LevelID                 dd  ?  ; 4 bytes to sync interface to PMDD.

     ; The following variables are in the PM DD's default data segment.
     ulMemRegBase          dd  ?  ; 16:16 addr of memory mapped XGA regs
     usIORegBase           dw  ?  ; Base of IO XGA regs
     ulVramBase            dd  ?  ; 32-bit physical memory addr of VRAM
     ulVramSize            dd  ?  ; Size of VRAM in bytes
     bfUseExternalPolling  db  ?  ; TRUE if external polling is supported

     usScreenWidthMM       dw  ?
     usScreenHeightMM      dw  ?
     usScreenWidthPels     dw  ?
     usScreenHeightPels    dw  ?
     bBitsPerPel           db  ?

     pSemaphore            dd  ?  ; Flat pointer to FSRamSemaphore
     pHeartBeat            dd  ?  ; Flat pointer to heartbeat counter

     pNumDefaultColors     dd  ?  ; Flat ptr to # of default colors in use

     pCursorStatus         dd  ?  ; Byte ptr: bit 0x80 set if sfw cursor
     pExcludeCursor        dd  ?  ; 16:16 addr of exclude cursor function
     pDisableCursor        dd  ?  ; 16:16 addr of disable cursor function
     pEnableCursor         dd  ?  ; 16:16 addr of enable cursor function

     WindowsPrivateArea    db WINDOWS_PRIVATE_AREA_SIZE dup (?)
  ;------------------------------------------------------------------
  ; Information shared among the XGA Windows' drivers.
  ; Multiple Windows drivers can exist, running in multiple DOS sessions.
  ; SecondaryFontStart     dd  ?
  ; SecondaryFontEnd       dd  ?
  ;
  ; SystemFontTable        dd  256 dup (?)
  ; SecondaryFontTable     dd  256 dup (?)
  ;
  ; SystemFontHeight       dw  ?
  ; SystemFontPoints       dw  ?
  ; SystemFontWidth        dw  ?
  ; SystemFontCached       db  0
  ;
  ; SecondaryFontName      db  0
  ;                        db  32 dup (?) ; Max facename length=32.
  ;
  ; SecondaryFontNameLen   dw  1
  ; SecondaryFontHeight    dw  0
  ; SecondaryFontPoints    dw  0
  ; SecondaryFontWidth     dw  0
  ;
  ; SecondaryFontHdr       db  32 dup(0)
  ; SystemFontHdr          dw  16 dup(0)
  ; PaddedField            db  32 dup(0) ; Remaining reserved.
  ;------------------------------------------------------------------
  ; Total 2200 bytes reserved by the PM driver for Windows' drivers.

     bfPaletteIsFixed      db  ;  TRUE if palette manager not enabled
     ulLastPalUpdate       dd  ;  Timestamp of last foreground realize
     pHWPalette            dd  ;  16:16 ptr to HWPalette structure
     PMKWSPhysicalBase     dw  ;  Physical addr of 64KB kernel workspace for
                               ;   bus-mastering into/out of system memory
     PMKWSLinearBAse       dd  ;  Linear addr of 64KB workspace

  PMDD_IO_STRUC ends

The initial entry in this shared structure must be a driver signature. For XGA, the signature is XG01. For VGA, the signature is VG01. This field must be checked by the Windows driver at initialization. If an incorrect entry is found, the Windows driver must report initialization failure to the GDI. This mechanism prohibits the running of non-compatible seamless driver pairs (for example, using a VGA seamless windows driver with a Presentation Manager XGA driver).

Coordination of Off-Screen Video RAM

A static division of off-screen video memory is typically employed to permit access to this resource for both the Presentation Manager and seamless windows drivers. Alternatively, dynamic allocation or total dedication of the memory to one driver is used. However, these alternatives could decrease performance.

At a minimum, both the PM and seamless windows driver's character caches are maintained in off-screen video memory for the sake of performance.

Save/Restore Processing of Video Registers/Hardware

A straightforward approach to save/restore processing is to force both the PM and seamless windows drivers to explicitly set video hardware registers anytime the registers are required. Since the video FSRamSemaphore must be used to coordinate hardware access, this semaphore can be obtained, the necessary register(s) set and used, and the semaphore released with no problem.

An alternative approach is to design the necessary save/restore processing and mark the associated registers and resources with handles (such as SessionIDs).

Implementation of Semaphore Processing

Most 16-bit presentation drivers use the FSRamSemaphore mechanism to serialize output. This same mechanism is used by the PM and seamless windows drivers in the 32-bit environment. FSRamSemaphores use the driver's data area to store the semaphore. Therefore, the Presentation Manager driver must establish the semaphore and provide its address to the seamless windows driver in the shared data/code structure. This logic flow is true for both the 16-bit and 32-bit environments.

In the 32-bit environment, there are new FSRamSemaphore entry points, and 16-bit drivers now have alternative entry points. The new entry points have been optimized for efficiency. The following is a list of both the new and alternative semaphore entry points:

New and Alternative Entry Points Original Entry Points
RAMSEMREQUEST16 FSRSemEnter
RAMSEMCLEAR16 FSRSemLeave
RAMSEMREQUEST32
RAMSEMCLEAR32

The semaphore entry points all have one parameter-a pointer to a FSRamSemaphore structure. The structure contains the following fields:

usLength Length of structure
usPadding
usProcessID ID of owning process
usThreadID ID of owning thread
usUsage Usage counter
usClient Client field, see note below
ulTimeout System default timeout value
ulRamSem Semaphore
Note
The usClient field is the only field that, for normal processing, the presentation driver should access directly. This field is initialized as 0 when the semaphore is first acquired and thereafter is controlled by the driver. The intention is to give a DC some way of flagging a semaphore to notify the driver's ExitList processing routine of any special action it needs to take when releasing the semaphores.

The RAMSEMREQUESTxx functions return 0 if successful, and a nonzero error code otherwise.

The RAMSEMCLEARxx functions have no return information, and are void functions.

To support FSRamSemaphores, 32-bit Presentation Manager drivers must link with the OS2386 library, and 16-bit drivers must link with the OS2286 library.

To use FSRamSemaphores for coordinating hardware access, the seamless windows drivers must implement request_semaphore() and clear_semaphore() code logic. The purpose of request_semaphore() is to own the semaphore; clear_semaphore() relinquishes ownership.

When requesting the semaphore (if it is already owned by the current process), the semaphore's usage count must be incremented. If the semaphore is available, it is marked as owned by the current process. However, if the semaphore is owned by a different process, a call is made (indirectly) to the OS/2 kernel to block the thread until the semaphore is released. The mechanism for calling the OS/2 block_semaphore function is to issue an INT 66h to VWIN with some parameters passed through registers. VWIN then calls OS/2 block_semaphore on behalf of the seamless windows driver to wait on the specified FSRamSemaphore. The following code section illustrates how to acquire the FSRamSemaphore:

     mov     ax, _DATA
     mov     ds, ax
     assumes ds, Data

;---------------------------------------------------------------------
; Get our process ID and thread ID
;---------------------------------------------------------------------

     mov     cx, init_struct.thread_id       ; Get the current thread ID 
     mov     dx, init_struct.proc_id         ;  and current process 

;---------------------------------------------------------------------
; Get addressability to the hardware semaphore structure 
;---------------------------------------------------------------------

     mov     di, PMDD_IO_SEL                 ; PM selector
     mov     fs, di
     mov     edi, init_struct.pmdd_io        ; FS:EDI -> pmdd_io struct 
     mov     edi, fs:[edi].pSemaphore        ; FS:EDI -> pSemaphore 

sem_retry:
     mov     ax, word ptr fs:[edi].fs_ProcID ; Touch the page
     cli
     mov     ax, word ptr fs:[edi].fs_ProcID ; Is the semaphore owned?
     or      ax, ax
     jnz     SHORT sem_owned                 ; Yes, see if it is caller?

;---------------------------------------------------------------------
; Here, if the semaphore is currently unowned, marked as owned by the
; current process ID and thread ID; set the usage count to 1 and mark
; the RAM semaphore as SET.
;---------------------------------------------------------------------

     mov     WORD PTR fs:[edi].fs_ProcID, dx
     mov     WORD PTR fs:[edi].fs_ThrdID, cx
     mov     ax, 1
     mov     fs:[edi].fs_Usage, ax             ; Set usage count to 1.
     mov     fs:[edi].fs_RAMSem.RamSemOwner,al ; Set RAM semaphore.
     sti
     jmp     SHORT request_semaphore_exit

;---------------------------------------------------------------------
; Here, if the semaphore is currently owned. Check to see if current
; owner is the caller.
;---------------------------------------------------------------------
sem_owned:
     cmp     ax, dx                            ; Is the semaphore owned
                                                 by caller?
                                               ; Essentially, pidOwner
                                                 == pidCaller?
     jne     SHORT sem_owned2                  ; No, go wait.


;---------------------------------------------------------------------
; If the semaphore is already owned by the current process ID and
; thread ID, then nothing to do but increment the usage count.
;---------------------------------------------------------------------

     inc     fs:[edi].fs_Usage
     sti
     jmp     SHORT request_semaphore_exit

;---------------------------------------------------------------------
; If the semaphore is already owned by some other process ID and
; thread ID, then perform an INT 66h to request the VDD (VWIN)
; to call the CPDOS RAM Semaphore mechanism on our behalf. When
; it returns, jump back to the beginning of this function to try
; to get the semaphore again.
;---------------------------------------------------------------------

sem_owned2:
     sti

;---------------------------------------------------------------------
; Block this thread until the semaphore is available.
;---------------------------------------------------------------------

; AH = 82H ( Function Code for VWIN )
     xor     ax, ax
     mov     ah, VWIN_SEM_BLOCK                ; Block for semaphore function

; ECX -> Semaphore timeout
     mov     ecx, fs:[edi].fs_Timeout

; EBX -> CPDOS RAM Semaphore
     ;Thunk the high word of the 32-bit offset in esi into 16:16 addr in ebx
     ;ie, multiply high word by 8 and set the LS 3 bits on.
     lea     esi, fs:[edi].fs_RAMSem
     shld    ebx, esi, 19
     or      bx, 7
     shl     ebx, 16
     mov     bx, si

; Set DS:SI to "VWIN"
     mov     si, OFFSET vwin_id

; Block on the semaphore
     pushf
     call     DWORD PTR init_struct.pfvwin
;****   int     66h

     jmp     sem_retry                         ; Go back and try to get it

request_semaphore_exit:
     mov     edi, Heartbeat
     inc     DWORD PTR fs:[edi]                ; Increment the heartbeat counter
     .....

When clearing the semaphore, the seamless windows driver should decrement the FSRamSemaphore's usage count. When this usage count reaches 0 (after decrementing), the semaphore's RamSemFlag field is saved, and then the entire semaphore structure is set as not owned. The saved RamSemFlag is checked (TRUE or FALSE) to determine whether any processes that are being blocked by the semaphore need to be unblocked. To unblock a requesting process, an INT 66h is issued to VWIN with the parameters passed in the appropriate registers. VWIN then invokes the OS/2 kernel wake_up function. The following code fragment shows how to clear the FSRamSemaphore:

     mov     ax, _DATA
     mov     ds, ax
     assumes ds, Data

;---------------------------------------------------------------------
; Get our process ID and thread ID
;---------------------------------------------------------------------

     mov     cx, init_struct.thread_id          ; Get current thread ID
     mov     dx, init_struct.proc_id            ; and current process ID

;---------------------------------------------------------------------
; Get addressability to the Hardware Semaphore structure
;---------------------------------------------------------------------

     mov     di, PMDD_IO_SEL                    ; PM selector
     mov     fs, di
     mov     edi, Init_struct.pmdd_io           ; FS:DI -> pmdd_io struct
     mov     edi, fs:[edi].pSemaphore           ; FS:DI -> pSemaphore

     mov     ax, fs:[edi].fs_ProcID             ; Touch the page
     cli

;---------------------------------------------------------------------
; See if semaphore is owned by calling process/thread
;---------------------------------------------------------------------

     cmp     fs:[edi].fs_Usage, 0               ; See if owned
     je      SHORT sem_leavebad                 ; No, declare an error

     mov     ax, fs:[edi].fs_ProcID
     cmp     dx, ax                             ; pidOwner == pidCaller?
     jne     SHORT sem_leavebad                 ; No, declare an error
     jmp     SHORT sem_leaveok                  ; Yes, proceed

sem_leavebad:

     sti
     jmp     SHORT exit_clear_semaphore

sem_leaveok:

;---------------------------------------------------------------------
; Decrement the usage count
;---------------------------------------------------------------------

     dec     fs:[edi].fs_Usage                  ; Decrement the usage count
     jz      SHORT release_sem
     sti
     jmp     exit_clear_semaphore

;---------------------------------------------------------------------
; Release the semaphore by setting the process ID and thread ID
; fields to 0, clearing the RAM semaphore and remembering if any
; other threads were waiting on the RAM semaphore.  If not, re-enable
; interrupts and return.
;---------------------------------------------------------------------

release_sem:

     xor     dx, dx
     mov     word ptr fs:[edi].fs_ProcID, dx     ; Clear pid
     mov     word ptr fs:[edi].fs_ThrdID, dx     ; Clear tid
     mov     fs:[edi].fs_Client, dx              ; Clear client
     mov     fs:[edi].fs_RAMSem.RamSemOwner, dl  ; Clear ramsemowner
     xor     cx, cx                              ; Clear the cx register
     xchg    fs:[edi].fs_RAMSem.RamSemFlag, cl   ; and set it to the sem flag
     or      cx, cx                              ; Is the sem being requested?
     jnz     SHORT sem_waiting                   ; Yes, call wakeup

     sti
     jmp     SHORT exit_clear_semaphore

;---------------------------------------------------------------------
; Some other process/thread is waiting for this semaphore.  Perform an
; INT 66h with the appropriate function, which will call the CPDOS
; wakeup code (done through the VDD) to unblock all of the waiting
; threads.  Non-deterministic as to which one will actually get the
; semaphore first.  The others will have to wait again.
;---------------------------------------------------------------------

sem_waiting:
     sti

;--------------------------------------------------------------------
; Issue the INT 66h call to wake up any threads that are blocked on
; the semaphore.
;--------------------------------------------------------------------

; AH = 83H ( Function Code for VWIN )
     xor     ax, ax
     mov     ah, VWIN_SEM_WAKE                   ; Wake function

; Set DI:SI to "VWIN"
     mov     si, OFFSET vwin_id

; EBX -> CPDOS RAM Semaphore
     ; Thunk the high word of the 32-bit offset in edit into 16:16 addr in ebx
     ; ie, multiply the high-word by 8 and set the LS 3 bits ON.
     lea     edi, fs:[edi].fs_RAMSem
     shld    ebx, edi, 19
     or      bx, 7
     shl     ebx, 16
     mov     bx, di

; Block on the semaphore.  CX should contain the old RamSemFlag value.
     pushf
     call     DWORD PTR init_struct.pfvwin
;****   int       66H 

exit _clear _semaphore : 
      .....

At times, the PM driver must free the video semaphore to continue processing. This might be required in the case of a DOS session failure when the seamless windows driver is the semaphore owner. Sample semaphore release processing is included in the following code fragment. It is important to note that, in freeing the semaphore, the PM driver's process ID and thread ID (PID/TID) must be placed in the semaphore structure.

VOID SeamlessForceSemRelease(VOID)
{
     PTIB pThreadInfo;
     PPIB pProcessInfo;

     /***********************************************************/
     /* Set the semaphore owner to be us.  The changing of the  */
     /* semaphore owner must be atomic to avoid letting in any  */
     /* other threads.                                          */
     /***********************************************************/
      DosGetInfoBlocks(&pThreadInfo,
                       &pProcessInfo);
  //  FSRDriverSem.ProcID = (USHORT) pProcessInfo->pib_ulpid;
  //  FSRDriverSem.ThrdID = (USHORT) pThreadInfo->tib_ptib2->tib2_ultid;

      *((PULONG)&FSRDriverSem.ProcID) =
      ((pThreadInfo->tib_ptib2->tib2_ultid) << 16) |
      (pProcessInfo->pib_ulpid);

/****************************************************************/
/* Free the semaphore.                                          */
/****************************************************************/
      while (FSRDriverSem.Usage != 0)
      {
  ReleaseDriverSemaphore();
      }
  }

Implementation of Heartbeat Processing

For seamless windows drivers, the only heartbeat processing required is to increment the heartbeat counter in the PM and Windows shared data/code structure. This counter must be incremented after obtaining the video hardware semaphore and prior to accessing the hardware.

The counter is checked by the PM driver as part of its semaphore timeout logic. Upon a second timeout, if the semaphore owner is unchanged and the heartbeat counter also is unchanged, the Presentation Manager driver will assume that the DOS session is hung and try to force release of the video semaphore. The following code sequence demonstrates this processing logic:

  /********************************************************************/
  /* This function carries out PM Heartbeat Processing.               */
  /* It detects when the Windows driver has stopped while             */
  /* holding the semaphore and tidies up if need be.                  */
  /********************************************************************/
  VOID SeamlessHeartbeat(VOID)
  {
    HVDD  hSeamlessVDD;
    ULONG ulReturnCode;

    /******************************************************************/
    /* If seamless windows is not enabled, we do nothing.             */
    /******************************************************************/
    if (fSeamlessEnabled)
    {
        /**************************************************************/
        /* See if we are timing out for the second time with the same */
        /* PID, TID, and heartbeat.                                   */
        /**************************************************************/
        if (   (usHeartBeatPID == FSRDriverSem.ProcID)
            && (usHeartBeatTID == FSRDriverSem.ThrdID)
            && (ulHeartBeat == 0))
        {
            /**********************************************************/
            /* This is the second time we have timed out with the     */
            /* same PID and TID owning the semaphore and the heart    */
            /* beat has not changed.  We must call VWIN to see if a   */
            /* clean up is required.                                  */
            /**********************************************************/
            /**********************************************************/
            /* Open the seamless VDD ("VWIN").                        */
            /**********************************************************/
            ulReturnCode = DosOpenVDD("VWIN", &hSeamlessVDD);

            if (ulReturnCode != 0)
            {
                /******************************************************/
                /* The DosOpenVDD call encountered an error of some   */
                /* sort!                                              */
                /******************************************************/
                LogDosError(ulReturnCode);
                return;
            }

            /**********************************************************/
            /* Send VWIN the timeout on semaphore signal.             */
            /**********************************************************/
            ulReturnCode = DosRequestVDD(hSeamlessVDD,
                                NULL,
                                VWIN_HEARTBEAT,
                                FSRDriverSem.ProcID,
                                NULL,
                                FSRDriverSem.ThrdID,
                                NULL);

            if ((ulReturnCode == 0) || (ulReturnCode == 2))
            {


                /******************************************************/
                /* The return code indicates that we should clean up. */
                /******************************************************/
                SeamlessForceSemRelease();

                /******************************************************/
                /* Clean up other heartbeat stuff.                    */
                /******************************************************/
                usHeartBeatPID = 0;
                usHeartBeatTID = 0;
                ulHeartBeat = 0;
            }

            /**********************************************************/
            /* Close the handle to VWIN.                              */
            /**********************************************************/
            DosCloseVDD(hSeamlessVDD);
        }
        else
        {
            /**********************************************************/
            /* Just record the PID and TID of the semaphore owner and */
            /* reset the heartbeat counter.                           */
            /**********************************************************/
            usHeartBeatPID = FSRDriverSem.ProcID;
            usHeartBeatTID = FSRDriverSem.ThrdID;
            ulHeartBeat = 0;
        }
    }
  }

Windows Cursors and Icons in the PM Environment

The Windows standard cursors (crossbar, arrow, etc.) have been converted to PM resources as part of the seamless VGA and XGA development. These resources are used, unchanged, by the PM driver. It is important to notice that when the cursor is over a seamless windows application, Windows cursors should appear, not Presentation Manager resources. The converted standard Windows cursors are provided as PM resource files.

Non-standard Windows cursors and icons are passed by the Win Shield component to the PM Shield and, ultimately, to the PM driver, for conversion when they are created by an application.

Palette Handling

Seamless palette management is achieved using the existing seamless components, hardware synchronization, and event-flow mechanisms. Currently, the Windows GDI component handles all palette issues, calling the Windows driver only to actually set the hardware registers. This processing must be modified for seamless palette management. to permit only palette realizations by PM, using the PM driver palette logic.

Note
PM Palette Management is actually a superset of Windows Palette Management in that PM must coordinate logical color table processing (default palette) as well as permit palette changes by way of the Palette Management interface. There is so much similarity in the PM and Windows palette application calls and processing that permitting PM to process a Windows palette realization is quite straightforward.

The Windows GDI has been modified to request palette entries and changes through normal OS/2 GPI/GRE processing. Also, the color mapping of the 20 Windows system colors must be supported in the PM driver palette. This requires a remapping of the PM palette, moving the 20 Windows colors to the top 10 slots and bottom 10 slots of the physical palette. Remapping the PM palette involves moving entries such that the closest entry to the Windows default color is at the specified location. Later, a translation table is used by PM when the driver selects a "closest fit" color, using its algorithms. The result of the algorithms is run through the translation table to determine the selected color's actual palette location. This has a negligible effect (fewer than 50 clock cycles) on performance.

The key item is that seamless palette management can exist because the Windows and PM palette APIs, and associated functionality are so similar. In both Windows and PM, an application creates, selects, and realizes a palette (in that order). In addition, there is a concept of palette animation in both Windows and PM. Animation permits a palette entry's color to be changed quickly, without affecting the rest of the palette or redrawing the image. Therefore, all Windows palette manipulation can be requested through normal GPI/PMWIN APIs, with the exception of animation. Animation is even simpler. It can be handled directly by the Windows GDI once PM has defined the animateable palette slot and returned this information to GDI.

The most straightforward way to describe the design of seamless palette management is to look at the processing flow:

1.At PM seamless startup, a PM and Windows shared memory area is established and initialized. Several entries are added to this shared area for seamless palette management, as follows:
  • FixedPMPalette (Boolean, indicating a non-Palette Management PM Driver)
-If the PM Driver is not palette-aware, the GDI will operate, assuming a fixed palette. This assumption is accounted for in the GDI code, since Windows drivers exist for fixed palette hardware.
-For XGA and SVGA, because the drivers incorporate palette management, the flag is always FALSE.
  • TimeLastPalUpdate (timestamp of the last reorganization of the palette due to focus change and resultant realize request)
-When the focus changes and the application now in focus realizes, the entire palette is reshuffled. This invalidates the current GDI palette entries. The time stamp is a mechanism for the GDI to be instantly aware of this change.
Note: For simplicity, this could also be implemented as a counter.
  • PtrPhysicalPalette (Pointer to a shadow of the physical hardware palette)
2.After Windows driver initialization, the GDI issues a Driver Control() call requesting the address of the data described above. (A Control() call is really the end result of an application device escape. The GDI is responsible for translating Escape() calls to Windows Driver Control() functions.) After this call, the GDI has addressability to all the necessary PM palette information.
The format of the Control() function is:
     rc = Control ( lpDevice, SEAMLESS_PAL_INIT, lpInDate, lpOutData)

     where

     lpDevice = a long pointer to a data structure of type PDEVICE,
        the destination device bit map

     SEAMLESS_PAL_INIT = a word of value 6010
     lpInData  = NULL
     lpOut Data = a long pointer to a structure that contains:

        bfPaletteIsfixed
        ulLastPalUpdate
        pHWPalette

     (These are the palette-related entries in the PM/Windows shared
     data/code area).
3. In the course of normal seamless processing, if the GDI requires a hardware palette change, the GDI requests this change through PM's GPI/GRE, using the Windows and PM Shields. However, the GDI also issues a standard call to OEMSetPalette in the seamless windows driver. In this call, a null pointer is passed, instead of a pointer to a valid palette, to notify the seamless windows driver that a palette change has occurred through PM. In this case, the seamless windows driver updates only its private image copy of the palette, using the data pointed to by the 16:16 hardware palette address (pHWPalette) in the PM and Windows shared data/code area.
Note: The first 10 entries and last 10 entries of the palette in the shared data/code area are not exact matches to the static Windows** colors set forth by Microsoft**. They are the closest fit colors available in the PM default palette. Therefore, these 20 entries must never be modified in the seamless windows driver private image.
When the palette address pointer in OEMSetPalette is not NULL (that is, when a valid color table is passed), the seamless windows driver must update the video hardware palette as usual, as well as update its private image copy of the palette. This only occurs in seamless processing when a Windows application is animating the palette. It is important that the seamless windows driver first requests the video semaphore and then clears the semaphore after updating the hardware palette.
4. The Win Shield and PM Shield are responsible for forwarding all RealizePalette requests to the Windows DOS sessions and Presentation Manager applications. These requests are received and processed as usual.
5. On a palette realization for GDI, the PM Shield returns the logical-to-physical mapping of the requested color table to the DOS session's Windows GDI. This information is obtained from the PM driver using a GRE call that is hooked by the PM driver - GREQueryPaletteRealization. When the PM Shield calls this function and passes a device context and a pointer to an array of ULONGS, the PM driver returns the mapping from the logical color table to the hardware palette in the ULONG array. Seamless operation requires no special flags or different processing.
6. There is one additional requirement in seamless Presentation Manager. In the Windows OEMUpdateColors function, the seamless windows driver must add the hardware serialization code to its processing logic before performing any video hardware access. The video FSRamSemaphore must be requested, and cleared upon exit of this routine. If this is not done, screen and font damage can occur.

As always, before requesting the video fSRamSemaphore, the seamless windows driver should check the hardware access state. If the driver is not enabled, the Windows driver should call Win Shield, requesting a repaint of the Windows Desktop.

Sharing Cursor Exclusion and Enable/Disable Code

Cursor exclusion or disable code is always required when software cursors are in use. The seamless windows driver must use the PM cursor routines. Even when hardware cursors are used, it is recommended that the PM cursor routines be called by the seamless windows driver. This enables the PM driver to accumulate bounding rectangles of modified areas of the screen to support applications such as remote help-desk screen access.

The example of a PM and Windows shared data/code area given previously for XGA demonstrates how cursor exclusion and enable/disable can be implemented.

That example includes the following entries in the shared structure:

 pCursorStatus        dd  ?       ; Byte ptr: bit 0x80 set if sfw cursor
 pExcludeCursor       dd  ?       ; 16:16 addr of exclude cursor function
 pDisableCursor       dd  ?       ; 16:16 addr of disable cursor function
 pEnableCursor        dd  ?       ; 16:16 addr of enable cursor function

In this example, the seamless windows driver has the option of calling the PM cursor routines, but only when a software cursor is in use (by checking the CursorStatus byte). However, in the current XGA implementation, the seamless windows driver calls the PM routines whenever it requests the video FSRamSemaphore and the destination is the screen. (This enables the XGA PM driver to accumulate bounding rectangles of all screen windows.) The seamless windows driver calls the PM ExcludeCursor routine when a hardware cursor is in use, DisableCursor when a software cursor is in use, and EnableCursor whenever the video FSRamSemaphore is cleared and the destination is the screen. For XGA, the cursor exclusion rectangle coordinates are passed on the stack.

The PM cursor functions are accessed by a 16:16 address (entry point) that is exported by the PM driver. At this address is the PM thunk code and the call to the actual PM 32-bit cursor function. The thunk is not compiled but done by hand in the code itself. Sample code from the XGA PM driver is included in the following code fragment:

  ;-----------------------------------------------------------------------
  ;
  ; SeamlessExcludeCursor is the thunked entry point to eddm_ExcludeCursor.
  ; The exclusion rectangle is passed in the following registers in AI coords
  ; (that is, 0,0 is top left of screen).
  ;
  ;       left    top     right   bottom
  ;       cx      dx      si      di
  ;
  ;-----------------------------------------------------------------------
        align   4
  _SeamlessExcludeCursor   proc far

        ; If we are not using a software cursor, we can go for a
        ; fast exit.  We know that the Windows 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

        ; 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.
        ; An interrupt can damage 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 re-enable interrupts).

        call    SeamlessTouchPages
        cli

        ; Save ss:sp (that is, 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 exclusion 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
Note
Interrupts must be disabled before setting and using esp and eip. This is done to prevent entering 32-bit interrupt handling code when the current task, the DOS session, is known to be 16-bit. In this case, the ip and sp pointers would be set for a 16-bit environment, not 32-bit.

All code pages that might be required by the execution of the shared seamless functions must be present in memory before disabling interrupts. A page fault cannot be taken while in the seamless shared code.

Care must be taken that an STI instruction is not included in the PM cursor routines when executed by a DOS session. Interrupts must remain disabled (when executed by a DOS session) until returning through the thunk logic and being enabled.

Care also must be taken not to cause any ring transitions (from Ring 3) within the PM code executed from a DOS session. Therefore, there cannot be any operating system calls, etc. executed.

Set Up and Sharing of a Pointer to Video RAM

A shared pointer to video memory might be required in a seamless environment.

To establish the pointer in a 32-bit environment, the PM display driver calls PMDD.SYS (using DOSDevIOCtl) at initialization. The PM driver passes in the physical address of video RAM and its size, and gets back a Ring 2- or Ring 3-accessible linear address for the video memory. This address is then included and initialized in the seamless shared data/code area. VWIN handles the sharing requests necessary to access the pointer from the seamless windows driver.

To support the allocation of the global pointer to VRAM, the function AllocGlobalVRAM has been added to PMDD.SYS:

     AllocGlobalVRAM - (Function 0x7E)
     Called via:  DosDevIOCtl( pData, pParms, 0x7E, 3, hDev )

     where:

         pData points to a ULONG in which the flat address to
         VRAM will be returned.
         pParms points to a structure of the following type:
               struct _PARMS {
                   ULONG PhysicalAddress;
                   ULONG Length;
                   ULONG Flags;
                } PARMS;
               where:
                   PhysicalAddress is the beginning of the
                   video RAM.
                   Length is the length of video RAM in bytes.
                   Flags is a field of flags of which only the
                         least significant bit is currently
                         defined.  If the first bit is set, the
                         pointer returned will be shareable and
                         can be used to access VRAM at any
                         privilege level.  If the first bit is
                         0, the pointer returned will be global
                         and only accessible from Ring 0.  All
                         other bits are reserved and should be 0.
               (For the seamless environment, Flags should be 1.)
        hDev is the handle returned from a DosOpen call of the
              SINGLEQ$ device.
    Returns:  0 if successful, or a non-zero error code on failure.

As mentioned above, all addressability to the video memory for the seamless windows drivers is handled by VWIN. However, if additional PM processes also require addressability, they must issue an AccessGlobalVRAM call to PMDD.SYS. (Please note that the process that allocates the pointer does not require this AccessGlobal call. The AllocGlobalVRAM function performs all necessary processing to allow the calling process' access of video memory.)

     AccessGlobalVRAM - (Function 0x7F)
     Called via:  DosDevIOCtl( NULL, pParms, 0x7F, 3, hDev )
     Where:
         pParms points to a structure of the following type:
               struct _PARMS {
                   ULONG FlatAddress;
                   ULONG Length;
                } PARMS;
               where:
                    FlatAddress is a pointer that was returned
                          from a previous call to
                          AllocGlobalVRAM.
                    Length is the length of Video Memory in
                          bytes.
         hDev is the handle returned from a DosOpen call of the
             SINGLEQ$ device.
   Returns:  0 if successful, or a non-zero error code on failure.

PM Driver Calls to VWIN - Accessed via DOSRequestVDD

  • Function = Pass initialization structure
     HVDD  = Handle of VDD (returned from DosOpenVDD)
     SGID  = NULL
     ULONG = 0x000000C0
     ULONG = Number of array elements
     PVOID = Pointer to array of SM_PMDISP structures
     ULONG = 0
     PVOID = NULL

     typedef struct _SM_PMDISP
     {
       ULONG  flOptions;/* BIT1 BIT0=xx ring level if BIT3=1  */
                        /* BIT2=0 for DATA    BIT2=1 for CODE */
                        /* BIT3=0 for 16:16   BIT3=1 for 0:32 */
                        /* BIT4=0 for mapping BIT4=1 for      */
                        /* passthru; if passthru, VWIN does   */
                        /* not touch                          */
                        /* BIT5=1 to force linear addresses   */
                        /* to match otherwise, 16:16 addrs    */
                           are remapped in the DOS session    */
                        /* BIT6 - BIT31 reserved (must be 0)  */

       ULONG  ulLength; /* Length of the data in bytes        */

       union            /* Pointer to the beginning address   */
                        /* of shared memory structure         */
       {
         PVOID  p16;    /* for 16:16 (BIT3=0)                 */
         ULONG  p32;    /* for  0:32 (BIT3=1)                 */
       } Start;

     } SM_PMDISP;
  • Function = Signal timeout of the hardware semaphore
    HVDD  = Handle of VDD (returned from DosOpenVDD)
    SGID  = NULL
    ULONG = 0x000000C1
    ULONG = PID to test/kill
    PVOID = NULL
    ULONG = TID to test/kill
    PVOID = NULL

    Returns 0 for "valid Seamless VDM PID/TID was killed"
            1 for "valid PID/TID was not killed" (held by a PM driver)
            2 for "non-valid PID/TID" (went away or is going away)
  • Function = DOS session Dirty notification (Send)
    HVDD  = Handle of VDD (returned from DosOpenVDD)
    SGID  = -1 indicates broadcast; the PM display driver
            always broadcasts
    ULONG = 0x000000C2
    ULONG = Function code to use for the interrupt ( 0x4001
            or 0x4002 )
    PVOID = NULL
    ULONG = Force Repaint ( 0 = NO, 1 = YES )
    PVOID = NULL

Sends VWIN a DOS session Dirty notification. This is used at PM death and resurrection to indicate to the DOS sessions to suspend drawing or resume redrawing and repainting.

  • Function = Set VMOUSE Display Resolution
    HVDD  = Handle of VDD (returned from DosOpenVDD)
    SGID  = NULL
    ULONG = 0x000000C4
    ULONG = sizeof(VMSSIZE structure)
    PVOID = pointer to VMSSIZE structure
    ULONG = NULL
    PVOID = NULL

    typedef struct vmss_s {
      ULONG  vmss_nb;             // Size of structure, in bytes (36)
      LONG   vmss_lMode;          // Video mode (eg, 00h-13h, or -1)
      ULONG  vmss_ulWidth;        // Width of screen, in pels
      ULONG  vmss_ulHeight;       // Height of screen, in pels
      ULONG  vmss_ulCellWidth;    // Width of screen cells, in pels
      ULONG  vmss_ulCellHeight;   // Height of screen cells, in pels
      ULONG  vmss_ulPtrWidth;     // Width of ptr drawing size, pels
      ULONG  vmss_ulPtrHeight;    // Height of ptr drawing size, pels
      ULONG  vmss_ulPtrUnitWidth; // Width of ptr drawing unit, pels
    } VMSSIZE;

Windows Driver Calls to VWIN - Accessed via INT 66h

  • Windows DD - Initialization
    Input:
    AH    = 0x81 - VWIN_INITIALIZE
    DS:SI = "VWIN"
    CX    = SIZEOF windd_init
    EBX   = windd_init struc

    WINDD_INIT  struc
        proc_id      dw  0   ; (out) WinDD's process id
        thread_id    dw  0   ; (out) WinDD's thread id
        pfvwin       dd  ?   ; (out) VWIN's interrupt handler
        pmdd_io      dd  0   ; (out) pointer to pmdd_io structure
    WINDD_INIT  ends
Note
After this initialization call, instead of issuing INT 66H, the seamless windows driver can call directly into VWIN's interrupt handler using the pfvwin function pointer, passed in the WINDD_INIT structure. If this mechanism is used, the seamless windows driver must first perform a "pushf" before calling VWIN's handler.

The pmdd_io field is a pointer passed directly from the PM display driver. This pointer addresses a structure of values that are shared between the PM and seamless windows display drivers. The definition of this structure is set by the display driver pair. However, as noted above, the first four bytes of the structure must contain some type of signature value agreed on by the display driver pair.

   Output:
   AX    = 0... success
           n... failure code defined by VWIN
  • Windows DD - Block on FSRamSemaphore
    Input:
    AH    = 0x82 - VWIN_SEM_BLOCK
    EBX   = CPDOS RAM Semaphore
    ECX   = Timeout value
    DS:SI = "VWIN"

    Output:
    AX    = 0... success
            n... failure

Note: Most of the driver semaphore handling is at Ring 3. However, this exception (interrupt) is necessary because the seamless windows driver DOS session cannot make a kernel call. When the video hardware semaphore is in use, the Driver must block, and this requires a call to the kernel through VWIN.

  • Windows DD - Wakeup FSRamSemaphore request
    Input:
    AH    = 0x83 - VWIN_SEM_WAKE
    EBX   = CPDOS RAM Semaphore
    CX    = old RamSemFlag value
    DS:SI = "VWIN"

Note: When freeing and resetting the FSRamSemaphore, the seamless windows driver first checks whether RamSemFlag in the semaphore structure is 0. If the flag is nonzero, the seamless windows driver must call INT 66h, VWIN_ SEM_WAKE. The RamSemFlag value before being reset is the "old RamSemFlag value".

   Output:
   AX    = 0... success (call cannot fail)
  • Windows DD - Request hardware
    Input:
    AH    = 0x84 - VWIN_REQUEST_VVIDEO
    DS:SI = "VWIN"

    Output:
    AX    = 0... success (call cannot fail; call will block
                  until hardware is available)

Note: In seamless processing, three components share the video hardware. These are:

VVIDEO
PM
Windows

PM and Windows coordinate access to the hardware via a FSRamSemaphore. However, virtual video drivers do not have this mechanism available. A virtual driver is never sure when a DOS application is finished accessing the screen; therefore, this interrupt exists to signal to VWIN (which forwards the request to the virtual video driver) that the seamless windows driver needs hardware access. Before making the call, the driver must obtain the hardware semaphore. Upon return, the seamless windows driver is guaranteed exclusive use of the video. (This mechanism of obtaining the semaphore and checking with VVIDEO already exists in the PM Driver code and is not unique to seamless operation.)

  • Windows DD - Notify that hardware is available.
    Input:
    AH    = 0x85 - VWIN_NOTIFY_VVIDEO
    DS:SI = "VWIN"

    Output:
    AX    = 0... success (call cannot fail)
  • Windows DD - Critical section processing
    Input:
    AH    = 0x86 - VWIN_WINDD_ENTERCRITSEC
    DS:SI = "VWIN"

    Output:
    AX    = 0... success (call cannot fail)

    Input:
    AH    = 0x87 - VWIN_WINDD_EXITCRITSEC
    DS:SI = "VWIN"

    Output:
    AX    = 0... success (call cannot fail)

Note: The enter/exit critical section calls can be nested and, therefore, must come in pairs. This interrupt usually is issued as part of INT 2Fh processing, when nonreentrant code is being executed. It requests VWIN to temporarily stop sending interrupts to the DOS session.

Device Escapes() from Win Shield and GDI to Seamless Windows Driver

  • rc = Escape( hDC, SEAMLESS_ESC_INIT, nCount, lpInData, lpOutData )
    hDC       = GetDC( hWnd )
    nEscape   = 6000 - SEAMLESS_ESC_INIT
    nCount    = 0
    lpInData  = Pointer to Win Shield "call-back" entry point
    lpOutData = NULL

    On Exit: rc = negative......Error
             rc = positive......Success

The SEAMLESS_ESC_INIT call is made by Win Shield at initialization time. On input, Win Shield provides the address of a call-back entry point. The seamless windows driver uses this entry point, in addition to passing a clip region, to cause an area of the Windows Desktop to be repainted. This function is used whenever the seamless windows driver is disabled but must write to the screen. Win Shield is responsible for accumulating the clip regions passed to it.

Note:

  1. This call is made before the screen is enabled by the Win Shield via INT 2Fh.
  2. The seamless driver must always invalidate the Windows Desktop when OEMUpdateColorsis called and the driver is in the disabled state. Miscellaneous translation table and color-mapping problems can otherwise occur.
  • rc = Escape( hDC, SEAMLESS_ESC_ENABLE, nCount, lpInData, lpOutData )
    hDC       = GetDC( hWnd )
    nEscape   = 6002 - SEAMLESS_ESC_ENABLE
    nCount    = 0
    lpInData  = NULL
    lpOutData = Pointer to hw_access

    On Exit: rc = negative......Error
             rc = positive......Success

SEAMLESS_ESC_ENABLE permits a Windows program to determine the current hardware state. The escape returns the address of the driver's internal variable, hw_access, which reflects the hardware state at any time.

  • rc = Escape( hDC, SEAMLESS_ESC_EXIT, nCount, lpInData, lpOutData )
    hDC       = GetDC( hWnd )
    nEscape   = 6001 - SEAMLESS_ESC_EXIT
    nCount    = 0
    lpInData  = NULL
    lpOutData = NULL

    On Exit: rc = negative......Error
             rc = positive......Success

Win Shield issues this call, requesting the seamless windows driver to reset its Win Shield call-back entry point. This is performed when the seamless windows DOS session is closing.

  • rc = Escape( hDC, SEAMLESS_ESC_REQSEM, nCount, lpInData, lpOutData )
    hDC       = GetDC( hWnd )
    nEscape   = 6004 - SEAMLESS_ESC_REQSEM
    nCount    = 0
    lpInData  = NULL
    lpOutData = NULL

    On Exit: rc = negative......Error
             rc = positive......Success

SEAMLESS_ESC_REQSEM requests the seamless windows driver to obtain the FSRamSemaphore on behalf of Win Shield.

  • rc = Escape( hDC, SEAMLESS_ESC_CLRSEM, nCount, lpInData, lpOutData )
    hDC       = GetDC( hWnd )
    nEscape   = 6005 - SEAMLESS_ESC_CLRSEM
    nCount    = 0
    lpInData  = NULL
    lpOutData = NULL

    On Exit: rc = negative......Error
             rc = positive......Success

SEAMLESS_ESC_CLRSEM requests the seamless windows driver to clear the FSRamSemaphore on behalf of Win Shield.

  • rc = Escape( hDC, SEAMLESS_ESC_PALINIT, nCount, lpInData, lpOutData )
    hDC       = GetDC( hWnd )
    nEscape   = 6010 - SEAMLESS_ESC_PALINIT
    nCount    = 0
    lpInData  = NULL
    lpOutData = Pointer to the start of the palette-related data in the
                PM and Windows shared data/code area

    On Exit: rc = negative......Error
             rc = positive......Success

SEAMLESS_ESCAPE_PALINIT permits the Windows GDI component to obtain the address of the palette-related data in the PM and Windows shared data/code area. There are three palette-related entries in this shared area, arranged in the following sequence:

   bfPaletteIsFixed   db  ?   ; TRUE if Palette Manager not enabled
   ulLastPalUpdate    dd  ?   ; Timestamp of last foreground realize
   pHWPalette         dd  ?   ; 16:16 ptr to HWPalette structure

Windows INT 2Fh Support

  • Windows DD - Notify Background Switch
    AX    = 4001H
    CX    = Seamless identifier "SM"
    DX    = Seamless sub-function

          0100H....disable hardware Write access
          0101H....disable hardware Read/Write access
  • Windows DD - Notify Foreground Switch
    AX    = 4002H
    CX    = Seamless identifier "SM"
    DX    = Seamless sub-function

          0200H....enable hardware Write access
          0201H....enable hardware Read/Write access
          0202H....enable hardware Read/Write access and
                   force repaint

Miscellaneous Windows Driver Information

In addition to the enabled and disabled states, the Windows driver also can be in a Read-only state, for example, when the Windows driver is disabled, yet can legitimately transfer bit-map data from video memory to system memory.

These various states are normally used to optimize execution speed, based on the needs of the calling application.

When processing INT 2Fh/disable from the PM Display Driver, it is important for the Windows driver to remain disabled until notified (again, via INT 2Fh) by the PM driver. The PM driver is notifying of its death and resurrection. Alternately, if enabled by the PM driver but otherwise INT 2Fh disabled, then the Windows driver can optimize processing and enter the read-only state.

The seamless windows driver must always check the hardware state before requesting the video FSRamSemaphore. If the hardware is disabled or in the "read-only" state, and the output destination is the screen, the driver should call Win Shield, requesting Win Shield to accumulate the screen areas (rectangles) requiring update.

There are two options when calling Win Shield for a repaint:

SEAMLESS_FORCEPAINT  To cause the entire Windows desktop to be repainted.
SEAMLESS_POSTPAINT   To repaint the accumulated area collected by Win Shield.

Normally, when a Windows session is switched to the background, its output is disabled. Then, when switched to the foreground, a repaint is forced, even if no modifications were made to the current screen. This is acceptable when running a full-screen Windows session. However, when running seamlessly, the PM Driver automatically saves the contents of the screen when it is switched to the background.

When Presentation Manager returns to foreground, the whole screen is restored (including the seamless windows). As a result, no refreshes from the seamless windows will be necessary unless the Windows program attempted a repaint while output was disabled. As a performance improvement, a repaint flag is implemented in Win Shield, which is set initially to FALSE. When the seamless windows driver is in the background, this flag is set by Win Shield to TRUE if any refresh of the screen is attempted by the driver (for example, if the driver calls-back to the Win Shield, passing a clip region). When the seamless driver is switched to the foreground, a repaint is forced only if the flag is TRUE.

Errors have been observed in seamless windows due to the Windows driver's failure to account for being in the Disabled state. For example, damage to the Min/Max buttons for a seamless window was observed. This occurred because the Min/Max button conversion was performed in the DIBtoScreen function. In some scenarios, when this function was invoked, the seamless windows driver was disabled. In this case, the Windows driver could not process the DIBtoScreen and ignored it. However, when finally enabled, the driver was told only to do a block logical transfer (Blt) and not a DIBtoScreen. The solution was for the seamless windows driver to store a flag indicating that the button conversion had not been performed, and to process it at a later time, when enabled.

The SaveScreenBitmap entry in the seamless windows driver should be disabled because the driver does not have full information of the Desktop when running seamlessly.

The seamless windows driver must not issue any INT 10h calls.

Previous seamless windows design assumed that the FS and GS registers were not modified once loaded. Under Windows 3.1 this is no longer a valid assumption. The seamless windows driver must save the FS and GS contents to global variables when FS and GS are initially loaded. Then, before these registers are used, the seamless driver should compare the contents to the global variables. If the contents have been modified, the registers must be reloaded.

It is important to modify the virtual video device driver, as well as the PM and Windows drivers, to operate seamlessly. The virtual video driver, which normally traps all hardware I/O, must be modified to permit the seamless windows driver to access the hardware. If the virtual video changes are not complete, you will see the following error message box:

     Error Message

   System does not support this session's video mode in
   a window.  The program cannot continue running in a
   window.

Seamless Testing

The essence of seamless windows testing is to run both OS/2 Presentation Manager and Windows applications together on the OS/2 Desktop. The tests should execute as many different Windows functions and options as possible, to stress the seamless drivers and environment.

The following situations and scenarios should be considered for seamless testing:

Execute standard Presentation Manager and Windows functionality - move, resize, minimize, maximize and overlay windows of both PM and Windows applications. When minimizing, minimize to the OS/2 Desktop, to the Minimized Window Viewer and hide the applications. Open and close several PM and Windows applications.
When closing applications, exercise various mechanisms (close from the Window List, double click in the window's upper left corner, etc.). For the Windows applications, test within the same DOS session and in different DOS sessions.
Use the Window List, mouse pointer and hot-key sequences (for example, Alt+Esc) to change window focus. Include full-screen, and DOS and OS/2 windowed sessions in some test scenarios.
Verify application functionality - pull-down and pop-up menus, control keys, radio buttons, and so on. Are text font and positioning correct? Are valid colors displayed?
Actual Windows and PM applications should be executed to exercise seamless modifications.
A verification of Windows driver functionality can be obtained using the driver test routines from the Microsoft Windows Device Driver Kit. These tests should execute seamlessly.
Drag both PM and Windows icons and move the cursor over the application windows. Test both hardware and software cursors if available. Exercise various bit map formats - device dependent (DDB), device independent (DIB) and run length encoded (RLE).
Transfer data between Presentation Manager and Windows applications using the Clipboard and DDE.
Exercise all supported hardware resolutions and bits per pels. A different set of problems may be detected at different resolutions and numbers of colors.

Three possible test scenarios are outlined below:

Scenario A (Initial seamless verification):
Two passes:
-Pass One uses a single instance of Windows Clock on the OS/2 Desktop
-Pass Two has multiple instances
Active Sessions:
-Windows Clock
Move, resize, attempt both analog and digital display, overlay OS/2 folder icon view, clip by icon view, minimize, maximize.
Scenario B:
Two passes:
-Pass One with one DOS session for both Windows applications
-Pass Two uses separate DOS sessions.
Exercise the outlined functionality by performing some tasks within an application, then change focus to the next application and continue to test, ultimately returning to the first application.
Active Sessions:
-PM - Jigsaw
Minimize, maximize, move, resize, overlay Windows applications, clip by Windows applications, play the game.
-Windows - Excel
Change fonts, copy data to Clipboard, resize, display chart, minimize, maximize, move, close, cut/paste, overlay PM and Windows applications, clipped by Presentation Manager and Windows applications, change height and width of cells, change colors in cells.
-Windows - Paintbrush
Select color, draw, fill, cut/paste, rotate, edit palette, view bit map, minimize, maximize, move, resize, clipped by and overlay other windows.
Scenario C:
This scenario includes multiple focus changes between the various windows, and exercises hardware palette updates and switching to/from a full-screen session.
The functionality discussed (minimize, maximize, resize, clipping, etc.) should be exercised while changing focus and performing the session switches.
Active Sessions:
-PM - PalDisp
Display hardware palette for verification.
-PM - PalTest
Display bit map using PM Palette Management, and verify palette update.
-PM - Solitaire
Continuous play.
-Windows - ShowDIB
Display bit map using seamless windows Palette Management, and verify palette update.
-Windows - Clock
Analog and digital display.
-DOS Window - batch file in loop, text mode
Run batch file printing text messages, coded in an endless loop.
-DOS Full-Screen - graphics application
Run graphics application program.

Checklist for Palette Management Support

To enable current Windows driver palette management support in a seamless display driver, follow the steps below:

1.Make sure that the following structure is part of the PM-SL share data, that is, the PMDD_IO_STRUC structure defined in IPC.INC.
SL_PaletteData struc
   bfPaletteIsFixed     db  ?       ;TRUE if palette manager not enabled.
   ulLastPalUpdate      dd  ?       ;Time stamp of last foreground realize.
   pHWPalette           dd  ?       ;16-bit pointer to HWPalette structure.
SL_PaletteData ends
2.Add SEAMLESS_ESC_PALINIT function support in Windows entry Control ( lpDevice, Function, lpInData, lpOutData), do the following:
a.Claim the support of SEAMLESS_ESC_PALINIT when this function is being queried.
b.When Function = SEAMLESS_ESC_PALINIT, return the address of init_Struct->pmdd_io.SL_PaletteData in the buffer whose address is in lpOutData.
This address, &(init_Struct->pmdd_io.SL_PaletteData), must be in 16-bit sel :offset format.
Note:
If init_Struct->pmdd_io is a 32-bit address of the PM-SL share area, you have to thunk the &(init_Struct->pmdd_io.SL_PaletteData) 32-bit address to 16-bit sel:off format, using the following algorithm:
sel = (high word of the 32-bit address * 8) | 7
off = the low word of the 32-bit address.
If this function is not implemented, or not correctly implemented, a General Protection Fault will occur.
3. Change Windows entry SetPalette() as follows:
   if( lpPalette != NULL ) {
     a) Request_Semaphore(..)
     b) Update the hardware palette in exactly the same way as you do in
        regular Windows driver.
     c) Clear_Semaphore(..)
   } else {
     Update the private copy of the hardware palette image if there is one being
     kept in the data segment.
   }
4. Change Windows entry UpdateColors() as follows:
Call check_hw_access() for HW_FORCEREADWRITE hardware state before any screen update.
If check_hw_access() returns Success, call request_semaphore() as you do before all hardware access and clear_semaphore() after you are done updating the screen.
5. Change check_hw_access() in IPC.ASM as follows:
Add HW_FORCEREADWRITE as one of the possible values in AL when this call is made. Here is an example of code needed to add to check_hw_access():
   check_hw_access PROC FAR
         .....
         cmp     al, HW_READWRITE        ;Request for HW_READWRITE access?
         jnz     check_forcereadwrite    ;No, go check for HW_FORCEREADWRITE
                                         ;access.
         .....
   check_forcereadwrite:
         cmp     al, HW_FORCEREADWRITE   ;Request for HW_FORCEREADWRITE access?
         jnz     check_write_access      ;No, go check for HW_WRITEONLY access.

         VWIN_ENTER_CRITSEC              ;Turn off interrupts from VWIN.

         mov     hw_virgin, HW_DOREPAINT ;Repaint when HW_READWRITE allowed.
         mov     ax, SEAMLESS_FORCEPAINT ;Paint the whole VDM.
         call    winshield_callback      ;

         VWIN_EXIT_CRITSEC               ;Turn on interrupts from VWIN.

         jmp     check_exit_bad          ;We are done. Exit.
         ....
   check_hw_access ENDP
6. Remarks
Values for symbolic names used above are as follows:
  SEAMLESS_ESC_PALINIT    equ  6010    ;Pass back address of 1st entry of the
                                       ;palette-related data in PM-SL share
                                       ;area.

  HW_FORCEREADWRITE       equ   'F'    ;Request R/W hardware state. If not
                                       ;available, ask winshield to do force
                                       ;repaint when the driver is once again
                                       ;allowed to draw the screen.