/* devPVME501.c */
/* devPVME501.c - Device Support Routines for  VME PVME-501 */
/*     general I/O (40 bits I/O) */
/*
 *      Original Author: M. Tobiyama
 *      Current Author:  M. Tobiyama
 *      Date:            
 *
 *      Experimental Physics and Industrial Control System (EPICS)
 *
 *      Copyright 1997, KEKB.
 *
 *
 * Modification Log:
 * -----------------
 *	ver0.0 11/Jul/98	M.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>
#include        <mbbiDirectRecord.h>
#include        <mbboDirectRecord.h>

/* #define	Base_IO		0x20000 */ /* Std. I/O Address */
#define UTREG      0x00
#define BM1REG     0x00
#define BM2REG     0x00
#define ETREG      0x00
#define UVEC       0x00
#define BM1VEC     0x00
#define BM2VEC     0x00
#define ETVEC      0x00
#define CKCREG     0x34
#define PMCREG     0x74
#define UTCREG     0xB4
#define C0ENAB     0x00
#define C1ENAB     0x00
#define C2ENAB     0x00
#define IOD1       0x00
#define IOD2       0x1F
#define PMCOMP     0x00
#define PORTCP     0x00
#define PORTDP     0x00
#define PATEQ      0x00
#define PORTEN1    0x1F
#define PORTEN2    0x1F

struct DPvme501 {
  char     dummy00;
  char     bim_cntlreg0;
  char     dummy0;
  char     bim_cntlreg1;
  char     dummy1;
  char     bim_cntlreg2;
  char     dummy2;
  char     bim_cntlreg3;
  char     dummy3;
  char     bim_vecreg0;
  char     dummy4;
  char     bim_vecreg1;
  char     dummy5;
  char     bim_vecreg2;
  char     dummy6;
  char     bim_vecreg3;
  char     dummy7;
  char     timer_counter0;
  char     dummy8;
  char     timer_counter1;
  char     dummy9;
  char     timer_counter2;
  char     dummy10;
  char     timer_cntlreg;
  char     dummy11;
  char     timer_gate0;
  char     dummy12;
  char     timer_gate1;
  char     dummy13;
  char     timer_gate2;
  char     dummy14;
  char     io_reg_a;
  char     dummy15;
  char     io_reg_b;
  char     dummy16;
  char     comp_pat_cond;
  char     dummy17;
  char     pattern_c_reg;
  char     dummy18;
  char     pattern_d_reg;
  char     dummy19;
  char     pattern_match_out;
  char     dummy20;
  char     port_a_enable;
  char     dummy21;
  char     port_b_enable;
  char     dum[14];
  unsigned short     port_j;
  unsigned short     port_k;
  unsigned short     port_ab;
  unsigned short     port_cd;
  unsigned short     port_ef;
  unsigned short     port_gh;
  unsigned short     dums[92];
};

#define	Status	Enable

static long init();
static long init_li_record();
static long init_lo_record();
static long init_mi_record();
static long init_mo_record();
static long read_longin();
static long write_longout();
static long read_mbbiDirect();
static long write_mbboDirect();

static int  checkLink();

/* for devLiPvme501 */
struct {
	long		number;
	DEVSUPFUN	report;
	DEVSUPFUN	init;
	DEVSUPFUN	init_li_record;
	DEVSUPFUN	get_ioint_info;
	DEVSUPFUN	read_longin;
	DEVSUPFUN	special_linconv;
}devLiPvme501={
	6,
	NULL,
	init,
	init_li_record,
	NULL,
	read_longin,
    NULL};

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

/* For devMbbiPvme501  */
struct{
        long		number;
	DEVSUPFUN	report;
	DEVSUPFUN	init;
	DEVSUPFUN	init_mi_record;
	DEVSUPFUN	get_ioint_info;
	DEVSUPFUN	read_mbbiDirect;
}devMbbiPvme501={
	5,
	NULL,
	NULL,
	init_mi_record,
	NULL,
	read_mbbiDirect};

/* For devMbboPvme501  */
struct{
        long		number;
	DEVSUPFUN	report;
	DEVSUPFUN	init;
	DEVSUPFUN	init_mo_record;
	DEVSUPFUN	get_ioint_info;
	DEVSUPFUN	write_mbboDirect;
}devMbboPvme501={
	5,
	NULL,
	NULL,
	init_mo_record,
	NULL,
	write_mbboDirect};

struct ioCard {
        volatile struct DPvme501     *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;
static int     pvme501_num_links;

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

int devPvme501Config(ncards,a24base)
int ncards;
long a24base;
{
  pvme501_num_links = ncards;
  Base_IO = a24base;
  printf("Pvme501 NumLink= %d BaseIO= %x\n",pvme501_num_links,Base_IO);
  init(0);
}

static long init(after)
int after;
{
  int                          cardNum, chanNum;
  unsigned char                probeVal;
  volatile  struct DPvme501    *p;

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

  init_flag = 1;

  if (sysBusToLocalAdrs(VME_AM_STD_SUP_DATA,(char *)Base_IO,(char **)&p) == ERROR)
	{
		printf("VmeP501: cannot find A24 address space\n");
		return(ERROR);
	}
#ifdef DEBUG_ON  
    if ( CDEBUG)printf("PVME501 (init) Called. pass = %d\n", after);
#endif
  for (cardNum=0; cardNum< pvme501_num_links; cardNum++)
   {
     probeVal = UTREG;
     if (vxMemProbe((char*) &(p->bim_cntlreg0), WRITE, 1, &probeVal)< OK)
       {
	 if (debug_flag >0 ) 
         printf("No PVME501 with cardNum= %d\n probe= %x\n",cardNum,p);
	 cards[cardNum].card = NULL;
       }
     else
       {
	 probeVal = BM1REG;
	 if ((vxMemProbe((char*) &(p->bim_cntlreg1), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d bit pattern  reg 1 init\n",cardNum);
	 probeVal = BM2REG;
	 if ((vxMemProbe((char*) &(p->bim_cntlreg2), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d bit pattern reg 2 init\n",cardNum);
	 probeVal = ETREG;
	 if ((vxMemProbe((char*) &(p->bim_cntlreg3), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d ext trig reg init\n",cardNum);
	 probeVal = UVEC;
	 if ((vxMemProbe((char*) &(p->bim_vecreg0), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d user timer int vec init\n",cardNum);
	 probeVal = BM1VEC;
	 if ((vxMemProbe((char*) &(p->bim_vecreg1), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d bit pattern 1 int vec init\n",cardNum);
	 probeVal = BM2VEC;
	 if ((vxMemProbe((char*) &(p->bim_vecreg2), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d bit pattern 2 int vec init\n",cardNum);
	 probeVal = ETVEC;
	 if ((vxMemProbe((char*) &(p->bim_vecreg3), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d ext trig int vec init\n",cardNum);
	 probeVal = CKCREG;
	 if ((vxMemProbe((char*) &(p->timer_cntlreg), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d clock timer cntl\n",cardNum);
	 probeVal = 0xFF;
	 if ((vxMemProbe((char*) &(p->timer_counter0), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d timer 0 lower init\n",cardNum);
	 probeVal = 0xFF;
	 if ((vxMemProbe((char*) &(p->timer_counter0), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d timer 0 upper init\n",cardNum);
	 probeVal = PMCREG;
	 if ((vxMemProbe((char*) &(p->timer_cntlreg), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d pattern match timer cntl\n",cardNum);
	 probeVal = 0xFF;
	 if ((vxMemProbe((char*) &(p->timer_counter1), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d timer 1 lower init\n",cardNum);
	 probeVal = 0xFF;
	 if ((vxMemProbe((char*) &(p->timer_counter1), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d timer 1 upper init\n",cardNum);
	 probeVal = UTCREG;
	 if ((vxMemProbe((char*) &(p->timer_cntlreg), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d user timer cntl\n",cardNum);
	 probeVal = 0xFF;
	 if ((vxMemProbe((char*) &(p->timer_counter2), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d timer 2 lower init\n",cardNum);
	 probeVal = 0xFF;
	 if ((vxMemProbe((char*) &(p->timer_counter2), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d timer 2 upper init\n",cardNum);
	 probeVal = C0ENAB;
	 if ((vxMemProbe((char*) &(p->timer_gate0), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d timer gate0 init\n",cardNum);
	 probeVal = C1ENAB;
	 if ((vxMemProbe((char*) &(p->timer_gate1), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d timer gate1 init\n",cardNum);
	 probeVal = C2ENAB;
	 if ((vxMemProbe((char*) &(p->timer_gate2), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d timer gate2 init\n",cardNum);
	 probeVal = IOD1;
	 if ((vxMemProbe((char*) &(p->io_reg_a), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d I/O direction for ABCDJ init\n",cardNum);
	 probeVal = IOD2;
	 if ((vxMemProbe((char*) &(p->io_reg_b), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d I/O direction for EFGHK init\n",cardNum);
	 probeVal = PMCOMP;
	 if ((vxMemProbe((char*) &(p->comp_pat_cond), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d comparation cond init\n",cardNum);
	 probeVal = PORTCP;
	 if ((vxMemProbe((char*) &(p->pattern_c_reg), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d port C comp pattern init\n",cardNum);
	 probeVal = PORTDP;
	 if ((vxMemProbe((char*) &(p->pattern_d_reg), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d port D comp pattern init\n",cardNum);
	 probeVal = PATEQ;
	 if ((vxMemProbe((char*) &(p->pattern_match_out), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d pattern match out init\n",cardNum);
	 probeVal = PORTEN1;
	 if ((vxMemProbe((char*) &(p->port_a_enable), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d port ABCDJ enable init\n",cardNum);
	 probeVal = PORTEN2;
	 if ((vxMemProbe((char*) &(p->port_b_enable), WRITE, 1, &probeVal) == OK) && (debug_flag >10))
	     printf("PVME501 card %d port EFGHK enable init\n",cardNum);
	 if (debug_flag >0)
         printf("Found PVME501 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_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) 
   printf("write_mbboDirect called with card %d\n",cardN);

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

  FASTLOCK(&(cards[cardN].lock));
  if (debug_flag >5)
   printf("card locked...\n");
   
  switch(pmbbo->out.value.vmeio.signal){
         case 0: /* Port EF */
	        cards[cardN].card->port_ef = pmbbo->rval;
		pmbbo->rbv=cards[cardN].card->port_ef;
		break;
         case 1: /* Port GH */
                cards[cardN].card->port_gh = pmbbo->rval;
		pmbbo->rbv=cards[cardN].card->port_gh;
		break;
         case 2: /* Port k */
	        cards[cardN].card->port_k = ((pmbbo->rval) & (0xff));
		pmbbo->rbv=((cards[cardN].card->port_gh) & (0xff));
		break;
         default:
                FASTUNLOCK(&(cards[cardN].lock));
                return(-1);
  }
  if (debug_flag >5)
   printf("write complete \n");
  FASTUNLOCK(&(cards[cardN].lock));
  if (debug_flag >0)
   printf("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: /* port AB */
	        pmbbi->rval = cards[cardN].card->port_ab;
		break;
         case 1: /* port CD */
                pmbbi->rval = cards[cardN].card->port_cd;
		break;
         case 2: /* port J */
                pmbbi->rval = ((cards[cardN].card->port_j) & (0xff));
		break;

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

        return(CONVERT);
}


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

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

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

  cardN = plongin->inp.value.vmeio.card;
  if (debug_flag >5)
    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: /* port ab */
		        plongin->val = cards[cardN].card->port_ab;
                        if (debug_flag >10)
                        printf("read_longin signal 0 port ab %d\n",
                                        plongin->val);
			break;
		case 1: /* port cd */
		        plongin->val = cards[cardN].card->port_cd;
                        if (debug_flag >10)
                        printf("read_longin signal 1 port cd %d\n",
                                        plongin->val);
		        break;
                case 2: /* port j */
		        plongin->val = cards[cardN].card->port_j;
                        if (debug_flag >10)
                        printf("read_longin signal 2 port j %d\n",
                                        plongin->val);
		        break;
		default:
				return(-1);
		}
        return(CONVERT);
}
static long init_lo_record(plongin)
struct longinRecord	*plongin;
{
  return(0);
}

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

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

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

  if (checkLink(cardN) == ERROR)
    return(ERROR);
  FASTLOCK(&(cards[cardN].lock));
  if (debug_flag >4)
   printf("card locked...\n");
		switch(plongout->out.value.vmeio.signal){
		case 0: /* port ef */
		        cards[cardN].card->port_ef = (short)plongout->val;
                        if (debug_flag >4)
                        printf("write_longout signal 0 port ef\n");
			break;
		case 1: /* port gh */
		        cards[cardN].card->port_gh = (short)plongout->val;
                        if (debug_flag >4)
                        printf("write_longout signal 1 port gh\n");
			break;
                case 2: /* port k */
		        cards[cardN].card->port_k = (short)plongout->val;
                        if (debug_flag >4)
                        printf("write_longout signal 2 port k\n");
			break;
		default:
				return(-1);
		}
  FASTUNLOCK(&(cards[cardN].lock));
  if (debug_flag >4)
   printf("unlock card ...\n");

        return(CONVERT);
}

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

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