;       SCCSID = @(#)bksmain.asm        6.3 91/10/14
; ****************************************************************************
; *                                                                          *
; *                       IBM/Microsoft Confidential                         *
; *                                                                          *
; *                 Copyright (c) IBM Corporation  1987, 1990                *
; *                 Copyright (c) Microsoft Corp.  1987, 1990                *
; *                           All Rights Reserved                            *
; *                                                                          *
; ****************************************************************************
        PAGE    60,132
        TITLE   BKSMAIN.ASM - Base Keyboard Subsystem API Dispatch Routine

;******************************************************************************
;*******   C H A N G E       H I S T O R Y   **********************************
;
;       87/01/12  TPL   Zero out AX after DOSGETSHRSEG of CDIB
;       87/04/07  TPL   Get private handle for newly started process
;       88/05/02  CDB   Get LIS_CurScrnGrp from local infoseg on every call
;P2847  88/06/01  THG   Call Win API with logical handle -or- Win_Handle
;P2981  88/06/15  THG   Add Proc_Hand field to IDSEG for KBD_Handle storage
;P3925  88/10/23  STJ   Use stack for return area passed to DosGetProcAddr
;P3932  88/10/24  THG   Scan for module names up to 31 length in GetProcAddr
;D451.8 89/06/27  THG   Add GetHWID() since KBDCALLS removed that function ;2.0
;@T52   90/01/15  TPL   DCR 704 work
;B728277 10-14-91 GDW   Super Project closes the keyboard handle, needs reopen
;67355  93/06/11  WCH   Add ERROR_BAD_COMMAND checking in B728277 fix
;MDLL   01/10/94  BJN   Page Tune segments for Merged DLL.
;******************************************************************************

        .286p                           ; 286 Protect Mode instructions


        INCL_ERRORS  equ 1              ; force errors from bseerr.inc

        .xlist
        INCLUDE bseerr.inc              ; Main error code defines
        INCLUDE error2.inc              ; Extended error code file
        INCLUDE struc.inc               ; Structured Macros
        INCLUDE bksxxx.inc              ; Equates and structure template file
        INCLUDE bksextrn.inc            ; External data declaration file
        include infoseg.inc             ;global and local information segment
        .list

CSEG    SEGMENT BYTE PUBLIC 'CODE'
CSEG    ENDS

GDSEG   SEGMENT BYTE PUBLIC 'FAR_DATA'  ; Global data segment shared    ;@T52
GDSEG   ENDS                            ;   among all sessions in the system

IDSEG   SEGMENT BYTE PUBLIC 'DATA'      ; Per process instance data segment
IDSEG   ENDS
;
;       Internal handler routine name(s)
;
        EXTRN   GetCharIn:NEAR          ; Destructive read routine
        EXTRN   PeekAtIt:NEAR           ; Non-destructive read routine
        EXTRN   FlushBuffer:NEAR        ; Empty keyboard input buffer
        EXTRN   GetStatus:NEAR          ; Get current keyboard states
        EXTRN   SetStatus:NEAR          ; Modify keyboard states
        EXTRN   GetStringIn:NEAR        ; Character string input
        EXTRN   HandleOpen:NEAR         ; Per process keyboard open
        EXTRN   HandleClose:NEAR        ; Per process keyboard close
        EXTRN   GetFocus:NEAR           ; Per process keyboard bond
        EXTRN   FreeFocus:NEAR          ; Release keyboard bond
        EXTRN   SetCodepage:NEAR        ; Switch code page
        EXTRN   GetCodepage:NEAR        ; Get current keyboard code page
        EXTRN   Translate:NEAR          ; Translate scan code to ASCII
        EXTRN   SetCustCP:NEAR          ; Set custom code page
        EXTRN   GetHWID:NEAR            ; Get keyboard hardware ID      ;2.0

        EXTRN   ValidateInHand:NEAR     ; Query handle type
;
;       System services routine name(s)
;
        PUBLIC  LoadWinthorn
        EXTRN   WINCONSOLEREADKEYEVENT:DWORD
        EXTRN   WINCONSOLEFLUSHKEYEVENTS:DWORD
        EXTRN   WINCONSOLEOPENKBD:DWORD
        EXTRN   WINCONSOLECLOSEKBD:DWORD
        EXTRN   WINCONSOLESETSTATUS:DWORD
        EXTRN   WINCONSOLEGETSTATUS:DWORD
        EXTRN   WINCONSOLEGETCP:DWORD
        EXTRN   WINCONSOLESETCP:DWORD
        EXTRN   WINCONSOLEKBDXLATE:DWORD
        EXTRN   WINCONSOLESETCUSTXT:DWORD
        EXTRN   WINCONSOLEGETFOCUS:DWORD
        EXTRN   WINCONSOLEFREEFOCUS:DWORD
        EXTRN   VIOQUERYCONSOLE:FAR
        EXTRN   DOSGETINFOSEG:FAR
        EXTRN   WINCONSOLEGETKBDHANDLE:DWORD
        EXTRN   DOSDEVIOCTL:FAR         ; Validate handle for DosOpen
        EXTRN   DOSLOADMODULE:FAR       ; Load dynamic link library
        EXTRN   DOSGETPROCADDR:FAR      ; Get procedure addresses
        EXTRN   DOSGETSHRSEG:FAR        ; Get CDIB selector
        EXTRN   DOSOPEN:FAR             ; Get device handle from file system
        EXTRN   KBDSYNCH:FAR            ; Synchronize calling threads
                                        ;   for the current session
        PUBLIC  BKSMAIN

CTEXT_TUNE5  SEGMENT BYTE PUBLIC 'CODE'                                 ;MDLL
        ASSUME  CS:CTEXT_TUNE5,DS:NOTHING,ES:NOTHING                    ;MDLL
        PAGE

;********************START OF SPECIFICATIONS****************************
;
; SUBROUTINE NAME:      BKSMain
;
; DESCRIPTIVE NAME:     Keyboard Handler Entry Point
;
; FUNCTION:     Provides an entry point for the KBDROUT.  Serialize
;               access to BKS, obtain selector to CDIB, validate
;               input device handle parameter, and dispatch to the
;               appropriate handler routine based on the requrested
;               function number.
;
; ENTRY POINT:          BKSMain
;
;   LINKAGE:            Far Call (dynamic link)
;
; INPUT PARAMETERS
;    SYMBOLIC NAME:     FunctionNum
;
;    DESCRIPTION:       Number representing a requested function
;
;                       00  =  GetCharIn    (KbdCharIn)
;                       01  =  PeekAtIt     (KbdPeek)
;                       02  =  FlushBuffer  (KbdFlushBuffer)
;                       03  =  GetStatus    (KbdGetStatus)
;                       04  =  SetStatus    (KbdSetStatus)
;                       05  =  GetStringIn  (KbdStringIn)
;                       06  =  HandleOpen   (KbdOpen)
;                       07  =  HandleClose  (KbdClose)
;                       08  =  GetFocus     (KbdGetFocus)
;                       09  =  FreeFocus    (KbdFreeFocus)
;                       10  =  GetCodePage  (KbdGetCP)
;                       11  =  SetCodePage  (KbdSetCP)
;                       12  =  Translate    (KbdXlate)
;                       13  =  SetCustCP    (KbdSetCustXT)
;                       14  =  GetHWID      (KbdGetHWID)
;
;    TYPE:              Word (placed on stack by KbdRout)
;
;    USAGE:             Route to handling routine
;
; EXIT-NORMAL:          AX  =   0
;
; EXIT-ERROR:           AX  =   ERROR_KBD_CANNOT_CREATE_KCB
;                               ERROR_KBD_CODEPAGE_LOAD_INCOMPLETE
;                               ERROR_KBD_FOCUS_REQUIRED
;                               ERROR_KBD_KEYBOARD_BUSY
;                               ERROR_KBD_INVALID_CODEPAGE
;                               ERROR_KBD_INVALID_ECHO_MASK
;                               ERROR_KBD_INVALID_HANDLE
;                               ERROR_KBD_INVALID_INPUT_MASK
;                               ERROR_KBD_INVALID_IOWAIT
;                               ERROR_KBD_INVALID_LENGTH
;                               ERROR_KBD_NO_CODEPAGE_SUPPORT
;                               ERROR_KBD_NO_MORE_HANDLE
;                               ERROR_KBD_UNABLE_TO_FOCUS
;
; INTERNAL REFERENCES:  IDSEG     - Per Process Instance Data Segment
;                       GDSEG     - Global Data Segment
;          ROUTINES:    GetCharIn,PeekAtIt,FlushBuffer,GetStatus,
;                       SetStatus,GetStringIn,HandleOpen,HandleClose,
;                       GetFocus,FreeFocus,SetCodepage,GetCodepage,
;                       Translate,SetCustCP
;
;                       ValidateInHand - Validate input handle
;
; EXTERNAL REFERENCES:  none
;          ROUTINES:    DosGetShrSeg - Get CDIB selector
;                       KbdSynch     - Serialize BKS access
;
;******************END OF SPECIFICATIONS********************************
;
;
;BKSMAIN PROC   FAR
;
; CALLFAR KBDSYNCH                      ; Serialize access to BKS
; DS = IDSEG                            ; Establish addressability to IDSEG
; ES = GDSEG                            ; Establish addressability to GDSEG
; AX = 0                                ; Assumed no error
;.IF <DS:Entry_Count EQ 0>              ; Handle validation necessary?
;|                                      ;   (optimized for recursive calls)
;| .IF <ES:CDIB_Sel EQ NULL>            ; CDIB selector initialized?
;| |  CALLFAR DOSGETSHRSEG              ; Get CDIB selector
;| | .IF <Error>                        ; At sysinit time, CDIB selector may
;| | |  AX = 0                          ;   not be available.  This insures
;| | |  ES:CDIB_Sel = NULL              ;   at least one more try.
;| | .ENDIF
;| .ENDIF
;| .IF <SS:[bp].FunctionNum NE FC_OPEN>    ; Not KbdOpen call?
;| | .IF <DS:Dev_Handle EQ 0>              ; Valid handle NOT available?
;| | | .IF <SS:[bp].KBD_Handle EQ 0>       ; Handle 0 passed on stack?
;| | | |  DS:Dev_Handle = ES:Shared_Handle ; Use global default handle
;| | | .ELSE                               ; Non-zero handle passed!
;| | | |  CALLNEAR ValidateInHand          ; Validate non-zero handle
;| | | .ENDIF
;| | .ELSEIF <SS:[bp].KBD_Handle A 0>      ; Valid handle already available
;| | |                                     ;   and the input handle passed
;| | |                                     ;   is non-zero then, go validate
;| | |  CALLNEAR ValidateInHand            ;   non-zero handle
;| | .ENDIF
;| .ENDIF
;.ENDIF
; DS:Entry_Count = Entry_Count + 1      ; Bypass handle validation check
;                                       ;   when BKS is reentered
;.IF <No Error>                         ; Error on handle validation?
;|  Dispatch to handler routine         ; Based on the FunctionNum parameter
;.ENDIF                                 ;   passed on the stack by KbdRout
; DS:Entry_Count = Entry_Count - 1      ; Balance count on the way out
; ret
;
;BKSMAIN ENDP
        PAGE

TblStrt dw      OFFSET  CSEG:GetCharIn  ; Dispatch table                ;@T52
        dw      OFFSET  CSEG:PeekAtIt
        dw      OFFSET  CSEG:FlushBuffer
        dw      OFFSET  CSEG:GetStatus
        dw      OFFSET  CSEG:SetStatus
        dw      OFFSET  CSEG:GetStringIn
        dw      OFFSET  CSEG:HandleOpen
        dw      OFFSET  CSEG:HandleClose
        dw      OFFSET  CSEG:GetFocus
        dw      OFFSET  CSEG:FreeFocus
        dw      OFFSET  CSEG:GetCodepage
        dw      OFFSET  CSEG:SetCodepage
        dw      OFFSET  CSEG:Translate
        dw      OFFSET  CSEG:SetCustCP
        dw      0
        dw      0
        dw      OFFSET  CSEG:GetHWID

BKSMAIN proc far
   ASSUME  DS:IDSEG,ES:GDSEG
                                ;
                                ;****************************************************************
                                ;   Synchronize KBDxxx calls within a screen group              *
                                ;****************************************************************
                                ;
;  push 01H                     ; Wait indefinitely if another
;  call KBDSYNCH                ;   process trying to gain access
                                ;   to BKS while it is busy servicing
                                ;   a thread already
   pusha                        ; Save all general registers
   mov  bp,sp                   ; Establish addressability to the
   mov  bp,[bp].SP_REG          ;   parameters on the stack
   push ds                      ; Save all selector registers
   push es
   mov  ax,IDSEG                ; Establish addressablity to the per
   mov  ds,ax                   ;   instance data segment
   mov  ax,GDSEG                ; Establish addressability to the
   mov  es,ax                   ;   global data segment

   mov  si,[bp].KBD_Handle      ;save caller's kbd handle
   mov  Proc_Hand,si            ;

   sub  si,si                   ; Clear for infoseg index
   push ds                      ; Save IDSEG

   .if <es:LocalSeg EQ si>      ; Infoseg available?
     push es                    ; Get GDT and LDT information
     push offset es:GlobalSeg   ;   selectors
     push es                    ;
     push offset es:LocalSeg    ;
     call DosGetInfoSeg         ;

     mov  ds,es:GlobalSeg       ; DS = GDT infoseg
     mov  al,[si].SIS_MaxScrnGrp; Get base screen groups allowed
     dec  al                    ; Normalize for 0 base
     cbw                        ;
     mov  es:LBaseSG,ax         ; Save it in global data segment
     mov  ds,es:LocalSeg        ; DS = LDT infoseg
     mov  dx,[si].LIS_CurScrnGrp; Get current screen group #
   .else                        ;
     mov  ax,es:LBaseSG         ; Get last base SG #
     mov  ds,es:LocalSeg        ; DS = LDT infoseg
     mov  dx,[si].LIS_CurScrnGrp; Get current screen group #
   .endif                       ;

   pop  ds                      ; Restore IDSEG
   mov  LastBaseSG,ax           ; Save last base SG # in IDSEG
   mov  KBD_SG,dx               ; Save current SG # in IDSEG
   sub  ax,ax                   ; @@DTF

   .if <dx A LastBaseSG>        ; Winthorn screen group

     .if <hConsole EQ si>       ;   and console handle = NULL?
       call LoadWinthorn        ;Load Winthorn modules

       .if <nonzero ax>         ;Error loading Winthorn
         mov  ax,ERROR_KBD_NO_CONSOLE
       .else                    ;
         push ds                ;
         push offset hConsole   ;
         call VIOQUERYCONSOLE   ; Get Shield Console Handle

         .if <hConsole EQ 0>       ; console handle stll = NULL?
           mov  ax,ERROR_KBD_NO_CONSOLE
         .else
           push es
           push hConsole
           push IDSEG
           push offset Win_Handle
           call ES:WINCONSOLEGETKBDHANDLE
           pop  es
         .endif

       .endif

     .elseif <Win_Handle EQ ax> ;
       push es                  ;
       push hConsole            ;
       push IDSEG               ;
       push offset Win_Handle
       call ES:WINCONSOLEGETKBDHANDLE
       pop  es                  ;
     .endif

   .endif

   .if <zero ax> near           ; Encountered error?
     ;NO ERROR :
     ;
     ;
     ;
     ;
     mov  si,[bp].FunctionNum   ; Get function number from stack
     mov  bx,[bp].KBD_Handle    ; Get handle parameter from stack
     mov  dx,KBD_SG             ; Get current SG number

     .if <dx be LastBaseSG> near
       ;
       ;FullScreen session type :
       ;

       .if <Entry_Count EQ 0> near
         ;
         ;this is the first call from the current thread,
         ;therefore the passed handle must be checked for
         ;validity.
         ;

         .if <Dev_Handle EQ ax>
           ;
           ;first call from this process
           ;
           push es              ; Setup:  Address of device name
           push OFFSET Dev_Name ;
           push ds              ;         Address of device handle
           push OFFSET Dev_Handle ;          to be returned by DOS
           push es              ;         Address of action taken
           push OFFSET Action_Taken ;        by DOS
                                ; file size = 0 (2 words)
           push ax              ;
           push ax              ; file attribute
           push ax              ; open flag - fail if device
           push 01H             ;   does not exists
                                ; open mode = ISSSRAAA
           push 0C2H            ;             11000010
                                ; I   - Non inheritable handle
                                ; SSS - Deny None access
                                ; R   - Reserved must be 0
                                ; AAA - Read/Write access
           push ax              ; Double words of 0
           push ax              ;
           call DOSOPEN         ;

; ******** START of EEP ship issue temp fix for SuperProject       CJJ ********
; ******** do dummy call just to check if handle is invalid        ;B728277
; ******** if handle is invalid then redo DosOpen                  ;B728277
                                                                   ;B728277
         .else                                                     ;B728277
           sub    sp,2          ; dummy variable                   ;B728277
           mov    ax,sp                                            ;B728277
           push   ss            ; dummy address for return info    ;B728277
           push   ax                                               ;B728277
           xor    ax,ax                                            ;B728277
           push   ax            ; @  Dummy input parmlist          ;B728277
           push   ax            ; @                                ;B728277
           push   71H           ; Function code: Get input mode    ;B728277
           push   04H           ; Category code: Keyboard control  ;B728277
           push   Dev_Handle    ; Device Handle to KBD:            ;B728277
           call   DOSDEVIOCTL                                      ;B728277
           add    sp,2                                             ;B728277
                                                                   ;B728277
           .if <ax EQ ERROR_INVALID_HANDLE>  or        ;WCH 67355  ;B728277
           .if <ax EQ ERROR_BAD_COMMAND>               ;WCH 67355  ;B728277
             xor  ax,ax                                            ;B728277
             push es              ; Setup: Address of device name  ;B728277
             push OFFSET Dev_Name ;                                ;B728277
             push ds              ;        Address of device handle;B728277
             push OFFSET Dev_Handle ;         to be returned by DOS;B728277
             push es              ;        Address of action taken ;B728277
             push OFFSET Action_Taken ;       by DOS               ;B728277
                                  ; file size = 0 (2 words)        ;B728277
             push ax              ;                                ;B728277
             push ax              ; file attribute                 ;B728277
             push ax              ; open flag - fail if device     ;B728277
             push 01H             ;   does not exists              ;B728277
                                  ; open mode = ISSSRAAA           ;B728277
             push 0C2H            ;             11000010           ;B728277
                                  ; I   - Non inheritable handle   ;B728277
                                  ; SSS - Deny None access         ;B728277
                                  ; R   - Reserved must be 0       ;B728277
                                  ; AAA - Read/Write access        ;B728277
             push ax              ; Double words of 0              ;B728277
             push ax              ;                                ;B728277
             call DOSOPEN         ;                                ;B728277
           .else                                                   ;B728277
             xor  ax,ax           ;clear return code from dummy call;B728277
           .endif                                                  ;B728277

; ******** END of EEP ship issue temp fix for SuperProject         CJJ ********
         .endif

         .if <[bp].FunctionNum NE FC_OPEN>
           call ValidateInHand
         .endif

         .if <zero ax> AND         ; @  If no error encountered and
         .if <es:CDIB_Sel EQ ax>   ; @@ CDIB selector initialized?
           push es                ; @@ Setup: Address of segment name
           push OFFSET CDIB_Label ; @@
           push es                ; @@        Address of selector to
           push OFFSET CDIB_Sel   ; @@          be returned
           call DOSGETSHRSEG      ; @@ Obtain Codepage Data Information
                                     ; @@   Block selector
           xor  ax,ax             ; @@ At sysinit time, CDIB selector
                                     ; @@   may not be available.  This
                                     ; @@   insures at least one more try.
         .endif

       .endif

     .endif

   .endif                          ; Winthorn screen group!

   inc  Entry_Count             ; Bypass validation check when

   .if <zero ax>                ; Handle validation error?
                           ;
                           ;**********************************************
                           ;*  SI has FunctionNum, dispatch to appropriate
                           ;*  BKS handling routine based on SI.
                           ;**********************************************
                           ;
     shl  si,1             ; @  Index to handler routine address
     call cs:[si].TblStrt  ; @  Call indirect to handler routine        ;@T52
   .endif

   dec  Entry_Count             ; Balance entry count on the way out
   mov  word ptr [bp-2],ax      ; Set return code
   pop  es
   pop  ds
   popa                         ; Restore caller's registers
   ret                          ; Return to KbdRout()
                                ; KbdRout() is responsible for cleaning
BKSMAIN endp                    ;  up the original parameters passed
                                ;  by its caller




LoadWinthorn proc near
   lea  si,ShieldHandle         ;offset to Shield Module handle         ;MDLL
   sub  cx,cx                                                           ;MDLL
   push cx                      ;Get access to DLL                      ;MDLL
   push cx                      ;                                       ;MDLL
   push cx                      ;                                       ;MDLL
   push es                      ;
   push offset Shield_DLL       ;PMVIOP.DLL                             ;MDLL
   push es                      ;
   push si                      ;Module handle to be returned           ;MDLL
   call DOSLOADMODULE           ;

   .if <zero ax> AND            ;Module loaded successfully
   xchg es:ShieldEntries,cx     ;Get number of Shield entries           ;MDLL
   .if <ncxz>                   ;AND first time module loaded

     mov  dx,es:[si]            ;Module Handle
     add  si,2                  ;Location to store proc addr

     .repeat                    ;Get procedure address CX times
       sub  sp,4                ;                                       ;MDLL
       mov  di,sp               ;Alloc return value on stack            ;MDLL

       push dx                  ;Handle
       push ax                  ;MUST be 0 when using ordinal #         ;MDLL
       push word ptr es:[si]    ;Hardcoded ordinal #                    ;MDLL
       push ss                  ;@ of returned pointer
       push di                  ;                                       ;MDLL
       call DOSGETPROCADDR      ;

       .if <nonzero ax>         ;Successful?                            ;MDLL
         add  sp,4              ;Deallocate space on stack              ;MDLL
         .leave                 ;Exit on error                          ;MDLL
       .else                    ;
         pop  es:[si]           ;                                       ;MDLL
         pop  es:[si+2]         ;Copy pointer to table                  ;MDLL
                                                                        ;MDLL
         add  si,4              ;Index to next pointer location         ;MDLL
       .endif                   ;

     .loop                      ;Next procedure

   .endif

   ret
LoadWinthorn endp

CTEXT_TUNE5 ENDS                                                        ;MDLL
     END
