/**************************************************************************
 *
 * SOURCE FILE NAME = STGY.C
 *
 * DESCRIPTIVE NAME =
 *
 * Copyright : COPYRIGHT IBM CORPORATION, 1991, 1992 - PATENT PENDING
 *             LICENSED MATERIAL - PROGRAM PROPERTY OF IBM
 *             REFER TO COPYRIGHT INSTRUCTION FORM#G120-2083
 *             RESTRICTED MATERIALS OF IBM
 *             IBM CONFIDENTIAL
 *
 * VERSION =
 *
 * DATE
 *
 * DESCRIPTION This file contains the device driver entry point
 *             and strategy routine
 *
 * FUNCTIONS
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
 * CHANGE ACTIVITY =
 *  DATE      FLAG        APAR   CHANGE DESCRIPTION
 *  --------  ----------  -----  --------------------------------------
 *  mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
 ****************************************************************************/

#include "types.h"
#include "cs.h"
#include "cs_idc.h"
#include "com_idc.h"
#include "devhlp.h"
#include "config.h"
#include "shell.h"


#define DEV_ATTRIB 0x8180              /* 1000 0001 1000 0000         */
                 /*
                 ** 15 = 1    character device
                 ** 14 = 0    offset to idc entry point is not set
                 ** 13 = 0    for block device driver use only
                 ** 12 = 0    not shared device
                 ** 11 = 0    open / close is not required
                 ** 10 = 0    reserved
                 **  9 - 7 = 011   enable capabilities bit strip
                 **  4 - 6    reserved
                 **  3 = 0     not clock device
                 **  2 = 0     not null device
                 **  1 = 0     not stdout device
                 **  0 = 0     not stdin device
                 */

#define DEV_CAPS 0x00000010


#define CMD_INIT 0x00                  /* comand for device initialization */
#define CMD_INIT_COMP 0x1f

#define RPDONE 0x0100                  /* return successful                */
#define RPERR 0x8000                   /* return error                     */
#define RPGENFAIL 0x000c               /* return error: General failure    */

#define MAX_ARG_LEN 25
#define MAX_ARG_NUM 3

   /*
   ** type definitons
   */
typedef struct dev_hdr {               /* template for device header       */
   ULONG next;                         /* next driver in chain             */
   USHORT attrib;                      /* attribute                        */
   void near *strategy;                /* address of strategy routine      */
   void near *idc;                     /* address of IDC routine           */
   UCHAR name[16];                     /* 8 char device driver name        */
   ULONG capablities;                  /*     and 8 bytes reserved         */
} DEVHDR;

typedef struct req_packet {            /* template for request header      */
   UCHAR length;                       /* request packet length            */
   UCHAR unit;                         /* unit code for block DD only      */
   UCHAR command;                      /* command code                     */
   USHORT status;                      /* return status                    */
   UCHAR reserved[4];                  /* reserved bytes                   */
   ULONG qlink;                        /* queue linkage                    */
   union {                             /* command-specific data            */
      struct {
         UCHAR dummy1;
         ULONG devhlp_entry;           /* dev help address                 */
         ULONG argP;                   /* argument pointer                 */
         UCHAR dummy3;
      } init_in;
      struct {
         UCHAR dummy1;
         USHORT code_end;              /* final code offset                */
         USHORT data_end;              /* final data offset                */
         ULONG dummy2;
         UCHAR dummy3;
      } init_out;
      struct {
         UCHAR category;               /* category code                    */
         UCHAR function;               /* function code                    */
         void far *param_bufP;         /* pointer to parameters            */
         void far *data_bufP;          /* pointer to data                  */
      } ioctl;
   } s;
} REQPACKET;

   /*
   ** private function prototypes
   */
void get_parameters(ULONG argP, short *argc, char **argv);

   /*
   ** private global variable declarations
   */
DEVHDR dev_hdr = {0xffffffff,            /* link                           */
                 DEV_ATTRIB,             /* attribute                      */
                 (void near *) strategy, /* &Strategy routine              */
                 (void near *) 0,        /* &IDC routine for stream Handler*/
                 "ESTDFM$         ",     /* 8 bytes name and               */
                 DEV_CAPS                /*           8 bytes reserved     */
};

static BOOL Installed = 0;               /* flag for driver installed status */

static char oco_notice[8][40] = {
                              "Licensed Material - Property of IBM",
                              "                                   ",
                              "(C) Copyright IBM Corp. 1992,",
                              "All Rights Reserved.",
                              "U.S. Government Users Restricted Rights",
                              "- Use, duplication or disclosure",
                              "restricted by GSA ADP Schedule Contract",
                              "with IBM Corp."};

char   Arg[MAX_ARG_NUM][MAX_ARG_LEN];
short  Argc;
char   *Argv[MAX_ARG_NUM];

   /*
   ** external global variable declarations
   */
extern USHORT End_of_data;               /* end of data marker             */


/****************************************************************************
 *
 * FUNCTION NAME = do_start
 *
 * DESCRIPTION   = This function is the device driver strategy routine.
 *                 The parameter 'rpP' is a pointer to a block of information
 *                 from the operating system called the request packet.
 *
 * INPUT         =
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 *
 * RETURN-ERROR  =
 *
 ****************************************************************************/

void do_strat(REQPACKET far *rpP)
{
    USHORT num_of_sockets, i;

        /* initialization event
        */
    switch(rpP->command)
    {
      case CMD_INIT:

                /* error if driver already installed
                */
            if (Installed)
            {
                rpP->status = RPDONE | RPERR | RPGENFAIL;
                rpP->s.init_out.code_end = 0;
                rpP->s.init_out.data_end = 0;
                return;
            }

                /* initialize operating system device helper access
                */
            devhlp_init(rpP->s.init_in.devhlp_entry);

                /* establish idc with card services driver
                */
            if (cs_idc_init() == -1)
            {
                rpP->status = RPDONE | RPERR | RPGENFAIL;
                rpP->s.init_out.code_end = 0;
                rpP->s.init_out.data_end = 0;
                return;
            }

                /* establish idc with com driver
                */
            if (com_idc_init() == -1)
            {
                rpP->status = RPDONE | RPERR | RPGENFAIL;
                rpP->s.init_out.code_end = 0;
                rpP->s.init_out.data_end = 0;
                return;
            }

                /* process and store the arguments
                */
            for (i = 0; i <= MAX_ARG_NUM - 1; i++)
                Argv[i] = &Arg[i][0];
            get_parameters(rpP->s.init_in.argP, &Argc, (char**) Argv);

                /* driver has successfully installed
                */
            rpP->status == RPDONE;
            rpP->s.init_out.code_end = (USHORT) end_of_text;
            rpP->s.init_out.data_end = (USHORT) &End_of_data;
            Installed = 1;
            return;

      case CMD_INIT_COMP:

                /* check for card services
                */
            if (!cs_services_present())
            {
                rpP->status = RPDONE | RPERR | RPGENFAIL;
                return;
            }

                /* get number of sockets and store configuration info
                */
            num_of_sockets = cs_get_num_of_sockets();
            if (store_config_info(Argc, Argv, num_of_sockets) != 0)
            {
                rpP->status = RPDONE | RPERR | RPGENFAIL;
                return;
            }
                /* register with card services
                */
            if (cs_register_client() != 0)
            {
                rpP->status = RPDONE | RPERR | RPGENFAIL;
                return;
            }

                /* everythings successful
                */
            rpP->status = RPDONE;
            return;
    }
}


/****************************************************************************
 *
 * FUNCTION NAME = get_parameters
 *
 * DESCRIPTION   =
 *
 * INPUT         =
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 *
 * RETURN-ERROR  =
 *
 ****************************************************************************/


static void get_parameters(ULONG argP, short *argc, char **argv)
{
    char far *strP;
    USHORT i, j;

    i = 0;
    j = 0;
    *argc = 0;

    strP = (char far *) argP;

    while (1)
    {
        if (j > MAX_ARG_LEN - 2)
        {
            argv[i][j] = '\0';
            (*argc)++;
            i++;
            j = 0;
            while ((*strP != ' ') && (*strP != '\0'))
                strP++;
            while (*strP == ' ')
                strP++;
            if (*strP == '\0')
                return;
        }

        if (i > MAX_ARG_NUM - 1)
            return;

        if (*strP == ' ')
        {
            argv[i][j] = '\0';
            (*argc)++;
            i++;
            j = 0;
            while (*strP == ' ')
                strP++;
            if (*strP == '\0')
                return;
        }

        if (*strP == '\0')
        {
            argv[i][j] = '\0';
            (*argc)++;
            return;
        }

        argv[i][j++] = *strP++;
    }
}
