diff --git a/src/dev/devMpc.c b/src/dev/devMpc.c new file mode 100644 index 000000000..1641483e7 --- /dev/null +++ b/src/dev/devMpc.c @@ -0,0 +1,1118 @@ +/***************************************************************** + * + * Author: John Winans + * Date: 3/95 + * + * $Id$ + * + ***************************************************************** + * 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). + ***************************************************************** + * + * $Log$ + * + * 00: + * HBI OSC AND3 AND2 AND1 OUT2 OUT1 OUT x x x x T2 T1 RR TEST + * + * HBI = Heartbeat in OK (just the input HB is OK) + * OSC = Onboard OSC OK + * AND3 = AND2 && LB2 + * AND2 = AND1 && LB1 + * AND1 = HBI + * OUT2 = LB2 + * OUT1 = LB1 + * OUT = OUT1 && OUT2 + * T2 = (output) force LB2 == 0 + * T1 = (output) force LB1 == 0 + * RR = (output) pulse 0-1-0 to reset LED latches + * TEST = (output) 1 = puts latch logic into test mode, 0 = normal + * + * 02: IRQ mask of + * 7r 7f 6r 6f 5r 5f 4r 4f 3r 3f 2r 2f 1r 1f 0r 0f + * + * 04: IRQ mask of + * 15r 15f 14r 14f 13r 13f 12r 12f 11r 11f 10r 10f 9r 9f 8r 8f + * + * 06: IRQ mask of + * 23r 23f 22r 22f 21r 21f 20r 20f 19r 19f 18r 18f 17r 17f 16r 16f + * + * input [0..19] = Signals 0 thru 19 + * input 20 = OR of all inputs, 1=all true + * input 21 = OR of all test signals, 1=all true + * input 22 = AND of both logic blocks, LB1 && LB2 + * input 23 = Input heartbeat OK, 1 = OK + * r = rising, f = falling + * + * 08: Latched image of transition + * 7r 7f 6r 6f 5r 5f 4r 4f 3r 3f 2r 2f 1r 1f 0r 0f + * + * 0a: Latched image of transition + * 15r 15f 14r 14f 13r 13f 12r 12f 11r 11f 10r 10f 9r 9f 8r 8f + * + * 0c: Latched image of transition + * 23r 23f 22r 22f 21r 21f 20r 20f 19r 19f 18r 18f 17r 17f 16r 16f + * + * 0e: IRQ settings + * xxxxELLLVVVVVVVV + * + * x = don't care + * E = Enable IRQs + * LLL = IRQ level + * VVVVVVVV = IRQ vector + * + * 10: State of LEDs + * 7c 7l 6c 6l 5c 5l 4c 4l 3c 3l 2c 2l 1c 1l 0c 0l + * + * 12: State of LEDs + * 15c 15l 14c 14c 13l 13c 12l 12c 11l 11c 10c 10l 9c 9l 8c 8l + * + * 14: State of LEDs + * xxx xxx xxx xxx HBI HBO TRP LT 19c 19l 18c 18l 17c 17l 16c 16l + * + * LED[0..19] = Signals 0 thru 19 + * LT = ORd result of all LED latch signals, 1=all true + * TRP = ORd result of all trip outputs, 1 = all true + * HBO = Heartbeat out OK = AND3 (HBI && LB1 &&LB2) + * HBI = Heartbeat in OK (just the input HB is OK) + * xxx = don't care + * c = current state, l = latched + * + * 16: + * TRIP[15..0] + * + * 18: + * xxxxxxxx TRIP[20..16] + * + * NOTE: the TRIP outputs are negative-true logic feeding the OR gate + * referenced by byte 06, label 21[rf] + * + ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alarm.h" +#include "dbDefs.h" +#include "dbAccess.h" +#include "recSup.h" +#include "devSup.h" +#include "link.h" + +#include "aiRecord.h" +#include "boRecord.h" +#include "biRecord.h" +#include "mbboRecord.h" +#include "mbbiRecord.h" + +#include "dbScan.h" +#include "errMdef.h" +#include "eventRecord.h" + +#define MPC_DOG_POLL_RATE 6 +#define NUM_LINKS 4 /* Max number of allowed cards */ +#define STATIC /* static /* */ + +int MpcConfig(); +STATIC long MpcInit(); +STATIC long MpcReport(); +STATIC void MpcIsr(); + +STATIC long MpcInitBoRec(); +STATIC long MpcWriteBo(); + +STATIC long MpcInitBiRec(); +STATIC long MpcReadBi(); +STATIC long MpcGetIointInfoBi(); + +#if 0 +STATIC long MpcInitMbboRec(); +STATIC long MpcInitMbbiRec(); + +STATIC long MpcWriteMbbo(), MpcReadMbbi(); +#endif + +int devMpcDebug = 0; + +typedef struct ParmTableStruct +{ + char *parm_name; +} ParmTableStruct; + +#define MPC_PARM_TESTMODE 0 +#define MPC_PARM_RESETLATCHES 1 +#define MPC_PARM_TESTLB1 2 +#define MPC_PARM_TESTLB2 3 +#define MPC_PARM_TI 4 + +#define MPC_PARM_LB1OK 5 +#define MPC_PARM_LB2OK 6 +#define MPC_PARM_AND1OK 7 +#define MPC_PARM_AND2OK 8 +#define MPC_PARM_AND3OK 9 +#define MPC_PARM_OSCOK 10 +#define MPC_PARM_HBIOK 11 +#define MPC_PARM_HBOOK 12 +#define MPC_PARM_DI 13 +#define MPC_PARM_LI 14 +#define MPC_PARM_ALLLATCHTRUE 15 +#define MPC_PARM_ALLTRIPTRUE 16 + +static ParmTableStruct ParmTable[] = +{ + /* Binary Out (BI allowed for readback) */ + {"TestMode"}, /* 1 = place unit in test mode */ + {"ResetLatches"}, /* A one-shot that resets the latches */ + {"TestLb1"}, /* 1 = force a false from LB1 */ + {"TestLb2"}, /* 1 = force a falce from LB2 */ + {"Ti"}, /* Trip test input bit values */ + + /* Binary In */ + + {"LB1OK"}, /* 1 = LB1 output true */ + {"LB2OK"}, /* 1 = LB2 output true */ + {"And1OK"}, /* AND1 output true */ + {"And2OK"}, /* AND2 output true */ + {"And3OK"}, /* AND3 output true */ + {"OscOK"}, /* Oscilator OK */ + {"HBIOK"}, /* Heart beat input OK */ + {"HBOOK"}, /* Heart beat output OK */ + {"Di"}, /* Current input values */ + {"Li"}, /* Latched input values */ + + {"AllLatchTrue"}, /* 1 = all latch signals are true */ + {"AllTripTrue"}, /* 1 = all test trip signals are true */ +}; +#define PARM_TABLE_SIZE (sizeof(ParmTable)/sizeof(ParmTable[0])) + +typedef struct MpcStruct { + volatile unsigned short Stat; + volatile unsigned short EdgeMask0; + volatile unsigned short EdgeMask1; + volatile unsigned short EdgeMask2; + volatile unsigned short EdgeState0; + volatile unsigned short EdgeState1; + volatile unsigned short EdgeState2; + volatile unsigned short Irq; + + volatile unsigned short LatchState0; + volatile unsigned short LatchState1; + volatile unsigned short LatchState2; + volatile unsigned short LatchTest0; + volatile unsigned short LatchTest1; + volatile char fill[6+32]; +}MpcStruct; + +/***************************************************************************** + * + * Per-record private structure hooked onto dpvt. + * + *****************************************************************************/ +typedef struct PvtStruct +{ + int index; /* Parameter/operation type */ + volatile unsigned short *pReg; /* Pointer to actual register */ + unsigned short mask; /* value mask derived from signal number */ +} PvtStruct; + +/***************************************************************************** + * + * Per-card global variables. + * + *****************************************************************************/ +struct ioCard { /* structure maintained for each card */ + int CardValid; /* card exists */ + unsigned long MpcBaseA16; /* A16 card address */ + int VMEintVector; /* IRQ vector used by mpc */ + int VMEintLevel; /* IRQ level */ + + MpcStruct *MpcBase; /* Physical card address */ + FAST_LOCK lock; /* semaphore */ + IOSCANPVT ioscanpvt; /* Token for I/O intr scanned records */ + WDOG_ID Doggie; /* Used to poll the I/O pinz */ + unsigned short s0; + unsigned short s1; + unsigned short s2; +}; + +static struct ioCard cards[NUM_LINKS]; /* card information structure */ + +typedef struct MpcDsetStruct { + 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 */ +} MpcDsetStruct; + +MpcDsetStruct devBoMpc={ + 5, + NULL, + MpcInit, + MpcInitBoRec, + NULL, + MpcWriteBo +}; + +/* Create the dset for devBiMpc */ +MpcDsetStruct devBiMpc={ + 5, + MpcReport, + MpcInit, + MpcInitBiRec, + MpcGetIointInfoBi, + MpcReadBi +}; + +#if 0 +/* Create the dset for devMbboMpc */ +MpcDsetStruct devMbboMpc={ + 5, + NULL, + MpcInit, + MpcInitMbboRec, + NULL, + MpcWriteMbbo +}; + +/* Create the dset for devMbbiMpc */ +MpcDsetStruct devMbbiMpc={ + 5, + NULL, + MpcInit, + MpcInitMbbiRec, + NULL, + MpcReadMbbi +}; +#endif + +/***************************************************************************** + * + *****************************************************************************/ +STATIC long MpcReport(void) +{ + int j; + + for (j=0; j= NUM_LINKS)) + { + printf("ERROR: Invalid card number specified %d\n", Card); + return(0); + } + + cards[Card].CardValid = 0; + cards[Card].VMEintVector = 0; + cards[Card].VMEintLevel = 0; + cards[Card].MpcBaseA16 = 0; + + if ((VMEintVector < 64) || (VMEintVector > 255)) + { + printf("devMpc: ERROR VME IRQ vector out of range\n"); + return(0); + } + if (devMpcDebug >= 5) + printf("devMpc: MpcInit VME int vector = 0x%2.2X\n", VMEintVector); + + if ((VMEintLevel < 0) || (VMEintLevel > 7)) + { + printf("devMpc: ERROR VME IRQ level out of range\n"); + return(0); + } + if (devMpcDebug >= 5) + printf("devMpc: MpcInit VME int level = %d\n", VMEintLevel); + + if ((MpcBaseA16 > 0x0ffff) || (MpcBaseA16 & 0x003f)) + { + printf("devMpc: ERROR Invalid address specified 0x%4.4X\n", MpcBaseA16); + return(0); + } + if (devMpcDebug >= 5) + printf("devMpc: MpcInit VME base address = %p\n", MpcBaseA16); + + cards[Card].VMEintVector = VMEintVector; + cards[Card].VMEintLevel = VMEintLevel; + cards[Card].MpcBaseA16 = MpcBaseA16; + + cards[Card].CardValid = 1; + return(0); +} + +/***************************************************************************** + * + * Used as an alternate to raw IRQ handling because the IRQ rate can exceed + * what vxWorks can handle. Using the MpcDogWatcher will allow I/O Scanned + * records to operate w/o actually using IRQs. + * + *****************************************************************************/ +STATIC void MpcDogWatcher(struct ioCard *p) +{ + unsigned short junk0; + unsigned short junk1; + unsigned short junk2; + + junk0 = p->MpcBase->LatchState0; + junk1 = p->MpcBase->LatchState1; + junk2 = p->MpcBase->LatchState2; + + if ((p->s0 != junk0) || (p->s1 != junk1) || (p->s2 != junk2)) + { + if (devMpcDebug > 9) + { + logMsg("MpcDogWatcher was %04.4X %04.4X %04.4X\n", p->s0, p->s1, p->s2); + logMsg("MpcDogWatcher is %04.4X %04.4X %04.4X\n", junk0, junk1, junk2); + } + scanIoRequest(p->ioscanpvt); + } + + p->s0 = junk0; + p->s1 = junk1; + p->s2 = junk2; + + if (devMpcDebug > 10) + logMsg("MpcDogWatcher %04.4X %04.4X %04.4X\n", junk2, junk1, junk0); + + wdStart(p->Doggie, MPC_DOG_POLL_RATE, (FUNCPTR)MpcDogWatcher, (int)p); + + return; +} +/************************************************************************** + * + * IRQ handler registered in MpcInit(). This routine clears the status + * registers and fires off any IO-scanned records. + * + **************************************************************************/ +STATIC void MpcIsr(int Card) +{ + unsigned short junk0; + unsigned short junk1; + unsigned short junk2; + + junk0 = cards[Card].MpcBase->EdgeState0; + junk1 = cards[Card].MpcBase->EdgeState1; + junk2 = cards[Card].MpcBase->EdgeState2; + + if (devMpcDebug >= 10) + logMsg("MpcIsr %04.4X %04.4X %04.4X\n", junk2, junk1, junk0); + + scanIoRequest(cards[Card].ioscanpvt); + + /* Disable and then reenable the IRQs */ + + cards[Card].MpcBase->EdgeMask0 = 0; + cards[Card].MpcBase->EdgeMask1 = 0; + cards[Card].MpcBase->EdgeMask2 = 0; + + cards[Card].MpcBase->EdgeMask0 = 0xffff; + cards[Card].MpcBase->EdgeMask1 = 0xffff; + cards[Card].MpcBase->EdgeMask2 = 0xffff; + + return; +} +/************************************************************************** + * + * Initialization of MPC Binary I/O Card. Called from the DSET init + * entry points. + * + ***************************************************************************/ +STATIC long MpcInit(int flag) +{ + int Card; + unsigned short probeVal; + static int init_flag = 0; + unsigned short junk; + + if (init_flag != 0) + return(OK); + + init_flag = 1; + + /* We end up here 1 time before all records are initialized */ + for (Card=0; Card < NUM_LINKS; Card++) + { + if (cards[Card].CardValid != 0) + { + if (devMpcDebug >= 5) + logMsg("devMpc: init link %d\n", Card); + + if (sysBusToLocalAdrs(VME_AM_SUP_SHORT_IO, (char *)cards[Card].MpcBaseA16, (char **)&(cards[Card].MpcBase)) == ERROR) + { + if (devMpcDebug >= 5) + logMsg("devMpc: can not find short address space\n"); + return(ERROR); /* BUG */ + } + + if (vxMemProbe((char *)&cards[Card].MpcBase->Stat, READ, sizeof(cards[Card].MpcBase->Stat), (char *)&probeVal) != OK) + { + cards[Card].CardValid = 0; /* No card found */ + if (devMpcDebug >= 5) + logMsg("devMpc: init vxMemProbe FAILED\n"); + } + else + { + if (devMpcDebug >= 5) + logMsg("devMpc: init vxMemProbe OK\n"); + + FASTLOCKINIT(&(cards[Card].lock)); + + if (devMpcDebug >= 5) + logMsg("devMpc: init address\n"); + + scanIoInit(&cards[Card].ioscanpvt); /* interrupt initialized */ + + if (devMpcDebug >= 5) + logMsg("devMpc: init ScanIoInit \n"); + + if (devMpcDebug >= 5) + logMsg("devMpc: init address of MPC Card %8.8x \n", cards[Card].MpcBase); + +#ifdef MPC_USE_IRQS + /* Register a reboot handler in here */ + + /* Read all the stat regs here to clear bogus edges. */ + junk = cards[Card].MpcBase->EdgeState0; + junk = cards[Card].MpcBase->EdgeState1; + junk = cards[Card].MpcBase->EdgeState2; + + + cards[Card].MpcBase->EdgeMask0 = 0xffff; + cards[Card].MpcBase->EdgeMask1 = 0xffff; + cards[Card].MpcBase->EdgeMask2 = 0xffff; + + probeVal = cards[Card].VMEintVector; + probeVal |= (cards[Card].VMEintLevel<<8)|0x0800; + + cards[Card].MpcBase->Irq = probeVal; + + if (devMpcDebug >= 5) + logMsg("devMpc: init Interrupt vector loaded \n"); + + if(intConnect(INUM_TO_IVEC(cards[Card].VMEintVector),(FUNCPTR)MpcIsr, Card)!=OK) + { + logMsg("devMpc (init) intConnect failed \n"); + return(ERROR); + } + + /* Read all the stat regs here to clear any bogus edges. */ + junk = cards[Card].MpcBase->EdgeState0; + junk = cards[Card].MpcBase->EdgeState1; + junk = cards[Card].MpcBase->EdgeState2; +#else + cards[Card].MpcBase->EdgeMask0 = 0; + cards[Card].MpcBase->EdgeMask1 = 0; + cards[Card].MpcBase->EdgeMask2 = 0; + + /* Read all the stat regs here to clear any bogus edges. */ + junk = cards[Card].MpcBase->EdgeState0; + junk = cards[Card].MpcBase->EdgeState1; + junk = cards[Card].MpcBase->EdgeState2; + + cards[Card].s0 = 0; + cards[Card].s1 = 0; + cards[Card].s2 = 0; + + cards[Card].Doggie = wdCreate(); + wdStart(cards[Card].Doggie, MPC_DOG_POLL_RATE, (FUNCPTR)MpcDogWatcher, (int)(&cards[Card])); +#endif + } +#ifdef MPC_USE_IRQS + sysIntEnable(cards[Card].VMEintLevel); +#endif + } + } + return(OK); +} + +/*************************************************************************** + * + * generic init record + * + ***************************************************************************/ +static long GenericInitRecord(struct dbCommon *pr, DBLINK *link) +{ + struct vmeio *pvmeio = (struct vmeio*)&(link->value); + int j; + PvtStruct *pvt; + + if (link->type != VME_IO) + { + recGblRecordError(S_dev_badBus,(void *)pr, "devMpc (init_record) Illegal Bus Type"); + return(S_dev_badBus); + } + + /* makes sure that card is valid */ + if ((pvmeio->card > NUM_LINKS) || (pvmeio->card < 0) || (!cards[pvmeio->card].CardValid)) + { + if (devMpcDebug >= 10) + { + logMsg("devMpc: Illegal CARD field ->%s, %d<- \n", pr->name, pvmeio->card); + if(!cards[pvmeio->card].CardValid) + logMsg("devMpc: Illegal CARD field card NOT VALID \n\n"); + } + + recGblRecordError(S_dev_badCard,(void *)pr, "devMpc (init_record) Illegal CARD field"); + return(S_dev_badCard); + } + + /* verifies that parm field is valid */ + for (j = 0; (j < PARM_TABLE_SIZE) && strcmp(ParmTable[j].parm_name, pvmeio->parm); j++ ); + + if (j >= PARM_TABLE_SIZE) + { + if (devMpcDebug >= 10) + logMsg("devMpc: Illegal parm field ->%s<- \n", pr->name); + + recGblRecordError(S_dev_badSignal,(void *)pr, "devMpc (init_record) Illegal parm field"); + return(S_dev_badSignal); + } + if (devMpcDebug >= 10) + logMsg("devMpc: %s of record type %d - %s\n", pr->name, j, ParmTable[j].parm_name); + + pvt = (PvtStruct *) malloc(sizeof(PvtStruct)); + pvt->index = j; + + pr->dpvt = pvt; + + return(0); +} + +/************************************************************************** + * + * BO Initialization (Called one time for each BO MPC card record) + * + **************************************************************************/ +STATIC long MpcInitBoRec(struct boRecord *pRec) +{ + struct vmeio* pvmeio = (struct vmeio*)&(pRec->out.value); + int status = 0; + PvtStruct *pvt; + + status = GenericInitRecord((struct dbCommon *)pRec, &pRec->out); + + if(status) + { + pRec->dpvt = NULL; + return(status); + } + + pvt = (PvtStruct *)pRec->dpvt; + + switch (pvt->index) + { + case MPC_PARM_RESETLATCHES: + break; /* don't need to do anything here */ + case MPC_PARM_TESTMODE: + pvt->mask = 0x0001; + pvt->pReg = &(cards[pvmeio->card].MpcBase->Stat); + break; + case MPC_PARM_TESTLB1: + pvt->mask = 0x0004; + pvt->pReg = &(cards[pvmeio->card].MpcBase->Stat); + break; + case MPC_PARM_TESTLB2: + pvt->mask = 0x0008; + pvt->pReg = &(cards[pvmeio->card].MpcBase->Stat); + break; + case MPC_PARM_TI: + if ((pvmeio->signal >= 0)&&(pvmeio->signal <= 15)) + { + pvt->mask = 1 << (pvmeio->signal); + pvt->pReg = &(cards[pvmeio->card].MpcBase->LatchTest0); + } + else if ((pvmeio->signal >= 16)&&(pvmeio->signal <= 19)) + { + pvt->mask = 1 << ((pvmeio->signal)-16); + pvt->pReg = &(cards[pvmeio->card].MpcBase->LatchTest1); + } + else + { + free(pRec->dpvt); + pRec->dpvt = NULL; + + if (devMpcDebug >= 10) + logMsg("devMpc: Illegal signal field ->%d<- \n", pvmeio->signal); + + recGblRecordError(S_dev_badSignal,(void *)pRec, "devMpc (init_record) Illegal parm field"); + return(S_dev_badSignal); + } + break; + + default: + pRec->dpvt = NULL; + if (devMpcDebug >= 10) + logMsg("devMpc: Illegal parm field ->%s<- \n", pvmeio->parm); + + recGblRecordError(S_dev_badSignal,(void *)pRec, + "devMpc (init_record) Illegal parm field"); + return(S_dev_badSignal); + } + return (0); +} + +/************************************************************************** + * + * BI Initialization (Called one time for each BI MPC card record) + * + **************************************************************************/ +STATIC long MpcInitBiRec(struct biRecord *pRec) +{ + struct vmeio* pvmeio = (struct vmeio*)&(pRec->inp.value); + PvtStruct *pvt; + int status = 0; + int signal; + + status = GenericInitRecord((struct dbCommon *)pRec, &pRec->inp); + + if(status) + { + pRec->dpvt = NULL; + return(status); + } + + pvt = (PvtStruct *)pRec->dpvt; + switch (pvt->index) + { + case MPC_PARM_TESTMODE: + pvt->mask = 0x0001; + pvt->pReg = &(cards[pvmeio->card].MpcBase->Stat); + break; + case MPC_PARM_LB1OK: + pvt->mask = 0x0200; + pvt->pReg = &(cards[pvmeio->card].MpcBase->Stat); + break; + case MPC_PARM_LB2OK: + pvt->mask = 0x0400; + pvt->pReg = &(cards[pvmeio->card].MpcBase->Stat); + break; + case MPC_PARM_AND1OK: + pvt->mask = 0x0800; + pvt->pReg = &(cards[pvmeio->card].MpcBase->Stat); + break; + case MPC_PARM_AND2OK: + pvt->mask = 0x1000; + pvt->pReg = &(cards[pvmeio->card].MpcBase->Stat); + break; + case MPC_PARM_AND3OK: + pvt->mask = 0x2000; + pvt->pReg = &(cards[pvmeio->card].MpcBase->Stat); + break; + case MPC_PARM_OSCOK: + pvt->mask = 0x4000; + pvt->pReg = &(cards[pvmeio->card].MpcBase->Stat); + break; + case MPC_PARM_HBIOK: + pvt->mask = 0x8000; + pvt->pReg = &(cards[pvmeio->card].MpcBase->Stat); + break; + + case MPC_PARM_LI: + if ((pvmeio->signal >= 0)&&(pvmeio->signal <= 7)) + { + pvt->mask = 2 << ((pvmeio->signal) * 2); + pvt->pReg = &(cards[pvmeio->card].MpcBase->LatchState0); + } + else if ((pvmeio->signal >= 8)&&(pvmeio->signal <= 15)) + { + pvt->mask = 2 << ((pvmeio->signal - 8) * 2); + pvt->pReg = &(cards[pvmeio->card].MpcBase->LatchState1); + } + else if ((pvmeio->signal >= 16)&&(pvmeio->signal <= 19)) + { + pvt->mask = 2 << ((pvmeio->signal - 16) * 2); + pvt->pReg = &(cards[pvmeio->card].MpcBase->LatchState2); + } + else + { + free(pRec->dpvt); + pRec->dpvt = NULL; + + if (devMpcDebug >= 10) + logMsg("devMpc: Illegal signal field ->%d<- \n", pvmeio->signal); + + recGblRecordError(S_dev_badSignal,(void *)pRec, "devMpc (init_record) Illegal parm field"); + return(S_dev_badSignal); + } + break; + case MPC_PARM_DI: + if ((pvmeio->signal >= 0)&&(pvmeio->signal <= 7)) + { + pvt->mask = 1 << ((pvmeio->signal) * 2); + pvt->pReg = &(cards[pvmeio->card].MpcBase->LatchState0); + } + else if ((pvmeio->signal >= 8)&&(pvmeio->signal <= 15)) + { + pvt->mask = 1 << ((pvmeio->signal - 8) * 2); + pvt->pReg = &(cards[pvmeio->card].MpcBase->LatchState1); + } + else if ((pvmeio->signal >= 16)&&(pvmeio->signal <= 19)) + { + pvt->mask = 1 << ((pvmeio->signal - 16) * 2); + pvt->pReg = &(cards[pvmeio->card].MpcBase->LatchState2); + } + else + { + free(pRec->dpvt); + pRec->dpvt = NULL; + + if (devMpcDebug >= 10) + logMsg("devMpc: Illegal signal field ->%d<- \n", pvmeio->signal); + + recGblRecordError(S_dev_badSignal,(void *)pRec, "devMpc (init_record) Illegal parm field"); + return(S_dev_badSignal); + } + break; + + case MPC_PARM_ALLLATCHTRUE: + pvt->mask = 0x0100; + pvt->pReg = &(cards[pvmeio->card].MpcBase->LatchState2); + break; + case MPC_PARM_ALLTRIPTRUE: + pvt->mask = 0x0200; + pvt->pReg = &(cards[pvmeio->card].MpcBase->LatchState2); + break; + case MPC_PARM_TESTLB1: + pvt->mask = 0x0040; + pvt->pReg = &(cards[pvmeio->card].MpcBase->Stat); + break; + case MPC_PARM_TESTLB2: + pvt->mask = 0x0080; + pvt->pReg = &(cards[pvmeio->card].MpcBase->Stat); + break; + case MPC_PARM_TI: + if ((pvmeio->signal >= 0)&&(pvmeio->signal <= 15)) + { + pvt->mask = 1 << (pvmeio->signal); + pvt->pReg = &(cards[pvmeio->card].MpcBase->LatchTest0); + } + else if ((pvmeio->signal >= 16)&&(pvmeio->signal <= 19)) + { + pvt->mask = 1 << ((pvmeio->signal)-16); + pvt->pReg = &(cards[pvmeio->card].MpcBase->LatchTest1); + } + else + { + free(pRec->dpvt); + pRec->dpvt = NULL; + + if (devMpcDebug >= 10) + logMsg("devMpc: Illegal signal field ->%d<- \n", pvmeio->signal); + + recGblRecordError(S_dev_badSignal,(void *)pRec, "devMpc (init_record) Illegal parm field"); + return(S_dev_badSignal); + } + break; + + default: + free(pRec->dpvt); + pRec->dpvt = NULL; + + if (devMpcDebug >= 10) + logMsg("devMpc: Illegal parm field ->%s<- \n", pvmeio->parm); + + recGblRecordError(S_dev_badSignal,(void *)pRec, "devMpc (init_record) Illegal parm field"); + return(S_dev_badSignal); + } + + if (devMpcDebug >= 10) + logMsg("devMpc BI record mask = 0x%04.4X reg=0x%08.8X\n", pvt->mask, pvt->pReg); + + return (0); +} + +/************************************************************************** + * + * MBBO Initialization (Called one time for each MBBO MPC card record) + * + **************************************************************************/ +STATIC long MpcInitMbboRec(struct mbboRecord *pmbbo) +{ +#if 0 + struct vmeio* pvmeio = (struct vmeio*)&(pmbbo->out.value); + PvtStruct *pvt; + int status = 0; + + status = GenericInitRecord((struct dbCommon *)pmbbo, &pmbbo->out); + + if(status) + { + pmbbo->dpvt = NULL; + return(status); + } + pvt = (PvtStruct *)pmbbo->dpvt; + + if (pvt->index != MPC_PARM_DO) + { + pmbbo->dpvt = NULL; + if (devMpcDebug >= 10) + logMsg("devMpc: Illegal parm field ->%s<- \n", pvmeio->parm); + + recGblRecordError(S_dev_badSignal,(void *)pmbbo, + "devMpc (init_record) Illegal parm field"); + return(S_dev_badSignal); + } + + pvt->pReg = &(cards[pvmeio->card].MpcBase->MpcDio); + + pmbbo->shft = pvmeio->signal; + pmbbo->mask <<= pmbbo->shft; +#endif + return(0); + +} + +/************************************************************************** + * + * MBBI Initialization (Called one time for each MBBI MPC card record) + * + **************************************************************************/ + +STATIC long MpcInitMbbiRec(struct mbbiRecord *pmbbi) +{ +#if 0 + struct vmeio* pvmeio = (struct vmeio*)&(pmbbi->inp.value); + PvtStruct *pvt; + int status = 0; + + status = GenericInitRecord((struct dbCommon *)pmbbi, &pmbbi->inp); + + if(status) + { + pmbbi->dpvt = NULL; + return(status); + } + pvt = (PvtStruct *)pmbbi->dpvt; + + if ((pvt->index != MPC_PARM_DI) && (pvt->index != MPC_PARM_DO)) + { + pmbbi->dpvt = NULL; + if (devMpcDebug >= 10) + logMsg("devMpc: Illegal parm field ->%s<- \n", pvmeio->parm); + + recGblRecordError(S_dev_badSignal,(void *)pmbbi, + "devMpc (init_record) Illegal parm field"); + return(S_dev_badSignal); + } + + pvt->pReg = &(cards[pvmeio->card].MpcBase->MpcDio); + + pmbbi->shft = pvmeio->signal; + + if (pvt->index == MPC_PARM_DI) + pmbbi->shft += 8; + + pmbbi->mask <<= pmbbi->shft; +#endif + return(0); +} + +/************************************************************************** + * + * Perform a write operation from a BO record + * + **************************************************************************/ +STATIC long MpcWriteBo(struct boRecord *pRec) +{ + struct vmeio *pvmeio = (struct vmeio*)&(pRec->out.value); + PvtStruct *pvt = (PvtStruct *)pRec->dpvt; + + if (pvt == NULL) + return(0); + + FASTLOCK(&cards[pvmeio->card].lock); + switch (pvt->index){ + case MPC_PARM_RESETLATCHES: + /* Toggle the reset bit on and off again */ + cards[pvmeio->card].MpcBase->Stat |= 0x0002; + cards[pvmeio->card].MpcBase->Stat &= ~0x0002; + break; + default: + if (pRec->val) + *(pvt->pReg) |= pvt->mask; + else + *(pvt->pReg) &= ~pvt->mask; + } + FASTUNLOCK(&cards[pvmeio->card].lock); + + return(0); +} + +/************************************************************************** + * + * Perform a read operation from a BI record + * + **************************************************************************/ +STATIC long MpcReadBi(struct biRecord *pRec) +{ + struct vmeio *pvmeio = (struct vmeio*)&(pRec->inp.value); + unsigned short regVal = 0; + PvtStruct *pvt = (PvtStruct *)pRec->dpvt; + + if (pvt == NULL) + return(0); + + regVal = *(pvt->pReg); + + if (devMpcDebug) + logMsg("read 0x%4.4X, masking with 0x%4.4X\n", regVal, pvt->mask); + + regVal &= pvt->mask; + + if(regVal) + pRec->rval = 1; + else + pRec->rval = 0; + + return(0); +} + +/************************************************************************** + * + * Perform a write operation from a MBBO record + * + **************************************************************************/ +STATIC long MpcWriteMbbo(struct mbboRecord *pmbbo) +{ +#if 0 + struct vmeio *pvmeio = (struct vmeio*)&(pmbbo->out.value); + unsigned short regVal; + PvtStruct *pvt = (PvtStruct *)pmbbo->dpvt; + + if (pvt == NULL) + return(0); + + FASTLOCK(&cards[pvmeio->card].lock); + + regVal = *(pvt->pReg); + regVal &= ~pmbbo->mask; + regVal |= pmbbo->rval; + *(pvt->pReg) = regVal; + + if (devMpcDebug) + printf("MpcReadMbbo masked value %8.8X\n", regVal); + + FASTUNLOCK(&cards[pvmeio->card].lock); +#endif + return(0); +} + +/************************************************************************** + * + * Perform a read operation from a MBBI record + * + **************************************************************************/ +STATIC long MpcReadMbbi(struct mbbiRecord *pmbbi) +{ +#if 0 + struct vmeio *pvmeio = (struct vmeio*)&(pmbbi->inp.value); + unsigned short regVal; + PvtStruct *pvt = (PvtStruct *)pmbbi->dpvt; + + if (pvt == NULL) + return(0); + + regVal = ~(*(pvt->pReg)); /* Stupid inputs are inverted */ + regVal &= pmbbi->mask; + + if (devMpcDebug) + printf("MpcReadMbbi masked value %8.8X\n", regVal); + + pmbbi->rval = regVal; + pmbbi->udf = 0; +#endif + return(0); +} + +/***************************************************** + * + * record support interrupt routine + * + * cmd = 0 if being added + * cmd = 1 if taken off the I/O Event scanned list + * + ****************************************************/ + +STATIC long MpcGetIointInfoBi(int cmd, struct biRecord *pr, IOSCANPVT *ppvt) +{ + struct vmeio *pvmeio = (struct vmeio *)(&pr->inp.value); + int intmask; + + if (pr->dpvt == NULL) + return(0); + + if(pvmeio->card > NUM_LINKS) { + recGblRecordError(S_dev_badCard,(void *)pr, "devMpc (get_int_info) exceeded maximum supported cards"); + return(S_dev_badCard); + } + *ppvt = cards[pvmeio->card].ioscanpvt; + + return(0); +}