/*
*   IBM Confidential
*
*   OCO Source Materials
*
*   (c) Copyright IBM Corp. 1994, 1998
*
*   The source code for this program is not published or otherwise divested of its
*   tradesecrets, irrespective of what has been deposited with the U.S. Copyright Office.
*/

/*****************************************************************************/
/*                                                                           */
/* SOURCE FILE NAME = KBDSTRA.C                                              */
/*                                                                           */
/* DESCRIPTIVE NAME = Physical Keyboard Device Driver Strategy Routine       */
/*                                                                           */
/* VERSION      V2.2                                                         */
/*                                                                           */
/* DATE         01/11/94                                                     */
/*                                                                           */
/* DESCRIPTION  Entry Point from Device Independent Driver and Kernel.       */
/*                                                                           */
/* FUNCTIONS   void Block_Thread(void)                                       */
/*             void Run_Thread(void)                                         */
/*           USHORT Query_Open(void)                                         */
/*           USHORT Query_Close(void)                                        */
/*           USHORT Query_Capabilites(USHORT,USHORT)                         */
/*           USHORT Query_Typematic(void)                                    */
/*           USHORT Query_LEDs(void)                                         */
/*           USHORT Query_ID(USHORT,USHORT)                                  */
/*           USHORT Query_Disabled(void)                                     */
/*           USHORT Disable_Keyboard(void)                                   */
/*           USHORT Enable_Keyboard(void)                                    */
/*           USHORT CheckKBD(void)                                           */
/*           USHORT Reset_Hardware(void)                                     */
/*           USHORT Set_Typematic(BYTE)                                      */
/*           USHORT Set_LEDs(BYTE)                                           */
/*           USHORT Send_Generic(USHORT,USHORT)                              */
/*           USHORT Query_Kbd_Rdy(void)                                      */
/*           USHORT Flush_Partial(void)                                      */
/*           USHORT Save_State(void)                                         */
/*           USHORT Restore_State(void)                                      */
/*           USHORT IDC_Entry_Point(USHORT,USHORT,USHORT)                    */
/*             void Strategy(void)                                           */
/*                                                                           */
/* NOTES        DEPENDENCIES:  Controller or keyboard must be set to the     */
/*                             PC compatible scan code set.                  */
/*              RESTRICTIONS:  Machine must be a 386 or compatible with      */
/*                             a 386.                                        */
/*                                                                           */
/*                                                                           */
/* STRUCTURES     CapStruc                                                   */
/*                IDstruc                                                    */
/*                CmdStruc                                                   */
/*                                                                           */
/* EXTERNAL FUNCTIONS                                                        */
/*              KbdStatusWait                                                */
/*              SendData                                                     */
/*              DevHelp_ProcBlock                                            */
/*              DevHelp_ProcRun                                              */
/*              DevHelp_Yield                                                */
/*                                                                           */
/*   CHANGE ACTIVITY =                                                       */
/*     DATE      FLAG        APAR   CHANGE DESCRIPTION                       */
/*     --------  ----------  -----  -----------------------------------------*/
/*     10/07/96  MERLIN_J           IF def'd merlin j changes                */
/*     08/28/95  JS08356            Disable Set_LEDs on 5576-001&-002(H.Mori)*/
/*     09/22/95  JS08412   PJ20273  Disable Set_LEDs when no keyboard(H.Mori)*/
/*     07/08/97  CN181212           Added InitTime flag because DevHlp_Yield */
/*                                  can not be called at init time           */
/*     06/20/98  LR_USB             Modified to support USB Keyboard Client. */
/*                                                                           */
/*****************************************************************************/

/*-----------------------------*/
/*     Include files           */
/*-----------------------------*/

#include "os2.h"
#include "conio.h"
#include "devcmd.h"
#include "strat2.h"
#include "reqpkt.h"
#include "dhcalls.h"
#include "kbd.h"
#include "kbddd.h"
#include "cmdphdr.h"
#include "kbdusb.h"     //LR_USB

/*-----------------------------*/
/*   Define Constants          */
/*-----------------------------*/

#define MK_FP(seg,off) (void FAR *)(((ULONG)(((ULONG)(seg)<<16)+(ULONG)(off))))

/*-----------------------------*/
/*     External Variables      */
/*-----------------------------*/

extern  PRPH  pRPH;

extern  USHORT KData;
extern  USHORT KbdCS;
extern  USHORT Keycount;

extern  BYTE  Current_State;
extern  BYTE  LED_State;
extern  BYTE  Type_Rate;
extern  BYTE  DataByte1;
extern  BYTE  DataByte2;
extern  BYTE  AsyncInterruptTime;
extern  BYTE  SyncInterruptTime;
extern  BYTE  InitTime;
extern  BYTE  KbdError;
extern  BYTE  DisableFlag;
extern  BYTE  Save_LED;
extern  BYTE  Save_Type;
extern  BYTE  Next_Block;
extern  BYTE  Next_Run;
extern  BYTE  KbdResend;
#define SRFC_Save 0
#define SRFC_Restore 1
extern  BYTE  InitialSetLED;                                                             //@IBM JS08356(A)

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Block_Thread                                             */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* DESCRIPTION    : Blocks the current thread.  Checks for normal wake-up.   */
/*                                                                           */
/*****************************************************************************/

void Block_Thread (void)
{
  Next_Block++;                             /* Increment pointer.            */

  /* Start the block thread timer.                                           */
  /* Block the current thread and test if it is a natural wakeup.            */

  StartBTTimer();
  if (DevHelp_ProcBlock ((ULONG)MK_FP(KbdCS, Next_Block),
                         (ULONG)-1, (USHORT)0) != 0) {
    Next_Block--;                       /* If unnatural then remove pointer. */
  }
  CLI;
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Run_Thread                                               */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* DESCRIPTION    : Starts up the next blocked thread.                       */
/*                                                                           */
/*****************************************************************************/

void Run_Thread (void)
{
  USHORT *awake;

  Next_Run++;                               /* Increment pointer to threads. */
                                            /* Run blocked thread.           */
  DevHelp_ProcRun ((ULONG)MK_FP(KbdCS,Next_Run), (PUSHORT)&awake);
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Query_Open                                               */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* RETURN-NORMAL  : AX=0  : There is no command in progress.                 */
/*                  AX=-1 : There is currently a command in progress.        */
/*                                                                           */
/*****************************************************************************/

USHORT Query_Open(void)
{
 if (gLegKbd)                                     //LR_USB
    return (Current_State == S_NOCMDIPG ? -1: 0);
 else if (gUSBKbd) return (0);                    //LR_USB
 else              return (-1);                   //LR_USB
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Query_Close                                              */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* DESCRIPTION    : This function has no function.                           */
/*                                                                           */
/*****************************************************************************/

USHORT Query_Close(void)
{
        return (0);
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Query_Capabilities                                       */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* INPUT          : Offset and data segment to structure that needs to be    */
/*                  filled in with keyboard capabilities                     */
/*                                                                           */
/*****************************************************************************/

USHORT Query_Capabilites (USHORT CMD_Offset, USHORT CMD_Segment)
{
  CapStruc FAR *ptr;

  ptr = MK_FP(CMD_Segment, CMD_Offset);    /* Initialize pointer.            */
        ptr->DevFlags = 0x33;              /* Three LEDs, HotPlug, Keyboard. */
        ptr->KeyCount = Keycount;          /* Number of keys.                */
        ptr->MaxTypa = 31;                 /* Max type rate = 30 codes sec.  */
        ptr->MinTypa = 0;                  /* Min type rate = 2  codes sec.  */
        ptr->MaxDelay = 3;                 /* Max delay = 1 second.          */
        ptr->MinDelay = 0;                 /* Min delay = 250 milliseconds.  */
        return (0);                        /* Return finished with command.  */
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Query_Typematic                                          */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* RETURN-NORMAL  : Current type rate and delay                              */
/*                                                                           */
/*****************************************************************************/

USHORT Query_Typematic (void)
{
  return (Type_Rate);
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Query_LEDs                                               */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* RETURN-NORMAL  : Current LED state                                        */
/*                                                                           */
/*****************************************************************************/

USHORT Query_LEDs (void)
{
  return (LED_State);
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Query_ID                                                 */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* INPUT          : Offset and data segment to structure that needs to be    */
/*                  filled in with keyboard identification.                  */
/*                                                                           */
/* RETURN-NORMAL  : Number of keys on the keyboard.                          */
/*                                                                           */
/*****************************************************************************/

USHORT Query_ID (USHORT CMD_Offset, USHORT CMD_Segment)
{
  IDstruc FAR *ptr;

  ptr = MK_FP (CMD_Segment, CMD_Offset);        /* Initialize pointer.       */
  ptr->idlen = 2;                               /* Enter two ID byte length. */
  ptr->idbytes[0] = DataByte1;                  /* Store first byte.         */
  ptr->idbytes[1] = DataByte2;                  /* Store second byte.        */
  return (Keycount);                            /* Return number of keys.    */
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Disable_Keyboard                                         */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* RETURN-NORMAL  : AX=0  : Keyboard is enabled.                             */
/*                  AX=-1 : Keyboard is disabled.                            */
/*                                                                           */
/*****************************************************************************/

USHORT Query_Disabled(void)
{
        return(DisableFlag ? -1 : 0);
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Disable_Keyboard                                         */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* DESCRIPTION    : Disable the keyboard.                                    */
/*                                                                           */
/* RETURN-NORMAL  : AX=0 : Did not disable keyboard.                         */
/*                  AX=1 : Disabled keyboard.                                */
/*                                                                           */
/*****************************************************************************/

USHORT Disable_Keyboard (void)
{
 //LR_USB if (DisableFlag == TURNOFF) {     /* keyboard not already disabled */
 if (gLegKbd && !DisableFlag) {             //LR_USB
    PUSHF;
    if (KbdStatusWait()) {                  /* Make sure keyboard is ready.  */
        outp (PORT_CMD, CMD_DISABLEKBD);    /* Disable Keyboard.             */
        DisableFlag = TURNON;               /* Show that it is disabled.     */
        POPF;
        return (1);                         /* Return that keyboard disabled.*/
    }
    POPF;
 }
 return (0);                             /* Kbd not disabled by this routine.*/
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Enable_Keyboard                                          */
/*                  "IBM Unique Code"                                        */
/*                                                                           */
/* DESCRIPTION    : Enable the keyboard.                                     */
/*                                                                           */
/* RETURN-NORMAL  : AX=0 : Enabled keyboard.                                 */
/*                                                                           */
/*****************************************************************************/

USHORT Enable_Keyboard(void)
{
 //LR_USB   if (DisableFlag == TURNON) {    /* If disabled.                  */
 if (gLegKbd && DisableFlag) {              //LR_USB
    PUSHF;
    if (KbdStatusWait()) {                  /* Make sure keyboard is ready.  */
        outp (PORT_CMD, CMD_ENABLEKBD);     /* Enable Keyboard.              */
        DisableFlag = TURNOFF;              /* Show that it is enabled.      */
    }
    POPF;
 }
 return (0);
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : BeginSyncCommand                                         */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* DESCRIPTION    : Find out if a command is in progress already.  If there  */
/*                  is, and it's not interrupt time then block this thread.  */
/*                  If it is interrupt time then we can not run this routine */
/*                  at this time.  If there isn't a command in progress then */
/*                  continue to process this command.                        */
/*                                                                           */
/*****************************************************************************/

USHORT BeginSyncCommand (void)
{
  PUSHF;
  while (Current_State != S_NOCMDIPG) {     /* If someone not useing kbd.    */
    if (!SyncInterruptTime) Block_Thread(); /*  then block thread.           */
    else {
        POPF;
        KeyERROR();
        return (0);                         /* Cannot process at this time.  */
    }
  }
  POPF;
  return (1);                               /* Disable keyboard.             */
}

/*****************************************************************************/

void EndSyncCommand (void)                //LR_USB USHORT EndSyncCommand (void)
{
  if (Next_Block != Next_Run) {             /* Check if blocked thread.      */
    Run_Thread();                           /* If yes then run it.           */
  }
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Reset_Hardware                                           */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* DESCRIPTION    : Send a reset to the keyboard hardware.                   */
/*                                                                           */
/*****************************************************************************/

USHORT Reset_Hardware (void)
{
 if (gLegKbd) {                                    //LR_USB
    BeginSyncCommand();                            // block if we need to
    do {
        Current_State = S_WAIT_ACK;                /* Change current state.  */
        SendData (KBD_RESET);                      /* Reset keyboard.        */
        while (Current_State != S_NOCMDIPG) {      /* Wait until CMD finished. */
                                                   /* CN181212 - Added inittime because */
                                                   /* DevHelp_Yield can not be called at init time */
            if ((!INTERRUPTTIME) && (!InitTime)) { /* If not int & not init time */
                DevHelp_Yield();                   /*  then Yield processor. */
            }
        }
    } while (KbdResend);
    EndSyncCommand();
 }
 return (0);                                       /* Return done.           */
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Set_Typematic                                            */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* DESCRIPTION    : Set the type rate and delay of the keyboard.             */
/*                                                                           */
/*****************************************************************************/

USHORT Set_Typematic (BYTE New_Type_Rate)
{
 if (New_Type_Rate != Type_Rate) {          /* If type rate is not the same. */
                                            //LR_USB begin
    if (gUSBKbd) {
        Type_Rate = New_Type_Rate;          // Get new type rate
        SetUSBTypematic (Type_Rate);
    }
    if (gLegKbd) {
                                            //LR_USB end
        if (BeginSyncCommand()) {
            Type_Rate = New_Type_Rate;      /* Get new type rate.            */
            Current_State = S_SENTTYPC;     /* Set new current state.        */
            SendData (KBD_SETREPEAT);       /* Send data to keyboard.        */
        }
    }                                       //LR_USB
 }
 return (0);                                /* Return that we are finished.  */
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Set_LEDs                                                 */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* DESCRIPTION    : Changes the state of the keyboard LEDs.                  */
/*                                                                           */
/* INPUT          : New state of LEDs                                        */
/*                                                                           */
/*****************************************************************************/

USHORT Set_LEDs (BYTE New_LED_State)
{
#ifdef DBCSKBD
 if (DataByte2 != 00   &&          /* If not Keyboard-less */ //@IBM JS08412(A)
     DataByte2 != 0x90 &&          /*  and not 5576-001    */ //@IBM JS08356(A)
     DataByte2 != 0x92)  {         /*  and not 5576-002    */ //@IBM JS08356(A)
#endif
    if (New_LED_State != LED_State) {      /* Do we need to change the LEDs? */
                                           //LR_USB begin
        if (gUSBKbd) {
            LED_State = New_LED_State;
            if (!(INTERRUPTTIME)) SetUSBLEDs (LED_State);
            else                  DevHelp_ArmCtxHook (0, gHookHandle); 
        }
        if (gLegKbd) {
                                           //LR_USB end
            if (BeginSyncCommand()) {
                LED_State = New_LED_State;         /* Save new LED state.    */
                Current_State = S_SENTLEDC;        /* Change current state.  */
                SendData (KBD_SETLEDS);            /* Send data to keyboard. */
            }
        }                                  //LR_USB
    }
#ifdef DBCSKBD
 }                          /* End if not 5576-001 or -002 */ //@IBM JS08356(A)
 else if (InitialSetLED == 0) {                               //@IBM JS08356(A)
    InitialSetLED = 1;                                                                                                               //@IBM JS08356(A)
    LED_State = 0;               /* Save new LED state.    */ //@IBM JS08356(A)
    Current_State = S_SENTLEDC;  /* Change current state.  */ //@IBM JS08356(A)
    SendData (KBD_SETLEDS);      /* Send data to keyboard. */ //@IBM JS08356(A)
 }                                                                                                                                                         //@IBM JS08356(A)
#endif
 return (0);
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Send_Generic                                             */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* DESCRIPTION    : This function will send a command or set of commands     */
/*                  providing that the data structure is set up right and    */
/*                  the wait necessary are consistent.                       */
/*                                                                           */
/* INPUT          : Data stucture offset and data segment.                   */
/*                                                                           */
/*****************************************************************************/

USHORT Send_Generic (USHORT CMD_Offset, USHORT CMD_Segment)
{
 USHORT c;
 CmdStruc FAR *ptr;

 if (gLegKbd) {                                       //LR_USB
    ptr = MK_FP(CMD_Segment, CMD_Offset);             /* Initialize pointer. */
    BeginSyncCommand();
    if (!KbdError) {
        if (ptr->wait_time == TURNOFF) {
            for (c = 0; c < ptr->strlength; c++) {      /* Loop through commands. */
                if (KbdStatusWait()) {                  /* Wait for controller ready. */
                    outp(PORT_BUFFER,ptr->strbytes[c]); /* Send to keyboard. */
                    IODelay();                          /* Delay to allow keyboard setup */
                }
            }
        }
        else {
            for (c=0; c < ptr->strlength; c++) {          /* Loop through commands. */
                do {
                    Current_State = S_WAIT_ACK;           /* Change current state. */
                    SendData(ptr->strbytes[c]);           /* Reset keyboard. */

                    while (Current_State != S_NOCMDIPG) { /* Wait until CMD finished. */
                        if (!(INTERRUPTTIME)) {           /* If not interrupt time. */
                            DevHelp_Yield();              /*  then Yield processor. */
                        }
                    }
                } while (KbdResend);
            }
        }
    }
    EndSyncCommand();
 }                    //LR_USB
 return (0);
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Query_Kbd_Rdy                                            */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* RETURN-NORMAL  : AX=0  : The keyboard is in the process of a command.     */
/*                  AX=-1 : The keyboard is ready for a new command.         */
/*                                                                           */
/*****************************************************************************/

USHORT Query_Kbd_Rdy(void)
{
 if (gLegKbd)                                     //LR_USB
    return (Current_State == S_NOCMDIPG ? 0: -1);
 else if (gUSBKbd) return (-1);                   //LR_USB
 else              return (0);                    //LR_USB
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Flush_Partial                                            */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* DESCRIPTION    : Resets the state machine.                                */
/*                                                                           */
/*****************************************************************************/

USHORT Flush_Partial(void)
{
        Current_State = S_NOCMDIPG;                               /* Reset the state machine.      */
        return(0);
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Save_Satae                                               */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* DESCRIPTION    : Saves the current state of the keyboard hardware.        */
/*                                                                           */
/*****************************************************************************/

USHORT Save_State(void)
{
        Save_LED  = LED_State;                                    /* Save the LED state.           */
        Save_Type = Type_Rate;                                    /* Save type rate.               */
        return(0);
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Restore_State                                            */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* DESCRIPTION    : Restores saved state of keyboard.                        */
/*                                                                           */
/*****************************************************************************/

USHORT Restore_State(void)
{
        Set_Typematic(Save_Type);                                                       /* Restore type rate.  */
        Set_LEDs(Save_LED);                                                                     /* Restore LED state.  */
        return(0);
}

/*****************************************************************************/
/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : IDC_Entry_Point                                          */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* DESCRIPTION    : Entry point for other device drivers, especially the     */
/*                  device independent keyboard.  Routes function to         */
/*                  correct procedure.                                       */
/*                                                                           */
/* INPUT          : Function and possibility of two other variables.         */
/*                                                                           */
/* RETURN-NORMAL  : AX=0 or value.                                           */
/*                                                                           */
/* RETURN-ERROR   : AX = -1.                                                 */
/*                                                                           */
/*****************************************************************************/

USHORT FAR _loadds IDC_Entry_Point (USHORT Req, USHORT Req_Off, USHORT Req_Seg)
{
 USHORT Ret_Req = 0;
 BYTE   Set_INFO = (BYTE)Req_Off;
 USHORT oldSync;

//LR_USB begin
#ifdef DEBUG
dsPrint1 (DBG_HLVLFLOW, "IBMKBD: IDC Function = 0x%x\r\n", Req);
#endif
//LR_USB end

 if (Req & 0x8000) {
    oldSync = SyncInterruptTime;
    SyncInterruptTime |= SYNC_STRAT;
 }
 switch (Req & 0x7FFF) {                   /* Case which function requested. */
   case Q_Open     : Ret_Req = Query_Open();                         break;
   case Q_Close    : Ret_Req = Query_Close();                        break;
   case Q_Cap      : Ret_Req = Query_Capabilites (Req_Off, Req_Seg); break;
   case Q_Type     : Ret_Req = Query_Typematic();                    break;
   case Q_LEDs     : Ret_Req = Query_LEDs();                         break;
   case Q_ID       : Ret_Req = Query_ID (Req_Off, Req_Seg);          break;
   case Q_Disabled : Ret_Req = Query_Disabled();                     break;
   case Disable_K  : Ret_Req = Disable_Keyboard();                   break;
   case Enable_K   : Ret_Req = Enable_Keyboard();                    break;
   case Reset_Hw   : Ret_Req = Reset_Hardware();                     break;
   case S_Type     : Ret_Req = Set_Typematic (Set_INFO);             break;
   case S_LED      : Ret_Req = Set_LEDs (Set_INFO);                  break;
   case Send_Gen   : Ret_Req = Send_Generic (Req_Off, Req_Seg);      break;
   case Q_Kbd_Rdy  : Ret_Req = Query_Kbd_Rdy();                      break;
   case Flush_Pt   : Ret_Req = Flush_Partial();                      break;
   case USB_Req    : USB_IDCfunc (Req_Off, Req_Seg);                 break; //LR_USB
   default         : Ret_Req = -1;                                   break;
 }
 if (Req & 0x8000) {
    SyncInterruptTime = (BYTE)oldSync;    //LR_USB SyncInterruptTime = oldSync;
 }
 if (KbdError) {
    Ret_Req = -1;                                 /* Return error to caller. */
    KbdError = TURNOFF;
 }

//LR_USB begin
#ifdef DEBUG
dsPrint1 (DBG_HLVLFLOW, "IBMKBD: IDC ReturnValue = 0x%x\r\n", Ret_Req);
#endif
//LR_USB end

 return (Ret_Req);                             /* Return value to requester. */
}

/*****************************************************************************/
/*                                                                           */
/* FUNCTION NAME  : Strategy                                                 */
/*                 "IBM Unique Code"                                         */
/*                                                                           */
/* DESCRIPTION    : Strategy routine entry point.                            */
/*                                                                           */
/* NOTES          : Currently only initialization is supported through the   */
/*                  Stategy routine.                                         */
/*                                                                           */
/* INPUT          : Initialization Packet from Kernel                        */
/*                                                                           */
/* RETURN-NORMAL  : Timer interrupt routine will occur in two clock cycles.  */
/*                                                                           */
/* RETURN-ERROR   : Do not install code.                                     */
/*                                                                           */
/* INTERNAL REFERENCES:  Init()                                              */
/*                                                                           */
/*****************************************************************************/

#ifndef WATCOM
void FAR Strategy (void)
{
 PRPSAVERESTORE pRPSaveRestore;
 _asm {
    mov word ptr pRPH[0], bx    /* pRPH (Request Packet Header) initialized. */
    mov word ptr pRPH[2], es    /* To ES:BX passed from the kernel.          */
 }
#else
void FAR Strategy (PRPH rparg)
{
 PRPSAVERESTORE pRPSaveRestore;
 pRPH = rparg;
#endif

//LR_USB begin
#ifdef DEBUG
dsPrint1 (DBG_HLVLFLOW, "IBMKBD: Strategy Command = 0x%x\r\n", pRPH->Cmd);
#endif
//LR_USB end

 switch (pRPH->Cmd) {
   case CMDInitBase:                                  /* 0x1B                */
        Init();
        STI;
        break;                  /* Init is the only one supported right now. */
   case CMDDeInstall:           
   case CMDOpen:                                      /* 0x0d                */
   case CMDClose:                                     /* 0x0e                */
        pRPH->Status = STATUS_DONE;
        break;
   case CMDSaveRestore:
        pRPSaveRestore=(PRPSAVERESTORE)pRPH;
        if (pRPSaveRestore->FuncCode==SRFC_Save) {
            Save_State();
        }
        if (pRPSaveRestore->FuncCode==SRFC_Restore) {
            Restore_State();
        }
        pRPH->Status = STATUS_DONE;
        break;
   case CMDGenIOCTL:                                  /* 0x10                */
   default:
        pRPH->Status = STATUS_DONE | STERR | STATUS_ERR_UNKCMD;
        break;                                        /* end switch          */
 }
//LR_USB begin
#ifdef DEBUG
dsPrint1 (DBG_HLVLFLOW, "IBMKBD: Strategy Status = 0x%x\r\n", pRPH->Status);
#endif
//LR_USB end
}

