/* devActiveIO.c */
/* devActiveIO.c - Device Support Routines for  VME 17k73 */
/*
 *      Original Author: M.Tobiyama
 *      Current Author:
 *      Date:            31/Aug/2000
 *
 *      Experimental Physics and Industrial Control System (EPICS)
 *
 *      Copyright 1997, KEKB.
 *
 *
 * Modification Log:
 * -----------------
 *	31-Aug-2000	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        <mbbiDirectRecord.h>
#include        <mbboDirectRecord.h>

struct DvmeAIO {
  unsigned short	Ch0out;
  unsigned short	Ch1out;
  unsigned short	Ch0inp;
  unsigned short	Ch1inp;
  unsigned short	Stat;
  unsigned short	Dummy1;
  unsigned short        Dummy2;
  unsigned short        Dummy3;
};


#define	Status	Enable

static long init_aio();
static long init_record();
static long read_longin();
static long write_longout();
static long init_mi_record();
static long read_mbbiDirect();
static long init_mo_record();
static long write_mbboDirect();
static int  checkLink();

struct {
	long		number;
	DEVSUPFUN	report;
	DEVSUPFUN	init;
	DEVSUPFUN	init_record;
	DEVSUPFUN	get_ioint_info;
	DEVSUPFUN	read_longin;
	DEVSUPFUN	special_linconv;
}devLiAIO={
	6,
	NULL,
	NULL,
	init_record,
	NULL,
	read_longin,
        NULL};
struct {
	long		number;
	DEVSUPFUN	report;
	DEVSUPFUN	init;
	DEVSUPFUN	init_record;
	DEVSUPFUN	get_ioint_info;
	DEVSUPFUN	write_longout;
	DEVSUPFUN	special_linconv;
}devLoAIO={
	6,
	NULL,
	NULL,
	NULL,
	NULL,
	write_longout,
        NULL};
struct{
        long		number;
	DEVSUPFUN	report;
	DEVSUPFUN	init;
	DEVSUPFUN	init_mi_record;
	DEVSUPFUN	get_ioint_info;
	DEVSUPFUN	read_mbbiDirect;
}devMbbiAIO={
	5,
	NULL,
	NULL,
	init_mi_record,
	NULL,
	read_mbbiDirect};
struct{
        long            number;
        DEVSUPFUN       report;
        DEVSUPFUN       init;
        DEVSUPFUN       init_mo_record;
        DEVSUPFUN       get_ioint_info;
        DEVSUPFUN       write_mbboDirect;
}devMbboAIO={
        5,
        NULL,
        NULL,
        init_mo_record,
        NULL,
        write_mbboDirect};

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

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

static int           debug_flag = 1;
static unsigned long Base_IO = 0x23000000;
int                  aio_num_links = 0;

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


int devAIOConfig(ncards,a32base)
int ncards;
long a32base;
{
  aio_num_links = ncards;
  Base_IO = a32base;
  logMsg("Vme ActiveIO NumLink= %d BaseIO= %x\n",aio_num_links,Base_IO);
  init_aio(0);
}


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

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

  init_flag = 1;

  if (sysBusToLocalAdrs(VME_AM_EXT_SUP_DATA,(char *)Base_IO,(char **)&p) == ERROR)
	{
		logMsg("VmeActiveIO: cannot find extended address space\n");
		return(ERROR);
	}
  for (cardNum=0; cardNum< aio_num_links; cardNum++)
   {
     if (vxMemProbe((char*) &(p->Stat), READ, 2, &probeVal[0])< OK)
       {
	 if (debug_flag >0 ) 
         logMsg("No ActiveIO with cardNum= %d\n probe= %x\n",cardNum,p);
	 cards[cardNum].card = NULL;
       }
     else
       {
	 if (debug_flag >0)
         logMsg("Found ActiveIO 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 >10)
    logMsg("read_longin called...\n");

  cardN = plongin->inp.value.vmeio.card;
  if (debug_flag >10)
    logMsg("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->Ch0inp;
                               if (debug_flag >10)
                                logMsg("read_longin signal 0 Ch0 %d\n",
                                        plongin->val);

				break;
			case 1:
			  	plongin->val = cards[cardN].card->Ch1inp;
                                if (debug_flag >10)
                                logMsg("read_longin signal 1 Ch1 %d\n",
                                        plongin->val);
				break;
			case 2:
		               plongin->val = cards[cardN].card->Ch0out;
                               if (debug_flag >10)
                                logMsg("read_longin signal 0 Ch0-set %d\n",
                                        plongin->val);

				break;
			case 3:
			  	plongin->val = cards[cardN].card->Ch1out;
                                if (debug_flag >10)
                                logMsg("read_longin signal 1 Ch1-out %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 >10) 
   logMsg("write_longout called with card %d\n",cardN);

  if (checkLink(cardN) == ERROR)
    return(ERROR);
  FASTLOCK(&(cards[cardN].lock));
  if (debug_flag >10)
   logMsg("card locked...\n");
  
  switch(plongout->out.value.vmeio.signal){
			case 0:
			        cards[cardN].card->Ch0out = (unsigned short)(plongout->val);
			        break;
                        case 1:
			        cards[cardN].card->Ch1out = (unsigned short)(plongout->val);
				break;
                        default:
			  FASTUNLOCK(&(cards[cardN].lock));
			  return(-1);
  }
  if (debug_flag >10)
   logMsg("write complete \n");
  FASTUNLOCK(&(cards[cardN].lock));
  if (debug_flag >10)
   logMsg("unlock card ...\n");

        return(CONVERT);
}

static long init_mi_record(pmbbi)
struct MbbiDirectRecord	*pmbbi;
{
  return(0);
}

static long read_mbbiDirect(pmbbi)
struct mbbiDirectRecord *pmbbi;
{
  short cardN;
  
  cardN = pmbbi->inp.value.vmeio.card;
  if (debug_flag >5) 
   printf("read_mbbiDirect called with card %d\n",cardN);

  if (checkLink(cardN) == ERROR)
    return(ERROR);
  switch (pmbbi->inp.value.vmeio.signal){
         case 0:
	   pmbbi->rval = cards[cardN].card->Ch0inp;
	   break;
         case 1:
	   pmbbi->rval = cards[cardN].card->Ch1inp;
	   break;
         case 2:
           pmbbi->rval = cards[cardN].card->Ch0out;
	   break;
         case 3:
	   pmbbi->rval = cards[cardN].card->Ch1out;
           break;
	 case4 :
           pmbbi->rval = (cards[cardN].card->Stat) && (0x03);
	   break;
         default:
           return(-1);
  }
   
        return(CONVERT);
}
static long write_mbboDirect(pmbbo)
struct mbboDirectRecord *pmbbo;
{
  short cardN;
  
  cardN = pmbbo->out.value.vmeio.card;
  if (debug_flag >5) 
   logMsg("write_mbboDirect called with card %d\n",cardN);

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

  FASTLOCK(&(cards[cardN].lock));
  if (debug_flag >5)
   logMsg("card locked...\n");
   
  switch(pmbbo->out.value.vmeio.signal){
         case 0: /* Ch0 */
                cards[cardN].card->Ch0out = pmbbo->rval;
                pmbbo->rbv=cards[cardN].card->Ch0out;
                break;
         case 1: /* Ch1 */
                cards[cardN].card->Ch1out = pmbbo->rval;
		pmbbo->rbv=cards[cardN].card->Ch1out;
                break;
         case 2: /* Status Enable=0 b0-Ch0 B1-Ch1 */
                cards[cardN].card->Stat = ((pmbbo->rval) & (0x03));
                pmbbo->rbv=((cards[cardN].card->Stat) & (0x03));
                break;
         default:
                FASTUNLOCK(&(cards[cardN].lock));
                return(-1);
  }
  if (debug_flag >5)
   logMsg("write complete \n");
  FASTUNLOCK(&(cards[cardN].lock));
  if (debug_flag >5)
   logMsg("unlock card ...\n");

        return(CONVERT);
}

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

  if (debug_flag >10)
    logMsg("Yes you have Active I/O with card No= %d\n",cardN);
  return(OK);
}