/************************************************** * scalerEndOfGateISRSetup() ***************************************************/ STATIC int scalerEndOfGateISRSetup(int card) { long status; volatile char *addr; volatile uint16 u16; Debug(5, "scalerEndOfGateISRSetup: Entry, card #%d\n", card); if (card >= scalerVS_total_cards) return(ERROR); addr = scalerVS_state[card]->localAddr; status = devConnectInterruptVME(vs_InterruptVector + card, (void *) &scalerEndOfGateISR, (void *)card); if (!RTN_SUCCESS(status)) { errPrintf(status, __FILE__, __LINE__, "Can't connect to vector %d\n", vs_InterruptVector + card); return (ERROR); } /* write interrupt level to hardware, and tell EPICS to enable that level */ u16 = readReg16(addr,IRQ_SETUP_OFFSET) & 0x0ff; /* OR in level for end-of-gate interrupt */ writeReg16(addr,IRQ_SETUP_OFFSET, u16 | (vs_InterruptLevel << 8)); status = devEnableInterruptLevelVME(vs_InterruptLevel); if (!RTN_SUCCESS(status)) { errPrintf(status, __FILE__, __LINE__, "Can't enable enterrupt level %d\n", vs_InterruptLevel); return (ERROR); } Debug(5, "scalerEndOfGateISRSetup: Wrote interrupt level, %d, to hardware\n", vs_InterruptLevel); /* Write interrupt vector to hardware */ writeReg16(addr,IRQ_3_GATE_VECTOR_OFFSET, (uint16)(vs_InterruptVector + card)); Debug(5, "scalerEndOfGateISRSetup: Wrote interrupt vector, %d, to hardware\n", vs_InterruptVector + card); Debug(5, "scalerEndOfGateISRSetup: Read interrupt vector, %d, from hardware\n", readReg16(addr,IRQ_3_GATE_VECTOR_OFFSET) & 0x0ff); Debug(5, "scalerEndOfGateISRSetup: Exit, card #%d\n", card); return (OK); }
/*Constructor */ drvSIS3801::drvSIS3801(const char *portName, int baseAddress, int interruptVector, int interruptLevel, int maxChans, int maxSignals) : drvSIS38XX(portName, maxChans, maxSignals) { int status; epicsUInt32 controlStatusReg; epicsUInt32 moduleID; static const char* functionName="SIS3801"; setIntegerParam(SIS38XXModel_, MODEL_SIS3801); /* Call devLib to get the system address that corresponds to the VME * base address of the board. */ status = devRegisterAddress("drvSIS3801", SIS3801_ADDRESS_TYPE, (size_t)baseAddress, SIS3801_BOARD_SIZE, (volatile void **)®isters_); if (status) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: %s, Can't register VME address %p\n", driverName, functionName, portName, baseAddress); return; } asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: Registered VME address: 0x%lX to local address: %p size: 0x%X\n", driverName, functionName, (long)baseAddress, registers_, SIS3801_BOARD_SIZE); /* Probe VME bus to see if card is there */ status = devReadProbe(4, (char *) ®isters_->csr_reg, (char *) &controlStatusReg); if (status) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: devReadProbe failure = %d\n", driverName, functionName, status); return; } /* Get the module info from the card */ moduleID = (registers_->irq_reg & 0xFFFF0000) >> 16; asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: module ID=%x\n", driverName, functionName, moduleID); firmwareVersion_ = (registers_->irq_reg & 0x0000F000) >> 12; setIntegerParam(SIS38XXFirmware_, firmwareVersion_); asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: firmware=%d\n", driverName, functionName, firmwareVersion_); // Create the mutex used to lock access to the FIFO fifoLockId_ = epicsMutexCreate(); /* Reset card */ asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: resetting port %s\n", driverName, functionName, portName); registers_->key_reset_reg = 1; /* Clear FIFO */ asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: clearing FIFO\n", driverName, functionName); resetFIFO(); setControlStatusReg(); /* Initialize board in MCS mode */ setAcquireMode(ACQUIRE_MODE_MCS); /* Set number of readout channels to maxSignals * Assumes that the lower channels will be used first, and the only unused * channels will be at the upper end of the channel range. * Create a mask with zeros in the rightmost maxSignals bits, * 1 in all higher order bits. */ registers_->copy_disable_reg = 0xffffffff<<maxSignals_; asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: setting copy disable register=0x%08x\n", driverName, functionName, 0xffffffff<<maxSignals_); /* Set up the interrupt service routine */ asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: interruptServiceRoutine pointer %p\n", driverName, functionName, intFuncC); status = devConnectInterruptVME(interruptVector, intFuncC, this); if (status) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: Can't connect to vector % d\n", driverName, functionName, interruptVector); return; } asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: Connected interrupt vector: %d\n\n", driverName, functionName, interruptVector); /* Write interrupt level to hardware */ asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: irq before setting IntLevel= 0x%x\n", driverName, functionName, registers_->irq_reg); registers_->irq_reg |= (interruptLevel << 8); asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: irq after setting IntLevel= 0x%x\n", driverName, functionName, registers_->irq_reg); registers_->irq_reg |= interruptVector; asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "m%s:%s: irq config register after setting interrupt vector = 0x%08x\n", driverName, functionName, registers_->irq_reg); /* Create the thread that reads the FIFO */ if (epicsThreadCreate("SIS3801FIFOThread", epicsThreadPriorityLow, epicsThreadGetStackSize(epicsThreadStackMedium), (EPICSTHREADFUNC)readFIFOThreadC, this) == NULL) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: epicsThreadCreate failure\n", driverName, functionName); return; } else asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: epicsThreadCreate success\n", driverName, functionName); erase(); /* Enable interrupts in hardware */ asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: irq before enabling interrupts= 0x%08x\n", driverName, functionName, registers_->irq_reg); enableInterrupts(); /* Enable interrupt level in EPICS */ status = devEnableInterruptLevel(intVME, interruptLevel); if (status) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: Can't enable enterrupt level %d\n", driverName, functionName, interruptLevel); return; } exists_ = true; return; }
IpUnidig::IpUnidig(const char *portName, int carrier, int slot, int msecPoll, int intVec, int risingMask, int fallingMask) :asynPortDriver(portName,1,NUM_IPUNIDIG_PARAMS, asynInt32Mask | asynUInt32DigitalMask | asynDrvUserMask, asynUInt32DigitalMask, 0,1,0,0), risingMask_(risingMask), fallingMask_(fallingMask), polarityMask_(risingMask) { //static const char *functionName = "IpUnidig"; ipac_idProm_t *id; epicsUInt16 *base; /* Default of 100 msec for backwards compatibility with old version */ if (msecPoll == 0) msecPoll = 100; pollTime_ = msecPoll / 1000.; messagesSent_ = 0; messagesFailed_ = 0; rebooting_ = 0; forceCallback_ = 0; oldBits_ = 0; msgQId_ = epicsMessageQueueCreate(MAX_MESSAGES, sizeof(ipUnidigMessage)); if (ipmCheck(carrier, slot)) { errlogPrintf("IpUnidig: bad carrier or slot\n"); } id = (ipac_idProm_t *) ipmBaseAddr(carrier, slot, ipac_addrID); base = (epicsUInt16 *) ipmBaseAddr(carrier, slot, ipac_addrIO); baseAddress_ = base; manufacturer_ = id->manufacturerId & 0xff; model_ = id->modelId & 0xff; switch (manufacturer_) { case GREENSPRING_ID: switch (model_) { case UNIDIG_E: case UNIDIG: case UNIDIG_D: case UNIDIG_O_24IO: case UNIDIG_HV_16I8O: case UNIDIG_E48: case UNIDIG_I_O_24I: case UNIDIG_I_E: case UNIDIG_I: case UNIDIG_I_D: case UNIDIG_I_O_24IO: case UNIDIG_I_HV_16I8O: case UNIDIG_O_12I12O: case UNIDIG_I_O_12I12O: case UNIDIG_O_24I: case UNIDIG_HV_8I16O: case UNIDIG_I_HV_8I16O: break; default: errlogPrintf("IpUnidig model 0x%x not supported\n",model_); break; } break; case SYSTRAN_ID: if(model_ != SYSTRAN_DIO316I) { errlogPrintf("IpUnidig model 0x%x not Systran DIO316I\n",model_); } break; case SBS_ID: if(model_ != SBS_IPOPTOIO8) { errlogPrintf("IpUnidig model 0x%x not SBS IP-OPTOIO-8\n",model_); } break; default: errlogPrintf("IpUnidig manufacturer 0x%x not supported\n", manufacturer_); break; } /* Set up the register pointers. Set the defaults for most modules */ /* Define registers in units of 16-bit words */ regs_.outputRegisterLow = base; regs_.outputRegisterHigh = base + 0x1; regs_.inputRegisterLow = base + 0x2; regs_.inputRegisterHigh = base + 0x3; regs_.outputEnableLow = base + 0x8; regs_.outputEnableHigh = base + 0x5; regs_.controlRegister0 = base + 0x6; regs_.intVecRegister = base + 0x8; regs_.intEnableRegisterLow = base + 0x9; regs_.intEnableRegisterHigh = base + 0xa; regs_.intPolarityRegisterLow = base + 0xb; regs_.intPolarityRegisterHigh = base + 0xc; regs_.intClearRegisterLow = base + 0xd; regs_.intClearRegisterHigh = base + 0xe; regs_.intPendingRegisterLow = base + 0xd; regs_.intPendingRegisterHigh = base + 0xe; regs_.DACRegister = base + 0xe; /* Set things up for specific models which need to be treated differently */ switch (manufacturer_) { case GREENSPRING_ID: switch (model_) { case UNIDIG_O_24IO: case UNIDIG_O_12I12O: case UNIDIG_I_O_24IO: case UNIDIG_I_O_12I12O: /* Enable outputs */ *regs_.controlRegister0 |= 0x4; break; case UNIDIG_HV_16I8O: case UNIDIG_I_HV_16I8O: /* These modules don't allow access to outputRegisterLow */ regs_.outputRegisterLow = NULL; /* Set the comparator DAC for 2.5 volts. Each bit is 15 mV. */ *regs_.DACRegister = 2500/15; break; } break; case SYSTRAN_ID: switch (model_) { case SYSTRAN_DIO316I: /* Different register layout */ regs_.outputRegisterLow = base; regs_.outputRegisterHigh = base + 0x1; regs_.inputRegisterLow = base + 0x2; regs_.inputRegisterHigh = NULL; regs_.controlRegister0 = base + 0x3; regs_.controlRegister1 = base + 0x4; /* Enable outputs for ports 0-3 */ *regs_.controlRegister0 |= 0xf; /* Set direction of ports 0-1 to be output */ *regs_.controlRegister1 |= 0x3; break; } break; case SBS_ID: switch (model_) { case SBS_IPOPTOIO8: /* Different register layout */ memset(®s_, 0, sizeof(regs_)); regs_.inputRegisterLow = base + 1; regs_.outputRegisterLow = base + 2; regs_.controlRegister0 = base + 3; *regs_.controlRegister0 = 0x00; /* Start state machine reset */ *regs_.controlRegister0 = 0x01; /* .... */ *regs_.controlRegister0 = 0x00; /* State machine in state 0 */ *regs_.controlRegister0 = 0x2B; /* Select Port B DDR */ *regs_.controlRegister0 = 0xFF; /* All Port B bits are inputs */ *regs_.controlRegister0 = 0x2A; /* Select Port B DPPR */ *regs_.controlRegister0 = 0xFF; /* All Port B bits inverted */ *regs_.controlRegister0 = 0x01; /* Select MCCR */ *regs_.controlRegister0 = 0x84; /* Enable ports A and B */ break; } break; } switch (model_) { case UNIDIG_I_O_24I: case UNIDIG_I_E: case UNIDIG_I: case UNIDIG_I_D: case UNIDIG_I_O_24IO: case UNIDIG_I_HV_16I8O: case UNIDIG_I_O_12I12O: case UNIDIG_I_HV_8I16O: supportsInterrupts_ = 1; break; default: supportsInterrupts_ = 0; break; } /* Create the asynPortDriver parameter for the data */ createParam(digitalInputString, asynParamUInt32Digital, &digitalInputParam_); createParam(digitalOutputString, asynParamUInt32Digital, &digitalOutputParam_); createParam(DACOutputString, asynParamInt32, &DACOutputParam_); // We use this to call readUInt32Digital, which needs the correct reason pasynUserSelf->reason = digitalInputParam_; // Set the values of rising mask and falling mask in the parameter library, just for reporting purposes asynPortDriver::setUInt32DigitalInterrupt(digitalInputParam_, risingMask_, interruptOnZeroToOne); asynPortDriver::setUInt32DigitalInterrupt(digitalInputParam_, fallingMask_, interruptOnOneToZero); /* Start the thread to poll and handle interrupt callbacks to * device support */ epicsThreadCreate("ipUnidig", epicsThreadPriorityHigh, epicsThreadGetStackSize(epicsThreadStackBig), (EPICSTHREADFUNC)pollerThreadC, this); /* If the interrupt vector is zero, don't bother with interrupts, * since the user probably didn't pass this * parameter to IpUnidig::init(). This is an optional parameter added * after initial release. */ if (supportsInterrupts_ && (intVec !=0)) { /* Interrupt support */ /* Write to the interrupt polarity and enable registers */ *regs_.intVecRegister = intVec; if (devConnectInterruptVME(intVec, intFuncC, (void *)this)) { errlogPrintf("ipUnidig interrupt connect failure\n"); } *regs_.intPolarityRegisterLow = (epicsUInt16)polarityMask_; *regs_.intPolarityRegisterHigh = (epicsUInt16)(polarityMask_ >> 16); writeIntEnableRegs(); /* Enable IPAC module interrupts and set module status. */ ipmIrqCmd(carrier, slot, 0, ipac_irqEnable); ipmIrqCmd(carrier, slot, 0, ipac_statActive); }
void xycom566setup( int id, int cbase, int dbase, int level, int vec, int bipol ){ xy566 *card; volatile epicsUInt8 **cb; volatile epicsUInt16 **db; epicsUInt16 junk; if(cbase<0 || cbase>0xffff){ printf("config (A16) out of range\n"); return; } if(dbase<0 || dbase>0xffffff){ printf("data (A24) out of range\n"); return; } if(level<0 || level>7){ printf("Level out of range (0->7)\n"); return; } if(vec<0 || vec>0xff){ printf("Vector out of range (0->255)\n"); return; } card=get566(id); if(!!card){ printf("ID %d already exists\n",id); return; } card=malloc(sizeof(xy566)); if(!card){ printf("Out of memory!\n"); return; } memset(&card->dlen,0,sizeof(card->dlen)); memset(&card->cb_irq,0,sizeof(card->cb_irq)); card->id=id; card->fail=0; card->clk_div=0; /* stc uninitialized */ card->use_seq_clk=0; ellInit(&card->seq_ctor); if(!bipol) card->nchan=32; else card->nchan=16; card->ivec=vec; card->base_addr=cbase; card->data_addr=dbase; cb=&card->base; db=&card->data_base; if(devBusToLocalAddr(atVMEA16, card->base_addr, (volatile void **)cb)){ printf("Failed to map A16 %lx for card %x\n", (unsigned long)card->base_addr,id); free(card); return; } if(devBusToLocalAddr(atVMEA24, card->data_addr, (volatile void **)db)){ printf("Failed to map A24 %lx for card %x\n", (unsigned long)card->data_base,id); free(card); return; } if(devReadProbe(2, card->base+U16_XY566_CSR, &junk)){ printf("Failed to read A16 %lx for card %x\n", (unsigned long)(card->base+U16_XY566_CSR),id); free(card); return; } if(devReadProbe(2, card->data_base, &junk)){ printf("Failed to read A24 %lx for card %x\n", (unsigned long)(card->data_base),id); free(card); return; } WRITE16(card->base, XY566_CSR, XY566_CSR_RST); /* Reset */ /* turn on green and red to indicate init start */ WRITE16(card->base, XY566_CSR, XY566_CSR_GRN); WRITE16(card->base, XY566_RAM, 0); WRITE8(card->base, XY566_SEQ, 0); card->guard=epicsMutexMustCreate(); scanIoInit(&card->seq_irq); callbackSetCallback(xycom566isrcb, &card->cb_irq); callbackSetPriority(priorityHigh, &card->cb_irq); callbackSetUser(card, &card->cb_irq); WRITE8(card->base, XY566_VEC, vec); devEnableInterruptLevelVME(level); assert(devConnectInterruptVME(vec, xycom566isr, card)==0); /* Configure card * Mode: continuous sequence (default) * 16 bit conversion (default) * sequence controller disable (will be enabled during drvsup init) */ WRITE16(card->base, XY566_CSR, XY566_CSR_GRN); ellAdd(&xy566s,&card->node); }
epicsStatus mrmEvgSetupVME ( const char* id, // Card Identifier epicsInt32 slot, // VME slot epicsUInt32 vmeAddress, // Desired VME address in A24 space epicsInt32 irqLevel, // Desired interrupt level epicsInt32 irqVector, // Desired interrupt vector number bool ignoreVersion) // Ignore errors due to firmware checks { volatile epicsUInt8* regCpuAddr = 0; volatile epicsUInt8* regCpuAddr2 = 0; //function 2 of regmap (fanout/concentrator specifics) struct VMECSRID info; deviceInfoT deviceInfo; info.board = 0; info.revision = 0; info.vendor = 0; deviceInfo.bus.busType = busType_vme; deviceInfo.bus.vme.slot = slot; deviceInfo.bus.vme.address = vmeAddress; deviceInfo.bus.vme.irqLevel = irqLevel; deviceInfo.bus.vme.irqVector = irqVector; deviceInfo.series = series_unknown; int status; // a variable to hold function return statuses try { if(mrf::Object::getObject(id)){ errlogPrintf("ID %s already in use\n",id); return -1; } volatile unsigned char* csrCpuAddr; // csrCpuAddr is VME-CSR space CPU address for the board csrCpuAddr = //devCSRProbeSlot(slot); devCSRTestSlot(vmeEvgIDs,slot,&info); //FIXME: add support for EVM id if(!csrCpuAddr) { errlogPrintf("No EVG in slot %d\n",slot); return -1; } epicsPrintf("##### Setting up MRF EVG in VME Slot %d #####\n",slot); epicsPrintf("Found Vendor: %08x\nBoard: %08x\nRevision: %08x\n", info.vendor, info.board, info.revision); epicsUInt32 xxx = CSRRead32(csrCpuAddr + CSR_FN_ADER(1)); if(xxx) epicsPrintf("Warning: EVG not in power on state! (%08x)\n", xxx); /*Setting the base address of Register Map on VME Board (EVG)*/ CSRSetBase(csrCpuAddr, 1, vmeAddress, VME_AM_STD_SUP_DATA); { epicsUInt32 temp=CSRRead32((csrCpuAddr) + CSR_FN_ADER(1)); if(temp != CSRADER((epicsUInt32)vmeAddress,VME_AM_STD_SUP_DATA)) { errlogPrintf("Failed to set CSR Base address in ADER1. Check VME bus and card firmware version.\n"); return -1; } } /* Create a static string for the card description (needed by vxWorks) */ char *Description = allocSNPrintf(40, "EVG-%d '%s' slot %d", info.board & MRF_BID_SERIES_MASK, id, slot); /*Register VME address and get corresponding CPU address */ status = devRegisterAddress ( Description, // Event Generator card description atVMEA24, // A24 Address space vmeAddress, // Physical address of register space EVG_REGMAP_SIZE, // Size of card's register space (volatile void **)(void *)®CpuAddr // Local address of card's register map ); if(status) { errlogPrintf("Failed to map VME address %08x\n", vmeAddress); return -1; } epicsUInt32 version = checkVersion(regCpuAddr, 0x3); epicsPrintf("Firmware version: %08x\n", version); if(version == 0){ if(ignoreVersion) { epicsPrintf("Ignoring version error.\n"); } else { return -1; } } /* Set the base address of Register Map for function 2, if we have the right firmware version */ if(version >= EVG_FCT_MIN_FIRMWARE) { deviceInfo.series = series_300; CSRSetBase(csrCpuAddr, 2, vmeAddress+EVG_REGMAP_SIZE, VME_AM_STD_SUP_DATA); { epicsUInt32 temp=CSRRead32((csrCpuAddr) + CSR_FN_ADER(2)); if(temp != CSRADER((epicsUInt32)vmeAddress+EVG_REGMAP_SIZE,VME_AM_STD_SUP_DATA)) { epicsPrintf("Failed to set CSR Base address in ADER2 for FCT register mapping. Check VME bus and card firmware version.\n"); return -1; } } /* Create a static string for the card description (needed by vxWorks) */ char *Description = allocSNPrintf(40, "EVG-%d FOUT'%s' slot %d", info.board & MRF_BID_SERIES_MASK, id, slot); status = devRegisterAddress ( Description, // Event Generator card description atVMEA24, // A24 Address space vmeAddress+EVG_REGMAP_SIZE, // Physical address of register space EVG_REGMAP_SIZE*2, // Size of card's register space (volatile void **)(void *)®CpuAddr2 // Local address of card's register map ); if(status) { errlogPrintf("Failed to map VME address %08x for FCT mapping\n", vmeAddress); return -1; } } else { deviceInfo.series = series_230; } evgMrm* evg = new evgMrm(id, deviceInfo, regCpuAddr, regCpuAddr2, NULL); if(irqLevel > 0 && irqVector >= 0) { /*Configure the Interrupt level and vector on the EVG board*/ CSRWrite8(csrCpuAddr + UCSR_DEFAULT_OFFSET + UCSR_IRQ_LEVEL, irqLevel&0x7); CSRWrite8(csrCpuAddr + UCSR_DEFAULT_OFFSET + UCSR_IRQ_VECTOR, irqVector&0xff); epicsPrintf("IRQ Level: %d\nIRQ Vector: %d\n", CSRRead8(csrCpuAddr + UCSR_DEFAULT_OFFSET + UCSR_IRQ_LEVEL), CSRRead8(csrCpuAddr + UCSR_DEFAULT_OFFSET + UCSR_IRQ_VECTOR) ); epicsPrintf("csrCpuAddr : %p\nregCpuAddr : %p\nreCpuAddr2 : %p\n",csrCpuAddr, regCpuAddr, regCpuAddr2); /*Disable the interrupts and enable them at the end of iocInit via initHooks*/ WRITE32(regCpuAddr, IrqFlag, READ32(regCpuAddr, IrqFlag)); WRITE32(regCpuAddr, IrqEnable, 0); // VME IRQ level will be enabled later during iocInit() vme_level_mask |= 1 << ((irqLevel&0x7)-1); /*Connect Interrupt handler to vector*/ if(devConnectInterruptVME(irqVector & 0xff, &evgMrm::isr_vme, evg)){ errlogPrintf("ERROR:Failed to connect VME IRQ vector %d\n" ,irqVector&0xff); delete evg; return -1; } } } catch(std::exception& e) { errlogPrintf("Error: %s\n",e.what()); errlogFlush(); return -1; } errlogFlush(); return 0; } //mrmEvgSetupVME
/*Constructor */ drvSIS3820::drvSIS3820(const char *portName, int baseAddress, int interruptVector, int interruptLevel, int maxChans, int maxSignals, bool useDma, int fifoBufferWords) : drvSIS38XX(portName, maxChans, maxSignals), useDma_(useDma) { int status; epicsUInt32 controlStatusReg; epicsUInt32 moduleID; static const char* functionName="SIS3820"; setIntegerParam(SIS38XXModel_, MODEL_SIS3820); /* Call devLib to get the system address that corresponds to the VME * base address of the board. */ status = devRegisterAddress("drvSIS3820", SIS3820_ADDRESS_TYPE, (size_t)baseAddress, SIS3820_BOARD_SIZE, (volatile void **)®isters_); if (status) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: %s, Can't register VME address 0x%x\n", driverName, functionName, portName, baseAddress); return; } asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: Registered VME address: 0x%x to local address: %p size: 0x%X\n", driverName, functionName, baseAddress, registers_, SIS3820_BOARD_SIZE); /* Call devLib to get the system address that corresponds to the VME * FIFO address of the board. */ fifoBaseVME_ = (epicsUInt32 *)(baseAddress + SIS3820_FIFO_BASE); status = devRegisterAddress("drvSIS3820", SIS3820_ADDRESS_TYPE, (size_t)fifoBaseVME_, SIS3820_FIFO_BYTE_SIZE, (volatile void **)&fifoBaseCPU_); if (status) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: %s, Can't register FIFO address 0x%x\n", driverName, functionName, portName, baseAddress + SIS3820_FIFO_BASE); return; } asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: Registered VME FIFO address: %p to local address: %p size: 0x%X\n", driverName, functionName, fifoBaseVME_, fifoBaseCPU_, SIS3820_FIFO_BYTE_SIZE); /* Probe VME bus to see if card is there */ status = devReadProbe(4, (char *) &(registers_->control_status_reg), (char *) &controlStatusReg); if (status) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: devReadProbe failure for address %p = %d\n", driverName, functionName, ®isters_->control_status_reg, status); return; } /* Get the module info from the card */ moduleID = (registers_->moduleID_reg & 0xFFFF0000) >> 16; asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: module ID=%x\n", driverName, functionName, moduleID); firmwareVersion_ = registers_->moduleID_reg & 0x0000FFFF; setIntegerParam(SIS38XXFirmware_, firmwareVersion_); asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: firmware=%d\n", driverName, functionName, firmwareVersion_); // Allocate FIFO readout buffer // fifoBufferWords input argument is in words, must be less than SIS3820_FIFO_WORD_SIZE if (fifoBufferWords == 0) fifoBufferWords = SIS3820_FIFO_WORD_SIZE; if (fifoBufferWords > SIS3820_FIFO_WORD_SIZE) fifoBufferWords = SIS3820_FIFO_WORD_SIZE; fifoBufferWords_ = fifoBufferWords; #ifdef vxWorks fifoBuffer_ = (epicsUInt32*) memalign(8, fifoBufferWords_*sizeof(epicsUInt32)); #else void *ptr; status = posix_memalign(&ptr, 8, fifoBufferWords_*sizeof(epicsUInt32)); if(status != 0) { printf("Error: posix_memalign status = %d\n", status); } fifoBuffer_ = (epicsUInt32*)ptr; #endif if (fifoBuffer_ == NULL) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: posix_memalign failure for fifoBuffer_ = %d\n", driverName, functionName, status); return; } dmaDoneEventId_ = epicsEventCreate(epicsEventEmpty); // Create the DMA ID if (useDma_) { dmaId_ = sysDmaCreate(dmaCallbackC, (void*)this); if (dmaId_ == 0 || (int)dmaId_ == -1) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: sysDmaCreate failed, errno=%d. Disabling use of DMA.\n", driverName, functionName, errno); useDma_ = false; } } /* Reset card */ asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: resetting port %s\n", driverName, functionName, portName); registers_->key_reset_reg = 1; /* Clear FIFO */ asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: clearing FIFO\n", driverName, functionName); resetFIFO(); // Disable 25MHz test pulses and test mode registers_->control_status_reg = CTRL_COUNTER_TEST_25MHZ_DISABLE; registers_->control_status_reg = CTRL_COUNTER_TEST_MODE_DISABLE; /* Set up the interrupt service routine */ asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: interruptServiceRoutine pointer %p\n", driverName, functionName, intFuncC); status = devConnectInterruptVME(interruptVector, intFuncC, this); if (status) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: Can't connect to vector % d\n", driverName, functionName, interruptVector); return; } asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: Connected interrupt vector: %d\n\n", driverName, functionName, interruptVector); /* Write interrupt level to hardware */ registers_->irq_config_reg &= ~SIS3820_IRQ_LEVEL_MASK; registers_->irq_config_reg |= (interruptLevel << 8); asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: irq after setting IntLevel= 0x%x\n", driverName, functionName, registers_->irq_config_reg); /* Write interrupt vector to hardware */ registers_->irq_config_reg &= ~SIS3820_IRQ_VECTOR_MASK; registers_->irq_config_reg |= interruptVector; asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: irq = 0x%08x\n", driverName, functionName, registers_->irq_config_reg); /* Initialize board in MCS mode. This will also set the initial value of the operation mode register. */ setAcquireMode(ACQUIRE_MODE_MCS); /* Create the thread that reads the FIFO */ if (epicsThreadCreate("SIS3820FIFOThread", epicsThreadPriorityLow, epicsThreadGetStackSize(epicsThreadStackMedium), (EPICSTHREADFUNC)readFIFOThreadC, this) == NULL) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: epicsThreadCreate failure\n", driverName, functionName); return; } else asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: epicsThreadCreate success\n", driverName, functionName); erase(); /* Enable interrupts in hardware */ asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: irq before enabling interrupts= 0x%08x\n", driverName, functionName, registers_->irq_config_reg); registers_->irq_config_reg |= SIS3820_IRQ_ENABLE; /* Enable interrupt level in EPICS */ status = devEnableInterruptLevel(intVME, interruptLevel); if (status) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: Can't enable enterrupt level %d\n", driverName, functionName, interruptLevel); return; } exists_ = true; return; }