;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
  Page  58,132
  Title   KBDIN - OS/2 2.2 Device Driver
  Name    KBDIN
;/*****************************************************************************
;*
;* SOURCE FILE NAME = KBDIN.ASM
;*
;* DESCRIPTIVE NAME = Keyboard Device Driver for OS/2
;*
;*
;* VERSION      V2.X
;*
;* DATE         ????
;*
;* DESCRIPTION  This device driver handles all physical I/O between OS/2
;*              and the keyboard device.
;*
;* FUNCTIONS KBDStrat       - The device driver strategy entry point.
;*           PDDCMD_Entry   - Physical Keyboard Device Driver IDC Interface
;*                            Entry Point.
;*           KbdInt         - The device driver interrupt entry point.
;*           MonDispEntry   - Notification routine called by Monitor Dispatcher
;*
;* NOTES   DEPENDENCIES:
;*          1) This device driver assumes scan-codes received from the key-
;*             board have make codes less than hex 80, with break codes
;*             equal to the make but with the value 80 added. Further, it
;*             expects the keyboard overrun code to be hex FF, keyboard
;*             resend requests to be hex FE, keyboard command acknowledge
;*             responses to be hex FA, and enhanced keyboard secondary key
;*             indicator prefix to be hex E0 or E1.
;*          2) This device driver expects the keyboard to recognize all
;*             commands as specified in the IBM PS/2 technical reference.
;*          3) This device driver utilizes the DevHlp routines of OS/2.
;*          4) This device driver expects the OS/2  monitor dispatcher to
;*             accept CharData records from it and return recs to it.
;*          5) This device driver expects the OS/2 SingleQ device driver
;*             to accept SingleQ Packets if the Presentation Manager is
;*             present.
;*          6) This device driver expects the OS/2 Virtual Keyboard Device
;*             Driver to accept scan code information through the establish-
;*             ed interface for all V86 mode sessions.  It also expects the
;*             VKBD DD to communicate and pass information through the
;*             established IDC interface for MVDM keyboard functions.
;*
;*
;*         RESTRICTIONS:
;*          1) This device driver must run on an 80386 based or compatible
;*             machine.
;*          2) This device driver must be used with a keyboard that has
;*             setable LEDs and Typamatic rate & delay (i.e., is IBM Enh.
;*             compatable), or a keyboard that does not have LED lights,
;*             but can handle and respond to commands as if it had them.
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*                    ROUTINES:    None.
;*                    DEVHELPS:    Jumps to ThrowMeAway, which calls:
;*                                 DevHlp (GetLIDEntry, SetIRQ, UnSetIRQ,
;*                                         ABIOSCall, GetDOSVar, AllocPhys,
;*                                         AllocGDTSelector, PhysToGDTSelector,
;*                                         TickCount, ResetTimer, ABIOSGetParms,
;*                                         RegisterPDD)
;*
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG         APAR        CHANGE DESCRIPTION
;*   --------  ----------  -------      --------------------------------------
;*                          DCR1187
;*                          PTR B787430
;*                          PTR B790171
;*                          DCR 408
;*                          DCR 1546
;*                          PTR B712571
;*                          PTR B727854
;*                          PTR B704150
;*                          DCR 549
;*                          PTM 5841
;*                          PTM 1811
;*                          PTM 1242
;*                          PTM 1361
;*****************************************************************************/
;*
BREAK   <Masm   directives, Included files>
.286p
.sall
.xcref
;/*
;**The following files are included, but XLISTed:
;*/
.xlist
        Include iodelay.inc    ; DevIODelay replaced IODelay
        Include basemaca.inc   ;DOS macros.
        Include osmaca.inc     ;Macro file for OS/2 kernel
        CPUMODE 286
        Include struc.inc      ;Structured assembly macros.
        Include devhlp.inc     ;DevHlp & Signal equates, char queue structure
        Include kbdxlat.inc    ; translation table equates.
        Include infoseg.inc    ;InfoSeg structure.
        Include devsym.inc     ;Device driver header definitions.
        Include kbdseg.inc     ;Segment definitions.
        Include kbdddr.inc     ;Keyboard Device Driver structures & equates.
        Include kbddi.inc      ; 
        Include kbdaim.inc     ;AIM equates
.list

StkFrameVars                   ; Macro to define the local stack
                               ; variables.

;/****
;* External routines
;****/
        Extrn   PDDCMD_Entry      :Near
        Extrn   FilterTimeOut     :Far    ;AIM
        Extrn   KBDBeep1KHz       :Far    ;AIM
        Extrn   KBDBeep2KHz       :Far    ;AIM

;/****
;* External variables
;****/
        Extrn   OtherFlags        :Byte
        Extrn   IDFlags           :Byte
        Extrn   XlateTable        :Byte
        Extrn   PKBDName          :Byte
        Extrn   MiscFlags         :Byte
        Extrn   SGCreatedTbl      :Byte

        Extrn   SInfoSeg          :Word
        Extrn   KeyboardType      :Word
        Extrn   CPCount           :Word
        Extrn   MaxSG             :Word
        Extrn   PSGPointers       :Word
        Extrn   CBDataSel         :Word
        Extrn   selKbdData        :Word
        Extrn   DeviceHelp        :DWord
        Extrn   SADump            :DWord
        Extrn   LInfoSeg          :DWord
        Extrn   CheckKBDDD        :Word
        Extrn   FilterFlags       :Byte    ;AIM
        EXtrn   Hw_Typa_Rate      :Word    ;AIM
        EXtrn   Em_Typa_Rate      :Word    ;AIM
        EXtrn   Hw_Typa_Delay     :Word    ;AIM
        EXtrn   Em_Typa_Delay     :Word    ;AIM
        EXtrn   Hw_Typa_Time      :Word    ;AIM


BREAK   <Throw-away code>

  Code    Segment                   ;=======================\

  Assume  cs:Code,Ds:DGROUP,ES:Nothing

ThrowOutAddr:
;/*
;** All code below this point will be thrown away after init time
;**            Moved the TempInt9H routine above this point for
;** Hot Plug reinit useage.
;*/

;/*
;*********************************************************************
;**  ThrowMeAway - Throw away code containing KbdDD initialization.  *
;*********************************************************************
;*/

Public  ThrowMeAway             ;Reference KBDSTRA.ASM for the KbdInit sublogue.
ThrowMeAway Proc            ;------------------------------------------\
                                ;           
        Or      OtherFlags, InitTime ; Init time code is executing.

                                ;- Figure out the typematic rate and delay -AIM-
        Get_KBD_Speed           ; AIM

                                ; Get DevHlp address from Request Block:

        Mov     AX, Word Ptr ES:[BX].InitDevHlp ;Get half of DevHlp address.
        Mov     Word Ptr [DeviceHelp],AX ;Save it.
        Mov     AX, Word Ptr ES:[BX].InitDevHlp+2 ;Get other half of DevHlp address.
        Mov     Word Ptr [DeviceHelp+2],AX ;Save it.

;/*
;** Edit code segment to hold KbdData selector
;** Due to a loader problem we must store our data selector in our code
;** segment. This will allow us to get to it at VDM time (PDDCMD_Entry)
;*/
                                        ; 
        SaveReg <BX,ES>                 ; Save ES and BX regs.
        SaveReg <DS>                    ; DS too.
        Push    DS                      ; Put the PKBD's DS into
        Pop     ES                      ; ES.
        ASSUME  ES:DGROUP               ; 
        Push    CS                      ; Put the PKBD's code seg into
        Pop     DS                      ; DS.
        ASSUME  DS:NOTHING              ; 
        Mov     SI, offset selKbdData   ; DS:SI now contains SelKbdData.
        Mov     DL, DevHlp_VirtToPhys   ; Set up DevHlp function.
        Call    ES:[DeviceHelp]         ; AX:BX will hold physical address
        Mov     CX, 2                   ; Word length to write into.
                                        ; 
        Mov     DX, DevHlp_PhysToVirt + ES_DI*100h
                                        ; 
        Call    ES:[DeviceHelp]         ; ES:DI now contains SelKbdData
        ASSUME  ES:NOTHING              ; 
        RestoreReg <DS>                 ; Restore data segment.
        ASSUME  DS:DGROUP               ; 
        Mov     ES:[DI],DS              ; DS saved inside the code segment now
        RestoreReg <ES,BX>              ; Restore regs.
        ASSUME  ES:NOTHING              ; 
        Mov     DL, DevHlp_UnPhysToVirt ; 
        Call    [DeviceHelp]            ; 
                                        ; 

;/*
;** *****************************************************************
;** * Register the PKBD's VDD services entry point with the VDD.    *
;** * This services entry point is the router for all the PDD/VDD   *
;** * interface functions.                                          *
;** *****************************************************************
;*/

        SaveReg <ES,BX>                 ; Save registers for a bit.
        Lea     SI, PKBDName            ; Load the Physical device name.
        Push    CS                      ; Copy code segment into BX.
        Pop     ES                      ; Make AX:BX point to the
        Lea     DI, KbdCode:PDDCMD_Entry ; interface entry point in PKBD.
        Mov     DL, DevHlp_RegisterPDD  ; Set up for RegisterPDD call.
        Call    [DeviceHelp]            ; Issue the DevHelp call.
        RestoreReg <BX,ES>              ; Bring 'em back.
        Or      AX,AX                   ; Check AX for an error code
        .If     <nz>                    ; IF an error occured then
            Jmp     InitFailed          ; we do not want to init, bag it.
        .Endif                          ; Endif error on RegisterPDD.
                ;*
                ;* Obtain GDT Selector to the Codepage count data area,which is
                ;* being passed as a command line pointer.  The offset for this
                ;* data area is (by convention) zero, so we don't care about the
                ;* other word in the request packet.
                ;*

        Mov     AX, ES:[BX+EntryArgsPtr+2] ; Get the segment.
        Mov     DI, ES:[BX+EntryArgsPtr] ; Get the offset.
        Push    ES                      ; Save for a bit.
        Mov     ES, AX                  ; Get Codepage count

                                        
                                        ; Get number of CPCB entries to allocate
        Mov     AX,ES:[DI]              ; from address in request block.
        Mov     CPCount, AX             ; Save in the data segment.
                                        

        Pop     ES                      ; Restore req. block seg.

                    ; Save certain needed variables on the local stack:

        Mov     StkRPS, ES              ; Request Packet selector.
        Mov     StkRPO, BX              ;   "       "    offset.
        Mov     StkDS, DS               ; Save the data segment sel.

                                        ;Set throw away code address:

        Mov     AX,Offset KbdCode:ThrowOutAddr ; Obtain address of code end.
        Mov     Word Ptr ES:[BX].InitEcode,AX ;Put it where DevHlp address was.

        Push    BX                      ; Save the request packet addr.
        Mov     AX, EntryCount          ; Get the number of codepages.

        Imul    AX, CPCBEntrySize       ; AX = AX * CPCB Entry Size.
        Add     AX, KIBSIZE             ; AX = CPCB Size + Size KIB.

;           
.386p
        SaveReg <ECX, EDI, EAX>         ; Save for later.
        Xor     ECX, ECX                ; Clear
        Mov     CX, AX                  ; 32-bit block size in bytes.
        Mov     EAX, VMDHA_FIXED + VMDHA_16M + VMDHA_SELMAP ; Type of memory needed.
        Mov     EDI, NO_PHYSADDR        ; Not used.
        Mov     DL, DevHlp_VMAlloc      ; Specify DevHlp function.
        Call    [DeviceHelp]            ; Allocate memory.
        .If     <c>                     ; Carry flag set means error.
            RestoreReg <EAX, EDI, ECX>  ; Clean up stack
            RestoreReg <BX>             ; Restore request packet addr.
            Jmp     InitFailed          ; Failed - drop out.
        .Endif                          ; Endif Carry flag set.
        SHR     ECX, 16                 ; Move selector for allocated
        Mov     CBDataSel, CX           ; Move selector to CBDataSel
        RestoreReg <EAX, EDI, ECX>      ; Put things back to normal
        RestoreReg <BX>                 ; Restore request packet addr.
.286p

  ;* Calculate the physical address of the GDT Selector just obtained,
  ;* so that the memory can be accessed at real mode interrupt time.

        Mov     AX, Word Ptr CBDataSel  ; Get CPCB Sel.
        Push    DS                      ; Copy data segment selector
        Pop     ES                      ;  for next DevHlp call.
        Mov     DS, AX                  ; GDT segment value.
        Xor     SI, SI                  ; Assumed zero offset.
        Mov     DL, DevHlp_VirtToPhys   ; Desired DevHlp function.
        Call    ES:[DeviceHelp]         ; AX:BX = Phys. address, or
                                        ;  carry flag set on error.
        Mov     DS, StkDS               ; Restore DD's data segment.
        .If     < c >                   ; If DevHlp had an error,
            Jmp     InitFailed          ; Initialization fails.
        .Endif

                                        ; Initialize the KIB Free List header.

        Mov     ES, CBDataSel           ; Get Sel:Off
        Mov     SI, KIBOFFSET           ; to start initializing KIB.

        Mov     ES:[SI].TotalEls, KIBElements ; # of KIB Elements in system.
        Mov     ES:[SI].MaxThisTime, KIBElements ; Max. KIB Elements while
                                        ;  session is active.
        Mov     ES:[SI].ElsInList, KIBElements ; Elements currently unused.
        Mov     CX, 1                   ; Set up forward pointer
                                        ;  counter.
        Mov     ES:[SI].FreeListIn, CX  ; First free list entry
                                        ;  available IS first entry!

 ;* Loop through each free list entry, setting the FwdPtr (indicating
 ;* at this point the next available free list entry) to the entry
 ;* following it.  This is done for all entries except the last, where
 ;* a -1 is placed in the FwdPtr field, indicating the end of the
 ;* available free list entries in the KIB.

        Mov     SI, FLISTOFFSET         ; Point to the beginning of the list.

        .While  < CX lt KIBElements >   ; Do for all entries except the last.
            Inc     CX                  ; This entry will point to the next.
            Mov     ES:[SI].KIBFwdPtr, CX ; MAKE the entry point to the next.
            Add     SI, KIBElLen        ; Increment to next entry.
        .EndWhile                       ; Process next entry if not the last.

        Mov     ES:[SI].KIBFwdPtr, -1   ; Mark last entry AS the last.

        Mov     DI, SI                  ; Switch index registers.
        Add     DI, KIBElLen            ; Add size of last KIB Element entry,

;/*
;**            Allocate memory only for the defaut xlation table.
;** DI points to CPCB entry 0.
;/*

.386p
        SaveReg <EAX,ECX, EDI>          ; Save counter.
        Mov     EAX, VMDHA_FIXED + VMDHA_16M + VMDHA_SELMAP ; Type of memory needed.
        Mov     EDI, NO_PHYSADDR        ; Not used.
        XOR     ECX, ECX                ; Clear for use.
        Mov     CX, XTLen               ; 32 bit block size in bytes
        Mov     DL, DevHlp_VMAlloc      ; Specify DevHlp function.
        Call    [DeviceHelp]            ; Go allocate the memory.
        .If     <c>                     ; Carry flag set means error.
            RestoreReg <EDI, ECX,EAX>   ; Clean up stack
            Jmp     InitFailed          ; Failed - drop out.
        .Endif                          ; Endif Carry flag set.
        SHR     ECX, 16                 ; Move selector to low word
        RestoreReg <EDI>
        Mov     Word Ptr ES:[DI].CPVAddr, CX ; Store selector allocated
        Mov     Dword Ptr ES:[DI].XTLinear, EAX ;Linear address of memory alloc
        Mov     Word Ptr ES:[DI].CPUseCount, XTLen ;Save length for future reference
        RestoreReg <ECX, EAX>           ; Restore counter.
        Mov     Word Ptr ES:[DI].CPValue, 0 ; zero out code page value.
.286p
                                        ;           
        Mov     CX, 3                   ; Set up counter
        Add     DI, CPCBEntrySize       ; Point to CPCB entry 1
CPCBInit:                               ; Init CPCB data areas to zero.
        Mov     Word Ptr ES:[DI].CPVAddr,0 ; Zero out selector
        Mov     Word Ptr ES:[DI].CPUseCount, 0 ; Zero out length value.
        Mov     Word Ptr ES:[DI].CPValue, 0 ; Zero out code page value.
        Add     DI, CPCBEntrySize       ; Point to next CPCB entry.
        Dec     CX                      ; Dec the counter
        Jnz     CPCBInit                ; loop again if nonzero cx
                                        ; Note: DI now points just beyond
                                        ; CPCB entry 3.


        Mov     SI, CPCBOFFSET          ; Point to zeroeth entry of CPCB, which
                                        ;  is the "hardware default" table.

  ;* At this point, DI now points beyond the last entry in the CPCB.
  ;* Since the CPCB is currently the last area in the CB data area,
  ;* DI = the size of this data area.

  ;* Copy "hardware default" translate table from area of data segment
  ;* that will be discarded.

        Push    ES
        Mov     ES, Word Ptr ES:[SI].CPVAddr ; Set destination register to point to
                                        ;  this entry's table.
        Xor     DI, DI                  ; Zero offset of target area.
        Mov     SI, Offset XlateTable   ; Point to beginning of translate table.
        Mov     AX, [SI].XT_CP          ; Save the code page ID of the table.
        Mov     CX,XTLen                ; Set byte length of XlateTable.
        cld                             ; ensure move direction
        Rep     Movsb                   ; Copy table to allocated memory.
        Mov     SI, CPCBOFFSET          ; Point back to entry 0 of the CPCB.
        Pop     ES
        Mov     ES:[SI].CPValue, AX     ; Put the code page id of the table
                                        ;  just loaded into the CPCB entry.

;/*
;**Get Dos Variables: RAS Dump,Reboot,LInfoSeg,SInfoSeg:
;*/

        Mov     DS, StkDS               ; Restore the DD's data segment.
        Mov     AL,VectorSDF            ; Set VAR index for RAS dump.
        Mov     DL,DevHlp_GetDOSVar     ; Set DevHlp function.
        Call    [DeviceHelp]            ; Go get variable address.
        Mov     ES,AX                   ; Make ES:BX point to dump address variable.
        Mov     AX,ES:[BX]              ; Get first half of address.
        Mov     Word Ptr SADump,AX      ; Save offset of variable address.
        Mov     AX,ES:[BX+2]            ; Get other half of address.
        Mov     Word Ptr SADump+2,AX    ; Save segment of variable address.

        Mov     AL,LocINFOseg           ; Set VAR index for Local InfoSeg.
        Mov     DL,DevHlp_GetDOSVar     ; Set DevHlp function.
        Call    [DeviceHelp]            ; Go get variable address.
        Mov     ES,AX            ; Make ES:BX point to InfoSeg address variable.
        Mov     AX,ES:[BX]              ; Get first half of address.
        Mov     Word Ptr LInfoSeg,AX    ; Save as the offset.
        Mov     AX,ES:[BX+2]            ; Get other half of address.
        Mov     Word Ptr LInfoSeg+2,AX  ; Save as the segment.

        Mov     AL,SysINFOseg           ; Set VAR index for System InfoSeg.
        Mov     DL,DevHlp_GetDOSVar     ; Set DevHlp function.
        Call    [DeviceHelp]            ; Go get variable address.
        Mov     ES,AX           ; Make ES:BX point to InfoSeg address variable.
        Mov     AX,ES:[BX]              ; Get the segment.
        Mov     Word Ptr SInfoSeg,AX    ; Save the segment.
        Mov     ES,AX                   ; Make ES point to SInfoSeg.

;/*
;** The next task is to determine the maximum number of sessions
;** currently allowed by the system (via interrogation of a System
;** Information Segment variable) and reserve space in the DD's
;** data segment for the per session data areas (PSG's).  A pointer
;** table is created, with each word pointing to the appropriate PSG.
;** ES already set to System Info. Segment from GetTime macro above.
;*/


        Mov     CL, ES:[SIS_MaxScrnGrp] ; Get maximum no. of sessions allowed.
        Xor     CH, CH                  ; Clear out high byte.
        Mov     MaxSG, CX               ; Save in DD's data segment.
        Shl     CX, 1                   ; CX = Memory needed for PSG pointers.
        Mov     SI, Offset PSGPointers  ; SI will index through the PSG
                                        ;  pointers.
        Mov     DI, SI                  ; DI will index through the PSG's
                                        ;  themselves. See next statement.
        Add     DI, CX                  ; DI now points to the beginning of
                                        ;  the PSG area.
        Shr     CX, 1                   ; Make CX = # of sessions again.
        Xor     AX, AX                  ; Zero out a register (used to zero
                                        ;  initialize the PSG area in the
                                        ;  first loop, then start with
                                        ;  session zero in the second loop).

;/*
;** Zero out the area to contain the PSG information.
;*/

        Push    CX                      ; Save session count.
        Push    DI                      ; Save PSG area offset.
        Imul    CX, SizePSG             ; Get number of bytes in whole area.
        ZeroPSG:                        ; Zero out each byte in the PSG area.
        Mov     Byte Ptr [DI], AL       ; AL was cleared out above.
        Inc     DI                      ; Get ready to clear the next byte.
        Loop    ZeroPSG                 ; End Zero out each byte in PSG area.
        Pop     DI                      ; Restore PSG area offset.
        Pop     CX                      ; Restore session count.

;/*
;** PTM 1361: Mark PSG0 as being the active screen group, to allow the
;** interrupt handler to handler to update any led keystrokes during
;** boot up.
;*/

        Or      [DI+2].PSGFlags, ActiveSG ;            Mark SG1 as active SG.

;/*
;** Loop through each PSG/PSG Pointer area, and initialize as
;** appropriate.
;*/

        .While  < AX lt CX >            ; Process each PSG/PSG Pointer.
            Mov     [SI], DI            ; Put offset of PSG in its pointer.
            Mov     [DI].PSGNum, AX     ; Put session number in PSG.

;/*
;** Initialize the Monitor Chain Output Buffer/Element zero portion
;**  of the PSG.
;*/

            Mov     [DI].MonChainEnd, KeyPacketLen + 2
            Mov     [DI].E0FwdPtr, -1   ; Nothing in the KIB yet.
            Mov     [DI].E0RevPtr, -1   ; Nothing in the KIB yet.

;/*
;** Set the KIB head/tail pointers in the Default KCB to indicate
;** that no elements are in the queue.
;*/

            Mov     [DI].DKCB.KCBInPtr, -1 ; Nothing in the KIB yet.
            Mov     [DI].DKCB.KCBOutPtr, -1 ; Nothing in the KIB yet.

;/*
;** Any more initialization goes here...
;*/
                                        ;           
            Mov     Word Ptr [DI].DKCB.KCBBufferSem, 0 ; Init. buffer access
            Mov     Word Ptr [DI].DKCB.KCBBufferSem+2, 0 ;serialization semaphore.

                           ;           
                           ;            Call to InitPSG removed.
                           ; Initialize ShiftFlags according to keyboard type

;/*
;** Any further SG initialization goes here.
;*/

            Mov     [DI].DKCB.KCBDBCSFl, DefaultDBCS ; Set default DBCS status.
            Mov     Word Ptr [DI].KCBAddress, 00h ; Make the PSG point
            Mov     Word Ptr [DI].KCBAddress+2, 00h ;  to the Default KCB
                                        ;  the first time.
                                        ;           

;/*
;** Initialization of the PSG/PSG Pointer combo is complete. Point
;** to the next set of data:
;*/

            Add     SI, 2               ; Next PSG pointer.
            Add     DI, SizePSG         ; Next PSG data area.

            Inc     AX                  ; Process next session.
        .EndWhile                       ; End While PSG data left to init.

;/*
;**             Mark SG's 0-->3 as created in the SGCreatedTbl.  The
;**           Session Manager does not call the SGController IOCTL
;**           for these sessions.
;*/

        Mov     SGCreatedTbl, 0Fh

;/*
;** DI now contains the offset to the first byte of data past the
;** end of the PSG data areas.  This marks the end of the device
;** driver's data segment.
;*/

        LES     BX, Dword Ptr StkRPO    ; Get request packet address.
        Mov     Word Ptr ES:[BX].InitEdata,DI ;Set throw away address for data.

;/*
;** All keystrokes will be thrown out until the first read or peek
;** from an SG that is the active SG
;*/

        Or      [MiscFlags],NoReadYet   ;Indicate no-one's read anything yet.

        Mov     AX, Offset KbdCode:KBDBeep1KHz ; AX = Offset of Keyboard
                                        ;  Timer Handler routine.
        Mov     BX, MAXIMUM_TICK        ; Tick Count = Maximum possible.
        Mov     DL, DevHlp_TickCount    ; Set DevHlp Service desired.
        Call    [DeviceHelp]            ; Carry flag set if an error.
        .If     < c >                   ; If carry flag is set, we're sunk.
            Jmp     InitFailed          ; Indicate failure and get out.
        .Endif                          ; End if tick count failed.

        Mov     AX, Offset KbdCode:KBDBeep2KHz ; AX = Offset of Keyboard
                                        ;  Timer Handler routine.
        Mov     BX, MAXIMUM_TICK        ; Tick Count = Maximum possible.
        Mov     DL, DevHlp_TickCount    ; Set DevHlp Service desired.
        Call    [DeviceHelp]            ; Carry flag set if an error.
        .If     < c >                   ; If carry flag is set, we're sunk.
            Jmp     InitFailed          ; Indicate failure and get out.
        .Endif                          ; End if tick count failed.

        Mov     AX, Offset KbdCode:FilterTimeOut ; AX = Offset of Keyboard
                                        ; Timer Handler routine.
        Mov     BX, MAXIMUM_TICK        ; Tick Count = Maximum possible.
        Mov     DL, DevHlp_TickCount    ; Set DevHlp Service desired.
        Call    [DeviceHelp]            ; Carry flag set if an error.
        .If     < c >                   ; If carry flag is set, we're sunk.
            Jmp     InitFailed          ; Indicate failure and get out.
        .Endif                          ; End if tick count failed.


        Mov     KeyboardType,1         ; Indicate ENH as default for IOCTL.
        Mov     CheckKBDDD, 0
;/*
;** 58671 Start:  Now flush out the BIOS keyboard typeahead buffer
;*/
        push    es
        mov     ax,0040h
        mov     es,ax
        mov     ax,es:[1Ah]
        mov     es:[1Ch],ax
        pop     es

;/*
;** 58671 End
;*/

        And     OtherFlags, NOT InitTime ; Init time code finished executing.
        Ret                             ;We're in business!

InitFailed:                             ; Jumped to if major problems.
        LES     BX, Dword Ptr StkRPO    ; Restore request packet addr.
        Mov     DI, PSGPointers         ; Restore caller's PSG offset,
                                        ;  which must be for SG 0.
        Mov     Word Ptr ES:[BX].InitEcode,0 ; Set code offset to zero.
        Mov     Word Ptr ES:[BX].InitEdata, 0 ; Set data offset to zero.
        And     OtherFlags, NOT InitTime ; Init time code finished executing.
        Ret                             ; Return to caller.

ThrowMeAway Endp


Code    Ends

        End
