# This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # camacEsone.c # This archive created: Wed Dec 6 12:24:05 1989 sed 's/^X//' << \SHAR_EOF > camacEsone.c X/* camacEsone.c - ESONE library of CAMAC functions */ X X/* Xwritten by; X XD'Anne Thompson XNational Optical Astronomy Observatories XP.O. Box 26732 XTucson, AZ 85726 X(602) 325-9335 Xdat@noao.edu {...}!uunet!noao.edu!dat X*/ X X X/* Xmodification history X-------------------- X01d 30may89,dat - changed mailboxes for semaphores. X01c 29may89,dat - fixed up for exporting X01b 04apr89,dat - fixed camacELM, so it re-enables crate Controller X with each enable operation. X01a 28oct88 dat written X*/ X X/* XThis module provides the functionality of the ESONE "Subroutines XFor Camac" DOE/EV-0016. Block transfer and scan functions are Xnot yet implemented. The calling sequences have been modified Xas little as possible to be consistent with a C language Xinterface. The original specification is for a FORTRAN interface. X XThe ESONE standard function names have all been prepended with Xthe module name camac, dropping the initial C character. XIn the case of functions that take a boolean flag to enable or Xdisable some function, the second character of C has been Xchanged to E to more clearly define the function. Xe.g. Function CCLM becomes camacELM (camac enable lam). X XThe initialization routine camacEsoneInit must be called prior Xto using any other functions within this module. X XPROBLEMS: X1) Taking a crate off-line for some work and then returning it to the system Xcauses many problems. XThe current solution is to do a branch initialize Xwhich disables lams throughout the branch. XPerhaps lam enabled status should be kept in the lam structure Xso that we could scan through the list and re-activate lams that Xwere previously enabled. X X2) Block transfer and scan functions are not yet implemented. X*/ X X#include "vxWorks.h" X#include "iv68k.h" /* interrupt routines */ X#include "vmeConfig.h" /* for 'CAM_MAX_BRANCH' */ X#include "camac.h" /* General camac interface definitions */ X#undef camacDREG /* we will define a non-macro version of CDREG */ X#include "am9519.h" /* vector generators on board ces8210 */ X X XIMPORT char * malloc (); XIMPORT free (); X X X/* External References (Other than #includes) */ XIMPORT FUNCPTR intHandlerCreate (); XIMPORT STATUS intConnect (); XIMPORT VOID intVecSet (); XIMPORT CES8210 *camacBaseAddr; /* local bus address */ X X/* Locally Defined Globals. */ XVOID camacEsoneInit (); /* () */ XCAM_REF camacDREG (); /* (b, c, n, a) */ XSTATUS camacSSA (); /* (f, reg, pShort, pStatus) */ XSTATUS camacFSA (); /* (f, reg, pLong, pStatus) */ XSTATUS camacCCC (); /* (reg) */ XSTATUS camacCCZ (); /* (reg) */ XSTATUS camacECI (); /* (reg, flag) */ XSTATUS camacECD (); /* (reg, flag) */ XBOOL camacTCI (); /* (reg) */ XBOOL camacTCD (); /* (reg) */ XBOOL camacTGL (); /* (reg) */ XCAM_LAM camacDLAM (); /* (b, c, n, m, intArray) */ XSTATUS camacLNK (); /* (lam, pFunc, arg) */ XSTATUS camacCLC (); /* (lam) */ XSTATUS camacELM (); /* (lam, flag) */ XBOOL camacTLM (); /* (lam) */ X X/* Local Symbols. (Forward References) */ XLOCAL STATUS camacBrInit (); /* (brNum, vecNum) */ XLOCAL VOID camacInterrupt(); /* common interrupt handler */ XLOCAL STATUS camacEGLAM(); /* (bglam, flag) */ XLOCAL BOOL br_init [CAM_MAX_BRANCH] = {0}; XLOCAL int br_vec [CAM_MAX_BRANCH] = {0}; XLOCAL LAM_DATA lamIt2 = /* LAM structure for IT2 */ X { {0,0}, 25, 0, 0, 0, 0}; XLOCAL LAM_DATA lamIt4 = /* lam structure for IT4 */ X { {0,0}, 26, 0, 0, 0, 0}; XLOCAL LIST listIt2; XLOCAL LIST listIt4; XLOCAL LIST lamList[CAM_MAX_BRANCH][24]; X X X/************************************************************* X* X* camacEsoneInit - initialize all branch controllers X* X* This function must be called prior to any use of the esone X* standard routines. This will initialize the interrupt controllers X* on the driver boards and will allow generation of lam interrupts. X*/ X XVOID camacEsoneInit () X X { X camacBrInit (0,CAMAC_BR0_INUM); X#if CAM_MAX_BRANCH > 1 X camacBrInit (1,CAMAC_BR1_INUM); X#if CAM_MAX_BRANCH > 2 X camacBrInit (2,CAMAC_BR2_INUM); X#if CAM_MAX_BRANCH > 3 X camacBrInit (3,CAMAC_BR3_INUM); X#if CAM_MAX_BRANCH > 4 X camacBrInit (4,CAMAC_BR4_INUM); X#if CAM_MAX_BRANCH > 5 X camacBrInit (5,CAMAC_BR5_INUM); X#if CAM_MAX_BRANCH > 6 X camacBrInit (6,CAMAC_BR6_INUM); X#if CAM_MAX_BRANCH > 7 X camacBrInit (7,CAMAC_BR7_INUM); X#endif X#endif X#endif X#endif X#endif X#endif X#endif X } X X/************************************************************* X* X* camacBrInit - initialize a single branch controller X* X* This local routine is used to initialize a single branch driver. X* It will initialize all 3 am_9519 interrupt vector generators. X* It will also send a branch Z signal to reset all crates on X* that branch. A previously initialized branch will just receive X* a Z signal and enabling of Glam scanning. X* X* Vectors are assigned in priority order. X* The first vector is associated with GL1, the highest priority graded lam X* The IT2 and IT4 vectors are assigned in hardware, and are X* common to all branches. X* X* RETURNS: X* Returns ERROR for invalid arguments, or an attempt to redefine X* the interrupt vector for a previously initialized controller. X* ERROR will also be returned if the controller is not present. X* Malloc failures can also cause an ERROR return. X*/ X XLOCAL STATUS camacBrInit (brNum, vectorNum) X int brNum; /* branch number 0-7 */ X int vectorNum; /* base vector (24 total) */ X X { X LOCAL FUNCPTR handlerIt2 = NULL; X LOCAL FUNCPTR handlerIt4 = NULL; X int dummy; X CES8210 *pBoard; X X if (brNum >= CAM_MAX_BRANCH) X { X /*HELP: set error code BAD_PARAMETERS*/ X return ERROR; X } X X pBoard = camacBaseAddr + brNum; X X if (vxMemProbe ((char *)&(pBoard->BCSR), READ, X sizeof(pBoard->BCSR), (char *)&dummy) == ERROR) X return ERROR; X X if (br_init [brNum] == TRUE) X { X if (vectorNum != br_vec [brNum]) X { X /* Attempt to redefine with different vector set */ X return ERROR; X } X pBoard->BZ = 0; X pBoard->BITF = 0; X pBoard->BCSR &= ~(CAM_MTO|CAM_MLAM); X return OK; X } X X if (handlerIt2 == NULL) X { X lstInit (&listIt2); X lstAdd (&listIt2, &(lamIt2.node)); X handlerIt2 = intHandlerCreate (camacInterrupt, (int)(&listIt2)); X if (handlerIt2 == NULL) X return ERROR; X intVecSet ((FUNCPTR *)INUM_TO_IVEC (CAMAC_IT2_INUM), handlerIt2); X } X X if (handlerIt4 == NULL) X { X lstInit (&listIt4); X lstAdd (&listIt4, &(lamIt4.node)); X handlerIt4 = intHandlerCreate (camacInterrupt, (int)(&listIt4)); X if (handlerIt4 == NULL) X return ERROR; X intVecSet ((FUNCPTR *)INUM_TO_IVEC (CAMAC_IT4_INUM), handlerIt4); X } X X /* X * Init the three interrupt vector generators. The vectors X * are assigned in priority order. The first vector is X * associated with GL1, the highest priority Glam. The X * IT2 and IT4 vectors are assigned in hardware, and are X * common to all branches. X */ X { X LIST *pList = &(lamList[brNum][0]); X FAST short *pDataReg = &(pBoard->BD1); X FAST short *pCmdReg = &(pBoard->BC1); X FAST int i,j; X int tempVec = vectorNum; X X for (i=0; i<3; i++) X { X *pCmdReg = AM_RESET; X *pCmdReg = AM_LOAD04 | AM_04INIT; X *pCmdReg = AM_CLIRR; X *pCmdReg = AM_LOAD56 | AM_56INIT; X for (j=0; j<8; j++) X { X lstInit (pList); X if (intConnect ((FUNCPTR *)INUM_TO_IVEC(tempVec), X camacInterrupt, (int)(pList++)) == ERROR) X return ERROR; X *pCmdReg = AM_WRMEM | AM_8BIT | j; X *pDataReg = tempVec++ ; X } X pCmdReg += 2; X pDataReg += 2; X } X } X X /* X * Branch successfully initialized. Set the br_init flag and X * then send a branch Z command to reset all crates. X * Enable branch Glam scanning, The driver will scan for Glam X * every 10 micro-seconds while the BD signal is active. X * Specific Glam interrupts are enabled/disabled by the camacEGLAM() X * routine. X */ X br_init [brNum] = TRUE; X br_vec [brNum] = vectorNum; X pBoard->BZ = 0; /* NECESSARY ?? */ X pBoard->BITF = 0; X pBoard->BCSR &= ~(CAM_MTO|CAM_MLAM); X X return OK; X} X X/************************************************************* X* X* camacEGLAM - enable/disable graded lam level (non-Esone) X* X* Enable/Disable individual Graded lam from an encoded bglam value. X* This sets/clears the interrupt mask bits in the appropriate X* vector generator modules. X* (For IT2 and IT4 it set/clears mask bits in the csr register X* for branch #0). X* X* The branch number and lam number are encoded together as an int. X* Shift the branch number left 5 bits and 'or' in the lam number X* to encode. Lam numbers are one based, with special codes for X* IT2 and IT4. IT2 is lam number 25, while IT4 is lam number 26. X* X* RETURNS: X* Returns ERROR if the referenced branch is not initialized. X*/ X XLOCAL STATUS camacEGLAM (bglam, flag) X int bglam; /* encoded branch & lam number */ X BOOL flag; /* TRUE-> enable, FALSE->disable */ X X { X FAST int glam; X FAST CES8210 * pBoard; X int brNum = bglam/32; X X glam = (bglam%32) - 1; /* 0 - 25 */ X X if (glam > 23) X { X /* Set/Clr Special interrupts. IT2 and IT4. (Branch 0) */ X if (br_init [0] == FALSE) X return ERROR; X pBoard = camacBaseAddr; X if (flag == TRUE) X pBoard->BCSR &= (glam==24 ? ~CAM_MIT2 : ~CAM_MIT4) ; X else X pBoard->BCSR |= (glam==24 ? CAM_MIT2 : CAM_MIT4) ; X } X else X { X /* X * Always clear the ISR flag. To enable interrupts X * clear both the IMR and IRR bits. To disable, just X * set the IMR bit. X */ X FAST short * pCmdReg; X X if (br_init [brNum] == FALSE) X return ERROR; X X pBoard = camacBaseAddr + brNum; X X pCmdReg = &(pBoard->BC1); X while (glam > 7) X { X pCmdReg += 2; X glam -= 8; X } X *pCmdReg = AM_CLISRB | glam ; X *pCmdReg = ((flag == TRUE ? AM_CLIMRIRRB : AM_STIMRB) | glam) ; X } X X return OK; X } X X X/************************************************************* X* X* camacInterrupt - camac graded lam interrupt service routine X* X* Each Graded lam vectors to this routine with X* a pointer to the linked list of lams on the stack. This routine X* searches the lam list for an active lam and executes the associated X* routine. The lam handler routine should return TRUE if the routine X* was successful in servicing (and clearing) the lam. If the routine was X* not successful, then we must assume the lam (interrupt) is still X* asserted. This routine will then try to disable the lam using X* camacCLM(). If camacCLM() is unsuccessful, then the only graceful way X* to exit is to report a major error and disable the complete graded lam X* for that branch. X*/ X XLOCAL VOID camacInterrupt (pList) X LIST * pList; /* A pointer to the first lam structure */ X X { X BOOL temp; X BOOL retval = FALSE; X FAST CAM_LAM pLam = lamFirst (pList); X int bglam; X X if (pLam == 0) X { X /*ERROR: No defined lam for this interrupt */ X /*ERROR: Major system fault, don't even know what bglam this is. */ X return; X } X X bglam = pLam->bglam; X X /* Search through the list for any and all active lam. */ X while (pLam != NULL) X { X if (camacTLM (pLam) == TRUE) X { X /* We have an active lam. */ X temp = FALSE; X if ((pLam->handler) != 0) X temp = (pLam->handler)(pLam->arg, pLam); X X /* X * If handler didn't do it, then we must try to clear the X * lam condition, if that fails try to disable it. X */ X if (temp == FALSE) X { X if (camacCLC (pLam) == OK X || camacELM (pLam,0) == OK X ) X retval = TRUE; X } X else X retval = TRUE; X X /* signal semaphore upon completion of handler routines. */ X if (pLam->sem) X semGive (pLam->sem); X } X pLam = lamNext (pLam); X } X X /* X * We were unable to process any lam attached to this Glam. X * We must therefore step back and PUNT. Lets report a X * major system error and then disable this complete BGlam. X */ X if (retval == FALSE) X { X /***ERROR: Unsuccessful Camac Interrupt ***/ X (void) camacEGLAM (bglam, 0); X } X else X (void) camacEGLAM (bglam, 1); /* Is this necessary ? */ X X return; X } X X X/************************************************************ X* X* camacDREG - define a camac register (CDREG) X* X* This routine creates an ESONE standard register reference X* and returns it to the caller. The register reference X* includes branch number, crate number, slot number, and module X* sub-address. It does not include function code or size X* information. X* X* RETURNS: X* The ESONE standard reference is returned in the form of a CAM_REF. X* (See camacBuildRef). NULL is returned for invalid arguments. X* X* SEE ALSO X* camacBuildRef X*/ X XCAM_REF camacDREG (b, c, n, a) X int b; /* branch */ X int c; /* crate */ X int n; /* slot */ X int a; /* sub-address */ X X { X /* use F0 and CAM_LONG to finish out the reference */ X return camacBuildRef (b, c, n, a, 0, CAM_LONG); X } X X/********************************************************* X* X* camacSSA - camac short single action (CSSA) X* X* Execute a short (16 bit) single action to a camac register. X* X* The transaction status is stored at the location given by X* pStatus. If pStatus is zero or NULL, then the X* camac status word is discarded. X* X* RETURNS: X* Returns ERROR if the camac cycle fails (no-X and no-Q). X*/ X XSTATUS camacSSA (f, reg, pShort, pStatus) X int f; /* function code, 0-31 */ X CAM_REF reg; /* register reference */ X short *pShort; /* data pointer */ X CAM_STAT *pStatus; /* result status pointer */ X X { X STATUS result; X X reg &= CAM_BCNA_MASK; X reg |= (f << CAM_F_SHIFT) | CAM_SHORT; X X if (f & 8) X result = camacTest (reg, pStatus); X else if (f < 16) X result = camacIn (reg , (char *)pShort, pStatus); X else X result = camacOut (reg, (ULONG)*pShort, pStatus); X X return result; X } X X X/********************************************************* X* X* camacFSA - camac full (24 bit) single action (CFSA) X* X* Execute a full (24-bit) single action to/from a camac register. X* X* The transaction status is stored at the location given by X* pStatus. If pStatus is zero or NULL, then the X* camac status word is discarded. X* X* RETURNS: X* Returns ERROR if the camac cycle fails (no-X and no-Q). X*/ X XSTATUS camacFSA (f, reg, pLong, pStatus) X int f; /* function code */ X CAM_REF reg; /* register reference */ X long *pLong; /* data pointer */ X CAM_STAT *pStatus; /* pointer to status result */ X X { X STATUS result; X X reg &= CAM_BCNA_MASK; X reg |= (f << CAM_F_SHIFT) ; X X if (f & 8) X result = camacTest (reg, pStatus); X X else if (f < 16) X result = camacIn (reg, (char *)pLong, pStatus); X X else X result = camacOut (reg, (ULONG)*pLong, pStatus); X X return result; X } X X X/************************************************************** X* X* camacCCC - generate a dataway clear cycle (CCCC) X* X* Causes a dataway clear cycle to be generated by the crate controller. X* The camRef argument may be any valid register reference within X* the crate. Slot number and sub-address are masked off by the X* routine. X* X* Type A-1 and A-2 parallel highway crate controllers respond X* to N28A8F26 by generating a dataway clear cycle. X* X* RETURNS: X* Returns the status code from the underlying camacTest operation. X* See camacTest. X*/ X XSTATUS camacCCC (camRef) X FAST CAM_REF camRef; /* any valid reference within crate */ X X { X camRef &= CAM_BC_MASK; X camRef |= (28 << CAM_N_SHIFT) + (8 << CAM_A_SHIFT) + (26 << CAM_F_SHIFT); X return (camacTest (camRef, (CAM_STAT *)NULL)); X } X X X/************************************************************** X* X* camacCCZ - generate a dataway initialize cycle (CCCZ) X* X* Causes a dataway initialize (Z) cycle to be generated by the crate controller. X* The camRef argument may be any valid register reference within X* the crate. Slot number and sub-address are masked off by the X* routine. X* X* Type A-1 and A-2 parallel highway crate controllers respond X* to N28A9F26 by generating a dataway initialize cycle. X* X* RETURNS: X* Returns the status code from the underlying camacTest operation. X* See camacTest. X*/ X XSTATUS camacCCZ (camRef) X CAM_REF camRef; /* any valid reference within crate */ X X { X camRef &= CAM_BC_MASK; X camRef |= (28 << CAM_N_SHIFT) + (9 << CAM_A_SHIFT) + (26 << CAM_F_SHIFT); X return (camacTest (camRef, (CAM_STAT *)NULL)); X } X X X/*********************************************************** X* X* camacECI - assert/release crate controller inhibit (CCCI) X* X* Controls the crate controller's output to the dataway inhibit line. X* X* The dataway inhibit line is a wire-or'd open-collector line X* common to all slot positions. Any module can drive the line X* active by pulling down on it (low true). At dataway X* initialize time, regular modules must release the line, but X* the crate controller will assert it. X* X* The camacECI function controls only the crate controller's X* assertion of the inhibit line. All modules within the crate X* must release the inhibit line for the line to go inactive (high). X* X* Type A-1 and A-2 crate controllers respond to N30A9F24 by X* asserting the inhibit line. An N30A9F26 command will cause X* them to release the inhibit line. X* X* RETURNS: X* The return code indicates success/failure of the actual camac cycle. X* See camacTest. X*/ X XSTATUS camacECI (camRef, flag) X CAM_REF camRef; /* any valid crate address */ X BOOL flag; /* enable/disable code */ X X { X camRef &= CAM_BC_MASK; X camRef |= (30 << CAM_N_SHIFT) + (9 << CAM_A_SHIFT) X + (flag ? (26 << CAM_F_SHIFT) : (24 << CAM_F_SHIFT)); X return (camacTest (camRef, (CAM_STAT *)NULL)); X } X X X/********************************************************** X* X* camacTCI - test crate inhibit line (CTCI) X* X* Returns the current status of the dataway inhibit line. X* Inhibit status is determined by accessing N30A9F27 through X* the type-A crate controller. The controller will respond with Q X* equal to the current state of the inhibit line. X* X* RETURNS: X* Returns the state of the dataway inhibit line. X* FALSE is returned upon any error conditions. X*/ X XBOOL camacTCI (camRef) X CAM_REF camRef; /* any reference into crate */ X X { X CAM_STAT status = 0; X X camRef &= CAM_BC_MASK; X camRef |= (30 << CAM_N_SHIFT) + (9 << CAM_A_SHIFT) + (27 << CAM_F_SHIFT); X camacTest (camRef, &status); X return (status & CAM_Q_BIT ? TRUE : FALSE); X } X X X/********************************************************* X* X* camacECD - enable/disable crate controller demands (CCCD) X* X* Enable/disable the crate controller's ability to generate X* a branch demand (graded lam). X* Type-A controller access at N30A10F26 will enable demands. X* Access at N30A10F24 will disable demand generation. X* X* RETURNS: X* Returns the camac cycle success/fail code. X* See camacTest. X*/ X XSTATUS camacECD (camRef, flag) X CAM_REF camRef; /* any reference within the crate */ X BOOL flag; /* enable/disable flag */ X X { X camRef &= CAM_BC_MASK; X camRef |= (30 << CAM_N_SHIFT) + (10 << CAM_A_SHIFT) X + (flag ? (26 << CAM_F_SHIFT) : (24 << CAM_F_SHIFT)); X return (camacTest (camRef, (CAM_STAT *)NULL)); X } X X X/************************************************************** X* X* camacTCD - test crate controller demand enable (CTCD) X* X* Returns the crate controller's demand enable status. X* Demand enable status is determined by accessing N30A10F27 through X* the type-A crate controller. The controller will respond with Q X* equal to the demand enable state. X* X* RETURNS: X* Returns TRUE if crate demands are enabled. X*/ X XBOOL camacTCD (camRef) X CAM_REF camRef; /* any reference within the crate */ X X { X CAM_STAT status = 0; X X camRef &= CAM_BC_MASK; X camRef |= (30<=CAM_MAX_BRANCH || c<1 || c>7 || n<1 || n>23 X || m<-32 || m>15 || GLAM<1 || GLAM>24) X { X /***ERROR: "Invalid parameters" ***/ X return (CAM_LAM) NULL; X } X pLam = lamFirst (&(lamList[b][ GLAM - 1])) ; X } X X /* X * generate BCNA for the lam. X * Bit position lam are recorded with A=0. X * generate flags for the lam. X */ X bcna = camacDREG (b, c, n, (m<0 ? 0 : m)); X bitnum = (m<0 ? -m : 0); X X /* X * Search the lam list for a match to BCNA. X * The list is ordered by bcna as the major key, with bitnum as X * the minor key. X */ X while (pLam && (pLam->bcna < bcna)) X pLam = lamNext (pLam); X X /* X * Continue the search on the minor key (only for bit position X * lams). X */ X if (pLam && bitnum) X while (pLam && (bcna==pLam->bcna) && (bitnum > pLam->bitnum)) X pLam = lamNext (pLam); X X /* X * Insert a completely new lam structure ? X */ X if (!pLam || (bcna != pLam->bcna) || (bitnum != pLam->bitnum)) X { X CAM_LAM pNew = (CAM_LAM) malloc (sizeof(LAM_DATA)); X X if (pNew == NULL) X return (CAM_LAM) NULL; X X pNew->bcna = bcna; X pNew->bitnum = bitnum; X pNew->bglam = b*32 + GLAM; X X lstInsert (&(lamList[b][GLAM-1]), X (pLam ? lstPrevious((NODE *)pLam) : (NODE *)NULL), X (NODE *)pNew); X X pLam = pNew; X } X X /* Enable the crate controller for this lam */ X camacECD (pLam->bcna, 1); X X /* X * Before returning, we must insure that the GLAM is enabled. X * Update the parameter fields in old lam structures. X */ Xexit: X pLam->sem = (SEM_ID) SEMAPHORE; X pLam->handler = (FUNCPTR) NULL; X pLam->arg = 0; X if (camacEGLAM (pLam->bglam, 1) == ERROR) X return (CAM_LAM) NULL; X X return (pLam); X } X X X/************************************************************* X* X* camacLNK - link a function to a lam (CLNK) X* X* This routine associates a C-callable function with a lam signal X* (interrupt). X* X* When enabled and active a lam (as defined by camacDLAM) generates X* an interrupt. The camacLNK routine will connect the user X* specified function with the processing of that interrupt. X* X* The function will be invoked, in interrupt context, with X* two arguments. The first argument is 'arg', the procedure X* argument specified in the camacLNK function. The CAM_LAM X* data structure pointer is the second argument. X* X* The user procedure must return a boolean result indicating that X* the lam has been properly serviced (TRUE). A FALSE return X* value indicates that the lam was not serviced and is still active. X* Under that situation the system code will attempt to disable the X* lam from generating further interrupts. X* X* .CS X* BOOL function (arg, pLam) X* int arg; X* CAM_LAM pLam; X* X* Returns TRUE if lam was properly serviced, FALSE otherwise. X* .CE X* X* NOTES: X* Be aware that the user procedure is executed in interrupt context. All X* of the warnings about restricted system calls apply. X* X* RETURNS: X* The camacLNK function normally returns OK. X* ERROR is returned for invalid arguments. X*/ X XSTATUS camacLNK (pLam, proc, arg) X CAM_LAM pLam; /* lam pointer */ X BOOL (*proc)(); /* procedure pointer*/ X long arg; /* procedure argument */ X X { X#define VALID_LAM 1 /*** HELP: Need better validation ***/ X if (VALID_LAM) X { X pLam->handler = proc; X pLam->arg = arg; X return OK; X } X else X return ERROR; X#undef VALID_LAM X } X X X/******************************************************* X* X* camacTLM - test lam status (CTLM) X* X* Test if a lam is active and enabled. X* X* Sub address lams are tested using F8 at the correct sub-address. X* Bit-address lams are tested by examining the proper bit X* of register A14 (F1A14). X* X* RETURNS: X* Returns TRUE if the lam is active and enabled. X*/ X XBOOL camacTLM (pLam) X CAM_LAM pLam; X X { X FAST CAM_REF addr; X X addr = pLam->bcna; X X if (pLam->bitnum) X { X /* X * Bit position type lam. Test by examining bit bitnum X * in the group 2 register at A14. X */ X FAST int mask; X long bits; X X mask = 1 << (pLam->bitnum - 1); X addr += 14 << CAM_A_SHIFT + 1 << CAM_F_SHIFT; X X if (camacIn (addr, (char *)&bits, (CAM_STAT *)NULL) == ERROR) X return FALSE; X X return ((bits & mask) ? TRUE : FALSE); X } X else X { X CAM_STAT status = 0; X /* X * Sub address type lam. Use F8 to test lam status. X * The lam status is returned as Q. X */ X camacTest (addr + (8 << CAM_F_SHIFT), &status); X return (status & CAM_Q_BIT) ? TRUE : FALSE; X } X } X X X/************************************************************** X* X* camacCLC - clear lam condition (CCLC) X* X* Clears a lam condition if possible. Sub-address lams are cleared X* using F10. Bit-address lams are cleared by selectively clearing X* the proper bit of register A12 (F23A12). X* X* RETURNS: X* The status code of the underlying action cycle is returned as X* the result of this function. See camacOut and camacTest. X*/ X XSTATUS camacCLC (pLam) X CAM_LAM pLam; X X { X FAST CAM_REF addr; X FAST STATUS retval; X X addr = pLam->bcna; X if (pLam->bitnum) X { X /* X * Bit position type lam. Clear by resetting X * bit bitnum of the group 2 register at address 12. X * (A=12, F=23, CAM_LONG) X */ X FAST int mask; X X mask = 1 << (pLam->bitnum - 1); X retval = camacOut (addr + (12 << CAM_A_SHIFT) + (23 << CAM_F_SHIFT), X (ULONG)mask, (CAM_STAT *)NULL); X } X else X { X /* X * Sub address type lam. Use F10 to clear lam status. X */ X retval = camacTest (addr + (10 << CAM_F_SHIFT), (CAM_STAT *)NULL); X } X X return (retval); X } X X X/***************************************************************** X* X* camacELM - enable/disable a lam (CCLM) X* X* Enable or disable lam. X* Sub-address lams are enabled with F26 and disabled with F24. X* X* Bit-address lams are enabled by setting the bit in the enable X* register A13 (F19A13). X* They are disabled by selectively clearing the bit (F23A13). X* X* RETURNS: X* The return code is that of the underlying camac cycle. X* See camacTest and camacOut. X*/ X XSTATUS camacELM (pLam, flag) X CAM_LAM pLam; /* lam pointer */ X BOOL flag; /* enable/disable flag */ X X { X FAST CAM_REF addr; X FAST STATUS retval; X X addr = pLam->bcna; X if (pLam->bitnum) X { X /*** X Bit position type lam. Update by setting/clearing X bit 'bitnum of the group 2 register at address 13. X F19A13 to set lam enable bit. F23A13 to clear lam enable bit. X ***/ X FAST int mask; X mask = 1 << (pLam->bitnum - 1); X addr |= (13 << CAM_A_SHIFT) + X (flag ? (19 << CAM_F_SHIFT) : (23 << CAM_F_SHIFT)); X retval = camacOut (addr, (ULONG)mask, (CAM_STAT *)NULL); X } X else X { X /* X * Sub address type lam. Use F26 to enable, F24 to disable. X */ X addr |= (flag ? (26 << CAM_F_SHIFT) : (24 << CAM_F_SHIFT)); X retval = camacTest (addr, (CAM_STAT *)NULL); X } X X /* re-enable the crate controller demand */ X if (flag && retval == OK) X { X return (camacECD (addr,flag)); X } X X return (retval); X } SHAR_EOF # End of shell archive exit 0