/* devVmeTd4v.c */
/* devVmeTd4v.c - Device Support Routines for  VME TD-4V */
/*
 *      Original Author: Akiyama
 *      Current Author:
 *      Date:            2th May 1997
 *
 *      Experimental Physics and Industrial Control System (EPICS)
 *
 *      Copyright 1997, KEKB.
 *
 *
 * Modification Log:
 * -----------------
 *	5-8-97		ak
 *      27-Oct-97       Makoto Tobiyama 
 */


#include	<vxWorks.h>
#include	<types.h>
#include	<stdioLib.h>
#include	<string.h>

#include        <vme.h>
#include	<dbDefs.h>
#include	<dbAccess.h>
#include        <recSup.h>
#include	<devSup.h>
#include	<devCamac.h>
#include	<link.h>
#include	<module_types.h>
#include	<longinRecord.h>
#include	<longoutRecord.h>
#include        <boRecord.h>
#include        <biRecord.h>

/* #define	Base_IO		0x20000 */ /* Std. I/O Address */


struct DvmeTd4v {
	unsigned short	PreSet;
	unsigned short	Dummy0;
	unsigned short	Enable;
	unsigned short	Dummy1;
	unsigned short	Last_PreSet;
	unsigned short	Dummy2;
        unsigned short  Dummy3;
        unsigned short  Dummy4;
};


#define	Status	Enable

static long init();
static long init_record();
static long read_longin();
static long write_longout();
static long init_bi_record();
static long init_bo_record();
static long read_bi();
static long write_bo();
static int  checkLink();

struct {
	long		number;
	DEVSUPFUN	report;
	DEVSUPFUN	init;
	DEVSUPFUN	init_record;
	DEVSUPFUN	get_ioint_info;
	DEVSUPFUN	read_longin;
	DEVSUPFUN	special_linconv;
}devLiTd4v={
	6,
	NULL,
	init,
	init_record,
	NULL,
	read_longin,
    NULL};

/* Create the dset for devLoTd4v */
struct {
	long		number;
	DEVSUPFUN	report;
	DEVSUPFUN	init;
	DEVSUPFUN	init_record;
	DEVSUPFUN	get_ioint_info;
	DEVSUPFUN	write_longout;
	DEVSUPFUN	special_linconv;
}devLoTd4v={
	6,
	NULL,
	NULL,
	NULL,
	NULL,
	write_longout,
    NULL};


/* Create the dset for devBoTd4v */
struct {
        long            number;
        DEVSUPFUN       report;         /* used by dbior */
        DEVSUPFUN       init;           /* called 1 time before & after all records */
        DEVSUPFUN       init_record;    /* called 1 time for each record */
        DEVSUPFUN       get_ioint_info; /* used for COS processing (not used for outputs)*/
        DEVSUPFUN       write_bo;       /* output command goes here */
}devBoTd4v={
        5,
        NULL,
        NULL,
        init_bo_record,
        NULL,
        write_bo
};

/* Create the dset for devBiTd4V */
struct {
        long            number;
        DEVSUPFUN       report;         /* used by dbior */
        DEVSUPFUN       init;           /* called 1 time before & after all records */
        DEVSUPFUN       init_record;    /* called 1 time for each record */
        DEVSUPFUN       get_ioint_info; /* used for COS processing */
        DEVSUPFUN       read_bi;        /* input command goes here */
}devBiTd4v={
        5,
        NULL,
        NULL,
        init_bi_record,
        NULL,
        read_bi
};

struct ioCard {
        volatile struct DvmeTd4v     *card; /* address of this card */
        FAST_LOCK                    lock; /* semaphore */
      };

#define CONST_NUM_LINKS 10
/* #define STATIC  */
#define DEBUG_ON

int            debug_flag = 0;
static unsigned long Base_IO;
static int     td4v_num_links;

static struct ioCard cards[CONST_NUM_LINKS];
static int           init_flag = 0;


int devTd4vConfig(ncards,a24base)
int ncards;
long a24base;
{
  td4v_num_links = ncards;
  Base_IO = a24base;
  printf("VmeTd4 NumLink= %d BaseIO= %x\n",td4v_num_links,Base_IO);
  init(0);cd 
}


static long init(after)
int after;
{
  int                          cardNum, chanNum;
  unsigned char                probeVal[2];
  volatile  struct DvmeTd4v    *p;

  if (init_flag != 0 ) 
   return(OK);

  init_flag = 1;

  if (sysBusToLocalAdrs(VME_AM_STD_SUP_DATA,(char *)Base_IO,(char **)&p) == ERROR)
	{
		printf("VmeTd4v: cannot find standard address space\n");
		return(ERROR);
	}
#ifdef DEBUG_ON  
    if ( CDEBUG)printf("devLiTd4v (init) Called. pass = %d\n", after);
#endif
  for (cardNum=0; cardNum< td4v_num_links; cardNum++)
   {
     if (vxMemProbe((char*) &(p->PreSet), READ, 2, &probeVal[0])< OK)
       {
	 if (debug_flag >0 ) 
         printf("No TD4V with cardNum= %d\n probe= %x\n",cardNum,p);
	 cards[cardNum].card = NULL;
       }
     else
       {
	 if (debug_flag >0)
         printf("Found TD4V with cardNum= %d\n address= %x\n",cardNum,p);
	 cards[cardNum].card = p;  /* Remember address of the board */
	 FASTLOCKINIT(&(cards[cardNum].lock));
	 FASTUNLOCK(&(cards[cardNum].lock)); /* Init the board lock */
       }
     p++;
   }
  return(OK);
}

static long init_record(plongin)
struct longinRecord	*plongin;
{
  return(0);
}

static long read_longin(plongin)
struct longinRecord	*plongin;
{
  short cardN;

  if (debug_flag >0)
    printf("read_longin called...\n");

  cardN = plongin->inp.value.vmeio.card;
  if (debug_flag >0)
    printf("read_longin called with card number of %d\n",cardN);

  if (checkLink(cardN) == ERROR)
    return(ERROR);

		switch(plongin->inp.value.vmeio.signal){
			case 0:
		               plongin->val = cards[cardN].card->PreSet;
                               if (debug_flag >0)
                                printf("read_longin signal 0 Preset %d\n",
                                        plongin->val);

				break;
			case 1:
				plongin->val = cards[cardN].card->Last_PreSet;
                                if (debug_flag >0)
                                printf("read_longin signal 1 Last Preset %d\n",
                                        plongin->val);
				break;
			default:
				return(-1);
		}
        return(CONVERT);
}

static long write_longout(plongout)
struct longoutRecord	*plongout;
{

  short cardN;
  
  cardN = plongout->out.value.vmeio.card;

  if (debug_flag >0) 
   printf("write_longout called with card %d\n",cardN);

  if (checkLink(cardN) == ERROR)
    return(ERROR);

  FASTLOCK(&(cards[cardN].lock));
  if (debug_flag >0)
   printf("card locked...\n");
  cards[cardN].card->PreSet = plongout->val;
  if (debug_flag >0)
   printf("write complete \n");
  FASTUNLOCK(&(cards[cardN].lock));
  if (debug_flag >0)
   printf("unlock card ...\n");

        return(CONVERT);
}

/**************************************************************************
 *
 * BO Initialization (Called one time for each BO PowerUT card record)
 *
 **************************************************************************/
static long init_bo_record(pbo)
struct boRecord *pbo;
{

        pbo->mask = 1;
		return(0);
}


/**************************************************************************
 *
 * Perform a write operation from a BO record
 *
 **************************************************************************/
static long
write_bo(pbo)
struct boRecord *pbo;
{

  short cardN;

  cardN = pbo->out.value.vmeio.card;
  if (checkLink(cardN) == ERROR)
    {
      printf("Error--- No TD4V for card %d\n",cardN);
      return(ERROR);
    }

  FASTLOCK(&(cards[cardN].lock));
  cards[cardN].card->Enable = pbo->rval & pbo->mask;
  FASTUNLOCK(&(cards[cardN].lock));
	return(0);
}

/**************************************************************************
 *
 * BI Initialization (Called one time for each BI PowerUT card record)
 *
 **************************************************************************/
static long 
init_bi_record(pbi)
struct biRecord *pbi;
{

        pbi->mask = 1;
		return(0);
}

/**************************************************************************
 *
 * Perform a read operation from a BI record
 *
 **************************************************************************/
static long 
read_bi(pbi)
struct biRecord *pbi;
{
  short cardN;

  cardN = pbi->inp.value.vmeio.card;
  if (checkLink(cardN) == ERROR)
    return(ERROR);

  pbi->rval = cards[cardN].card->Enable & pbi->mask;
	return(0);
}

/**************************************************************************
 *
 * Make sure card number is valid
 *
 **************************************************************************/
static int checkLink(cardN)
short   cardN;
{
  if (cardN >= td4v_num_links)
    return(ERROR);
  if (cards[cardN].card == NULL)
    {
      printf("No TD4V with this number = %d\n",cardN);
      return(ERROR);
    }

  if (debug_flag >0)
    printf("Yes you have TD4V with card No= %d\n",cardN);
  return(OK);
}