/* devVme17k46.c */
/* devVme17k46.c - Device Support Routines for  VME 17K46 */
/*
 *      Original Author: Makoto Tobiyama
 *      Current Author:
 *      Date:            15/Apr/98
 *
 *      Experimental Physics and Industrial Control System (EPICS)
 *
 *      Copyright 1997, KEKB.
 *
 *
 * Modification Log:
 * -----------------
 *	15-Apr-98	Makoto Tobiyama (original)
 */


#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 */


struct Dvme17k46 {
	unsigned short	Ch1Cntl;
	unsigned short	Ch2Cntl;
        unsigned short  Ch1Stat;
        unsigned short  Ch2Stat;
        short           Ch1FWD;
        short           Ch1REF;
        short           Ch2FWD;
        short           Ch2REF;
};


#define	Status	Enable

static long init();
static long init_li_record();
static long init_mi_record();
static long init_mo_record();
static long read_longin();
static long read_mbbiDirect();
static long write_mbboDirect();
static int  checkLink();

/* Create the dset for devLiK46 */

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

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

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

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

#define CONST_NUM_LINKS 20
/* #define STATIC  */
#define DEBUG_ON

static int      debug_flag = 1;
static unsigned long Base_IO;
static int      k46_num_links;

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


int devK46Config(ncards,a24base,init_set)
int ncards;
unsigned char init_set;
long a24base;
{
  k46_num_links = ncards;
  Base_IO = a24base;
  printf("Vme17k46 NumLink= %d BaseIO= %x\n",k46_num_links,Base_IO);
  fast_mask = init_set;
  init(0);
}


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

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

  init_flag = 1;

  if (sysBusToLocalAdrs(VME_AM_EXT_SUP_DATA,(char *)Base_IO,(char **)&p) == ERROR)
	{
		printf("Vme17k46: cannot find extended address space\n");
		return(ERROR);
	}
#ifdef DEBUG_ON  
    printf("devLiK46 (init) Called. pass = %d\n", after);
#endif
  for (cardNum=0; cardNum< k46_num_links; cardNum++)
   {
     if ((vxMemProbe((char*) &(p->Ch1Cntl), WRITE, 2, &fast_mask)< OK) ||
         (vxMemProbe((char*) &(p->Ch2Cntl), WRITE, 2, &fast_mask)< OK))
       {
	 if (debug_flag >0 ) 
         printf("No 17k46 with cardNum= %d\n probe= %x\n",cardNum,p);
	 cards[cardNum].card = NULL;
       }
     else
       {
	 
	 if (debug_flag >0)
         printf("Found 17k46 with cardNum= %d\n address= %x initialized %x\n",cardNum,p,fast_mask);
	 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_li_record(plongin)
struct longinRecord	*plongin;
{
  return(0);
}

static long read_power(long power)
{
short temp;
  
  temp = power<<4;
  temp = temp/16;  
  return(temp);
}
  

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:
		               plongin->val = read_power(cards[cardN].card->Ch1FWD);
                               if (debug_flag >5)
                                printf("read_longin signal 0 Ch1FWD %d\n",
                                        plongin->val);

				break;
			case 1:
		               plongin->val = read_power(cards[cardN].card->Ch1REF);
                               if (debug_flag >5)
                                printf("read_longin signal 0 Ch1REF %d\n",
                                        plongin->val);

				break;
			case 2:
		               plongin->val = read_power(cards[cardN].card->Ch2FWD);
                               if (debug_flag >5)
                                printf("read_longin signal 0 Ch2FWD %d\n",
                                        plongin->val);

				break;
			case 3:
		               plongin->val = read_power(cards[cardN].card->Ch2REF);
                               if (debug_flag >5)
                                printf("read_longin signal 0 Ch2REF %d\n",
                                        plongin->val);

				break;
			default:
				return(-1);
		}
        return(CONVERT);
}

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 >1) 
   printf("write_mbboDirect called with card %d\n",cardN);

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

  FASTLOCK(&(cards[cardN].lock));
  if (debug_flag >1)
   printf("card locked...\n");
   
  switch(pmbbo->out.value.vmeio.signal){
         case 0: /* Ch1 cntl */
	        cards[cardN].card->Ch1Cntl = pmbbo->rval;
		pmbbo->rbv=cards[cardN].card->Ch1Cntl;
		break;
         case 1: /* Ch2 cntl */
                cards[cardN].card->Ch2Cntl = pmbbo->rval;
		pmbbo->rbv=cards[cardN].card->Ch2Cntl;
		break;
         default:
                FASTUNLOCK(&(cards[cardN].lock));
                return(-1);
  }
  if (debug_flag >1)
   printf("write complete \n");
  FASTUNLOCK(&(cards[cardN].lock));
  if (debug_flag >1)
   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: /* Ch1 status */
	        pmbbi->rval = cards[cardN].card->Ch1Stat;
		break;
         case 1: /* Ch2 status */
                pmbbi->rval = cards[cardN].card->Ch2Stat;
		break;
         default:
                return(-1);
  }
  if (debug_flag >5)
   printf("read complete \n");

        return(CONVERT);
}




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

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