/* devVme17k76.c */
/* devVme17k76.c - Device Support Routines for VME adc board */
/*
 *      Original Author: Makoto Tobiyama
 *      Current Author:
 *      Date:            28/Dec/2001
 *      Modified         
 *
 *      Experimental Physics and Industrial Control System (EPICS)
 *
 *      Copyright 1997, KEKB.
 *
 *
 * Modification Log:
 * -----------------
 */


#include	<vxWorks.h>
#include	<types.h>
#include	<stdioLib.h>
#include	<string.h>
/* #include        <sys/time.h> */

#include	<vme.h>
#include	<dbDefs.h>
#include	<dbAccess.h>
#include	<recSup.h>
#include	<devSup.h>
#include	<devCamac.h>
#include	<link.h>
#include        <iv.h>
#include	<module_types.h>
#include	<longinRecord.h>
#include	<longoutRecord.h>
#include	<boRecord.h>
#include	<biRecord.h>
#include	<mbbiDirectRecord.h>
#include	<mbboDirectRecord.h>
#include	<waveformRecord.h>
#include        <stringoutRecord.h>
#include	<dbScan.h>

struct D17k76 {
  unsigned long  ch1ch3[262144];
  unsigned long  ch2ch4[262144];
  unsigned long  status;
  unsigned long  dummy[1048575];
};

#define	Status	Enable

static long init_all();
static long init_mi_record();
static long init_bo_record();
static long write_bo();
static long read_mbbiDirect();
static long init_wf_record();
static long read_wf_record();

static int  checkLink();

/* Create the dset for devBo17k76 */
struct {
        long            number;
        DEVSUPFUN       report;         
        DEVSUPFUN       init;   
        DEVSUPFUN       init_record;
        DEVSUPFUN       get_ioint_info;
        DEVSUPFUN       write_bo;       
}devBo17k76={
        5,
        NULL,
        NULL,
        init_bo_record,
        NULL,
        write_bo
};
/* For devMbbi17k76  */
struct{
        long            number;
        DEVSUPFUN       report;
        DEVSUPFUN       init;
        DEVSUPFUN       init_mi_record;
        DEVSUPFUN       get_ioint_info;
        DEVSUPFUN       read_mbbiDirect;
}devMbbi17k76={
        5,
        NULL,
        NULL,
        init_mi_record,
        NULL,
        read_mbbiDirect
};

struct {
    long        number;
    DEVSUPFUN   report;
    DEVSUPFUN   init;
    DEVSUPFUN   init_record;
    DEVSUPFUN   get_ioint_info;
    DEVSUPFUN   read_write;
    DEVSUPFUN   conv;
}devWf17k76 ={
  6,
  NULL,
  NULL,
  init_wf_record,
  NULL,
  read_wf_record,
  NULL
};

struct ioCard {
  volatile struct D17k76     *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            D17k76_num_links;

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

int dev17k76Config(ncards,a32base)
int ncards;
long a32base;
{
  D17k76_num_links = ncards;
  Base_IO = a32base;
  logMsg("dev17k76 NumLink= %d BaseIO= %x\n",D17k76_num_links,Base_IO);
  init_all(0);
}

static long init_all(after)
int after;
{
  int                          cardNum, chanNum;
  unsigned char                probeVal[4];
  volatile  struct D17k76     *p;
  unsigned short               mem_pat;

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

  init_flag = 1;

  if (sysBusToLocalAdrs(VME_AM_EXT_SUP_DATA,(char *)Base_IO,(char **)&p) == ERROR)
	{
		logMsg("17k76: cannot find extended address space\n");
		return(ERROR);
	}
  for (cardNum=0; cardNum< D17k76_num_links; cardNum++)
   {
     if (vxMemProbe((char*) &(p->status), READ, 4, &probeVal[0])< OK)
       {
	 if (debug_flag >0 ) 
         logMsg("No 17k76 with cardNum= %d\n probe= %x\n",cardNum,p);
	 cards[cardNum].card = NULL;
       }
     else
       {
	 if (debug_flag >0)
           logMsg("Found 17k76 with cardNum= %d\n address= %x\n",cardNum,p);
	 cards[cardNum].card = p;  /* Remember address of the board */
	 mem_pat = (((p->status)>>3) & 0x3) ;
         switch (mem_pat) {
         case 0x00 : {
	   mem_size[cardNum] = 32768;
           break;
	 }
	 case 0x01 : {
	   mem_size[cardNum] = 65536;
	   break;
	 }
	 case 0x02 : {
	   mem_size[cardNum] = 131072;
	   break;
	 }
	 default : {
	   mem_size[cardNum] = 262144;
	   break;
	 }
	 }
	 if (debug_flag >0){
           logMsg("Mem size of 17k76 with cardNum= %d is = %d\n",cardNum,mem_size[cardNum]);
	 }
	 p->status = 0x0;
	 p->status = 0x1;
	 FASTLOCKINIT(&(cards[cardNum].lock));
	 FASTUNLOCK(&(cards[cardNum].lock)); /* Init the board lock */
       }
     p++;
   }
  return(OK);
}

/**************************************************************************
 *
 * BO Initialization (Called one time for each BO PowerUT card record)
 *
 **************************************************************************/
static long init_bo_record(pbo)
struct boRecord *pbo;
{

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


/**************************************************************************
 *
 * Perform a write operation from a BO record
 *
 **************************************************************************/
static long write_bo(pbo)
struct boRecord *pbo;
{

  short cardN;

  cardN = pbo->out.value.vmeio.card;
  if (checkLink(cardN) == ERROR)
    {
      logMsg("Error--- No 17k76 for card %d\n",cardN);
      return(ERROR);
    }

  FASTLOCK(&(cards[cardN].lock));
  switch(pbo->out.value.vmeio.signal){
  case 0 :{
    cards[cardN].card->status = 0x0;
    break;
  }
  case 1:{
    cards[cardN].card->status = 0x1;
    break;
  }
  }
  FASTUNLOCK(&(cards[cardN].lock));
  return(0);
}

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

  if (checkLink(cardN) == ERROR)
    return(ERROR);
   
  pmbbi->rval = (cards[cardN].card->status) & 0x1f;

  if (debug_flag >5)
   logMsg("mbbi read complete \n");

        return(CONVERT);
}

static long init_wf_record(pwf)
struct waveformRecord	*pwf;
{
  return(0);
}

static long read_wf_record(pwf)
struct waveformRecord	*pwf;
{
  short cardN;
  unsigned long a1;
  long i;
  unsigned short* us_thing = (unsigned short*)pwf->bptr;

  cardN = pwf->inp.value.vmeio.card;

  if (debug_flag >5)
    logMsg("read_wf_record called with card number of %d\n",cardN);

  if (checkLink(cardN) == ERROR)
    return(ERROR);
  if (((((cards[cardN].card->status)>>2) & 0x01) == 0 ) &&
         (((cards[cardN].card->status) & 0x01) ==1)){
    logMsg("17k76 card %d Memory not ready\n",cardN);
    return(ERROR);
  }
    cards[cardN].card->status = 0x0; /* disable trigger */

  switch(pwf->inp.value.vmeio.signal){
  case 0: { /* ch1ch3 */
    for (i=0;i<(mem_size[cardN]);i++)
      {
	(unsigned long)a1 = (unsigned long)(cards[cardN].card->ch1ch3[i]);
	us_thing[i] = (unsigned short)(a1 & 0xfff);
	us_thing[i+262144] = (unsigned short)((a1>>16) & 0xfff);
      }
    pwf->nord = 524288;
    break;
  }
  case 1: { /* ch2ch4 */
    for (i=0;i<(mem_size[cardN]);i++)
      {
	(unsigned long)a1 = (unsigned long)(cards[cardN].card->ch2ch4[i]);
	us_thing[i] = (unsigned short)(a1 & 0xfff);
	us_thing[i+262144] = (unsigned short)((a1>>16) & 0xfff);
	if ((debug_flag >10 ) && (i<40)){
	  logMsg("i= %d down %d up %d\n",i,us_thing[i],us_thing[i+262144]);
	}
      }
    pwf->nord = 524288;
    cards[cardN].card->status = 0x1;    
    break;
  }


  }
  /*  cards[cardN].card->status = 0x1; */

  if (debug_flag >5) logMsg("17k76 card %d end of read\n",cardN); 
  return(0);
}


/**************************************************************************
 *
 * Make sure card number is valid
 *
 **************************************************************************/



static int checkLink(cardN)
short   cardN;
{
  if (cardN >= D17k76_num_links)
    return(ERROR);
  if (cards[cardN].card == NULL)
    {
      logMsg("No 17K76 with this number = %d\n",cardN);
      return(ERROR);
    }

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