/*DDK*************************************************************************/
/*                                                                           */
/* 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.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = CS.C
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION =
 *
 * DATE
 *
 * DESCRIPTION
 *
 *
 * FUNCTIONS
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#include "types.h"
#include "cs.h"
#include "cs_util.h"
#include "cs_help.h"
#include "config.h"
#include "cs_idc.h"
#include "comport.h"
#include "com_idc.h"

   /*
   ** constant definitions
   */
#define CARD_INSERTION 0x40            /* card insertion call back code  */
#define CARD_REMOVAL 0x05              /* card removal call back code    */
#define VENDOR_STR_LEN 25              /* len of string buffer           */

   /*
   ** type definitions
   */
typedef void (far *FPFV_V)(void);

#if defined (CS_2_0)
typedef struct {
    USHORT info_len;                   /* length of data returned by cs  */
    char signature[2];                 /* ASCII signature                */
    USHORT count;                      /* number of sockets              */
    USHORT revision;                   /* BCD val of CS rev              */
    USHORT release;                    /* BCD val of CS rel              */
    USHORT vendor_str_max_len;         /* length of buffer               */
    USHORT vendor_str_len;             /* Vendor string length           */
    UCHAR vendor_str[VENDOR_STR_LEN];  /* ASCIIZ vendor string           */
} GET_CARD_SERV_INFO;
#endif

#if defined (CS_1_7)
typedef struct {                       /* function 0BH                   */
    char signature[2];                 /* ASCII signature                */
    USHORT count;                      /* number of sockets              */
    USHORT revision;                   /* BCD val of CS rev              */
     USHORT release;                   /* BCD val of CS rel              */
    USHORT vendor_str_max_len;         /* length of buffer               */
    USHORT vendor_str_len;             /* Vendor string length           */
    UCHAR vendor_str[VENDOR_STR_LEN];  /* ASCIIZ vendor string           */
} GET_CARD_SERV_INFO;
#endif

typedef struct {
    USHORT socket;                     /* logical status                 */
    USHORT card_status;                /* card status  data              */
    USHORT socket_status;              /* socket  status data            */
} GET_STATUS;

#if defined (CS_2_0)
typedef struct {
    USHORT attributes;                 /* bit-mapped attribute           */
    USHORT event_mask;                 /* events to notify client        */
    UCHAR client_data[8];
    USHORT version;
} REGISTER_CLIENT;
#endif

#if defined (CS_1_7)
typedef struct {
    USHORT attributes;                 /* bit-mapped attribute           */
    USHORT event_mask;                 /* events to notify client        */
    USHORT client_data;                /* data for the client            */
    USHORT client_data_segment;        /* data for the client            */
    USHORT client_data_offset;         /* data for the client            */
    USHORT reserved;                   /* reserved                       */
} REGISTER_CLIENT;
#endif

    /*
    ** external global variables
    */
extern CONFIG_INFO Config_info;        /* configuration information      */

    /*
    ** private global variables
    */
static USHORT Num_of_sockets;

    /*
    ** public global variables
    */
USHORT Client_handle, Resources_acquired[MAX_NUM_IO_ADDRESSES];


/****************************************************************************
 *
 * FUNCTION NAME = cs_services_present
 *
 * DESCRIPTION   = This function determines if card services is present on the
 *                 system.
 *                 The function returns the value TRUE if card services is
 *                 present.  Otherwise, the value FALSE is returned.
 *
 * INPUT         =
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 *
 * RETURN-ERROR  =
 *
 ****************************************************************************/

    GET_CARD_SERV_INFO data1;
    IDC_PACKET         idc_pack1;

BOOL cs_services_present(void)
{
        /* initialize signature field - set maximum length for vendor
        ** string - get card services info
        */
    data1.signature[0] = 0;
    data1.signature[1] = 0;
    data1.vendor_str_max_len = VENDOR_STR_LEN;

        /* set up codes for get card services information
        */
    idc_pack1.function = 0x0b;

    idc_pack1.pointer = (ULONG) 0;

        /* set up size of packet
        */
    idc_pack1.arglength = sizeof(GET_CARD_SERV_INFO);

        /* set up segment and offset of packet
        */
    idc_pack1.argpointer = (ULONG) (GET_CARD_SERV_INFO far *) &data1;


    if (do_card_services(&idc_pack1) != SUCCESS)
         return(FALSE);

        /* store number of sockets
        */
    Num_of_sockets = data1.count;

        /* if card services are present then return true
        */
    if ((data1.signature[0] == 'C') && (data1.signature[1] == 'S'))
          return(TRUE);

    return(FALSE);
}

/****************************************************************************
 *
 * FUNCTION NAME = cs_card_present
 *
 * DESCRIPTION   = This function determines if a card is present in a
 *                 particular socket.
 *                 The parameter 'socket_num' contains the socket to
 *                 check for a card.
 *                 The function returns the value TRUE if a card is present.
 *                 Otherwise, the function returns the value FALSE.
 *
 * INPUT         =
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 *
 * RETURN-ERROR  =
 *
 ****************************************************************************/

    GET_STATUS data2;
    IDC_PACKET idc_pack2;

BOOL cs_card_present(USHORT socket_num)
{
        /* set up socket number
        */
    data2.socket = socket_num;

        /* set up codes for get status
        */
    idc_pack2.function = 0x0c;

    idc_pack2.pointer = (ULONG) 0;

        /* set up size of packet
        */
    idc_pack2.arglength = sizeof(GET_STATUS);

        /* set up segment and offset for packet
        */
    idc_pack2.argpointer = (ULONG) (GET_STATUS far *) &data2;


    if (do_card_services(&idc_pack2) != SUCCESS)
       return(FALSE);

        /* return true if card present bit is set or false if clear
        */
    if ((data2.card_status & 0x0080)  == 0x0080)
       return(TRUE);

    return(FALSE);
}

/****************************************************************************
 *
 * FUNCTION NAME = cs_register_client
 *
 * DESCRIPTION   = This function registers as a client with card services.
 *                 The function returns an error code in parameter 'statusP'
 *                 if an error  occurs.
 *
 * INPUT         =
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL = 0
 *
 * RETURN-ERROR  = -1
 *
 ****************************************************************************/

    REGISTER_CLIENT data3;
    IDC_PACKET      idc_pack3;

USHORT cs_register_client(void)

{
    USHORT ret_code;

        /* set up attributes - memory client device driver - generate
        ** artificial insertion events
        */
    data3.attributes = 0x001c;

        /* set up event mask - global notification of insertion and
        ** ejection events
        */
    data3.event_mask = 0x0081;

        /* set up codes for register client
        */
    idc_pack3.function = 0x10;

        /* set up segment and offset of call back handler routine
        */
    idc_pack3.pointer = (ULONG) (FPFV_V) callback_handler;

        /* set up size of packet
        */
    idc_pack3.arglength = sizeof(REGISTER_CLIENT);

        /* set up segment and offset of packet
        */
    idc_pack3.argpointer = (ULONG) (REGISTER_CLIENT far *) &data3;


    if ((ret_code = do_card_services(&idc_pack3)) != SUCCESS)
          return(ret_code);

        /* store client handle
        */
    Client_handle = idc_pack3.handle;

        /* return success
        */
    return(SUCCESS);
}

/****************************************************************************
 *
 * FUNCTION NAME = service_callback
 *
 * DESCRIPTION   = This function services card insertion and card removal
 *                 callback events from card services
 *
 * INPUT         =
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 *
 * RETURN-ERROR  =
 *
 ****************************************************************************/

void service_callback(USHORT socket_num, USHORT event_num)
{
        /*
        ** release resources if a card removal event occurs
        ** acquire resources if card insertion event occurs
        **                    - check for modem card - release
        ** resources if not modem card
        ** acquire resources if card insertion event occurs -  display
        ** critical message if unsuccessful - release resources an display
        ** critical message if it's not a modem card - display informational
        ** message if everythings ok
        */
    switch (event_num)
    {
        case CARD_REMOVAL:
            if (Resources_acquired[socket_num - 1] == FALSE)
                return;
            if (cs_release_resource(socket_num,
                             Config_info.io_address[socket_num - 1],
                             Config_info.irq_num[socket_num - 1]) != SUCCESS)
            {
                return;
            }

            set_com_port(0, Config_info.com_port_num[socket_num - 1],
                         Config_info.io_address[socket_num - 1],
                         Config_info.irq_num[socket_num - 1]);

            release_com_port(Config_info.io_address[socket_num - 1]);

            Resources_acquired[socket_num - 1] = FALSE;
            return;

        case CARD_INSERTION:
            if (Config_info.io_address[socket_num - 1] == 0)
                return;

            if (!cs_is_modem_card(socket_num))
            {
                return;
            }

            if (cs_acquire_resource(socket_num,
                              Config_info.io_address[socket_num - 1],
                              Config_info.irq_num[socket_num - 1]) != SUCCESS)
            {
                return;
            }

            if (set_com_port(1, Config_info.com_port_num[socket_num - 1],
                         Config_info.io_address[socket_num - 1],
                         Config_info.irq_num[socket_num - 1]) != SUCCESS)
            {
                cs_release_resource(socket_num,
                              Config_info.io_address[socket_num - 1],
                              Config_info.irq_num[socket_num - 1]);
                return;
            }

            if (acquire_com_port(Config_info.io_address[socket_num - 1])
                                                                != SUCCESS)
            {
                cs_release_resource(socket_num,
                              Config_info.io_address[socket_num - 1],
                              Config_info.irq_num[socket_num - 1]);


                set_com_port(0, Config_info.com_port_num[socket_num - 1],
                             Config_info.io_address[socket_num - 1],
                             Config_info.irq_num[socket_num - 1]);
                return;

            }

            Resources_acquired[socket_num - 1] = TRUE;

            return;
     }
}


/****************************************************************************
 *
 * FUNCTION NAME = cs_get_num_of_sockets
 *
 * DESCRIPTION   = This function reports the number of sockets present in the
 *                 system.
 *                 The function returns the number of sockets.
 *
 * INPUT         =
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 *
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT cs_get_num_of_sockets(void)
{
        /* return the number of sockets
        */
    return(Num_of_sockets);
}
