/* devVme18k11.c */
/* devVme18k11.c - Device Support Routines for VME adc board */
/*
 *    
 *      Original Author: Makoto Tobiyama
 *      Current Author:
 *      Date:            29/Jun/2010
 *      Modified for MVME5500  11/Jun/2011        
 *
 *      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        <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>

#include        <epicsMutex.h>
#include        <epicsExport.h>
#if 1
#include        </space/wind221/target/config/mv5500/sysDma.h>
#include        </space/wind221/target/config/mv5500/universe.h>
#include        <vxLib.h>
#include        <time.h> 
#endif


void dmaCallBackCh0( void );
void dmaCallBackCh1( void );

struct D18k11 {
  unsigned long  call[524288];
  unsigned long  ad_start;
  unsigned long  ad_memory;
  unsigned long  trg_pos;
  unsigned long  irq_enb;
  unsigned long  reserve_io;
  unsigned long  ad_status;
  unsigned long  irq_no;
  unsigned long  irq_id;
  unsigned long  dum1[262136];
  unsigned long  trigger;
  unsigned long  dummy[262143];
};


#defineStatusEnable

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

static long init_lo_record();
static long write_longout();
static long init_li_record();
static long read_longin();
static void vme18k11_isr();

static int  checkLink();

/* Create the dset for devBo18k11 */
struct {
        long            number;
        DEVSUPFUN       report;         
        DEVSUPFUN       init;   
        DEVSUPFUN       init_record;
        DEVSUPFUN       get_ioint_info;
        DEVSUPFUN       write_bo;       
}devBo18k11={
        5,
        NULL,
        NULL,
        init_bo_record,
        NULL,
        write_bo
};
epicsExportAddress(dset,devBo18k11);

/* For devMbbi18k11  */
struct{
        long            number;
        DEVSUPFUN       report;
        DEVSUPFUN       init;
        DEVSUPFUN       init_mi_record;
        DEVSUPFUN       get_ioint_info;
        DEVSUPFUN       read_mbbiDirect;
}devMbbi18k11={
        5,
        NULL,
        NULL,
        init_mi_record,
        get_mbbi_int_info,
        read_mbbiDirect
};
epicsExportAddress(dset,devMbbi18k11);

struct {
    long        number;
    DEVSUPFUN   report;
    DEVSUPFUN   init;
    DEVSUPFUN   init_record;
    DEVSUPFUN   get_ioint_info;
    DEVSUPFUN   read_write;
    DEVSUPFUN   conv;
}devWf18k11 ={
  6,
  NULL,
  NULL,
  init_wf_record,
  NULL,
  read_wf_record,
  NULL
};
epicsExportAddress(dset,devWf18k11);

struct {
        long            number;
        DEVSUPFUN       report;
        DEVSUPFUN       init;
        DEVSUPFUN       init_record;
        DEVSUPFUN       get_ioint_info;
        DEVSUPFUN       write_longout;
        DEVSUPFUN       special_linconv;
}devLo18k11={
        6,
        NULL,
        NULL,
        NULL,
        NULL,
        write_longout,
        NULL
};
epicsExportAddress(dset,devLo18k11);

struct {
        long            number;
        DEVSUPFUN       report;
        DEVSUPFUN       init;
        DEVSUPFUN       init_record;
        DEVSUPFUN       get_ioint_info;
        DEVSUPFUN       read_longin;
        DEVSUPFUN       special_linconv;
}devLi18k11={
        6,
        NULL,
        NULL,
        init_li_record,
        NULL,
        read_longin,
        NULL};
epicsExportAddress(dset,devLi18k11);

struct ioCard {
  volatile struct D18k11     *card; /* address of this card */
  epicsMutexId               lock;  /* semaphore */
  IOSCANPVT                  ioscanpvt; 
      };

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

static int            debug_flag = 0;
static unsigned long  Base_IO;
static int            D18k11_num_links;

static struct ioCard  cards[CONST_NUM_LINKS];
static int            init_flag = 0;
static unsigned short INT_VEC_BASE;
static unsigned char int_level;
#if 1
static unsigned long *gplTmpData; /* 256K Word * 4ch(256*1024*2*4/4) */
#endif


int dev18k11Config(ncards,a32base,irq,intvecbase)
int ncards;
long a32base;
int irq;
int intvecbase;
{
  D18k11_num_links = ncards;
  Base_IO = a32base;
  int_level= irq;
  INT_VEC_BASE=intvecbase;
  logMsg("dev18k11 NumLink= %d BaseIO= %x IRQ = %d INTVECBASE =%x\n",D18k11_num_links,Base_IO,int_level,INT_VEC_BASE,0,0);
  init_all(0);
}

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

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

  init_flag = 1;
#if 1
  if ( sysVmeDmaInit() != OK ) {
    logMsg("sysVmeDmaInit() Error!!\n",0,0,0,0,0,0);
    return(ERROR);
  }
  logMsg("sysVmeDmaInit() OK!!\n",0,0,0,0,0,0);
#endif
  if (sysBusToLocalAdrs(VME_AM_EXT_SUP_DATA,(char *)Base_IO,(char **)&p) == ERROR)
{ logMsg("18k11: cannot find extended address space\n",0,0,0,0,0,0); return(ERROR); }
for (cardNum=0; cardNum< D18k11_num_links; cardNum++) { if (vxMemProbe((char*) &(p->ad_status), READ, 4, &probeVal[0])!= OK) {
if (debug_flag >0 )
logMsg("No 18k11 with cardNum= %d\n probe= %x\n",cardNum,p,0,0,0,0);
cards[cardNum].card = NULL;
} else {
if (debug_flag >0)
logMsg("Found 18k11 with cardNum= %d\n address= %x\n",cardNum,p,0,0,0,0);
cards[cardNum].card = p; /* Remember address of the board */ scanIoInit(&(cards[cardNum].ioscanpvt));
} p->irq_enb = 0x00; cards[cardNum].lock = epicsMutexMustCreate(); epicsMutexUnlock((cards[cardNum].lock)); /* Init the board lock */ p++; } gplTmpData = memalign( 256, 524288*4 ); /* 256K Word x 4ch */ if (sysVmeDmaCnfgSet(DCTL_VDW_64 | DCTL_VCT_BLK, DCTL_VAS_A32, DCTL_PGM_DATA, DCTL_SUPER_SUP) != OK){ logMsg("devVme18k11 error DMA setting\n",0,0,0,0,0,0);} return(OK); } /****************************************************************** * * Interrupt service routine * *******************************************************************/ static void vme18k11_isr(pmbbi) struct mbbiDirectRecord*pmbbi; { unsigned char mode; short cardN; unsigned long ad; unsigned char intreg; cardN = pmbbi->inp.value.vmeio.card; ad = (cards[cardN].card->ad_status) & 0xff; scanIoRequest(cards[cardN].ioscanpvt); /* logMsg("18k11 int called \n");*/ return; } /************************************************************************** * * 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 18k11 for card %d\n",cardN,0,0,0,0,0); return(ERROR); } if (debug_flag>5) logMsg("BO\n",0,0,0,0,0,0); epicsMutexMustLock((cards[cardN].lock)); /* ADC start */ cards[cardN].card->ad_start = 0x1; epicsMutexUnlock((cards[cardN].lock)); return(0); } static long init_lo_record(plongout) struct longoutRecord *plongout; { return(0); } static long write_longout(plongout) struct longoutRecord *plongout; { short cardN; cardN = plongout->out.value.vmeio.card; if (debug_flag >10) logMsg("write_lo called with card %d\n",cardN,0,0,0,0,0); if (checkLink(cardN) == ERROR) return(ERROR); epicsMutexMustLock((cards[cardN].lock)); switch(plongout->out.value.vmeio.signal){ case 0 : /* adc_memory_size */
cards[cardN].card->ad_memory = 0x3 & (plongout->val); break;
case 1 : /* trigger position */ cards[cardN].card->trg_pos = 0x7 & (plongout ->val);
break;
case 2 : /* interrupt enable */
cards[cardN].card->irq_enb = 0x3 & (plongout -> val); break;
default: break; } epicsMutexUnlock((cards[cardN].lock)); return(OK); } static long init_li_record(plongin) struct longinRecord *plongin; { return(0); } static long read_longin(plongin) struct longinRecord *plongin; { short cardN; if (debug_flag >10) logMsg("read_longin called...\n",0,0,0,0,0,0); cardN = plongin->inp.value.vmeio.card; if (checkLink(cardN) == ERROR) return(ERROR); switch(plongin->inp.value.vmeio.signal){ case 0: /* AD_MEMORY */ plongin->val = (cards[cardN].card->ad_memory) & 0x3; break; case 1: /* TRG_POS */ plongin->val = (cards[cardN].card->trg_pos) & 0x7; break; case 2: /* IRQ_ENB */ plongin->val = (cards[cardN].card->irq_enb) & 0x3; break; case 3 : /* AD_status */ plongin->val = (cards[cardN].card->ad_status) & 0xff; break; case 4: /* IRQ_NO */ plongin->val = (cards[cardN].card->irq_no) & 0xf;
break;
case 5: /* IRQ_VECTOR */ plongin->val = (cards[cardN].card->irq_id) &0xff; break; default: break; } return(OK); } static long init_mi_record(pmbbi) struct mbbiDirectRecord*pmbbi; { short cardNum; short signal; cardNum = pmbbi->inp.value.vmeio.card; signal = pmbbi->inp.value.vmeio.signal; if (signal == 1) { if (intConnect(INUM_TO_IVEC(INT_VEC_BASE + cardNum),
(VOIDFUNCPTR)vme18k11_isr, (int)pmbbi) != OK)
logMsg("devVme18k11: Interrupt connect failed for card %d\n",pmbbi->inp.value.vmeio.card,0,0,0,0,0); logMsg("intConnect 0x%x\n",pmbbi);
sysIntEnable(int_level); logMsg("devVme18k11 int set for int 0x%x\n",int_level,0,0,0,0,0); } 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,0,0,0,0,0); if (checkLink(cardN) == ERROR) return(ERROR); switch(pmbbi->inp.value.vmeio.signal){ case 0: /* IRQ_ENB */ pmbbi->rval = (cards[cardN].card->irq_enb) & 0x3; break; case 1: /* AD_STATUS */ pmbbi->rval = (cards[cardN].card->ad_status) & 0xff; break; default: break; } if (debug_flag >5) logMsg("mbbi read complete \n",0,0,0,0,0,0); return(OK); } static long get_mbbi_int_info(cmd,pmbbi,ppvt) int cmd; struct mbbiDirectRecord *pmbbi; IOSCANPVT *ppvt; { short cardN; unsigned char stat; cardN = pmbbi->inp.value.vmeio.card; *ppvt = cards[cardN].ioscanpvt; if (debug_flag >5) logMsg("mbbi_INT CALLED\n",0,0,0,0,0,0); return(0); } static long init_wf_record(pwf) struct waveformRecord*pwf; { /* short cardNum; cardNum = pwf->inp.value.vmeio.card; if (intConnect(INUM_TO_IVEC(INT_VEC_BASE + cardNum),
(VOIDFUNCPTR)vme18k11_isr, (int)pwf) != OK)
logMsg("devVme18k11: Interrupt connect failed for card %d\n",pwf->inp.value.vmeio.card); logMsg("intConnect 0x%x\n",pwf);
sysIntEnable(int_level); logMsg("devVme18k11 int set for int 0x%x\n",int_level); */ return(0); } static long read_wf_record(pwf) struct waveformRecord*pwf; { short cardN; unsigned long a1,a2; unsigned long taddress,sta,t_set,mems,mem_start; long ii,start,is; unsigned short* us_thing = (unsigned short*)pwf->bptr; #if 1 STATUS iDmaStartRc; unsigned int p1=0,p2=0,p3=0,p4=0,pSta=0; #endif #if 1 struct timespec oTimeSpec1; struct timespec oTimeSpec2; struct timespec oTimeSpec3; struct timespec oTimeSpec4; struct timespec oTimeSpec5; /* clock_gettime( CLOCK_REALTIME, &oTimeSpec1 ); */ #endif cardN = pwf->inp.value.vmeio.card; if (debug_flag >5) logMsg("read_wf_record called with card number of %d\n",cardN,0,0,0,0,0); if (checkLink(cardN) == ERROR) return(ERROR); taddress = (cards[cardN].card->trigger) & 0x3ffff; t_set = (cards[cardN].card->trg_pos) & 0x7; /* 0 for -100% */ mems = 0x8000 << ((cards[cardN].card->ad_memory) & 0x3 ); /* logMsg("MEMS %x TADDRESS %x\n",mems, taddress); */ mem_start = mems *(t_set)/4; start = taddress - mem_start; if (start < 0) start = start + mems; switch(pwf->inp.value.vmeio.signal){ case 0: { /* all channel */ #if 0 logMsg("card[%d] address[%x] mems[%x]\n",cardN,&cards[cardN].card->call[0],mems); #endif #if 0 /* clock_gettime( CLOCK_REALTIME, &oTimeSpec1 ); */ for (ii=0;ii<mems;ii++) {
is = (ii-start);
if (is <0) is += mems;
(unsigned long)a1 = (unsigned long)(cards[cardN].card->call[ii]); us_thing[is] = (unsigned short)(a1 & 0x3fff); us_thing[is+262144] = (unsigned short)((a1>>16) & 0x3fff);
(unsigned long)a2 = (unsigned long)(cards[cardN].card->call[ii+262144]); us_thing[is+524288] = (unsigned short)(a2 & 0x3fff); us_thing[is+786432] = (unsigned short)((a2>>16) & 0x3fff); /* logMsg("A1 =%x\n",a1); */ /* if (ii<10) logMsg("call %d A1=%x\n",ii,a1); */
} /* clock_gettime( CLOCK_REALTIME, &oTimeSpec2 ); */ #else sysUnivVERRClr(); if(sysVmeDmaStatusGet(&pSta) != OK ) { logMsg("sysVmeDmaStatusGet() Error!!\n", 0, 0, 0, 0, 0); } #if 0 logMsg("VmeDmaStatus[%x]\n",pSta,0,0,0,0,0); #endif if(sysVmeDmaCnfgGet(&p1,&p2,&p3,&p4) != OK ) { logMsg("sysVmeDmaCnfgGet() Error!!\n", 0, 0, 0, 0, 0); } #if 0 logMsg("xferType[%x] addrSpace[%x] dataType[%x] userType[%x]\n",p1,p2,p3,p4,0,0); #endif /* clock_gettime( CLOCK_REALTIME, &oTimeSpec1 ); */ /* iDmaStartRc = sysVmeDmaV2LCopy( &cards[cardN].card->call[0], gplTmpData+0, mems * 4 ); */ iDmaStartRc = sysVmeDmaV2LCopy( &cards[cardN].card->call[0], gplTmpData+0, mems * 8 ); /* clock_gettime( CLOCK_REALTIME, &oTimeSpec2 ); */ if(iDmaStartRc != 0) { logMsg("-->sysVmeDmaV2LCopy() error!! Rc[%d] card[%d] ch1ch3\n", iDmaStartRc, cardN, 0, 0 ,0, 0 ); } /* clock_gettime( CLOCK_REALTIME, &oTimeSpec3 ); */ /* iDmaStartRc = sysVmeDmaV2LCopy( &cards[cardN].card->call[262144], gplTmpData+262144, mems * 4 ); */ /* clock_gettime( CLOCK_REALTIME, &oTimeSpec4 ); */ if(iDmaStartRc != 0) { logMsg("-->sysVmeDmaV2LCopy() error!! Rc[%d] card[%d] ch2ch4\n", iDmaStartRc, cardN, 0, 0 ,0, 0 ); } /* logMsg("--gplTmpData[0,1] %x %x\n",gplTmpData[0],gplTmpData[1],0,0,0,0);
logMsg("--gplTmpData[2,3] %x %x\n",gplTmpData[2],gplTmpData[3],0,0,0,0); */
/* for ( ii = 0; ii < mems; ii++ ) {
us_thing[ii + 0] = (unsigned short)( gplTmpData[ii + 0] & 0x3fff ); us_thing[ii + 262144] = (unsigned short)( ( gplTmpData[ii + 0] >> 16 ) & 0x3fff ); us_thing[ii + 524288] = (unsigned short)( gplTmpData[ii + 262144] & 0x3fff ); us_thing[ii + 786432] = (unsigned short)( ( gplTmpData[ii + 262144] >> 16 ) & 0x3fff );
}*/ for ( ii = 0; ii < mems ; ii++ ) {
us_thing[ii+ 0] = (unsigned short)( gplTmpData[ii*2+1] & 0x3fff ); us_thing[ii + 262144] = (unsigned short)( ( gplTmpData[ii*2+1] >> 16 ) & 0x3fff ); us_thing[ii + 524288] = (unsigned short)( gplTmpData[ii*2] & 0x3fff ); us_thing[ii + 786432] = (unsigned short)( ( gplTmpData[ii*2] >> 16 ) & 0x3fff );
} /* logMsg("--us_thing[0,1] %x %x\n",us_thing[0],us_thing[1],0,0,0,0); */ /* clock_gettime( CLOCK_REALTIME, &oTimeSpec5 ); */ #endif pwf->nord = 1048576; cards[cardN].card->ad_start = 0x1; #if 0 logMsg("ad_start[%d]\n",cardN,0,0,0,0,0); #endif break; } case 1: { /* ch2ch4 */ /* for (ii=0;ii<mems;ii++) {
is = (ii-start); if (is <0) is += mems; (unsigned long)a1 = (unsigned long)(cards[cardN].card->ch2ch4[ii]); us_thing[is] = (unsigned short)(a1 & 0xfff); us_thing[is+262144] = (unsigned short)((a1>>16) & 0xfff); if ((debug_flag >10 ) && (ii<40)){ logMsg("ii= %d down %d up %d\n",ii,us_thing[ii],us_thing[ii+262144]); }
} pwf->nord = 524288; cards[cardN].card->ad_start = 0x1; */ break; } default : logMsg("Invalid Signal\n",0,0,0,0,0,0); } /* cards[cardN].card->status = 0x1; */ if (debug_flag >5) logMsg("18k11 card %d end of read\n",cardN,0,0,0,0,0); #if 0 /* logMsg( "card[%d] ch1ch3 DMA Info. vmeaddr[0x%x]->memaddr[0x%x] readlen[0x%x]", &cards[cardN].card->call[0], gplTmpData+0, mems*4,0,0,0 ); */ logMsg( "card[%d] ch1ch3 DMA stime[%ld.%09ld] etime[%ld.%09ld]\n", cardN, oTimeSpec1.tv_sec, oTimeSpec1.tv_nsec, oTimeSpec2.tv_sec, oTimeSpec2.tv_nsec, 0 ); /* logMsg( "card[%d] ch2ch4 DMA Info. vmeaddr[0x%x]->memaddr[0x%x] readlen[0x%x]", &cards[cardN].card->call[262144], gplTmpData+262144, mems*4,0,0,0 ); */ logMsg( "card[%d] ch2ch4 DMA stime[%ld.%09ld] etime[%ld.%09ld]\n", cardN, oTimeSpec3.tv_sec, oTimeSpec3.tv_nsec, oTimeSpec4.tv_sec, oTimeSpec4.tv_nsec, 0 ); logMsg( "card[%d] Move&Shift eTime[%ld.%09ld] \n",cardN,oTimeSpec5.tv_sec,oTimeSpec5.tv_nsec,0,0,0 ); #endif return(0); } /* static long get_wf_int_info(cmd,pwf,ppvt) int cmd; struct waveformRecord *pwf; IOSCANPVT *ppvt; { short cardN; unsigned char stat; cardN = pwf->inp.value.vmeio.card; *ppvt = cards[cardN].ioscanpvt; if (debug_flag >5) logMsg("wf_INT CALLED\n"); return(0); } */ /************************************************************************** * * Make sure card number is valid * **************************************************************************/ static int checkLink(cardN) short cardN; { if (cardN >= D18k11_num_links) return(ERROR); if (cards[cardN].card == NULL) { logMsg("No 18K11 with this number = %d\n",cardN,0,0,0,0,0); return(ERROR); } if (debug_flag >10) logMsg("Yes you have 18k11 with card No= %d\n",cardN,0,0,0,0,0); return(OK); } void dmaCallBackCh0( void ) { logMsg( "call dmaCallBackCh0\n",0,0,0,0,0,0 ); } void dmaCallBackCh1( void ) { logMsg( "call dmaCallBackCh1\n", 0,0,0,0,0,0 ); }