/* * Xy542 Analog input / Analog output driver. * Updated from Xy540 driver. Oleg A. Makarov 06/10/99 * * Xy540 Analog input / Analog output driver. * * Author: Matthew Needes * Updated: 4-18-95 * * Written for the William Keck Observatory * * * The A/D conversions are setup for random channel mode. The * routine xy540_change_conv_mode is not implemented (ie. one * cannot change the A/D conversion mode). Ahoney 04/16/96 * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "koDevLib.h" #include "drvXy542Ko.h" /* Indicates that no channel is pending */ #define NONE_PENDING -1 /* ISR queue length */ #define Q_SIZE 64 #define IO_AI 0 #define IO_AO 1 /* * Set random channel mode * ENABLE interrupts. */ #define RAND_CH 0x200 #define INT_EN 0x8 /* * Zero reset, turn on green, turn off red */ #define XY_ALL_OK 0x3 /* * Disable interrupts, reset board, turn on red, turn off green */ #define XY_RESET 0x10 /* * Mask for programming gain for gain register */ #define XY_PROGRAM_GAIN 0x500 #define XY542_VME_SIZE 0x400 typedef volatile uint8_t REG8BIT; typedef volatile uint16_t REG16BIT; /* Xycom 542 structure */ struct io_xy542_reg { REG8BIT id[22]; /* board ID, compare with id_expected */ REG8BIT pad1[107]; /* next byte offset is 22+107 = 0x81 */ REG8BIT csr; /* control status register (rw) 0x20 1-simultaneous D/A update mode requires write to d_a_upd, 0-transparent mode 0x10 combination 0-1-0 performs a software reset to D/A section this resets all DAC outputs and clears d_a_upd register 0x03 LED control: 0-GRS=011, 1-GRS=000, 2-GRS=110, 3-GRS=100 */ REG8BIT pad2[6]; /* next byte offset is 0x81+1+6 = 0x88 */ REG16BIT dac[8]; /* DAC data (w) */ REG8BIT pad3[81]; /* next byte offset is 0x88 + 16 + 81 = 0xE9 */ REG8BIT d_a_upd; /* D/A update register (w) */ REG8BIT pad4[23]; /* next byte offset is 0xE9 + 1 + 23 = 0x101*/ REG8BIT itr; /* interrupt timer register (rw) 0x80 enables periodic interrupts 0x47 interrupt timeout periods: 0x00 - 8.192 msec 0x01 - 16.384 msec 0x02 - 24.576 msec 0x03 - 32.768 msec 0x04 - 40.960 msec 0x05 - 49.152 msec 0x06 - 57.344 msec 0x07 - 65.536 msec 0x40 - 131.072 msec 0x41 - 262.144 msec 0x42 - 393.216 msec 0x43 - 524.288 msec 0x44 - 655.360 msec 0x45 - 786.432 msec 0x46 - 917.504 msec 0x47 - 1048.576 msec */ REG8BIT pad5; /* next byte offset is 0x101 + 1 + 1= 0x103 */ REG8BIT ivr; /* interrupt vector register (w) */ REG8BIT pad6[13]; /* next byte offset is 0x103 + 1 + 13 = 0x111*/ REG8BIT autoscan_ctrl; /* autoscasn control register (rw) used for autoscanning mode ie 0x4 is written to adm: 0x80 enable autoscan control register. It is cleared on power up, sysreset or A/D software reset 0x3 used to select channels scanned: 0x0 0-7 channels 0x1 0-15 channels 0x2 0-31 channels 0x3 0-64 channels */ REG8BIT pad7[110]; /* next byte offset is 0x111 + 1 +110 = 0x180 */ REG16BIT admsc; /* A/D mode/status/control (rw) 0x0700 operating mode for analog inputs: 0x0000 single channel 0x0100 sequential channel 0x0200 random channel 0x0300 external trigger 0x0400 autoscanning 0x0500 programming gain 0x0080 A/D conversion in process 0x0040 initiates conversion 0x0010 software reset for analog input section 0x0008 enables interrupt at the end of A/D conversion 0x0004 flag bit: end of conversion has occured cleared by: starting new A/D conversion backplane or software reset read the converted input data from the low order byte of data select autoscanning mode */ REG8BIT pad8; /* next byte offset is 0x180 + 2 + 1 = 0x183 */ REG8BIT ivc; /* End-of-Conversion vector register (w) */ REG16BIT gain_ch_trig; /* gain / channel trig register (rw) 0x0300 select the gain: 0x0000 - 1/4/10 0x0100 - 2/8/20 0x0200 - 5/20/50 0x0300 - 10/50/100 0x003f channel number to program gain */ REG16BIT adc; /* ADC data (r) */ REG8BIT pad9[120]; /* next byte offset is 0x183 + 1 + 2 + 2 + 120 = 0x200 */ REG16BIT adcs[64]; /* ADC scan data (r) */ REG8BIT padX[384]; /* pad until next card, offset is 0x200 + 64*2 + 384 = 0x400 */ }; struct io_xy542 { struct io_xy542_reg *reg; /* Registers */ XY542_CBACK *rd_cback[NUM_I_CHAN];/* Callbacks, one per channel */ uint16_t gain_setting[NUM_I_CHAN]; /* Channel gain */ uint16_t last_read[NUM_I_CHAN]; /* Last read values from board */ uint16_t last_write[NUM_O_CHAN];/* Last written values to board */ int fresh_read[NUM_I_CHAN]; /* 1 if last_read[x] has valid data */ int fresh_write[NUM_O_CHAN]; /* 1 if last_write[x] has valid data */ enum input_mode inp_mode; /* Diff. or single ended input mode */ int ch_pending; /* Channel # undergoing conversion */ unsigned int Q[Q_SIZE]; /* Channel conversion queue */ unsigned int startQ, endQ; /* Queue pointers */ int inQ[NUM_I_CHAN]; /* Whether a channel is already Q'ed */ int configured; int enableItrOnInit; }; STATIC void xy542_isr(int card); STATIC void xy542_reboot_hook(); STATIC long xy542_driver_init(); long xy542_io_report(); /* * Run-time operation: * This driver employs a simple * queueing-scheme, where any user task * can add a request for a conversion. * * Any task can call "xy542_req_conversion()" to * request a conversion. If there aren't any * reads currently pending, this function will * queue a request directly to the 542 board. * If, on the other hand, there are reads * currently pending it will add the request to a * queue (a fixed length array of channels), and * then increment the queue tail pointer. * * When a conversion completes, an ISR will * be invoked. This ISR will queue the next * request if there is one available on top * of the queue, and will then call a user-defined * callback to inform device-support or some other * higher level software that the original conversion * has completed. * * The higher-level software, can then invoke * xy542_read() to obtain the channel's value. * * Initialization: * On initialization the higher-level software * will call xy542_conf_channel() to associate callbacks * with particular channels and tell driver support * whether the board is running in single-ended or * differential mode. */ #define DEBUG #define DEVICE_NOT_VALID(LIST,NODE,CARD) \ (NODE = koDevPrivate(koDevNodeByCardNum(LIST,CARD))) == NULL ? 1 \ : (NODE->configured == FALSE) ? 1 : 0 #define PARAMS_NOT_VALID(LIST,NODE,CARD,SIGNAL,TYPE) \ (NODE = koDevPrivate(koDevNodeByCardNum(LIST,CARD))) == NULL ? 1 \ : xy542_signal_check( NODE,(long)SIGNAL,TYPE) == ERR ? 1 \ : (NODE->configured == FALSE) ? 1 : 0 /* * Driver entry table */ struct { long number; long (*report)(); long (*init)(); } drvXy542 = { 2, xy542_io_report, xy542_driver_init }; /* * pointers to the binary output cards */ STATIC struct devInfo *pXy542List = NULL; STATIC char *id_expected = "VMEIDXYC542"; /* * Lists the board configuration info */ void xy542List() { koDevList( id_expected, pXy542List ); } /* * XY542CONFIGURE * caches board info for use during driver init */ long xy542Configure( int cardNum, /* card number as used in INP fields */ void *base, /* base address of the board */ int vectorNum, /* interrupt vector number. If 0 then one */ /* will be found */ int itrLevel, /* board's interrupt level */ int itrState, /* whether or not interrupts should be */ /* enabled at init time */ int aiType /* analog input signal type (differential=0 */ /* or single-ended=1 */ ) { struct io_xy542 *pPrivate; if ( koDevInUse( base, cardNum, &pXy542List ) ) { logMsg("%s: card %2d or address %x already used!\n", (int)id_expected,(int)cardNum, (int)base, 0,0,0); return -1; } /* * Allocate space for the device descriptors */ pPrivate = calloc (1, sizeof(struct io_xy542) ); if ( pPrivate == NULL ) { logMsg ("%s: Memory allocation error\n", (int)id_expected,0,0,0,0,0 ); return -1; } pPrivate->configured = FALSE; pPrivate->enableItrOnInit = itrState; pPrivate->inp_mode = aiType+1; return koDevConfigure( id_expected, cardNum, (void *)base, vectorNum, itrLevel, pPrivate, &pXy542List ); } STATIC void xy542_reboot_hook() { struct devInfo *pCard; struct io_xy542 *pPrivate; pCard = koDevFirst(pXy542List); while (pCard != NULL) { pPrivate = koDevPrivate( pCard ); if (pPrivate->configured) pPrivate->reg->admsc = pPrivate->reg->admsc & !INT_EN; pCard = koDevNext( pCard ); } } /* * Driver init entry point follows. This routine confirms that the cards * exist and */ STATIC long xy542_driver_init() { struct devInfo *pCard; struct io_xy542 *pPrivate; int rprobe, vecNum, numChans, chan, status, index=0; pCard = koDevFirst(pXy542List); while (pCard != NULL) { pPrivate = koDevPrivate( pCard ); /* register the card in the A24 address space */ if ( (status = devRegisterAddress( id_expected, atVMEA24, (void *) koDevAddrs(pCard), XY542_VME_SIZE, (void **) &pPrivate->reg) != OK )) { logMsg( "%s: Cannot register device at %x. Error is %x\n", (int)id_expected, (int)koDevAddrs(pCard), status, 0,0,0 ); /* * Verify that something exists at the specified address */ } else if ( (vxMemProbe ( (char *) pPrivate->reg, READ, sizeof (short), (char *) &rprobe )) != OK ) { logMsg("%s: NO DEVICE at VME A24 address 0x%x, IOC address: 0x%x, error is: 0x%x\n", (int)id_expected, (int)koDevAddrs(pCard),(int)pPrivate->reg, status,0,0); } else { /* * verify that the device is an XVME-542 board by examining the id ROM */ for (index = 0; id_expected[index] != EOS; index++) { if (id_expected[index] != ((char*) pPrivate->reg->id)[2*index + 1]) break; } if ( id_expected[index] != EOS ) { logMsg("%s: card does not exist at the VME A24 address 0x%x\n", (int)id_expected,(int)koDevAddrs(pCard), 0,0,0,0); (void) devUnregisterAddress( atVMEA24, (void *)koDevAddrs(pCard), id_expected); pPrivate->configured = FALSE; } else { logMsg("%s: 0x%x VME A24 address -> 0x%x IOC address\n", (int)id_expected,(int)koDevAddrs(pCard),(int)pPrivate->reg, 0,0,0); pPrivate->configured = TRUE; pPrivate->reg->csr = XY_ALL_OK; numChans = pPrivate->inp_mode == XY542_DI ? 31 : 63; pPrivate->reg->admsc = XY_PROGRAM_GAIN; for ( chan = 0; chan <= numChans; chan++ ) { pPrivate->reg->gain_ch_trig = pPrivate->gain_setting[chan] | chan; } pPrivate->ch_pending = NONE_PENDING; if ( (vecNum = koDevVectorNum( pCard )) > 0 ) { /* * Connect the ISR to the interrupt vector */ if ( (status = devConnectInterrupt( intVME, vecNum, xy542_isr, (void *)koDevCardNum(pCard) )) != OK) vecNum = -1; } else { for ( vecNum = FIRST_USER_VECTOR; vecNum <= LAST_USER_VECTOR; vecNum++ ) { if ((status = devConnectInterrupt( intVME, vecNum, xy542_isr, (void *)koDevCardNum( pCard ))) == OK) break; } } if (vecNum > LAST_USER_VECTOR) vecNum = -1; koDevSetVectorNum(pCard, vecNum); if (vecNum > 0) { pPrivate->reg->csr = XY_ALL_OK; pPrivate->reg->ivc = vecNum; logMsg ("%s: card #%d, 0x%x VME A24 address, 0x%x interrupt vector\n", (int)id_expected,(int)koDevCardNum(pCard),(int)koDevAddrs(pCard),pPrivate->reg->ivc,0,0); /* * Read the ADC to prevent spurious interrupt * conditions on initialization. */ chan = pPrivate->reg->adc; /* * If appropriate, enable the interrupts */ if (pPrivate->enableItrOnInit == TRUE) if ( devEnableInterruptLevel( intVME, koDevItrLevel( pCard ) ) == OK ) pPrivate->reg->admsc = RAND_CH | INT_EN; else pPrivate->enableItrOnInit = FALSE; } else { logMsg("%s: Interrupt vector not allocated for card %d at address %x\n", (int)id_expected,(int)koDevCardNum(pCard), (int)koDevAddrs(pCard), 0,0,0); pPrivate->enableItrOnInit = FALSE; pPrivate->configured = FALSE; return status; } } } pCard = koDevNext(pCard); } if ( rebootHookAdd( (FUNCPTR) xy542_reboot_hook) != OK ) logMsg("%s: xy542_reboot_hook could not be added!\n", (int)id_expected, 0,0,0,0,0); return Ok; } long xy542_last_card() { struct devInfo *descrp; long cardNum = 0, highCard = 0; descrp = koDevFirst( pXy542List ); while (descrp != NULL) { cardNum = koDevCardNum( descrp ); if (cardNum > highCard) highCard = cardNum; descrp = koDevNext( descrp ); } return highCard; } STATIC int xy542_signal_check( struct io_xy542 *descrp, long signal, int io_type) { int status = S_drvXy542_OK; switch (io_type){ case IO_AO: if ( signal < 0 || signal > NUM_O_CHAN ) status = S_drvXy542_badParam; break; case IO_AI: if ( (signal < 0) || (signal > (descrp->inp_mode == XY542_DI ? 31 : 63)) ) status = S_drvXy542_badParam; break; default: status = S_drvXy542_badParam; } return (status); } /* * Register a callback for a particular channel * Informs the driver of the board's mode, * differential or single-ended. */ int xy542_conf_channel( unsigned short card, unsigned short channel, XY542_CBACK *callback, enum input_mode inp_mode) { struct io_xy542 *descrp; XY542_CBACK *orig_callback; int status = S_drvXy542_OK; /* * verify that the card and signal are valid */ if ( DEVICE_NOT_VALID(pXy542List,descrp,card) ) return S_drvXy542_noDevice; if (descrp->inp_mode != XY542_UNSET && descrp->inp_mode != inp_mode ) status = S_drvXy542_invSigMode; orig_callback = descrp->rd_cback[channel]; /* * If a previous callback does not match the new callback, * something is wrong. Change the callback anyway. */ if (orig_callback != NULL && orig_callback != callback) status = S_drvXy542_cbackChg; descrp->rd_cback[channel] = callback; return status; } /* * Queue a conversion request with * the driver. */ int xy542_req_conversion( unsigned short card, unsigned short channel) { struct io_xy542 *pio; int status = S_drvXy542_OK; int level; /* * verify that the card and signal are valid */ if ( PARAMS_NOT_VALID(pXy542List,pio,card,channel,IO_AI) ) { if (pio == NULL) return S_drvXy542_noDevice; if (!pio->configured) return S_drvXy542_noDevice; return S_drvXy542_badParam; } taskLock(); /* Disable context switching and interrupts */ level = intLevelSet( koDevItrLevel(koDevNodeByCardNum(pXy542List,card)) ); if (pio->ch_pending == NONE_PENDING) { /* * 1. Store the channel # that will be undergoing conversion * 2. Start a conversion * 3. Indicate that the channel is in queue */ pio->ch_pending = channel; pio->reg->gain_ch_trig = pio->gain_setting[channel]; pio->inQ[channel] = TRUE; } else { if ( pio->inQ[channel]) { /* * Already queued a request, multiple requests * are disallowed. */ status = S_drvXy542_alreadyQd; } else { /* * 1. Add channel to queue * 2. Indicate that channel is currently Q'ed * 3. Advance queue pointer */ pio->Q[pio->endQ] = channel; pio->inQ[channel] = TRUE; (pio->endQ == (pio->inp_mode == XY542_SE ? 63 : 31)) ? pio->endQ = 0 : pio->endQ++; } } /* Reenable interrupts and context switching */ intLevelSet( level ); taskUnlock(); return status; } #ifdef DEBUG int xy542_int_count = 0; #endif /* * XY542 Interrupt Service Routine */ STATIC void xy542_isr(int card) { struct io_xy542 *pio = NULL; int last_ch_pending; int level; #ifdef DEBUG xy542_int_count++; #endif pio = koDevPrivate( koDevNodeByCardNum( pXy542List,card )); /* * if the device list or descriptor is corrupted then the interrupt will * never be cleared */ if (pio == NULL){ logMsg("xy542_isr: descriptor corrupted!\n",0,0,0,0,0,0); return; } level = intLevelSet( koDevItrLevel(koDevNodeByCardNum(pXy542List,card)) ); last_ch_pending = pio->ch_pending; /* * 1. Read the card and acknowledge the interrupt * 2. Indicate that this channel is no longer undergoing a conversion * 3. Indicate that this channel is no longer queued */ pio->last_read[last_ch_pending] = pio->reg->adc; pio->fresh_read[last_ch_pending] = TRUE; pio->inQ[last_ch_pending] = FALSE; /* * See if anything else is on the queue */ if (pio->startQ == pio->endQ) { pio->ch_pending = NONE_PENDING; /* No further requests */ } else { /* 1. Store the channel # that will be undergoing conversion * 2. Start a conversion * 3. Advance queue pointer */ pio->ch_pending = pio->Q[pio->startQ]; pio->reg->gain_ch_trig = pio->gain_setting[pio->ch_pending]; (pio->startQ == (pio->inp_mode == XY542_SE ? 63 : 31)) ? pio->startQ = 0 : pio->startQ++; } /* Invoke the user callback */ if (pio->rd_cback[last_ch_pending] != NULL) (*(pio->rd_cback[last_ch_pending]))(card, last_ch_pending); intLevelSet( level ); } int xy542_change_conv_mode( unsigned short card, enum conv_mode conv_mode ) { struct io_xy542 *descrp; /* verify that the card and signal are valid */ if ( DEVICE_NOT_VALID(pXy542List,descrp,card) ) return S_drvXy542_noDevice; if (conv_mode == XY542_SINGLE) { } else { } return S_drvXy542_OK; } int xy542_change_gain( unsigned short card, unsigned short signal, unsigned int gain) { struct io_xy542 *descrp; /* verify that the card and signal are valid */ if ( PARAMS_NOT_VALID(pXy542List,descrp,card,signal,IO_AI) ) { if (descrp == NULL) return S_drvXy542_noDevice; if (!descrp->configured) return S_drvXy542_noDevice; return S_drvXy542_badParam; } /* Shift the two gain bits to the 0x300 * positions, then OR with the program gain mask * and channel number. */ descrp->reg->admsc = XY_PROGRAM_GAIN; /* set program gain mode */ descrp->gain_setting[signal] = ((gain << 8) | signal) & 0x33f; descrp->reg->gain_ch_trig = descrp->gain_setting[signal]; descrp->reg->admsc = RAND_CH | INT_EN; return S_drvXy542_OK; } int xy542_read_gain( unsigned short card, unsigned short signal, unsigned int *gain) { struct io_xy542 *descrp; /* verify that the card and signal are valid */ if ( PARAMS_NOT_VALID(pXy542List,descrp,card,signal,IO_AI) ) { if (descrp == NULL) return S_drvXy542_noDevice; if (!descrp->configured) return S_drvXy542_noDevice; return S_drvXy542_badParam; } /* Shift the two gain bits to the least significant positions. */ *gain = descrp->gain_setting[signal] >> 8; return S_drvXy542_OK; } /* * XY542 READ * read an analog input. */ int xy542_read( unsigned short card, unsigned short channel, unsigned long *val) { struct io_xy542 *descrp; /* verify that the card and signal are valid */ if ( PARAMS_NOT_VALID(pXy542List,descrp,card,channel,IO_AI) ) { if (descrp == NULL) return S_drvXy542_noDevice; if (!descrp->configured) return S_drvXy542_noDevice; return S_drvXy542_badParam; } *val = descrp->last_read[channel]; return S_drvXy542_OK; } /* * XY542 WRITE * write an analog output */ int xy542_write( unsigned short card, unsigned short signal, unsigned int val) { struct io_xy542 *descrp; /* verify that the card and signal are valid */ if ( PARAMS_NOT_VALID(pXy542List,descrp,card,signal,IO_AO) ) { if (descrp == NULL) return S_drvXy542_noDevice; if (!descrp->configured) return S_drvXy542_noDevice; return S_drvXy542_badParam; } descrp->reg->dac[signal] = val; descrp->last_write[signal] = val; descrp->fresh_write[signal] = TRUE; return S_drvXy542_OK; } /* Names for XY542 input modes */ STATIC char *mode_name[XY542_NUM_INP_MODES] = { "TYPE NOT SET", "Differential", "Single-Ended" }; /* XY542 IO report */ long xy542_io_report() { struct devInfo *pDevBlock; struct io_xy542 *pPrivate; int signal, num_signals, noCard; pDevBlock = koDevFirst( pXy542List ); while ( pDevBlock != NULL ) { noCard = FALSE; pPrivate = koDevPrivate( pDevBlock ); if (pPrivate == NULL) noCard = TRUE; if (pPrivate->configured == FALSE) noCard = TRUE; if (noCard) { logMsg("%s: card %ld NOT CONFIGURED!\n", (long)id_expected,koDevCardNum(pDevBlock),0,0,0,0); } else { logMsg( "%s: card %2ld (0x%lx) IVEC:0x%2lx IRQ:%2ld %s\n", (long)id_expected, koDevCardNum(pDevBlock), (long)pPrivate->reg, (long)(pPrivate->reg->ivc), (long)koDevItrLevel(pDevBlock), (long)mode_name[pPrivate->inp_mode] ); for (signal=0; signal < NUM_O_CHAN; signal++) { if (pPrivate->fresh_write[signal]) { logMsg("OUT %2d = 0x%04x ", signal, pPrivate->last_write[signal],0,0,0,0); } else { logMsg("OUT %2d = UNKNWN ", signal,0,0,0,0,0); } if (signal % 4 == 3) logMsg("\n",0,0,0,0,0,0); } num_signals = pPrivate->inp_mode == XY542_DI ? 32 : 64; for (signal=0; signal < num_signals; signal++) { if (pPrivate->fresh_read[signal]) { logMsg("INP %2d = 0x%04x ", signal, (unsigned int) pPrivate->last_read[signal],0,0,0,0); } else { logMsg("INP %2d = UNKNWN ", signal,0,0,0,0,0); } if (signal % 4 == 3) logMsg("\n",0,0,0,0,0,0); } } pDevBlock = koDevNext( pDevBlock ); } return Ok; } /* XY542 SOFT RESET CARD */ void xy542_reset(unsigned short card) { struct io_xy542 *descrp; /* verify that the card and signal are valid */ if ( DEVICE_NOT_VALID(pXy542List,descrp,card) ) return; /* Toggle reset bit, reset occurs on "falling-edge". */ descrp->reg->csr = XY_RESET; /* enable interrupts and enable random channel mode for AI */ descrp->reg->csr = XY_ALL_OK; descrp->reg->admsc = RAND_CH | INT_EN; } #ifdef DEBUG int xy542_test_callback( unsigned short card, unsigned short signal) { logMsg("XY542 TEST: CALLBACK CARD %d SIGNAL %d\n", card, signal, 0,0,0,0); return S_drvXy542_OK; } int xy542_read_test(unsigned short card) { int status, channel; /* initialize callback on all cards and channels. */ for (channel=0; channel < NUM_I_CHAN; channel++) { status = xy542_conf_channel(card, channel, xy542_test_callback, XY542_DI); if (status != S_drvXy542_OK && status != S_drvXy542_cbackChg) { logMsg("XY542: REGISTER CALLBACK FAILED\n",0,0,0,0,0,0); return status; } } /* queue reads for every channel */ for (channel=0; channel < NUM_I_CHAN; channel++) { status = xy542_req_conversion(card, channel); if (status != S_drvXy542_OK) { logMsg("XY542: QUEUE READ FAILED\n",0,0,0,0,0,0); return status; } } return Ok; } int xy542_test() { xy542_read_test(0); xy542_read_test(1); xy542_read_test(0); xy542_read_test(1); return Ok; } int xy542_write_test( unsigned short card, unsigned short channel, unsigned long value) { unsigned int val = value; int status; status = xy542_write(card, channel, val); if (status == S_drvXy542_OK) return Ok; logMsg("XY542: WRITE FAILED\n",0,0,0,0,0,0); return ERR; } #endif /*+********************************************************************* $Log: drvXy540Ko.c,v $ Revision 1.8 1998/02/13 02:47:48 ahoney Corrected gain_setting init. Revision 1.7 1998/02/05 19:07:12 ahoney Removed intLock() and intUnlock(). * Revision 1.5 1996/12/18 23:13:52 ahoney * Mods to xy540_read_test so that the routine does not abort on a * changed callback. * * Revision 1.4 1996/05/04 02:08:53 ahoney * Replaced all ERR and OK return codes with the appropriate device specific * code. * * Revision 1.3 1996/02/23 01:28:36 ahoney * Modified the reboot routine so that it functions correctly for a * non-existent board. * * Revision 1.2 1996/02/15 19:16:46 ahoney * Mods relevant to eliminating module_types. * Added all defines and structures, which were in drvXy540ko.h, that are * relevant only to this module - they are private to the driver so should * be herein. * Added xy540Configure for startup script card configurations. * Major changes to xy540_driver_init. * Changes to all other routines so as to use the list structure which * was added for the config routine and devLib usage. * * Revision 1.1 1995/10/27 20:51:14 ahoney * Moved from dev/src/drv to dev/xy540 * * Revision 1.1.1.2 1995/06/28 19:44:56 ahoney * Initial insert of the Force SIO2 Vxworks driver. * * Revision 1.1.1.1 1995/05/11 21:30:18 rwright * initial insertion of kss/dcs2/dev * * ***********************************************************************/