Initial revision

This commit is contained in:
John Winans
1993-08-12 14:28:10 +00:00
parent 7098bedd39
commit 4344a033e6

684
src/drv/drvMvme162.c Normal file
View File

@@ -0,0 +1,684 @@
/* share/src/drv/drvMvme162.c $Id$ */
/* Author: John Winans
* Date: 06-28-93
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* Modification Log:
* -----------------
*/
#include <vxWorks.h>
#include <types.h>
#include <iosLib.h>
#include <taskLib.h>
#include <semLib.h>
#include <memLib.h>
#include <wdLib.h>
#include <rngLib.h>
#include <lstLib.h>
#include <vme.h>
#include <sysLib.h>
#include <iv.h>
#include <module_types.h>
#include <task_params.h>
#include <drvSup.h>
#include <dbDefs.h>
#include <link.h>
#include <fast_lock.h>
#include <drvMvme162.h>
#include <drvGpibInterface.h>
#include "drvGpib.h"
struct IB162Link {
struct ibLink ibLink;
SEM_ID IOsem;
int IrqLevel;
int IrqVector;
Mvme162LinkStruct *pMvme162Link;
};
static struct IB162Link *pIB162[MVME162_NUM_LINKS*4];
static int linkTask(struct IB162Link *plink);
int mv167Debug = 0;
/******************************************************************************
*
* IRQ handler that is invoked when the default IRQ vector is generated
* from the MVME162 board.
*
******************************************************************************/
/* BUG have to add new extended IRQ handshake code in here */
static void my162Handler(Mvme162LinkStruct *pMvme162)
{
if (semGive(*(SEM_ID*)(pMvme162->pIrqParm)) != OK)
{
logMsg("my162Handler(0x%08.8X) semGive failed!!!!!\n", *(SEM_ID*)(pMvme162->pIrqParm));
}
pMvme162->IrqHandshake = 0; /* Clear the IRQ status */
return;
}
/******************************************************************************
*
* Initialize the specified GPIB link number for future use.
*
* Should only be called by GPIB library code.
******************************************************************************/
long
drv162IB_InitLink(int link)
{
int j;
link -= MVME162_LINK_NUM_BASE;
if ((link < 0) || (link >= MVME162_NUM_LINKS*4))
return(-1);
if (pIB162[link] == NULL)
{
/* Allocate the memory for the link descriptor. */
pIB162[link] = malloc(sizeof(struct IB162Link));
if (pIB162[link] == NULL)
return(-1);
pIB162[link]->ibLink.linkType = GPIB_IO;
pIB162[link]->ibLink.linkId = link;
pIB162[link]->ibLink.bug = -1;
pIB162[link]->ibLink.linkEventSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY);
lstInit(&pIB162[link]->ibLink.hiPriList);
pIB162[link]->ibLink.hiPriSem = semBCreate(SEM_Q_FIFO, SEM_FULL);
lstInit(&pIB162[link]->ibLink.loPriList);
pIB162[link]->ibLink.loPriSem = semBCreate(SEM_Q_FIFO, SEM_FULL);
pIB162[link]->ibLink.srqIntFlag = 0;
for (j=0; j<IBAPERLINK; j++)
{
pIB162[link]->ibLink.srqHandler[j] = NULL;
pIB162[link]->ibLink.srqParm[j] = NULL;
pIB162[link]->ibLink.deviceStatus[j] = 0;
pIB162[link]->ibLink.pollInhibit[j] = 0;
}
pIB162[link]->IOsem = semBCreate(SEM_Q_FIFO, SEM_EMPTY);
if (pIB162[link]->IOsem == NULL)
{
printf("drv162IB_InitLink(%d) IOsem creation failed\n", link);
return(-1);
}
printf("IOsem is %08.8X\n", pIB162[link]->IOsem);
/* BUG Should be using sysBusToLocal() in here */
j = link>>2;
pIB162[link]->pMvme162Link = (Mvme162LinkStruct *)(MVME162_EXT_OFF+(j*MVME162_EXT_SIZE));
pIB162[link]->IrqLevel = MVME162_IRQ_LEVEL;
pIB162[link]->IrqVector = MVME162_IVEC_BASE+j;
printf("drvMvme162_InitLink(%d) at 0x%08.8X - 0x%08.8X\n", link, pIB162[link]->pMvme162Link, &(pIB162[link]->pMvme162Link->pIrqParm));
if (intConnect(INUM_TO_IVEC(MVME162_IVEC_BASE+j), my162Handler, pIB162[link]->pMvme162Link) != OK)
{
printf("drv162IB_InitLink(%d) intConnect() failed\n", link);
return(-1);
}
sysIntEnable(MVME162_IRQ_LEVEL);
{ /* Send a message out to do GPIB link initialization */
CommandStruct cmd;
Mvme162GpibParmStruct parm;
cmd.Command = MVME162_GPIB_ALLINIT;
cmd.pOutput = NULL;
cmd.pInput = NULL;
parm.OutLength = 0;
parm.InLength = 0;
parm.Address = 0;
parm.Time = 0;
sysLocalToBusAdrs(VME_AM_EXT_SUP_DATA, &parm, &cmd.pParms);
cmd.IrqLevel = pIB162[link]->IrqLevel;
cmd.IrqVector = pIB162[link]->IrqVector;
cmd.pIrqParm = &(pIB162[link]->IOsem);
Send162(pIB162[link]->pMvme162Link, &cmd);
printf("init() Ready to take semaphore\n");
semTake(pIB162[link]->IOsem, WAIT_FOREVER);
printf("Got Semaphore, status = %08.8X\n", parm.Status);
}
/* Spawn the link task */
if (taskSpawn("162IB", GPIBLINK_PRI, GPIBLINK_OPT, GPIBLINK_STACK, linkTask, &pIB162[link]->ibLink) == ERROR)
{
printf("drv162IB_InitLink(%d): can't start link task\n", link);
return(-1);
}
}
return(0);
}
/******************************************************************************
*
* Return the address of an iblink structure.
*
* Should only be called by GPIB library code.
******************************************************************************/
long
drv162IB_GetLink(int link, struct ibLink **pplink)
{
link -= MVME162_LINK_NUM_BASE;
if(mv167Debug)
printf("drvMvme162_GetLink(%d, 0x%08.8X)\n", link, pplink);
if ((link < 0) || (link >= MVME162_NUM_LINKS*4))
return(-1);
*pplink = &(pIB162[link]->ibLink);
return(0);
}
/******************************************************************************
*
* This allows a device support module to register an SRQ event handler.
*
* It is used to specify a function to call when an SRQ event is detected
* on the specified link and device. When the SRQ handler is called, it is
* passed the requested parm and the poll-status from the gpib device.
*
******************************************************************************/
long
drv162IB_RegisterSrq(struct ibLink *pibLink, int device, int (*handler)(), void *parm)
{
if(mv167Debug)
printf("registerSrqCallback(%08.8X, %d, 0x%08.8X, %08.8X)\n", pibLink, device, handler, parm);
pibLink->srqHandler[device] = handler;
pibLink->srqParm[device] = parm;
return(0);
}
/******************************************************************************
*
*
* Should only be called by GPIB library code.
******************************************************************************/
long
drv162IB_QueueReq(struct dpvtGpibHead *pGpibHead, int prio)
{
if(mv167Debug)
printf("drv162IB_QueueReq()\n");
if (pGpibHead->pibLink == NULL)
{
printf("drv162IB_QueueReq(%08.8X, %d): dpvt->pibLink=NULL!\n", pGpibHead, prio);
return(-1);
}
switch (prio) {
case IB_Q_LOW: /* low priority transaction request */
semTake(pGpibHead->pibLink->loPriSem, WAIT_FOREVER);
lstAdd(&(pGpibHead->pibLink->loPriList), pGpibHead);
semGive(pGpibHead->pibLink->loPriSem);
semGive(pGpibHead->pibLink->linkEventSem);
break;
case IB_Q_HIGH: /* high priority transaction request */
semTake(pGpibHead->pibLink->hiPriSem, WAIT_FOREVER);
lstAdd(&(pGpibHead->pibLink->hiPriList), pGpibHead);
semGive(pGpibHead->pibLink->hiPriSem);
semGive(pGpibHead->pibLink->linkEventSem);
break;
default: /* invalid priority */
printf("invalid priority requested in call to drv162IB_QueueReq(%08.8X, %d)\n", pGpibHead, prio);
return(-1);
}
if (mv167Debug)
printf("drv162IB_QueueReq(%d, 0x%08.8X, %d): xact queued\n", pGpibHead, prio);
return(0);
}
/******************************************************************************
*
* At the time this function is started as its own task, the linked list
* structures will have been created and initialized.
*
* This function is spawned as a task for each GPIB bus present in the
* system. That is one for each Ni card port, and one for each Bit Bus
* bug that contains a GPIB port on it.
*
* All global data areas referenced by this task are limited to the non-port
* specific items (no niLink[] references allowed.) so that the same task
* can operate all forms of GPIB busses.
*
******************************************************************************/
static int
linkTask(struct ibLink *plink)
{
struct dpvtGpibHead *pnode;
int working;
if (mv167Debug)
printf("IB162 link task started for link link %d\n", plink->linkId);
working = 1; /* check queues for work the first time */
while (1)
{
if (!working)
{
#if 0
if (ibSrqLock == 0)
{
/* Enable SRQ interrupts while waiting for an event */
srqIntEnable(plink->linkType, plink->linkId, plink->bug);
}
#endif
/* wait for an event associated with this GPIB link */
semTake(plink->linkEventSem, WAIT_FOREVER);
#if 0
/* Disable SRQ interrupts while processing an event */
srqIntDisable(plink->linkType, plink->linkId, plink->bug);
#endif
if (mv167Debug)
{
printf("IB152LinkTask(%d, %d): got an event\n", plink->linkType, plink->linkId);
}
}
working = 0; /* Assume will do nothing */
#if 0
if ((plink->srqIntFlag) && (ibSrqLock == 0))
{
if (mv167Debug || ibSrqDebug)
printf("IB152LinkTask(%d, %d): srqIntFlag set.\n", plink->linkType, plink->linkId);
/* Read the SRQ message buffer and callback the handler for each
device. */
printf("IB152LinkTask(%d, %d): dispatching srq handler for device %d\n", plink->linkType, plink->linkId, ringData.device);
plink->deviceStatus[ringData.device] = (*(plink->srqHandler)[ringData.device])(plink->srqParm[ringData.device], ringData.status);
working=1;
}
#endif
/*
* see if the Hi priority queue has anything in it
*/
semTake(plink->hiPriSem, WAIT_FOREVER);
if ((pnode = (struct dpvtGpibHead *)lstFirst(&(plink->hiPriList))) != NULL)
{
while (plink->deviceStatus[pnode->device] == BUSY)
if ((pnode = (struct dpvtGpibHead *)lstNext(pnode)) == NULL)
break;
}
if (pnode != NULL)
lstDelete(&(plink->hiPriList), pnode);
semGive(plink->hiPriSem);
if (pnode != NULL)
{
if (mv167Debug)
printf("IB152LinkTask(%d, %d): got Hi Pri xact, pnode= 0x%08.8X\n", plink->linkType, plink->linkId, pnode);
plink->deviceStatus[pnode->device] = (*(pnode->workStart))(pnode);
working=1;
}
else
{
semTake(plink->loPriSem, WAIT_FOREVER);
if ((pnode = (struct dpvtGpibHead *)lstFirst(&(plink->loPriList))) != NULL)
{
while (plink->deviceStatus[pnode->device] == BUSY)
if ((pnode = (struct dpvtGpibHead *)lstNext(pnode)) == NULL)
break;
}
if (pnode != NULL)
lstDelete(&(plink->loPriList), pnode);
semGive(plink->loPriSem);
if (pnode != NULL)
{
if(mv167Debug)
printf("IB152LinkTask(%d, %d): got Lo Pri xact, pnode= 0x%08.8X\n", plink->linkType, plink->linkId, pnode);
plink->deviceStatus[pnode->device] = (*(pnode->workStart))(pnode);
working=1;
}
}
}
}
#if 0
/******************************************************************************
*
* The following are functions used to take care of serial polling. They
* are called from the ibLinkTask.
*
******************************************************************************/
/******************************************************************************
*
* Pollib sends out an SRQ poll and returns the poll response.
* If there is an error during polling (timeout), the value -1 is returned.
*
******************************************************************************/
static int
pollIb(plink, gpibAddr, verbose, time)
struct ibLink *plink;
int gpibAddr;
int verbose; /* set to 1 if should log any errors */
int time;
{
char pollCmd[4];
unsigned char pollResult[3];
int status;
int tsSave;
if(verbose && (mv167Debug || ibSrqDebug))
printf("pollIb(0x%08.8X, %d, %d, %d)\n", plink, gpibAddr, verbose, time);
tsSave = timeoutSquelch;
timeoutSquelch = !verbose; /* keep the I/O routines quiet if desired */
/* raw-read back the response from the instrument */
if (readIb(plink, gpibAddr, pollResult, sizeof(pollResult), time) == ERROR)
{
if(verbose)
printf("pollIb(%d, %d): data read error\n", plink->linkId, gpibAddr);
status = ERROR;
}
else
{
status = pollResult[0];
if (mv167Debug || ibSrqDebug)
{
printf("pollIb(%d, %d): poll status = 0x%02.2X\n", plink->linkId, gpibAddr, status);
}
}
timeoutSquelch = tsSave; /* return I/O error logging to normal */
return(status);
}
/******************************************************************************
*
* Functions used to enable and disable SRQ interrupts. These only make
* sense on a Ni based link, so they are ignored in the BitBus case.
* (In the BitBus, SRQ status is passed back via query. So there is no
* asynchronous interupt associated with it.)
*
* The interrupts referred to here are the actual VME bus interrupts that are
* generated by the GPIB interface when it sees the SRQ line go high.
*
******************************************************************************/
static int
srqIntEnable(linkType, link, bug)
int linkType;
int link;
{
if (linkType == GPIB_IO)
return(niSrqIntEnable(link));
if (linkType == BBGPIB_IO)
return(OK); /* Bit Bus does not use interrupts for SRQ handeling */
return(ERROR); /* Invalid link type specified on the call */
}
static int
srqIntDisable(linkType, link, bug)
int linkType;
int link;
{
if (linkType == GPIB_IO)
return(niSrqIntDisable(link));
if (linkType == BBGPIB_IO)
return(0); /* Bit Bus does not use interrupts for SRQ handeling */
return(ERROR); /* Invlaid link type specified on the call */
}
/****************************************************************************
*
* The following routines are the user-callable entry points to the GPIB
* driver.
*
****************************************************************************/
/******************************************************************************
*
* A device support module may call this function to request that the GPIB
* driver NEVER poll a given device.
*
* Devices are polled when an SRQ event is present on the GPIB link. Some
* devices are too dumb to deal with being polled.
*
* This is NOT a static function, because it must be invoked from the startup
* script BEFORE iocInit is called.
*
* BUG --
* This could change if we decide to poll them during the second call to init()
* when epics 3.3 is available.
*
******************************************************************************/
/* static */ int
srqPollInhibit(linkType, link, bug, gpibAddr)
int linkType; /* link type (defined in link.h) */
int link; /* the link number the handler is related to */
int bug; /* the bug node address if on a bitbus link */
int gpibAddr; /* the device address the handler is for */
{
if (mv167Debug || ibSrqDebug)
printf("srqPollInhibit(%d, %d, %d, %d): called\n", linkType, link, bug, gpibAddr);
if (linkType == GPIB_IO)
{
return(niSrqPollInhibit(link, gpibAddr));
}
if (linkType == BBGPIB_IO)
{
return(bbSrqPollInhibit(link, bug, gpibAddr));
}
printf("drvGpib: srqPollInhibit(%d, %d, %d, %d): invalid link type specified\n", linkType, link, bug, gpibAddr);
return(ERROR);
}
/******************************************************************************
*
* Allow users to operate the internal functions of the driver.
*
* This can be fatal to the driver... make sure you know what you are doing!
*
******************************************************************************/
static int
ioctlIb(linkType, link, bug, cmd, v, p)
int linkType; /* link type (defined in link.h) */
int link; /* the link number to use */
int bug; /* node number if is a bitbus -> gpib link */
int cmd;
int v;
caddr_t p;
{
int stat;
if (linkType == GPIB_IO)
return(niGpibIoctl(link, cmd, v, p));/* link checked in niGpibIoctl */
if (linkType == BBGPIB_IO)
return(bbGpibIoctl(link, bug, cmd, v, p));/* link checked in bbGpibIoctl */
if (mv167Debug || bbmv167Debug)
printf("ioctlIb(%d, %d, %d, %d, %08.8X, %08.8X): invalid link type\n", linkType, link, bug, cmd, v, p);
return(ERROR);
}
#endif
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/* BUG -- this has to be converted into a FIFO list insertion!!! */
static int Send162(Mvme162LinkStruct *pMvme162Link, CommandStruct *pCmd)
{
Mvme162GpibParmStruct *pParms;
if(mv167Debug>20)
{
printf("Send162() sending command:\n");
printf(" Command %d\n", pCmd->Command);
printf(" pParms 0x%08.8X\n", pCmd->pParms);
printf(" pOutput 0x%08.8X\n", pCmd->pOutput);
printf(" pInput 0x%08.8X\n", pCmd->pInput);
printf(" IrqLevel %d\n", pCmd->IrqLevel);
printf(" IrqVector 0x%02.2X\n", (unsigned char)(pCmd->IrqVector));
printf(" pIrqParm 0x%08.8X\n", pCmd->pIrqParm);
if (pCmd->pParms != NULL)
{
/* vxWorks is a pain in the bung */
pParms = (Mvme162GpibParmStruct *)((unsigned long)(pCmd->pParms) - ((unsigned long)(0x00800000)));
printf(" parms on command:\n");
printf(" OutLength %d\n", pParms->OutLength);
printf(" InLength %d\n", pParms->InLength);
printf(" Address %d\n", pParms->Address);
printf(" Time %d\n", pParms->Time);
}
}
/* Lock the command queue */
while(!vxTas(&pMvme162Link->DRListLock));
/* Insert the command */
pCmd->pNextCommand = pMvme162Link->pDRList;
sysLocalToBusAdrs(VME_AM_EXT_SUP_DATA, pCmd, &pMvme162Link->pDRList);
/* unlock the command queue */
pMvme162Link->DRListLock = 0;
return(0);
}
/******************************************************************************
*
* A device support callable entry point used to write data to GPIB devices.
*
* This function returns the number of bytes written out.
*
******************************************************************************/
int
drv162IB_write(struct ibLink *pibLink, int gpibAddr, char *data, int length, int time)
{
CommandStruct cmd;
Mvme162GpibParmStruct parm;
if(mv167Debug)
printf("drv162IB_write(%08.8X, %d, 0x%08.8X, %d, %d)\n", pibLink, gpibAddr, data, length, time);
cmd.Command = MVME162_GPIB_WRITE_X;
parm.OutLength = length;
parm.InLength = 0;
parm.Address = gpibAddr;
parm.Time = time;
sysLocalToBusAdrs(VME_AM_EXT_SUP_DATA, data, &cmd.pOutput);
sysLocalToBusAdrs(VME_AM_EXT_SUP_DATA, &parm, &cmd.pParms);
cmd.IrqLevel = pIB162[pibLink->linkId]->IrqLevel;
cmd.IrqVector = pIB162[pibLink->linkId]->IrqVector;
cmd.pIrqParm = &(pIB162[pibLink->linkId]->IOsem);
Send162(pIB162[pibLink->linkId]->pMvme162Link, &cmd);
semTake(pIB162[pibLink->linkId]->IOsem, WAIT_FOREVER);
return(parm.Status);
}
/******************************************************************************
*
* A device support callable entry point used to read data from GPIB devices.
*
* This function returns the number of bytes read from the device, or ERROR
* if the read operation failed.
*
******************************************************************************/
int
drv162IB_read(struct ibLink *pibLink, int gpibAddr, char *data, int length, int time)
{
CommandStruct cmd;
Mvme162GpibParmStruct parm;
if(mv167Debug)
printf("readIb(%08.8X, %d, 0x%08.8X, %d)\n", pibLink, gpibAddr, data, length);
cmd.Command = MVME162_GPIB_READ_X;
parm.OutLength = 0;
parm.InLength = length;
parm.Address = gpibAddr;
parm.Time = time;
sysLocalToBusAdrs(VME_AM_EXT_SUP_DATA, data, &cmd.pInput);
sysLocalToBusAdrs(VME_AM_EXT_SUP_DATA, &parm, &cmd.pParms);
cmd.IrqLevel = pIB162[pibLink->linkId]->IrqLevel;
cmd.IrqVector = pIB162[pibLink->linkId]->IrqVector;
cmd.pIrqParm = &(pIB162[pibLink->linkId]->IOsem);
Send162(pIB162[pibLink->linkId]->pMvme162Link, &cmd);
semTake(pIB162[pibLink->linkId]->IOsem, WAIT_FOREVER);
return(parm.Status);
}
#if 0
/******************************************************************************
*
* A device support callable entry point that is used to write commands
* to GPIB devices. (this is the same as a regular write except that the
* ATN line is held high during the write.
*
* This function returns the number of bytes written out.
*
******************************************************************************/
static int
writeIbCmd(pibLink, data, length)
struct ibLink *pibLink;
char *data; /* the data buffer to write out */
int length; /* number of bytes to write out from the data buffer */
{
if(ibDebug || (bbibDebug & (pibLink->linkType == BBGPIB_IO)))
printf("writeIbCmd(%08.8X, %08.8X, %d)\n", pibLink, data, length);
if (pibLink->linkType == GPIB_IO)
{
/* raw-write the data */
return(niGpibCmd(pibLink->linkId, data, length));
}
if (pibLink->linkType == BBGPIB_IO)
{
/* raw-write the data */
return(bbGpibCmd(pibLink, data, length));
}
return(ERROR);
}
#endif