/**************************************************************************
 *
 * SOURCE FILE NAME = UTIL.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
 *
 *
 * 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_util.h"
#include "cs_idc.h"
#include "card_id.h"

   /*
   ** type definitions
   */
#if defined (CS_2_0)
typedef struct {
    USHORT socket;                     /* logical socket                 */
    USHORT base_ports1;                /* base port address for range    */
    UCHAR num_ports1;                  /* number of contiguous ports     */
    UCHAR attributes1;                 /* bit-mapped attributes          */
    USHORT base_ports2;                /* base port address for range    */
    UCHAR num_ports2;                  /* number of contiguous ports     */
    UCHAR attributes2;                 /* bit-mapped attributes          */
    UCHAR address_lines;               /* num of address lines decoded   */
} REQUEST_IO;
#endif

#if defined (CS_1_7)
typedef struct {
    USHORT socket;                     /* logical socket                 */
    USHORT base_ports1;                /* base port address for range    */
    UCHAR num_ports1;                  /* number of contiguous ports     */
    UCHAR attributes1;                 /* bit-mapped attributes          */
    USHORT base_ports2;                /* base port address for range    */
    UCHAR num_ports2;                  /* number of contiguous ports     */
    UCHAR attributes2;                 /* bit-mapped attributes          */
    UCHAR address_lines;               /* num of address lines decoded   */
    UCHAR access_speed;                /* access speed for io ranges     */
} REQUEST_IO;
#endif

typedef struct {
    USHORT socket;                     /* logical socket;                */
    USHORT attributes;                 /* bit mapped attributes          */
    UCHAR assigned_irq;                /* irq number assigned by cs      */
    UCHAR irq_info1;                   /* first PCMCIA irq byte          */
    USHORT irq_info2;                  /* optional PCMCIA irq bytes      */
} REQUEST_IRQ;

#if defined (CS_2_0)
typedef struct {
    USHORT socket;                     /* logical socket                 */
    USHORT attributes;                 /* bit mask for attributes        */
    UCHAR vcc;                         /* vcc setting                    */
    UCHAR vpp1;                        /* vpp1 setting                   */
    UCHAR vpp2;                        /* vpp2 setting                   */
    UCHAR int_type;                    /* interface type                 */
    ULONG config_base;                 /* base address of registers      */
    UCHAR status;                      /* status register setting        */
    UCHAR pin;                         /* card pin register setting      */
    UCHAR copy;                        /* copy register setting          */
    UCHAR option;                      /* option register setting        */
    UCHAR present;                     /* config registers present       */
} REQUEST_CONFIGURATION;
#endif

#if defined (CS_1_7)
typedef struct {
    USHORT socket;                     /* logical socket                 */
    USHORT attributes;                 /* bit mask for attributes        */
    UCHAR vcc;                         /* vcc setting                    */
    UCHAR vpp1;                        /* vpp1 setting                   */
    UCHAR vpp2;                        /* vpp2 setting                   */
    UCHAR status;                      /* status register setting        */
    UCHAR pin;                         /* card pin register setting      */
    UCHAR copy;                        /* copy register setting          */
    UCHAR option;                      /* option register setting        */
    UCHAR present;                     /* config registers present       */
    ULONG config_base;                 /* base address of registers      */
    UCHAR int_type;                    /* interface type                 */
} REQUEST_CONFIGURATION;
#endif

#if defined (CS_2_0)
typedef struct {
    USHORT socket;                     /* logical socket;                */
    USHORT attributes;                 /* bit mapped attributes          */
    UCHAR assigned_irq;                /* irq number assigned            */
} RELEASE_IRQ;
#endif

#if defined (CS_1_7)
typedef struct {
    USHORT socket;                     /* logical socket;                */
    USHORT attributes;                 /* bit mapped attributes          */
    UCHAR assigned_irq;                /* irq number assigned            */
    UCHAR irq_info1;                   /* first PCMCIA irq byte          */
    USHORT irq_info2;                  /* optional PCMCIA irq bytes      */
} RELEASE_IRQ;
#endif

#if defined (CS_2_0)
typedef struct {
    USHORT socket;                     /* logical socket                 */
    USHORT base_ports1;                /* base port address for range    */
    UCHAR num_ports1;                  /* number of contiguous ports     */
    UCHAR attributes1;                 /* bit-mapped attributes          */
    USHORT base_ports2;                /* base port address for range    */
    UCHAR num_ports2;                  /* number of contiguous ports     */
    UCHAR attributes2;                 /* bit-mapped attributes          */
    UCHAR address_lines;               /* num of address lines decoded   */
} RELEASE_IO;
#endif

#if defined (CS_1_7)
typedef struct {
    USHORT socket;                     /* logical socket                 */
    USHORT base_ports1;                /* base port address for range    */
    UCHAR num_ports1;                  /* number of contiguous ports     */
    UCHAR attributes1;                 /* bit-mapped attributes          */
    USHORT base_ports2;                /* base port address for range    */
    UCHAR num_ports2;                  /* number of contiguous ports     */
    UCHAR attributes2;                 /* bit-mapped attributes          */
    UCHAR address_lines;               /* num of address lines decoded   */
    UCHAR access_speed;                /* access speed for io ports      */
} RELEASE_IO;
#endif

typedef struct {
    USHORT socket;                     /* logical socket                 */
} RELEASE_CONFIGURATION;

typedef struct {
    USHORT socket;                     /* logical socket                 */
    USHORT attributes;                 /* bit-mapped attributes          */
    UCHAR desired_tuple;               /* desired tuple code value       */
    UCHAR reserved;                    /* reserved                       */
    USHORT flags;                      /* cs tuple flags data            */
    ULONG link_offset;                 /* cs link state information      */
    ULONG cis_offset;                  /* cs cis state information       */
    UCHAR tuple_code;                  /* tuple found                    */
    UCHAR tuple_link;                  /* link value for tuple           */
} GET_FIRST_TUPLE;

typedef struct {
    USHORT socket;                     /* logical socket                 */
    USHORT attributes;                 /* bit-mapped attributes          */
    UCHAR desired_tuple;               /* desired tuple code value       */
    UCHAR tuple_offset;                /* offset into tuple              */
    USHORT flags;                      /* cs tuple flags data            */
    ULONG link_offset;                 /* cs link state info             */
    ULONG cis_offset;                  /* cs cis state information       */
    USHORT tuple_data_max;             /* max size of tuple data area    */
    USHORT tuple_data_len;             /* num of bytes in tuple body     */
    UCHAR  tuple_data[CARD_ID_LEN];    /* tuple data                     */
} GET_TUPLE_DATA;


   /*
   ** private global variables
   */
extern USHORT  Client_handle;

   /*
   ** private  function prototypes
   */
USHORT cs_request_io(USHORT, USHORT);
USHORT cs_request_irq(USHORT, USHORT);
USHORT cs_request_configuration(USHORT, USHORT);
USHORT cs_release_irq(USHORT, USHORT);
USHORT cs_release_io(USHORT, USHORT);
USHORT cs_release_configuration(USHORT);

/****************************************************************************
 *
 * FUNCTION NAME = cs_acquire_resource
 *
 * DESCRIPTION   = This function acquires resources and performs initialization
 *                 activities on both pcic and pcmcia card.
 *                 The parameter 'socket_num' contains the socket to initalize.
 *                 The parameters 'io_address' and 'irq_num' contain the io
 *                 address and the interrupt request number to assign to the
 *                 socket.
 *
 * INPUT         =
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL = 0
 *
 * RETURN-ERROR  = -1
 *
 ****************************************************************************/

USHORT  cs_acquire_resource(USHORT socket_num, USHORT io_address,
                                                        USHORT irq_num)
{
    USHORT ret_code;

        /* request the interrupt request number - return if error
        */
    if ((ret_code = cs_request_irq(socket_num, irq_num)) != SUCCESS)
        return(ret_code);

        /* request io address - return if error
        */
    if ((ret_code = cs_request_io(socket_num, io_address )) != SUCCESS)
    {
        cs_release_irq(socket_num, irq_num);
        return(ret_code);
    }

        /* request configuration - return if error
        */
    if ((ret_code = cs_request_configuration(socket_num, io_address))
                                                             != SUCCESS)
    {
        cs_release_irq(socket_num, irq_num);
        cs_release_io(socket_num, io_address);
        return(ret_code);
    }

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

/****************************************************************************
 *
 * FUNCTION NAME = cs_requiest_irq
 *
 * DESCRIPTION   = This function requests from card services that a
 *                 particular interrupt be assigned to a socket.
 *                 The parameters 'socket_num' and 'irq_num' are the
 *                 socket number and interrupt number
 *
 * INPUT         =
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL = 0
 *
 * RETURN-ERROR  = -1
 *
 ****************************************************************************/

     REQUEST_IRQ data4;
    IDC_PACKET   idc_pack4;

static USHORT cs_request_irq(USHORT socket_num, USHORT irq_num)

 {
    USHORT ret_code;

         /* set up logical socket number
         */
     data4.socket = socket_num;

         /* set up attributes - time multiplexed sharing
         */
#if defined (CS_2_0)
     data4.attributes = 0x0002;
#endif

#if defined (CS_1_7)
     data4.attributes = 0x0001;
#endif
         /* set up for level interrupt and make second info field valid
         */
     data4.irq_info1 = 0x30;
     data4.irq_info1 |= irq_num;

         /* designate desired irq number
         */
     data4.irq_info2 = 0x0001;
     data4.irq_info2 <<= irq_num;

         /* set codes for request irq
         */
     idc_pack4.function = 0x20;

         /* set client handle
         */
     idc_pack4.handle = Client_handle;

     idc_pack4.pointer = (ULONG) 0;

         /* set size of packet
         */
     idc_pack4.arglength = sizeof(REQUEST_IRQ);

         /* set segment and offset for packet
         */
     idc_pack4.argpointer = (ULONG) (REQUEST_IRQ far *) &data4;

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

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

/****************************************************************************
 *
 * FUNCTION NAME = cs_request_io
 *
 * DESCRIPTION   = This function requests from card services that a particular
 *                 io address be assigned to a socket.
 *                 The parameters 'socket_num' and 'io_address' contain the
 *                 socket number and io address.
 *
 * INPUT         =
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL = 0
 *
 * RETURN-ERROR  = -1
 *
 ****************************************************************************/

    REQUEST_IO data5;
    IDC_PACKET idc_pack5;

static USHORT cs_request_io(USHORT socket_num, USHORT io_address)

{
    USHORT ret_code;

        /* set up logical socket
        */
    data5.socket = socket_num;

        /* set up base address for ports
        */
    data5.base_ports1 = io_address;

        /* set up range for ports
        */
    data5.num_ports1 = 0x08;

        /* set up attributes - specify that the addresses are not shared with
        ** another client
        */
    data5.attributes1 = 0x00;

        /* set up additonal port info - no additional ports specified
        */
    data5.base_ports2 = 0x0000;
    data5.num_ports2= 0x00;
    data5.attributes2 = 0x00;

        /* set up address line info - specify no additional addresses need
        ** to marked as in use
        */
#if defined (CS_2_0)
    data5.address_lines = 16;
#endif

#if defined (CS_1_7)

        /* set up address line info - specify no additional addresses need
        ** to marked as in use
        */
    data5.address_lines = 0;

        /* set up access speed - specify that access speed for ports is
        ** 100 nsec
        */
    data5.access_speed = 0x04;
#endif
        /* set up codes for request io
        */
    idc_pack5.function = 0x1f;

        /* set up client handle
        */
    idc_pack5.handle = Client_handle;

    idc_pack5.pointer = (ULONG) 0;

        /* set up size of packet
        */
    idc_pack5.arglength = sizeof(REQUEST_IO);

        /* set up segment and offset for packet
        */
    idc_pack5.argpointer = (ULONG) (REQUEST_IO far *) &data5;

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

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

/****************************************************************************
 *
 * FUNCTION NAME = cs_request_configuration
 *
 * DESCRIPTION   = This function requests from card services that a
 *                 particular i/o address be assigned to a socket.
 *                 The parameters 'socket_num' and 'io_address' are
 *                 the socket number and io address.
 *
 * INPUT         =
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL = 0
 *
 * RETURN-ERROR  = -1
 *
 ****************************************************************************/

    REQUEST_CONFIGURATION data6;
    IDC_PACKET idc_pack6;

static USHORT cs_request_configuration(USHORT socket_num, USHORT io_address)

{
    UCHAR option_reg_value;
    USHORT ret_code;

        /* set up socket number
        */
    data6.socket = socket_num;

#if defined (CS_2_0)

        /* set up exclusive use and enable irq
        */
    data6.attributes = 0x0002;
#endif

#if defined (CS_1_7)

        /* set up exclusive use and enable irq
        */
    data6.attributes = 0x0003;
#endif
        /* set up for 5.0 volts (50 x 0.1)
        */
    data6.vcc = 50;

        /* set vpp - no requirements
        */
    data6.vpp1 = 0;
    data6.vpp2 = 0;

        /* set up option configuration register for normal operation, card
        ** enable, and designated com port
        */
    switch (io_address)
    {
        case 0x3f8:
            option_reg_value = 0x20;
            break;
        case 0x2f8:
            option_reg_value = 0x21;
            break;
        case 0x3e8:
            option_reg_value = 0x22;
            break;
        case 0x2e8:
            option_reg_value = 0x23;
            break;
    };
        /* set up interface type - memory and i/o
        */
    data6.int_type = 0x02;

        /* set up base address of config registers in attribute memory
        */
    data6.config_base = (ULONG) 0x100;

        /* set option register value
        */
    data6.option = option_reg_value;

        /* set pin register value
        */
    data6.pin = 0x00;

        /* set copy register value
        */
    data6.copy = 0x00;

        /* set status register value - enable audio and ring indicate
        */
    data6.status = 0x18;

        /* set which registers are present - option and status registers
        ** are present
        */
    data6.present = 0x03;

        /* set code for request configuration
        */
    idc_pack6.function = 0x30;

        /* set client handle
        */
    idc_pack6.handle = Client_handle;

    idc_pack6.pointer = (ULONG) 0;

        /* set size of packet
        */
    idc_pack6.arglength = sizeof(REQUEST_CONFIGURATION);

        /* set segment and offset for request configuration
        */
    idc_pack6.argpointer = (ULONG) (REQUEST_CONFIGURATION far *) &data6;

/* #define DEBUG
** _asm push ax
** _asm int 3
** _asm mov ax,7
** _asm pop ax
** #endif
*/
    if ((ret_code = do_card_services(&idc_pack6)) != SUCCESS)
        return(ret_code);

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

/****************************************************************************
 *
 * FUNCTION NAME = cs_is_modem_card
 *
 * DESCRIPTION   = This function determines if a modem card is present in
 *                 a particular socket.
 *                 The parameter 'socket_num' contains the number of the
 *                 socket to check.
 *                 The function returns the value TRUE if a modem card is
 *                 present.  Otherwise, the value FALSE is returned if a
 *                 modem card is not present or if an error occurred.
 *
 * INPUT         =
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  = FALSE
 *
 ****************************************************************************/

    GET_FIRST_TUPLE data7;
    GET_TUPLE_DATA  data8;
    IDC_PACKET      idc_pack7;

BOOL cs_is_modem_card(USHORT socket_num)

{

        /* set up socket number
        */
    data7.socket = socket_num;

        /* set up attributes
        */
    data7.attributes = 0x0000;

        /* set up to look for  first tuple
        */
    data7.desired_tuple = 0x15;

        /* set up codes for get first tuple
        */
    idc_pack7.function = 0x07;

        /* set up client handle
        */
    idc_pack7.handle = Client_handle;

    idc_pack7.pointer = (ULONG) 0;

        /* set up size of packet
        */
    idc_pack7.arglength = sizeof(GET_FIRST_TUPLE);

        /* set up segment and offset of packet
        */
    idc_pack7.argpointer = (ULONG) (GET_FIRST_TUPLE far *) &data7;


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

        /* set up socket number
        */
    data8.socket = socket_num;

        /* set up attributes
        */
    data8.attributes = data7.attributes;

        /* set up desired tuple code value
        */
    data8.desired_tuple = data7.desired_tuple;

        /* set up data flags
        */
    data8.flags = data7.flags;

        /* set up link state information
        */
    data8.link_offset = data7.link_offset;

        /* set up cis state information
        */
    data8.cis_offset = data7.cis_offset;

        /* set up offset into tuple from link byte
        */
    data8.tuple_offset = 0x04;

        /* set up maximum size of tuple data area
        */
    data8.tuple_data_max =  CARD_ID_LEN;

        /* set up codes for get tuple data
        */
    idc_pack7.function = 0x0d;

        /* set up client handle
        */
    idc_pack7.handle = Client_handle;

    idc_pack7.pointer = (ULONG) 0;

        /* set up size of packet
        */
    idc_pack7.arglength = sizeof(GET_TUPLE_DATA);

        /* set up segment and offset of packet
        */
    idc_pack7.argpointer = (ULONG) (GET_TUPLE_DATA far *) &data8;


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

        /* return true if expected tuple contents
        */
    if (correct_card_id((UCHAR far *) data8.tuple_data))
        return(TRUE);

    return(FALSE);
}

/****************************************************************************
 *
 * FUNCTION NAME = cs_release_resource
 *
 * DESCRIPTION   = This function requests from card services that resources
 *                 be released for a particular socket.
 *                 The parameter 'socket_num' is the socket number for
 *                 which to release resources. The parameters 'io_address'
 *                 and 'irq_num' are the io address and interrupt number
 *                 to release.
 *
 * INPUT         =
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL = 0
 *
 * RETURN-ERROR  = -1
 *
 ****************************************************************************/

USHORT cs_release_resource(USHORT socket_num, USHORT io_address,
                                                                                                                  USHORT irq_num)
{
    USHORT ret_code;

        /* release configuration - return if error
        */
    if ((ret_code = cs_release_configuration(socket_num)) != SUCCESS)
        return(ret_code);

        /* release interrupt - return if error
        */
    if ((ret_code = cs_release_irq(socket_num, irq_num)) != SUCCESS)
        return(ret_code);

        /* release io address - return if error
        */
    if ((ret_code = cs_release_io(socket_num, io_address)) != SUCCESS)
        return(ret_code);

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

/****************************************************************************
 *
 * FUNCTION NAME =
 *
 * DESCRIPTION   = This function requests from card services that a
 *                 configuration be released for a socket.
 *                 The parameter 'socket_num' is the socket number.
 *
 * INPUT         =
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL = -1
 *
 * RETURN-ERROR  = 0
 *
 ****************************************************************************/

    RELEASE_CONFIGURATION data11;
    IDC_PACKET            idc_pack10;

static USHORT cs_release_configuration(USHORT socket_num)

{
    USHORT ret_code;

        /* set up logical socket
        */
    data11.socket = socket_num;

        /* set codes for release configuration
        */
    idc_pack10.function = 0x1e;

        /* set client handle
        */
    idc_pack10.handle = Client_handle;

    idc_pack10.pointer = (ULONG) 0;

        /* set size of packet
        */
    idc_pack10.arglength = sizeof(RELEASE_CONFIGURATION);

        /* set segment and offset for packet
        */
    idc_pack10.argpointer = (ULONG) (RELEASE_CONFIGURATION far *) &data11;

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

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

/****************************************************************************
 *
 * FUNCTION NAME = cs_release_irq
 *
 * DESCRIPTION   = This function requests from card services that an
 *                 interrupt number be released for a socket.
 *                 The parameters 'socket_num' and 'irq_num' are the
 *                 socket number and interrupt number.
 *
 * INPUT         =
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL = 0
 *
 * RETURN-ERROR  = -1
 *
 ****************************************************************************/

    RELEASE_IRQ data9;
    IDC_PACKET  idc_pack8;

static USHORT cs_release_irq(USHORT socket_num, USHORT irq_num)

{
    USHORT ret_code;

        /* set up logical socket number
        */
    data9.socket = socket_num;

        /* set attributes - prefer exclusive irq
        */
#if defined (CS_1_7)
    data9.attributes = 0x0001;
#endif

#if defined (CS_2_0)
    data9.attributes = 0x0002;
#endif

        /* set up irq number - designate previously established irq
        */
    data9.assigned_irq = irq_num;

        /* set code for release irq
        */
    idc_pack8.function = 0x1c;

        /* set client handle
        */
    idc_pack8.handle = Client_handle;

    idc_pack8.pointer = (ULONG) 0;

        /* set size of packet
        */
    idc_pack8.arglength = sizeof(RELEASE_IRQ);

        /* set segment and offset for packet
        */
    idc_pack8.argpointer = (ULONG) (RELEASE_IRQ far *) &data9;


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

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

/****************************************************************************
 *
 * FUNCTION NAME = cs_release_io
 *
 * DESCRIPTION   = This function requests from card services that an
 *                 io address be released for a socket.
 *                 The parameters 'socket_num' and 'io_address' are
 *                 the socket number and io address.
 *
 * INPUT         =
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL = 0
 *
 * RETURN-ERROR  = -1
 *
 ****************************************************************************/

    RELEASE_IO data10;
    IDC_PACKET idc_pack9;

static USHORT cs_release_io(USHORT socket_num, USHORT io_address)

{
    USHORT ret_code;

        /* set up logical socket
        */
    data10.socket = socket_num;

        /* set up base address for ports
        */
    data10.base_ports1 = io_address;

        /* set up range for ports
        */
    data10.num_ports1 = 0x08;

        /* set attributes - specify that the addresses are not shared with
        ** another client
        */
    data10.attributes1 = 0x00;

        /* set additional port info - no additional ports specified
        */
    data10.base_ports2 = 0x0000;
    data10.num_ports2= 0x00;
    data10.attributes2 = 0x00;

        /* set address line info
        */
    data10.address_lines = 16;

        /* set codes for release io
        */
    idc_pack9.function = 0x1b;

        /* set client handle
        */
    idc_pack9.handle = Client_handle;

    idc_pack9.pointer = (ULONG) 0;

        /* set size of packet
        */
    idc_pack9.arglength = sizeof(RELEASE_IO);

        /* set segment and offset for packet
        */
    idc_pack9.argpointer = (ULONG) (RELEASE_IO far *) &data10;


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

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