/* devRPV130.c */
/* devRPV130.c - Device Support Routines for  VME RPV-130 */
/*     8 bit interrupt & I/O register */
/*
 *      Original Author: M. Tobiyama
 *      Current Author:  M. Tobiyama
 *      Date:            
 *
 *      Experimental Physics and Industrial Control System (EPICS)
 *
 *      Copyright 1997, KEKB.
 *
 *
 * Modification Log:
 * -----------------
 *	ver0.0 08/Mar/2001	M.Tobiyama 
 */


#include	<vxWorks.h>
#include	<types.h>
#include	<stdioLib.h>
#include	<string.h>
#include        <iv.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        <fast_lock.h>

#include	<longinRecord.h>
#include	<longoutRecord.h>
#include        <boRecord.h>
#include        <biRecord.h>
#include        <mbbiDirectRecord.h>
#include        <mbboDirectRecord.h>

#include        <dbScan.h>


/* #define INT_LEVEL  0x05 */

struct DRPV130 {
  unsigned short  latch1;
  unsigned short  latch2;
  unsigned short  ff;
  unsigned short  through;
  unsigned short  pulse;
  unsigned short  level;
  unsigned short  csr1;
  unsigned short  csr2;
};    


#define	Status	Enable 

int devRPV130Config();

static long init_all();
static long init_mi_record();
static long init_mo_record();
static long read_mbbiDirect();
static long write_mbboDirect();
static long init_bo_record();
static long write_bo();
static void rpv130_isr();
static long get_mi_int_info();

static int  checkLink();

struct{
        long		number;
	DEVSUPFUN	report;
	DEVSUPFUN	init;
	DEVSUPFUN	init_mi_record;
	DEVSUPFUN	get_ioint_info;
	DEVSUPFUN	read_mbbiDirect;
}devMbbiRPV130={
	5,
	NULL,
	NULL,
	init_mi_record,
	get_mi_int_info,
	read_mbbiDirect};

struct{
        long		number;
	DEVSUPFUN	report;
	DEVSUPFUN	init;
	DEVSUPFUN	init_mo_record;
	DEVSUPFUN	get_ioint_info;
	DEVSUPFUN	write_mbboDirect;
}devMbboRPV130={
	5,
	NULL,
	NULL,
	init_mo_record,
	NULL,
	write_mbboDirect};
struct {
        long            number;
        DEVSUPFUN       report;
        DEVSUPFUN       init;
        DEVSUPFUN       init_record; 
        DEVSUPFUN       get_ioint_info; 
        DEVSUPFUN       write_bo;
}devBoRPV130={
        5,
        NULL,
        NULL,
        init_bo_record,
        NULL,
        write_bo
};


struct ioCard {
  volatile struct DRPV130   *card;    /* address of this card */
  FAST_LOCK                 lock;     /* semaphore */
  IOSCANPVT                 ioscanpvt;/* list or records processed upon interrupt */
      };

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

static unsigned short INT_LEVEL = 0x07;
static int   debug_flag = 0;
static unsigned long Base_IO;
static int     rpv130_num_links;
static unsigned short INT_VEC_BASE;

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


int devRPV130Config(ncards,a16base,int_level,intvecbase)
int ncards;
long a16base;
int int_level;
int intvecbase;
{
  rpv130_num_links = ncards;
  Base_IO = a16base;
  INT_LEVEL = int_level;
  INT_VEC_BASE = intvecbase;
  logMsg("RPV130 NumLink= %d BaseIO= %x INT_LEVEL= %x INTVECBASE= %x\n",rpv130_num_links,Base_IO,INT_LEVEL,INT_VEC_BASE);
  init_all(0);
}

static long init_all(after)
int after;
{
  int                          cardNum, chanNum;
  int                          i,j;
  unsigned char                probeVal[2];
  unsigned short               p1;
  volatile  struct DRPV130    *p;

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

  init_flag = 1;

  if (sysBusToLocalAdrs(VME_AM_SUP_SHORT_IO,(char *)Base_IO,(char **)&p) == ERROR)
	{
		logMsg("VME RPV130: cannot find A16 address space\n");
		return(ERROR);
	}

  for (cardNum=0; cardNum< rpv130_num_links; cardNum++)
   {
     if (vxMemProbe((char*) &(p->csr1), READ, 2, &probeVal)!=OK)
       {
         logMsg("No RPV130 with cardNum= %d\n probe= %x\n",cardNum,p);
	 cards[cardNum].card = NULL;
       } 
     else
       {
         p->csr1 = 0x01;  /* clear all and dissable interrupt */ 
         int_level = INT_LEVEL;
	
         if (debug_flag >0)
	   logMsg("Found RPV130 with cardNum= %d address= %x\n",cardNum,p);
         cards[cardNum].card = p;  /* Remember address of the board */
	 scanIoInit(&cards[cardNum].ioscanpvt);
	 logMsg("rpv130 ioInit. 0x%X\n",cards[cardNum].ioscanpvt);

	 FASTLOCKINIT(&(cards[cardNum].lock));
	 FASTUNLOCK(&(cards[cardNum].lock)); /* Init the board lock */
       }
     p++;
   }
  return(OK);
}


static long init_bo_record(pbo)
struct boRecord *pbo;
{

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

static long write_bo(pbo)
struct boRecord *pbo;
{

  short cardN;
  unsigned char tgreg;

  cardN = pbo->out.value.vmeio.card;
  if (checkLink(cardN) == ERROR)
    {
      logMsg("Error--- No RPV130 for card %d\n",cardN);
      return(ERROR);
    }
  FASTLOCK(&(cards[cardN].lock));
  switch(pbo->out.value.vmeio.signal){
  case 0: /* clr all, enalble 3 unmask all */
        cards[cardN].card->csr1 = 0x01;
        cards[cardN].card->csr1 = 0x18;
        break;
  case 1: /* clr 1 , enable 1 mask 1 */
        cards[cardN].card->csr1 = 0x02;
        cards[cardN].card->csr1 = 0x18;
        break;
  case 2: /* clr 2 , enable 2 mask 2 */
        cards[cardN].card->csr2 = 0x02;
        cards[cardN].card->csr2 = 0x1A;
        break;
  case 3: /* clr all , enable all  mask 1 & 2 */
        cards[cardN].card->csr1 = 0x03; 
        cards[cardN].card->csr2 = 0x03;
        cards[cardN].card->csr1 = 0x18;
	cards[cardN].card->csr2 = 0x18;
        break;
  case4 : /* disable latch2 */
        cards[cardN].card->csr2 = 0x02;
        cards[cardN].card->csr2 = 0x00;
        break; 

  default:
    FASTUNLOCK(&(cards[cardN].lock));
    return(-1);
  }
  FASTUNLOCK(&(cards[cardN].lock));
  return(0);
}
/******************************************************************
*
* Interrupt service routine
*
*******************************************************************/
static void rpv130_isr(pmbbi)
struct mbbiDirectRecord	*pmbbi;
{
  unsigned char mode;
  short cardN;

  cardN = pmbbi->inp.value.vmeio.card;
  
  /*  logMsg("rpv130_isr int called \n");*/
  scanIoRequest(cards[cardN].ioscanpvt);
  /* logMsg("rpv130 int called \n");*/
  return;
}

static long init_mi_record(pmbbi)
struct mbbiDirectRecord	*pmbbi;
{
  short cardNum;
  cardNum = pmbbi->inp.value.vmeio.card;

  if (intConnect(INUM_TO_IVEC(INT_VEC_BASE + cardNum),
		 (VOIDFUNCPTR)rpv130_isr, 
		 (int)pmbbi) != OK)
     logMsg("devRPV130: Interrupt connect failed for card %d\n",pmbbi->inp.value.vmeio.card);
  logMsg("intConnect 0x%X\n",pmbbi);
	 
  sysIntEnable(int_level);
  
  logMsg("rpv130 int set for int 0x%x\n",int_level);
  /* cards[cardNum].card->csr1 = 0x58; *//* enable 3 mask 1*/ 
  /* cards[cardNum].card->csr2 = 0x58; *//* enable 3 mask 2*/ 
  return(0);
}
static long read_mbbiDirect(pmbbi)
struct mbbiDirectRecord *pmbbi;
{
  short cardN;
  unsigned short reg1,reg2;
  
  cardN = pmbbi->inp.value.vmeio.card;
  if (debug_flag >5) 
   logMsg("read_mbbiDirect called with card %d\n",cardN);

  if (checkLink(cardN) == ERROR)
    return(ERROR);
  reg1 = (cards[cardN].card-> csr1);
  reg2 = (cards[cardN].card-> csr2); 
  if (debug_flag > 5)
    logMsg("reg1 0x%x\n",reg1);
  switch(pmbbi->inp.value.vmeio.signal){
         case 0: /* set_reset_ff */
	        pmbbi->rval = (cards[cardN].card->ff) & 0xff;
		cards[cardN].card->csr1 = 0x01; /* clr 3 */ 
		cards[cardN].card->csr1 = 0x18; /* enable 1 mask 1 */ 
		break;
         case 1: /* through */
	        pmbbi->rval = (cards[cardN].card->through) & 0xff;
		break;
         case 2: /* latch1 */
	   if ((reg1 & 0x20) == 0x20){
                pmbbi->rval = (cards[cardN].card->latch1) & 0xff;
		cards[cardN].card->csr1 = 0x02; /* clr 1 */
	   }
		cards[cardN].card->csr1 = 0x18; /* enable 1 mask 1 */
		break;
         case 3: /* latch2 */
	   if ((reg2 & 0x20) == 0x20){
                pmbbi->rval = (cards[cardN].card->latch2)  & 0xff;
		cards[cardN].card->csr2 = 0x02; /* clr 2 */ 
	   }
		cards[cardN].card->csr2 = 0x18; /* enable 2 mask 2 */
  
		break;
         case 4: /* csr1 */
	        pmbbi->rval = reg1 & 0xff;
	        break;
         case 5: /* csr2 */
	        pmbbi->rval = reg2 & 0xff;
	        break;

         default:
                return(-1);
  }
  if (debug_flag >5)
   logMsg("read complete \n");

        return(CONVERT);
}




#define	ADDING  	0
#define DELETING	1

static long get_mi_int_info(cmd,pmbbi,ppvt)
int                    cmd;
struct mbbiDirectRecord *pmbbi;
IOSCANPVT              *ppvt;
{
  short                  cardN;

  cardN = pmbbi->inp.value.vmeio.card;
  *ppvt = cards[cardN].ioscanpvt;
  logMsg("rpv130 intInfo. 0x%X\n",*ppvt);
  cards[cardN].card->csr1 = 0x0; /* disable all interrupt */
  cards[cardN].card->csr2 = 0x0;   
 if (debug_flag >0) logMsg("MI_INT CALLED\n");
  return(0);
}

static long init_mo_record(pmbbo)
struct mbboDirectRecord	*pmbbo;
{
  return(0);
}

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: /* pulse */
	cards[cardN].card->pulse = pmbbo->rval;
	pmbbo->rbv=pmbbo->rval;
	break;
  case 1: /* level */
        cards[cardN].card->level = pmbbo->rval;
	pmbbo->rbv=pmbbo->rval;
	break;
  case 2: /* csr1 */
        cards[cardN].card->csr1 = (pmbbo->rval);
	pmbbo->rbv=pmbbo->rval;
	break;
  case 3 : /* csr2 */
        cards[cardN].card->csr2 = pmbbo->rval;
        pmbbo->rbv = pmbbo->rval;
        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 >= rpv130_num_links)
    return(ERROR);
  if (cards[cardN].card == NULL)
    {
      logMsg("No RPV130 with this number = %d\n",cardN);
      return(ERROR);
    }

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