/* devPVME321.c */
/* devPVME321.c - Device Support Routines for  VME PVME-321 */
/*     12 bit low cost D/A board (8ch) */
/*
 *      Original Author: M. Tobiyama
 *      Current Author:  M. Tobiyama
 *      Date:            
 *
 *      Experimental Physics and Industrial Control System (EPICS)
 *
 *      Copyright 1997, KEKB.
 *
 *
 * Modification Log:
 * -----------------
 *	ver0.0 27/Aug/98	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        <waveformRecord.h>

#include        <dbScan.h>

/* #define	Base_IO		0x20000 */ /* Std. I/O Address */
#define CNT        0xff
#define FC1        0x34
#define ALLENABLE  0xff
#define ALLDISABLE 0x00
#define TIMER      0x00

struct DPvme321 {
  unsigned char   func_reg_0;
  unsigned char   dummy0;
  unsigned char   dummy1;
  unsigned char   dummy2;
  unsigned char   dummy3;
  unsigned char   dummy4;
  unsigned char   func_reg_1;
  unsigned char   dummy5;
  unsigned short  dummy6;
  unsigned short  dummy7;
  unsigned short  dummy8;
  unsigned short  dummy9;
  unsigned short  dummy10;
  unsigned short  dummy11;
  unsigned short  dummy12;
  unsigned short  dummy13;
  unsigned char   dummy14;
  unsigned char   cntl_reg_0;
  unsigned short  dummy15;
  unsigned short  dummy16;
  unsigned short  dummy17;
  unsigned short  dummy18;
  unsigned short  cntl_reg_1;
  unsigned char   dummy19;
  unsigned char   cntl_reg_2;
  unsigned short  dummy20;
  unsigned short  dummy21;
  unsigned short  dummy22;
  unsigned short  dummy23;
  unsigned short  dummy24;
  unsigned short  dac_0;
  unsigned short  dac_1;
  unsigned short  dac_2;
  unsigned short  dac_3;
  unsigned short  dac_4;
  unsigned short  dac_5;
  unsigned short  dac_6;
  unsigned short  dac_7;
};


/* #define	Status	Enable */

static long init_all();

static long init_mi_record();
static long init_mo_record();
static long write_longout_record ();
static long read_mbbiDirect_record();
static long write_mbboDirect_record();

static int  checkLink();


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

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

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



struct ioCard {
  volatile struct DPvme321  *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     pvme321_num_links;

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


int devPvme321Config(ncards,a24base)
int ncards;
long a24base;
{
  pvme321_num_links = ncards;
  Base_IO = a24base;
  logMsg("Pvme321 NumLink= %d BaseIO= %x\n",pvme321_num_links,Base_IO);
  init_all(0);
}


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

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

  init_flag = 1;

  if (sysBusToLocalAdrs(VME_AM_STD_SUP_DATA,(char *)Base_IO,(char **)&p) == ERROR)
	{
		logMsg("VmeP321: cannot find A24 address space\n");
		return(ERROR);
	}
#ifdef DEBUG_ON  
    if ( CDEBUG)logMsg("PVME321 (init) Called. pass = %d\n", after);
#endif
  for (cardNum=0; cardNum< pvme321_num_links; cardNum++)
   {
     probeVal = CNT;
     if (vxMemProbe((char*) &(p->func_reg_0), WRITE, 1, &probeVal)< OK)
       {
	 if (debug_flag >0 ) 
         logMsg("No PVME321 with cardNum= %d\n probe= %x\n",cardNum,p);
	 cards[cardNum].card = NULL;
       }
     else
       {
	 p->func_reg_0 = CNT;
	 probeVal=FC1;
	 if ((vxMemProbe((char*) &(p->func_reg_1), WRITE,1,&probeVal)==OK) && (debug_flag>10))
	   logMsg("PVME321 card %d user timer cond set\n");

	 probeVal= ALLENABLE;
	 if ((vxMemProbe((char*) &(p->cntl_reg_0), WRITE,1,&probeVal)==OK) && (debug_flag>10))
	   logMsg("PVME321 card %d All D/A Enable\n");
	 
	 probeVal=TIMER;
	 if ((vxMemProbe((char*) &(p->cntl_reg_2), WRITE,1,&probeVal)==OK) && (debug_flag>10))
	   logMsg("PVME321 card %d TIMER Disable\n");
	 
	 if (debug_flag >0)
         logMsg("Found PVME321 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_record(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");

  cards[cardN].card->cntl_reg_0 = (char)(pmbbo->rval);
  pmbbo->rbv=(cards[cardN].card->cntl_reg_0) & 0xff;

  if (debug_flag >5)
   logMsg("write complete \n");
  FASTUNLOCK(&(cards[cardN].lock));
  if (debug_flag >0)
   logMsg("unlock card ...\n");

        return(CONVERT);
}

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

static long read_mbbiDirect_record(pmbbi)
struct mbbiDirectRecord *pmbbi;
{
  short cardN;
  
  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);

  pmbbi->rval = (cards[cardN].card->cntl_reg_0) & 0xff;
  if (debug_flag >5)
   logMsg("read complete \n");

        return(CONVERT);
}



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

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

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

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

  if (checkLink(cardN) == ERROR)
    return(ERROR);
  FASTLOCK(&(cards[cardN].lock));
  if (debug_flag >4)
   logMsg("card locked...\n");
		switch(plongout->out.value.vmeio.signal){
		case 0: /* DAC 0 */
		  cards[cardN].card->dac_0 = (short)plongout->val+2047;
		  if (debug_flag >4)
		    logMsg("write_longout signal 0 DAC0\n");
		  break;
		case 1: /* DAC 1 */
		  cards[cardN].card->dac_1 = (short)plongout->val+2047;
		  if (debug_flag >4)
		    logMsg("write_longout signal 1 DAC1\n");
		  break;
		case 2: /* DAC 2 */
		  cards[cardN].card->dac_2 = (short)plongout->val+2047;
		  if (debug_flag >4)
		    logMsg("write_longout signal 2 DAC0\n");
		  break;
		case 3: /* DAC 3 */
		  cards[cardN].card->dac_3 = (short)plongout->val+2047;
		  if (debug_flag >4)
		    logMsg("write_longout signal 3 DAC3\n");
		  break;
		case 4: /* DAC 4 */
		  cards[cardN].card->dac_4 = (short)plongout->val+2047;
		  if (debug_flag >4)
		    logMsg("write_longout signal 4 DAC4\n");
		  break;
		case 5: /* DAC 5 */
		  cards[cardN].card->dac_5 = (short)plongout->val+2047;
		  if (debug_flag >4)
		    logMsg("write_longout signal 5 DAC5\n");
		  break;
		case 6: /* DAC 6 */
		  cards[cardN].card->dac_6 = (short)plongout->val+2047;
		  if (debug_flag >4)
		    logMsg("write_longout signal 6 DAC6\n");
		  break;
		case 7: /* DAC 7 */
		  cards[cardN].card->dac_7 = (short)plongout->val+2047;
		  if (debug_flag >4)
		    logMsg("write_longout signal 7 DAC7\n");
		  break;
		default:
				return(-1);
		}
  FASTUNLOCK(&(cards[cardN].lock));
  if (debug_flag >4)
   logMsg("unlock card ...\n");

        return(CONVERT);
}


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

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