diff --git a/src/dev/devAvme9440.c b/src/dev/devAvme9440.c new file mode 100644 index 000000000..90d3c22b7 --- /dev/null +++ b/src/dev/devAvme9440.c @@ -0,0 +1,889 @@ +/* devAvme9440.c */ + +/***************************************************************** + * + * Author : Greg Nawrocki + * Date: 4/93 + * + * Experimental Physics and Industrial Control System (EPICS) + * + ***************************************************************** + * COPYRIGHT NOTIFICATION + ***************************************************************** + + * THE FOLLOWING IS A NOTICE OF COPYRIGHT, AVAILABILITY OF THE CODE, + * AND DISCLAIMER WHICH MUST BE INCLUDED IN THE PROLOGUE OF THE CODE + * AND IN ALL SOURCE LISTINGS OF THE CODE. + + * (C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO + + * Argonne National Laboratory (ANL), with facilities in the States of + * Illinois and Idaho, is owned by the United States Government, and + * operated by the University of Chicago under provision of a contract + * with the Department of Energy. + + * Portions of this material resulted from work developed under a U.S. + * Government contract and are subject to the following license: For + * a period of five years from March 30, 1993, the Government is + * granted for itself and others acting on its behalf a paid-up, + * nonexclusive, irrevocable worldwide license in this computer + * software to reproduce, prepare derivative works, and perform + * publicly and display publicly. With the approval of DOE, this + * period may be renewed for two additional five year periods. + * Following the expiration of this period or periods, the Government + * is granted for itself and others acting on its behalf, a paid-up, + * nonexclusive, irrevocable worldwide license in this computer + * software to reproduce, prepare derivative works, distribute copies + * to the public, perform publicly and display publicly, and to permit + * others to do so. + + ***************************************************************** + * DISCLAIMER + ***************************************************************** + + * NEITHER THE UNITED STATES GOVERNMENT NOR ANY AGENCY THEREOF, NOR + * THE UNIVERSITY OF CHICAGO, NOR ANY OF THEIR EMPLOYEES OR OFFICERS, + * MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL + * LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR + * USEFULNESS OF ANY INFORMATION, APPARATUS, PRODUCT, OR PROCESS + * DISCLOSED, OR REPRESENTS THAT ITS USE WOULD NOT INFRINGE PRIVATELY + * OWNED RIGHTS. + + ***************************************************************** + * LICENSING INQUIRIES MAY BE DIRECTED TO THE INDUSTRIAL TECHNOLOGY + * DEVELOPMENT CENTER AT ARGONNE NATIONAL LABORATORY (708-252-2000). + ***************************************************************** + + * Modification Log: + * ----------------- + * ... + */ + +/*To Use this device, Include the following before iocInit */ +/* devAvme9440Config(ncards,a16base,intvecbase) */ +/* For Example */ +/* devAvme9440Config(1,0x2800,0x78) */ + + /* + * This device support routine provides EPICS support for the * + * Acromag AVME-9440 16 bit binary input and output board. Change * + * of state I/O interrupts are available for binary input signals * + * 0 -7 only, and only for the BI record. If interrupts are * + * desired for MBBI type values, they must be done via BI records * + * linked to CALC records. As many I/O interrupt scan BI records * + * may be connected to a single binary input signal as desired. * + * + */ + + /*********************************************************************/ + /** **/ + /** Binary Outputs 0 - 15 ========== "AVME9440 O" Signals 0 - 15 **/ + /** Binary Input 0 - 15 ============ "AVME9440 I" Signals 0 - 15 **/ + /** Binary Output Readback 0 - 15 == "AVME9440 I" Signals 16 - 31 **/ + /** **/ + /*********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +long init(); +long report(); +long init_bo_record(), init_bi_record(); +long init_mbbo_record(), init_mbbi_record(); +long write_bo(), read_bi(); +long write_mbbo(), read_mbbi(); +long write_card(), write_mbbo_card(), read_card(); +long get_bi_int_info(); +int checkLink(); +void avme9440_isr(); + +int devAvme9440Debug = 0; + +/***** devAvme9440Debug *****/ + +/** devAvme9440Debug == 0 --- no debugging messages **/ +/** devAvme9440Debug >= 5 --- hardware initialization information **/ +/** devAvme9440Debug >= 10 -- record initialization information **/ +/** devAvme9440Debug >= 15 -- write commands **/ +/** devAvme9440Debug >= 20 -- read commands **/ + +#define INPUT_REG 1 +#define OUTPUT_REG 2 + +struct avme9440 { + unsigned char pad0[0x80]; + unsigned char pad1; + unsigned char boardStatus; + unsigned char pad2[0x1e]; + unsigned char pad3; + unsigned char intVector0; + unsigned char pad4; + unsigned char intVector1; + unsigned char pad5; + unsigned char intVector2; + unsigned char pad6; + unsigned char intVector3; + unsigned char pad7; + unsigned char intVector4; + unsigned char pad8; + unsigned char intVector5; + unsigned char pad9; + unsigned char intVector6; + unsigned char pada; + unsigned char intVector7; + unsigned char padb[0x10]; + unsigned char padc; + unsigned char intStatus; + unsigned char padd; + unsigned char intEnable; + unsigned char pade; + unsigned char intPolarity; + unsigned char padf; + unsigned char intTypeSelect; + unsigned char padg; + unsigned char intPaternEnable; + unsigned short inputData; + unsigned short outputData; + unsigned char padh[0x332]; +}; + +#define NUM_INT_CHAN 8 + +struct ioCard { + volatile struct avme9440 *card; /* address of this card's registers */ + int intCnt[8]; /* array to keep track of number of */ + /* interrupt records attached to a channel */ + FAST_LOCK lock; /* semaphore */ + IOSCANPVT ioscanpvt[NUM_INT_CHAN]; /* list or records processed upon interrupt */ +}; + +#define CONST_NUM_LINKS 6 +#define STATIC + +static unsigned short BASEADD; +#define LED_INIT 0x02 +#define LED_OKRUN 0x03 +#define LED_OKINTS 0x0B + +#define INT_LEVEL 5 +static unsigned short INT_VEC_BASE; + +int int_level = INT_LEVEL; + +int avme9440_num_links=0; + +static struct ioCard cards[CONST_NUM_LINKS]; +static int init_flag = 0; + +/* Create the dset for devBoAvme9440 */ +struct { + long number; + DEVSUPFUN report; /* used by dbior */ + DEVSUPFUN init; /* called 1 time before & after all records */ + DEVSUPFUN init_record; /* called 1 time for each record */ + DEVSUPFUN get_ioint_info; /* used for COS processing (not used for outputs)*/ + DEVSUPFUN write_bo; /* output command goes here */ +}devBoAvme9440={ + 5, + NULL, + init, + init_bo_record, + NULL, + write_bo +}; + +/* Create the dset for devBiAvme9440 */ +struct { + long number; + DEVSUPFUN report; /* used by dbior */ + DEVSUPFUN init; /* called 1 time before & after all records */ + DEVSUPFUN init_record; /* called 1 time for each record */ + DEVSUPFUN get_ioint_info; /* used for COS processing */ + DEVSUPFUN read_bi; /* input command goes here */ +}devBiAvme9440={ + 5, + NULL, + NULL, + init_bi_record, + get_bi_int_info, + read_bi +}; + +/* Create the dset for devMbboAvme9440 */ +struct { + long number; + DEVSUPFUN report; + DEVSUPFUN init; + DEVSUPFUN init_record; + DEVSUPFUN get_ioint_info; + DEVSUPFUN write_mbbo; +}devMbboAvme9440={ + 5, + NULL, + NULL, + init_mbbo_record, + NULL, + write_mbbo +}; + +/* Create the dset for devMbbiAvme9440 */ +struct { + long number; + DEVSUPFUN report; + DEVSUPFUN init; + DEVSUPFUN init_record; + DEVSUPFUN get_ioint_info; + DEVSUPFUN read_mbbi; +}devMbbiAvme9440={ + 5, + NULL, + NULL, + init_mbbi_record, + NULL, + read_mbbi +}; + + +/************************************************************************** +* +* Initialization of AVME9440 Binary I/O Card +* +***************************************************************************/ +int devAvme9440Config(ncards,a16base,intvecbase) +int ncards; +int a16base; +int intvecbase; +{ + avme9440_num_links = ncards; + BASEADD = a16base; + INT_VEC_BASE = intvecbase; + init(0); +} + +STATIC long +init(flag) +int flag; +{ + int cardNum, chanNum; + unsigned char probeVal, initVal; + volatile struct avme9440 *p; + + if (init_flag != 0) + return(OK); + + init_flag = 1; + + if (sysBusToLocalAdrs(VME_AM_SUP_SHORT_IO, (char *)(int)BASEADD, (char **)&p) == ERROR) + { + if (devAvme9440Debug >= 5) + printf("devAvme9440: can not find short address space\n"); + return(ERROR); + } + + /* We end up here 1 time before all records are initialized */ + for (cardNum=0; cardNum < avme9440_num_links; cardNum++) + { + if (devAvme9440Debug >= 5) + printf("devAvme9440: Init card %d\n", cardNum); + + probeVal = LED_INIT; /* sends init value to LEDs and disables interrupts */ + + if (vxMemProbe((char*) &(p->boardStatus) , WRITE, 1, &probeVal) < OK) + { + + if (devAvme9440Debug >= 5) + printf("devAvme9440: Probe at 0x%08.8X failed\n", &(p->boardStatus)); + cards[cardNum].card = NULL; /* No card found */ + } + else + { + if (devAvme9440Debug >= 5) + { + printf("devAvme9440: Probe at 0x%08.8X success, board status = 0x%02.2X\n", &(p->boardStatus), probeVal); + printf(" Beginning card %d initialization\n", cardNum); + } + + probeVal = INT_VEC_BASE + cardNum; + + for (chanNum=0; chanNum <= 7; chanNum++) + { + if ((vxMemProbe(((char*) &(p->intVector0) + (2 * chanNum)) , WRITE, 1, &probeVal) == OK) && (devAvme9440Debug >= 5)) + { + printf("devAvme9440: Interrupt vector 0x%02.2X being written to channel %d interrupt\n", probeVal, chanNum); + printf(" vector table entry at address 0x%08.8X\n", (&(p->intVector0) + (2 * chanNum))); + + cards[cardNum].intCnt[chanNum] = 0; /* clear channel interrupt counter */ + } + + scanIoInit(&cards[cardNum].ioscanpvt[chanNum]); /* interrupt initialized per channel */ + } + + probeVal = 0x00; + + if ((vxMemProbe((char*) &(p->intEnable) , WRITE, 1, &probeVal) == OK) && (devAvme9440Debug >= 5)) + printf("devAvme9440: Interrupts disabled for channels 0 - 7\n"); + + probeVal = 0xFF; + + if ((vxMemProbe((char*) &(p->intTypeSelect) , WRITE, 1, &probeVal) == OK) && (devAvme9440Debug >= 5)) + { + printf("devAvme9440: Change of state interrupts set for channels 0 - 7\n"); + printf(" Interrupt level should be set at %d\n", int_level); + } + + probeVal = 0x00; + + if ((vxMemProbe((char*) &(p->intPaternEnable) , WRITE, 1, &probeVal) == OK) && (devAvme9440Debug >= 5)) + printf("devAvme9440: Input pattern detection interrupts disabled for channels 0 - 7\n"); + + probeVal = LED_OKRUN; /* sends init value to LEDs and disables interrupts */ + + if ((vxMemProbe((char*) &(p->boardStatus) , WRITE, 1, &probeVal) == OK) && (devAvme9440Debug >= 5)) + printf("devAvme9440: Card %d initialization complete\n", cardNum); + + cards[cardNum].card = p; /* Remember address of the board */ + + if(intConnect(INUM_TO_IVEC(INT_VEC_BASE + cardNum),(FUNCPTR)avme9440_isr, + (int)&cards[cardNum]) != OK) + printf("devAvme9440: Interrupt connect failed for card %d\n", cardNum); + + + FASTLOCKINIT(&(cards[cardNum].lock)); + FASTUNLOCK(&(cards[cardNum].lock)); /* Init the board lock */ + } + p++; + } + return(OK); +} + + +/************************************************************************** + * + * Interrupt service routine + * + **************************************************************************/ +STATIC void avme9440_isr(struct ioCard *pc) +{ + volatile struct avme9440 *p = pc->card; + volatile unsigned char intStatusLocal = p->intStatus; + unsigned int chanNum; + volatile unsigned char intStatWrite = 0; + + for (chanNum=0; chanNum <= 7; chanNum++) + { + if(intStatusLocal & (1 << chanNum)) + { + scanIoRequest(pc -> ioscanpvt[chanNum]); + intStatWrite |= (1 << chanNum); + } + } + + p->intStatus = intStatWrite; +} + + +/************************************************************************** + * + * BO Initialization (Called one time for each BO AVME9440 card record) + * + **************************************************************************/ +STATIC long init_bo_record(pbo) +struct boRecord *pbo; +{ + int status = 0; + unsigned short stupid; + + /* bo.out must be an VME_IO */ + switch (pbo->out.type) { + + case (VME_IO) : + + if (pbo->out.value.vmeio.signal > 15) + { + pbo->pact = 1; /* make sure we don't process this thing */ + status = S_db_badField; + + if (devAvme9440Debug >= 10) + printf("devAvme9440: Illegal SIGNAL field ->%s<- \n", pbo->name); + + recGblRecordError(status,(void *)pbo, + "devAvme9440 (init_record) Illegal SIGNAL field"); + } + else + { + + pbo->mask = 1; + pbo->mask <<= pbo->out.value.vmeio.signal; + + if (read_card(pbo->out.value.vmeio.card, pbo->mask, &stupid, OUTPUT_REG) == OK) + { + pbo->rbv = pbo->rval = stupid; + if (devAvme9440Debug >= 10) + printf("devAvme9440: ->%s<- Record initialized \n", pbo->name); + } + + else + { + status = 2; + if (devAvme9440Debug >= 10) + printf("devAvme9440: ->%s<- Record failed to initialize \n", pbo->name); + } + + } + break; + + default : + pbo->pact = 1; /* make sure we don't process this thing */ + status = S_db_badField; + + if (devAvme9440Debug >= 10) + printf("devAvme9440: Illegal OUT field ->%s<- \n", pbo->name); + + recGblRecordError(status,(void *)pbo, + "devAvme9440 (init_record) Illegal OUT field"); + } + return(status); +} + +/************************************************************************** + * + * BI Initialization (Called one time for each BI AVME9440 card record) + * + **************************************************************************/ +STATIC long init_bi_record(pbi) +struct biRecord *pbi; +{ + int status = 0; + unsigned short stupid; + + switch (pbi->inp.type) { + case (VME_IO) : + + if (pbi->inp.value.vmeio.signal > 31) + { + pbi->pact = 1; /* make sure we don't process this thing */ + status = S_db_badField; + + if (devAvme9440Debug >= 10) + printf("devAvme9440: Illegal SIGNAL field ->%s<- \n", pbi->name); + + recGblRecordError(status,(void *)pbi, + "devAvme9440 (init_record) Illegal SIGNAL field"); + + } + else + { + pbi->mask = 1; + if (pbi->inp.value.vmeio.signal <= 15) + pbi->mask <<= pbi->inp.value.vmeio.signal; + else + pbi->mask <<= pbi->inp.value.vmeio.signal - 16; + if (read_card(pbi->inp.value.vmeio.card, pbi->mask, &stupid, INPUT_REG) == OK) + { + pbi->rval = stupid; + if (devAvme9440Debug >= 10) + printf("devAvme9440: ->%s<- Record initialized \n", pbi->name); + } + + else + { + status = 2; + if (devAvme9440Debug >= 10) + printf("devAvme9440: ->%s<- Record failed to initialize \n", pbi->name); + } + } + + break; + default: + pbi->pact = 1; /* make sure we don't process this thing */ + status = S_db_badField; + if (devAvme9440Debug >= 10) + printf("devAvme9440: Illegal INP field ->%s<- \n", pbi->name); + recGblRecordError(status,(void *)pbi, + "devAvme9440 (init_record) Illegal INP field"); + } + return(status); +} + + +/************************************************************************** + * + * MBBO Initialization (Called one time for each MBBO AVME9440 card record) + * + **************************************************************************/ +STATIC long init_mbbo_record(pmbbo) +struct mbboRecord *pmbbo; +{ + unsigned short stupid; + struct vmeio *pvmeio; + int status = 0; + + /* mbbo.out must be an VME_IO */ + switch (pmbbo->out.type) { + case (VME_IO) : + + if (pmbbo->out.value.vmeio.signal > 15) + { + pmbbo->pact = 1; /* make sure we don't process this thing */ + status = S_db_badField; + + if (devAvme9440Debug >= 10) + printf("devAvme9440: Illegal SIGNAL field ->%s<- \n", pmbbo->name); + + recGblRecordError(status,(void *)pmbbo, + "devAvme9440 (init_record) Illegal SIGNAL field"); + } + else + { + + pvmeio = &(pmbbo->out.value.vmeio); + pmbbo->shft = pvmeio->signal; + pmbbo->mask <<= pmbbo->shft; + + if (read_card(pmbbo->out.value.vmeio.card, pmbbo->mask, &stupid, OUTPUT_REG) == OK) + { + pmbbo->rbv = pmbbo->rval = stupid; + if (devAvme9440Debug >= 10) + printf("devAvme9440: ->%s<- Record initialized \n", pmbbo->name); + } + + else + { + status = 2; + if (devAvme9440Debug >= 10) + printf("devAvme9440: ->%s<- Record failed to initialize \n", pmbbo->name); + } + + } + break; + + default : + + pmbbo->pact = 1; /* make sure we don't process this thing */ + status = S_db_badField; + + if (devAvme9440Debug >= 10) + printf("devAvme9440: Illegal OUT field ->%s<- \n", pmbbo->name); + + recGblRecordError(status,(void *)pmbbo, + "devAvme9440 (init_record) Illegal OUT field"); + } + return(status); +} + +/************************************************************************** + * + * MBBI Initialization (Called one time for each MBBI AVME9440 card record) + * + **************************************************************************/ +STATIC long init_mbbi_record(pmbbi) +struct mbbiRecord *pmbbi; +{ + int status = 0; + unsigned short stupid; + + /* mbbi.inp must be an VME_IO */ + switch (pmbbi->inp.type) { + case (VME_IO) : + + if (pmbbi->inp.value.vmeio.signal > 31) + { + pmbbi->pact = 1; /* make sure we don't process this thing */ + status = S_db_badField; + + if (devAvme9440Debug >= 10) + printf("devAvme9440: Illegal SIGNAL field ->%s<- \n", pmbbi->name); + + recGblRecordError(status,(void *)pmbbi, + "devAvme9440 (init_record) Illegal SIGNAL field"); + + } + else + { + if (pmbbi->inp.value.vmeio.signal <= 15) + pmbbi->shft = pmbbi->inp.value.vmeio.signal; + else + pmbbi->shft = pmbbi->inp.value.vmeio.signal - 16; + pmbbi->mask <<= pmbbi->shft; + if (read_card(pmbbi->inp.value.vmeio.card, pmbbi->mask, &stupid, INPUT_REG) == OK) + { + pmbbi->rval = stupid; + if (devAvme9440Debug >= 10) + printf("devAvme9440: ->%s<- Record initialized \n", pmbbi->name); + } + else + { + status = 2; + if (devAvme9440Debug >= 10) + printf("devAvme9440: ->%s<- Record failed to initialize \n", pmbbi->name); + } + } + + break; + + default : + pmbbi->pact = 1; /* make sure we don't process this thing */ + status = S_db_badField; + if (devAvme9440Debug >= 10) + printf("devAvme9440: Illegal INP field ->%s<- \n", pmbbi->name); + recGblRecordError(status,(void *)pmbbi, + "devAvme9440 (init_record) Illegal INP field"); + return(status); + } + return(0); +} + + +/************************************************************************** + * + * Perform a write operation from a BO record + * + **************************************************************************/ +STATIC long write_bo(pbo) +struct boRecord *pbo; +{ + + unsigned short stupid; + + if (write_card(pbo->out.value.vmeio.card, pbo->mask, pbo->rval) == OK) + { + if(read_card(pbo->out.value.vmeio.card, pbo->mask, &stupid, OUTPUT_REG) == OK) + { + pbo->rbv = stupid; + return(0); + } + } + + /* Set an alarm for the record */ + recGblSetSevr(pbo, WRITE_ALARM, INVALID_ALARM); + return(2); +} + +/************************************************************************** + * + * Perform a read operation from a BI record + * + **************************************************************************/ +STATIC long read_bi(pbi) +struct biRecord *pbi; +{ + + unsigned short stupid; + unsigned int reg; + + if (pbi->inp.value.vmeio.signal <= 15) + reg = INPUT_REG; + else + reg = OUTPUT_REG; + + if (read_card(pbi->inp.value.vmeio.card, pbi->mask, &stupid, reg) == OK) + { + pbi->rval = stupid; + return(0); + } + + /* Set an alarm for the record */ + recGblSetSevr(pbi, READ_ALARM, INVALID_ALARM); + return(2); +} + + +/************************************************************************** + * + * Perform a write operation from a MBBO record + * + **************************************************************************/ +STATIC long write_mbbo(pmbbo) +struct mbboRecord *pmbbo; +{ + + unsigned short stupid; + + if (write_mbbo_card(pmbbo->out.value.vmeio.card, pmbbo->mask, pmbbo->rval) == OK) + { + if(read_card(pmbbo->out.value.vmeio.card, pmbbo->mask, &stupid, OUTPUT_REG) == OK) + { + pmbbo->rbv = stupid; + return(0); + } + } + + /* Set an alarm for the record */ + recGblSetSevr(pmbbo, WRITE_ALARM, INVALID_ALARM); + return(2); +} + +/************************************************************************** + * + * Perform a read operation from a MBBI record + * + **************************************************************************/ +STATIC long read_mbbi(pmbbi) +struct mbbiRecord *pmbbi; +{ + + unsigned short stupid; + unsigned int reg; + + if (pmbbi->inp.value.vmeio.signal <= 15) + reg = INPUT_REG; + else + reg = OUTPUT_REG; + + if (read_card(pmbbi->inp.value.vmeio.card, pmbbi->mask, &stupid, reg) == OK) + { + pmbbi->rval = stupid; + return(0); + } + /* Set an alarm for the record */ + recGblSetSevr(pmbbi, READ_ALARM, INVALID_ALARM); + return(2); +} + + +/************************************************************************** + * + * Raw read a bitfield from the card + * + **************************************************************************/ +STATIC long read_card(card, mask, value, reg) +short card; /* Link number from DCT */ +unsigned long mask; /* created in init_bo_record() */ +unsigned short *value; /* the value to return from the card */ +int reg; +{ + if (checkLink(card) == ERROR) + return(ERROR); + + if (reg == INPUT_REG) + *value = cards[card].card->inputData & mask; + else + *value = cards[card].card->outputData & mask; + + if (devAvme9440Debug >= 20) + printf("devAvme9440: read 0x%04.4X from card %d\n", *value, card); + + return(OK); +} + +/************************************************************************** + * + * Raw write a bitfield to the card + * + **************************************************************************/ +STATIC long write_card(card, mask, value) +short card; +unsigned long mask; +unsigned long value; +{ + if (checkLink(card) == ERROR) + return(ERROR); + + FASTLOCK(&(cards[card].lock)); + cards[card].card->outputData = (cards[card].card->outputData & ~mask) | value; + FASTUNLOCK(&(cards[card].lock)); + + if (devAvme9440Debug >= 15) + printf("devAvme9440: wrote 0x%04.4X to card %d\n", cards[card].card->outputData, card); + + return(0); +} + +/************************************************************************** + * + * Raw write a bitfield to the card for MBBO records + * + **************************************************************************/ +STATIC long write_mbbo_card(card, mask, value) +short card; +unsigned long mask; +unsigned long value; +{ + if (checkLink(card) == ERROR) + return(ERROR); + + FASTLOCK(&(cards[card].lock)); + cards[card].card->outputData = ((cards[card].card->outputData & ~mask) | (value & mask)); + FASTUNLOCK(&(cards[card].lock)); + + if (devAvme9440Debug >= 15) + printf("devAvme9440: wrote 0x%04.4X to card %d\n", cards[card].card->outputData, card); + + return(0); +} + + +/************************************************************************** + * + * Make sure card number is valid + * + **************************************************************************/ +STATIC int checkLink(card) +short card; +{ + if (card >= avme9440_num_links) + return(ERROR); + if (cards[card].card == NULL) + return(ERROR); + + return(OK); +} + +#define ADDING 0 +#define DELETING 1 +/************************************************************************** + * + * BI record interrupt routine + * + **************************************************************************/ +STATIC long get_bi_int_info(cmd, pbi, ppvt) +int cmd; +struct biRecord *pbi; +IOSCANPVT *ppvt; +{ + + struct vmeio *pvmeio = (struct vmeio *)(&pbi->inp.value); + volatile struct avme9440 *pc = cards[pvmeio->card].card; + unsigned int card; + + *ppvt = cards[pvmeio->card].ioscanpvt[pvmeio->signal]; + + if (cmd == ADDING) /* enable interrupts */ + { + sysIntEnable(int_level); + + pc->boardStatus = LED_OKINTS; /* Initialize global board interrupts */ + + pc->intEnable |= (1 << pvmeio->signal); /* Initialize individual channel interrupts */ + + cards[pvmeio->card].intCnt[pvmeio->signal]++; + + } + else + if(!(--(cards[pvmeio->card].intCnt[pvmeio->signal]))) + pc->intEnable &= ~(1 << pvmeio->signal); /* Disable individual channel interrupts */ + + return(0); +} + diff --git a/src/dev/devSysmon.c b/src/dev/devSysmon.c new file mode 100644 index 000000000..5de541196 --- /dev/null +++ b/src/dev/devSysmon.c @@ -0,0 +1,761 @@ +/* share/src/dev @(#)devSysmonInt.c 1.8 12/13/93 */ + +/***************************************************************** + * + * Author : Michael Hoffberg + * Date: 12-93 + * + ***************************************************************** + * COPYRIGHT NOTIFICATION + ***************************************************************** + + * THE FOLLOWING IS A NOTICE OF COPYRIGHT, AVAILABILITY OF THE CODE, + * AND DISCLAIMER WHICH MUST BE INCLUDED IN THE PROLOGUE OF THE CODE + * AND IN ALL SOURCE LISTINGS OF THE CODE. + + * (C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO + + * Argonne National Laboratory (ANL), with facilities in the States of + * Illinois and Idaho, is owned by the United States Government, and + * operated by the University of Chicago under provision of a contract + * with the Department of Energy. + + * Portions of this material resulted from work developed under a U.S. + * Government contract and are subject to the following license: For + * a period of five years from March 30, 1993, the Government is + * granted for itself and others acting on its behalf a paid-up, + * nonexclusive, irrevocable worldwide license in this computer + * software to reproduce, prepare derivative works, and perform + * publicly and display publicly. With the approval of DOE, this + * period may be renewed for two additional five year periods. + * Following the expiration of this period or periods, the Government + * is granted for itself and others acting on its behalf, a paid-up, + * nonexclusive, irrevocable worldwide license in this computer + * software to reproduce, prepare derivative works, distribute copies + * to the public, perform publicly and display publicly, and to permit + * others to do so. + + ***************************************************************** + * DISCLAIMER + ***************************************************************** + + * NEITHER THE UNITED STATES GOVERNMENT NOR ANY AGENCY THEREOF, NOR + * THE UNIVERSITY OF CHICAGO, NOR ANY OF THEIR EMPLOYEES OR OFFICERS, + * MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL + * LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR + * USEFULNESS OF ANY INFORMATION, APPARATUS, PRODUCT, OR PROCESS + * DISCLOSED, OR REPRESENTS THAT ITS USE WOULD NOT INFRINGE PRIVATELY + * OWNED RIGHTS. + + ***************************************************************** + * LICENSING INQUIRIES MAY BE DIRECTED TO THE INDUSTRIAL TECHNOLOGY + * DEVELOPMENT CENTER AT ARGONNE NATIONAL LABORATORY (708-252-2000). + ***************************************************************** + + * Modification Log: + * ----------------- + * mgh 1/31/94 Started to add interrupt + * ... + * ... + */ + + +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +void SysmonInit(); +static long init(); +static long report(); +static long init_bo_record(), init_bi_record(); +static long init_mbbo_record(), init_mbbi_record(); +static long write_bo(), read_bi(); +static long write_mbbo(), read_mbbi(); +static long get_ioint_info(); +static void Sysmon_isr(); + +int devSysmonDebug = 0; + +/***** devSysmonDebug *****/ + +/** devSysmonDebug == 0 --- no debugging messages **/ +/** devSysmonDebug >= 5 --- hardware initialization information **/ +/** devSysmonDebug >= 10 -- record initialization information **/ +/** devSysmonDebug >= 15 -- write commands **/ +/** devSysmonDebug >= 20 -- read commands **/ + + +struct parm_table { + char *parm_name; + int index; + }; +typedef struct parm_table PARM_TABLE; + + +static PARM_TABLE table[]={ +{"StatusLink", 0}, +{"Dio", 1}, +{"IntMask", 2}, +{"Temperature", 3}, +{"Watchdog", 4}, +{"VXIVector", 5}, +{"IntVector", 6}, +{"IRQ1", 7}, +{"IRQ2", 8}, +{"IRQ3", 9}, +{"IRQ4", 10}, +{"IRQ5", 11}, +{"IRQ6", 12}, +{"IRQ7", 13} +}; + +/*** SysMonStatusLink Rx, Tx ***/ +/*** SysmonDio output, input ***/ +/*** SysmonIntMask interrupt mask ***/ +/*** SysmonTemperature temperature monitor ***/ +/*** SysmonWatchdog watchdog & 4 status LEDs ***/ +/*** SysmonVXIVector VXI interrupt vector ***/ +/*** SysmonIntVector interrupt vector ***/ +/*** SysmonIRQ1 IRQ 1 vector ***/ +/*** SysmonIRQ2 IRQ 1 vector ***/ +/*** SysmonIRQ3 IRQ 1 vector ***/ +/*** SysmonIRQ4 IRQ 1 vector ***/ +/*** SysmonIRQ5 IRQ 1 vector ***/ +/*** SysmonIRQ6 IRQ 1 vector ***/ +/*** SysmonIRQ7 IRQ 1 vector ***/ + +struct sysmon { + char Pad[36]; /*** nF0 - nF17 36 bytes ***/ + unsigned short SysmonStatusLink; /*** nF18 ***/ + unsigned short SysmonDio; /*** nF19 ***/ + unsigned short SysmonIntMask; /*** nF20 ***/ + unsigned short SysmonTemperature; /*** nF21 ***/ + unsigned short SysmonWatchdog; /*** nF22 ***/ + unsigned short SysmonVXIVector; /*** nF23 ***/ + unsigned short SysmonIntVector; /*** nF24 ***/ + unsigned short SysmonIRQ1; /*** nF25 ***/ + unsigned short SysmonIRQ2; /*** nF26 ***/ + unsigned short SysmonIRQ3; /*** nF27 ***/ + unsigned short SysmonIRQ4; /*** nF28 ***/ + unsigned short SysmonIRQ5; /*** nF29 ***/ + unsigned short SysmonIRQ6; /*** nF30 ***/ + unsigned short SysmonIRQ7; /*** nF31 ***/ +}; + +struct pvtarea { + int index; + unsigned short mask; + }; + +struct ioCard { /* structure maintained for each card */ + int cardValid; /* card exists */ + volatile unsigned short *ThisCard; /* address of this cards registers */ + FAST_LOCK lock; /* semaphore */ + IOSCANPVT ioscanpvt; /* list of records that are processed at interrupt */ +}; + + +#define CONST_NUM_LINKS 1 +#define STATIC + +static int VMEintVector = 0x71; +static int VMEintLevel = 0x06; +static int VXIintVector = 0x72; +static unsigned short *SYSMON_BASE = (unsigned short *) 0x8b80; + +/* #define int1 0x71 */ +/* #define int2 0x72 */ +/* #define intlevel 0x06 */ +/* #define SYSMON_BASE 0x8b80 hard coded base address */ + +#define INITLEDS 0xff +#define mikeOFFSET 0x24 /* where first function starts */ + +volatile static struct sysmon *sysmon_base; /*base pointer of board */ +static struct ioCard cards[CONST_NUM_LINKS]; /* card information structure */ +static int init_flag = 0; +static int interrupt_info[2]; /*0x71, 0x72*/ + +/* Create the dset for devBoSysmon */ +struct dset_sysmon { + long number; + DEVSUPFUN report; /* used by dbior */ + DEVSUPFUN init; /* called 1 time before & after all records */ + DEVSUPFUN init_record; /* called 1 time for each record */ + DEVSUPFUN get_ioint_info; /* used for COS processing */ + DEVSUPFUN read_write; /* output command goes here */ +}; +typedef struct dset_sysmon DSET_SYSMON; + +DSET_SYSMON devEventSysmon={ + 5, + NULL, + NULL, + NULL, + get_ioint_info, + NULL +}; + +DSET_SYSMON devBoSysmon={ + 5, + NULL, + NULL, + init_bo_record, + NULL, + write_bo +}; + +/* Create the dset for devBiSysmon */ +DSET_SYSMON devBiSysmon={ + 5, + NULL, + NULL, + init_bi_record, + NULL, + read_bi +}; + +/* Create the dset for devMbboSysmon */ +DSET_SYSMON devMbboSysmon={ + 5, + NULL, + NULL, + init_mbbo_record, + NULL, + write_mbbo +}; + +/* Create the dset for devMbbiSysmon */ +DSET_SYSMON devMbbiSysmon={ + 5, + NULL, + NULL, + init_mbbi_record, + NULL, + read_mbbi +}; + +/************************* +initialization of the device support +************************/ + +void SysmonInit( + unsigned long xSYSMON_BASE, + int xVMEintVector, + int xVMEintLevel, + int xVXIintVector + ) +{ + if ( 64 < xVMEintVector || xVMEintVector < 256 ) + VMEintVector = xVMEintVector; + if (devSysmonDebug >= 5) + printf("devSysmon: SysmonInit VME int vector = 0x%X\n", VMEintVector); + + if ( 0 > xVMEintLevel || xVMEintLevel < 8) + VMEintLevel = xVMEintLevel; + if (devSysmonDebug >= 5) + printf("devSysmon: SysmonInit VME int level = %d\n", VMEintLevel); + + if ( 64 < xVXIintVector || xVXIintVector < 256 ) + VXIintVector = xVXIintVector; + if (devSysmonDebug >= 5) + printf("devSysmon: SysmonInit VXI int vector = 0x%X\n", VXIintVector); + + SYSMON_BASE = (unsigned short *) xSYSMON_BASE; + if (devSysmonDebug >= 5) + printf("devSysmon: SysmonInit VME (VXI) base address = 0x%X\n", SYSMON_BASE); + + interrupt_info[0] = VMEintVector; /*0x71*/ + interrupt_info[1] = VXIintVector; /*0x72*/ + init(0); + + } + + +/************************************************** + initialization of isr + ************************************************/ + +static void Sysmon_isr(IOSCANPVT ioscanpvt) +{ + logMsg("In Sysmon_isr\n"); + scanIoRequest(ioscanpvt); +} + + + +/************************************************************************** +* +* Initialization of SYSMON Binary I/O Card +* +***************************************************************************/ +static long init(int flag) +{ + int j; + unsigned char probeVal, initVal; + struct sysmon *sm; + + + if (init_flag != 0) + return(OK); + + init_flag = 1; + + if (sysBusToLocalAdrs(VME_AM_SUP_SHORT_IO, (char *)SYSMON_BASE, (char **)&sysmon_base) == ERROR) + { + if (devSysmonDebug >= 5) + printf("devSysmon: can not find short address space\n"); + return(ERROR); + } + + /* We end up here 1 time before all records are initialized */ + for (j=0; j < CONST_NUM_LINKS; j++) + { + if (devSysmonDebug >= 5) + printf("devSysmon: init link %d\n", j); + + probeVal = INITLEDS; + + if (devSysmonDebug >= 5) + printf("devSysmon: init SysmonWatchdog 0x%X\n", (char *)&sysmon_base[j].SysmonWatchdog); + + if (vxMemProbe((char *)&sysmon_base[j].SysmonWatchdog, WRITE, sizeof(probeVal), &probeVal) != OK) + { + cards[j].cardValid = 0; /* No card found */ + if (devSysmonDebug >= 5) + printf("devSysmon: init vxMemProbe FAILED\n"); + } + else + { + probeVal = 0; + vxMemProbe((char *)&sysmon_base[j].SysmonIntMask, WRITE, sizeof(probeVal), &probeVal); + cards[j].cardValid = 1; /* Remember address of the board */ + FASTLOCKINIT(&(cards[j].lock)); + FASTUNLOCK(&(cards[j].lock)); /* Init the board lock */ + cards[j].ThisCard = &sysmon_base[j].SysmonStatusLink; + + if (devSysmonDebug >= 5) + printf("devSysmon: init address\n"); + + + scanIoInit(&cards[j].ioscanpvt); /* interrupt initialized */ + + if (devSysmonDebug >= 5) + printf("devSysmon: init ScanIoInit \n"); + + sm = (struct sysmon *) &sysmon_base[j]; + if (devSysmonDebug >= 5) + printf("devSysmon: init address of System Monitor %8.8x \n", sm); + + sm->SysmonIntVector = interrupt_info[0]; + if (devSysmonDebug >= 5) + printf("devSysmon: init Interrupt vector loaded \n"); + + if(intConnect(INUM_TO_IVEC(interrupt_info[j]),(FUNCPTR)Sysmon_isr, + (int)cards[j].ioscanpvt)!=OK) { + errPrintf(M_devSup, __FILE__, __LINE__, "devSysmon (init) intConnect failed \n"); + return(M_devSup); + + if (devSysmonDebug >= 5) + printf("devSysmon: init intConnect\n"); + + } + + if (devSysmonDebug >= 5) + printf("devSysmon: init vxMemProbe OK\n"); + + } + } + return(OK); +} + +/*************************************************************************** + generic init record + *************************************************************************/ + +static long generic_init_record(struct dbCommon *pr, DBLINK *link) +{ + struct vmeio* pvmeio = (struct vmeio*)&(link->value); + int table_size, j; + struct pvtarea * pvt; + + switch (link->type) + { + case (VME_IO) : break; + default: + recGblRecordError(S_dev_badBus,(void *)pr, + "devSysmon (init_record) Illegal Bus Type"); + return(S_dev_badBus); + } + + /* makes sure that signal is valid */ + if (pvmeio->signal > 15) + { + pr->pact = 1; /* make sure we don't process this thing */ + + if (devSysmonDebug >= 10) + printf("devSysmon: Illegal SIGNAL field ->%s<- \n", pr->name); + + recGblRecordError(S_dev_badSignal,(void *)pr, + "devSysmon (init_record) Illegal SIGNAL field"); + return(S_dev_badSignal); + } + + /* makes sure that card is valid */ + if (pvmeio->card > CONST_NUM_LINKS || !cards[pvmeio->card].cardValid ) + { + pr->pact = 1; /* make sure we don't process this thing */ + + if (devSysmonDebug >= 10) + { + printf("devSysmon: Illegal CARD field ->%s, %d<- \n", pr->name, pvmeio->card); + if(!cards[pvmeio->card].cardValid) + printf("devSysmon: Illegal CARD field card NOT VALID \n\n"); + } + + recGblRecordError(S_dev_badCard,(void *)pr, + "devSysmon (init_record) Illegal CARD field"); + return(S_dev_badCard); + } + + /* verifies that parm field is valid */ + + table_size = sizeof(table) / sizeof(PARM_TABLE); + for (j = 0; (j < table_size) && strcmp(table[j].parm_name, pvmeio->parm); j++ ); + + if (j >= table_size) + { + pr->pact = 1; /* make sure we don't process this thing */ + + if (devSysmonDebug >= 10) + printf("devSysmon: Illegal parm field ->%s<- \n", pr->name); + + recGblRecordError(S_dev_badSignal,(void *)pr, + "devSysmon (init_record) Illegal parm field"); + return(S_dev_badSignal); + } + if (devSysmonDebug >= 10) + printf("devSysmon: %s of record type %d - %s\n", pr->name, j, table[j].parm_name); + + pvt = (struct pvtarea *) malloc(sizeof(struct pvtarea)); + pvt->index = j; + + pr->dpvt = pvt; + + return(0); +} + + +/************************************************************************** + * + * BO Initialization (Called one time for each BO SYSMON card record) + * + **************************************************************************/ +static long init_bo_record(struct boRecord *pbo) +{ + struct vmeio* pvmeio = (struct vmeio*)&(pbo->out.value); + int status = 0; + int table_size; + struct pvtarea * pvt; + + status = generic_init_record((struct dbCommon *)pbo, &pbo->out); + + if(status) + return(status); + + pvt = pbo->dpvt; + + pvt->mask = 1<signal; + + return (0); +} + +/************************************************************************** + * + * BI Initialization (Called one time for each BI SYSMON card record) + * + **************************************************************************/ +static long init_bi_record(struct biRecord *pbi) +{ + struct vmeio* pvmeio = (struct vmeio*)&(pbi->inp.value); + int status = 0; + int table_size; + struct pvtarea * pvt; + + status = generic_init_record((struct dbCommon *)pbi, &pbi->inp); + + if(status) + return(status); + + pvt = pbi->dpvt; + + pvt->mask = 1<signal; + + return (0); +} + + +/************************************************************************** + * + * MBBO Initialization (Called one time for each MBBO SYSMON card record) + * + **************************************************************************/ +static long init_mbbo_record(struct mbboRecord *pmbbo) +{ + struct vmeio* pvmeio = (struct vmeio*)&(pmbbo->out.value); + int status = 0; + int table_size; + struct pvtarea * pvt; + + status = generic_init_record((struct dbCommon *)pmbbo, &pmbbo->out); + + if(status) + return(status); + + if (pvmeio->signal > 15) + { + recGblRecordError(S_dev_badSignal,(void *)pmbbo, + "devSysmon(init_mbbo_record) Illegal OUT signal number"); + return(S_dev_badSignal); + } + + pvt = pmbbo->dpvt; + pmbbo->shft = pvmeio->signal; + pmbbo->mask <<= pmbbo->shft; + + return(0); + +} + +/************************************************************************** + * + * MBBI Initialization (Called one time for each MBBI SYSMON card record) + * + **************************************************************************/ + +static long init_mbbi_record(struct mbbiRecord *pmbbi) +{ + struct vmeio* pvmeio = (struct vmeio*)&(pmbbi->inp.value); + int status = 0; + int table_size; + struct pvtarea * pvt; + + status = generic_init_record((struct dbCommon *)pmbbi, &pmbbi->inp); + +/* load temperature values up */ + + if (!strcmp(table[3].parm_name, pvmeio->parm)) + { + printf("devSysmon: mbbi record is Temperature\n"); + + pmbbi->nobt = 0x08; /* make sure 8 bits wide */ + + /* load up proper mask values */ + pmbbi->zrvl = 0xff; + pmbbi->onvl = 0xfe; + pmbbi->twvl = 0xfc; + pmbbi->thvl = 0xf8; + pmbbi->frvl = 0xf0; + pmbbi->fvvl = 0xe0; + pmbbi->sxvl = 0xc0; + pmbbi->svvl = 0x80; + pmbbi->eivl = 0x10; + pmbbi->nivl = 0x00; + pmbbi->tevl = 0x55; + pmbbi->elvl = 0x55; + pmbbi->tvvl = 0x55; + pmbbi->ttvl = 0x55; + pmbbi->ftvl = 0x55; + pmbbi->ffvl = 0x55; + + /* load up proper string values, if you don't like it, change the strings somewhere else */ + strcpy(pmbbi->zrst,"Calibration Error (Boy is it cold)"); + strcpy(pmbbi->onst,"20"); + strcpy(pmbbi->twst,"25"); + strcpy(pmbbi->thst,"30"); + strcpy(pmbbi->frst,"35"); + strcpy(pmbbi->fvst,"40"); + strcpy(pmbbi->sxst,"45"); + strcpy(pmbbi->svst,"50"); + strcpy(pmbbi->eist,"Danger 55"); + strcpy(pmbbi->nist,"way too hot"); + strcpy(pmbbi->test,"undefined"); + strcpy(pmbbi->elst,"undefined"); + strcpy(pmbbi->tvst,"undefined"); + strcpy(pmbbi->ttst,"undefined"); + strcpy(pmbbi->ftst,"undefined"); + strcpy(pmbbi->ffst,"undefined"); + } + + if(status) + return(status); + + if (pvmeio->signal > 15) + { + recGblRecordError(S_dev_badSignal,(void *)pmbbi, + "devSysmon(init_mbbi_record) Illegal IN signal number"); + return(S_dev_badSignal); + } + + pvt = pmbbi->dpvt; + pmbbi->shft = pvmeio->signal; + pmbbi->mask <<= pmbbi->shft; + + return(0); +} + +/************************************************************************** + * + * Perform a write operation from a BO record + * + **************************************************************************/ +static long write_bo(struct boRecord *pbo) +{ + struct pvtarea *pvt = pbo->dpvt; + struct vmeio *pvmeio = (struct vmeio*)&(pbo->out.value); + volatile unsigned short *reg; + unsigned short regVal; + + FASTLOCK(&cards[pvmeio->card].lock); + reg = &cards[pvmeio->card].ThisCard[pvt->index]; + regVal = *reg; + + if(pbo->val) + { + regVal |= pvt->mask; + } + else + { + regVal &= ~pvt->mask; + } + + *reg = regVal; + FASTUNLOCK(&cards[pvmeio->card].lock); + + return(0); +} + +/************************************************************************** + * + * Perform a read operation from a BI record + * + **************************************************************************/ +static long read_bi(struct biRecord *pbi) +{ + struct pvtarea *pvt = pbi->dpvt; + struct vmeio *pvmeio = (struct vmeio*)&(pbi->inp.value); + volatile unsigned short *reg; + unsigned short regVal; + + reg = &cards[pvmeio->card].ThisCard[pvt->index]; + + FASTLOCK(&cards[pvmeio->card].lock); + regVal = *reg; + FASTUNLOCK(&cards[pvmeio->card].lock); + + regVal &= pvt->mask; + + if(regVal) + pbi->rval = 1; + else + pbi->rval = 0; + + return(0); +} + + +/************************************************************************** + * + * Perform a write operation from a MBBO record + * + **************************************************************************/ +static long write_mbbo(struct mbboRecord *pmbbo) +{ + struct pvtarea *pvt = pmbbo->dpvt; + struct vmeio *pvmeio = (struct vmeio*)&(pmbbo->out.value); + volatile unsigned short *reg; + unsigned short regVal; + + FASTLOCK(&cards[pvmeio->card].lock); + reg = &cards[pvmeio->card].ThisCard[pvt->index]; + regVal = *reg; + regVal = (regVal & ~pmbbo->mask) | (pmbbo->rval & pmbbo->mask); + *reg = regVal; + FASTUNLOCK(&cards[pvmeio->card].lock); + + return(0); +} + +/************************************************************************** + * + * Perform a read operation from a MBBI record + * + **************************************************************************/ +static long read_mbbi(struct mbbiRecord *pmbbi) +{ + + struct pvtarea *pvt = pmbbi->dpvt; + struct vmeio *pvmeio = (struct vmeio*)&(pmbbi->inp.value); + volatile unsigned short *reg; + unsigned short regVal; + + reg = &cards[pvmeio->card].ThisCard[pvt->index]; + + FASTLOCK(&cards[pvmeio->card].lock); + regVal = *reg; + FASTUNLOCK(&cards[pvmeio->card].lock); + + pmbbi->rval=regVal&pmbbi->mask; + pmbbi->udf = 0; + return(0); +} + +/***************************************************** + record support interrupt routine + ***************************************************/ + +static long get_ioint_info( + int cmd, + struct eventRecord *pr, + IOSCANPVT *ppvt) +{ + struct vmeio *pvmeio = (struct vmeio *)(&pr->inp.value); + unsigned int card,intvec; + + if(pvmeio->card > CONST_NUM_LINKS) { + recGblRecordError(S_dev_badCard,(void *)pr, + "devSysmon (get_int_info) exceeded maximum supported cards"); + return(S_dev_badCard); + } + *ppvt = cards[pvmeio->card].ioscanpvt; + + + if (cmd == 0) + sysIntEnable(VMEintLevel); + + return(0); +} +