1335 lines
25 KiB
C
1335 lines
25 KiB
C
/* devLib.c - support for allocation of common device resources */
|
||
/* @(#)$Id$*/
|
||
|
||
/*
|
||
* Original Author: Marty Kraimer
|
||
* Author: Jeff Hill
|
||
* Date: 03-10-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:
|
||
* -----------------
|
||
* .01 03-10-93 joh original
|
||
* .02 03-18-93 joh index address alloc array by fundamental type
|
||
* .03 03-23-93 joh changed input parameter to be a fund
|
||
* address type in favor of the argument
|
||
* that the BSP will be reconfigured
|
||
* to use an EPICS standard address
|
||
* mode
|
||
* .04 04-08-93 joh made unsolicitedHandlerEPICS() external
|
||
* .05 04-08-92 joh better diagnostic if we cant find
|
||
* a default interrupt handler
|
||
* .06 05-06-93 joh added new parameter to devDisconnectInterrupt().
|
||
* See comment below.
|
||
* .07 05-28-93 joh Added block probe routines
|
||
* .08 05-28-93 joh Added an argument to devRegisterAddress()
|
||
* .09 05-28-93 joh Added devAddressMap()
|
||
* .10 06-14-93 joh Added devAllocAddress()
|
||
* .11 02-21-95 joh Fixed warning messages
|
||
*
|
||
* NOTES:
|
||
* .01 06-14-93 joh needs devAllocInterruptVector() routine
|
||
*/
|
||
|
||
static char *sccsID = "@(#) $Id$";
|
||
|
||
|
||
#include <vxWorks.h>
|
||
#include <types.h>
|
||
#include <iv.h>
|
||
#include <vme.h>
|
||
#include <lstLib.h>
|
||
#include <sysLib.h>
|
||
#include <sysSymTbl.h>
|
||
#include <memLib.h>
|
||
#include <intLib.h>
|
||
#include <logLib.h>
|
||
#include <string.h>
|
||
#include <stdioLib.h>
|
||
#include <stdlib.h>
|
||
|
||
#include <fast_lock.h>
|
||
#define devLibGlobal
|
||
#include <devLib.h>
|
||
|
||
|
||
LOCAL LIST addrAlloc[atLast];
|
||
LOCAL LIST addrFree[atLast];
|
||
|
||
LOCAL void *addrLast[atLast] = {
|
||
(void *) 0xffff,
|
||
(void *) 0xffffff,
|
||
(void *) 0xffffffff,
|
||
(void *) 0xffffff
|
||
};
|
||
|
||
LOCAL long addrFail[atLast] = {
|
||
S_dev_badA16,
|
||
S_dev_badA24,
|
||
S_dev_badA32,
|
||
S_dev_badA24
|
||
};
|
||
|
||
LOCAL FAST_LOCK addrListLock;
|
||
LOCAL char addrListInit;
|
||
|
||
typedef struct{
|
||
NODE node;
|
||
const char *pOwnerName;
|
||
char *pFirst;
|
||
char *pLast;
|
||
}rangeItem;
|
||
|
||
/*
|
||
* A list of the names of the unexpected interrupt handlers
|
||
* ( some of these are provided by wrs )
|
||
*/
|
||
LOCAL char *defaultHandlerNames[] = {
|
||
"_excStub",
|
||
"_excIntStub",
|
||
"_unsolicitedHandlerEPICS"};
|
||
typedef void myISR (void *pParam);
|
||
LOCAL myISR *defaultHandlerAddr[NELEMENTS(defaultHandlerNames)];
|
||
|
||
/*
|
||
* These routines are not exported
|
||
*/
|
||
LOCAL void initHandlerAddrList(void);
|
||
LOCAL int vectorInUse(unsigned vectorNumber);
|
||
LOCAL long initAddrList(void);
|
||
LOCAL long addrVerify(epicsAddressType addrType, void *address);
|
||
LOCAL myISR *isrFetch(unsigned vectorNumber);
|
||
LOCAL long blockFind(
|
||
epicsAddressType addrType,
|
||
char *pBlockFirst,
|
||
char *pBlockLast,
|
||
/* size needed */
|
||
unsigned long size,
|
||
/* n ls bits zero in base addr */
|
||
unsigned alignment,
|
||
/* base address found */
|
||
char **ppBase);
|
||
LOCAL long report_conflict(
|
||
epicsAddressType addrType,
|
||
char *pFirst,
|
||
char *pLast,
|
||
const char *pOwnerName);
|
||
LOCAL long devInsertAddress(
|
||
LIST *pRangeList,
|
||
rangeItem *pNewRange);
|
||
LOCAL long devListAddressMap(
|
||
LIST *pRangeList);
|
||
LOCAL long devCombineAdjacentBlocks(
|
||
LIST *pRangeList,
|
||
rangeItem *pRange);
|
||
LOCAL long devInstallAddr(
|
||
rangeItem *pRange,
|
||
const char *pOwnerName,
|
||
epicsAddressType addrType,
|
||
char *pFirst,
|
||
char *pLast,
|
||
void **pLocalAddress);
|
||
LOCAL long blockDivide(
|
||
epicsAddressType addrType,
|
||
char *pBlockFirst,
|
||
char *pBlockLast,
|
||
/* base address found */
|
||
char **ppBase,
|
||
unsigned long requestSize
|
||
);
|
||
LOCAL long blockProbe(
|
||
epicsAddressType addrType,
|
||
char *pFirst,
|
||
char *pLast
|
||
);
|
||
long locationProbe(
|
||
epicsAddressType addrType,
|
||
char *pLocation
|
||
);
|
||
|
||
/*
|
||
* this routine needs to be in the symbol table
|
||
* for this code to work correctly
|
||
*/
|
||
void unsolicitedHandlerEPICS(int vectorNumber);
|
||
/*
|
||
* this is in veclist.c
|
||
*/
|
||
int cISRTest(void (*)(), void (**)(), void **);
|
||
|
||
#define SUCCESS 0
|
||
|
||
|
||
|
||
/*
|
||
*
|
||
* devConnectInterrupt
|
||
*
|
||
* coded to support other interrupting types in the future
|
||
*
|
||
* wrapper to minimize driver dependency on vxWorks
|
||
*/
|
||
long devConnectInterrupt(
|
||
epicsInterruptType intType,
|
||
unsigned vectorNumber,
|
||
void (*pFunction)(),
|
||
void *parameter)
|
||
{
|
||
int status;
|
||
|
||
switch(intType){
|
||
case intCPU:
|
||
case intVME:
|
||
case intVXI:
|
||
if(vectorInUse(vectorNumber)){
|
||
return S_dev_vectorInUse;
|
||
}
|
||
status = intConnect(
|
||
(void *)INUM_TO_IVEC(vectorNumber),
|
||
pFunction,
|
||
(int) parameter);
|
||
if(status<0){
|
||
return S_dev_vxWorksVecInstlFail;
|
||
}
|
||
break;
|
||
default:
|
||
return S_dev_uknIntType;
|
||
}
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
|
||
/*
|
||
*
|
||
* devDisconnectInterrupt()
|
||
*
|
||
* wrapper to minimize driver dependency on vxWorks
|
||
*
|
||
* The parameter pFunction should be set to the C function pointer that
|
||
* was connected. It is used as a key to prevent a driver from removing
|
||
* an interrupt handler that was installed by another driver
|
||
*
|
||
*/
|
||
long devDisconnectInterrupt(
|
||
epicsInterruptType intType,
|
||
unsigned vectorNumber,
|
||
void (*pFunction)()
|
||
)
|
||
{
|
||
void (*psub)();
|
||
int status;
|
||
|
||
/*
|
||
* If pFunction not connected to this vector
|
||
* then they are probably disconnecting from the wrong vector
|
||
*/
|
||
psub = isrFetch(vectorNumber);
|
||
if(psub != pFunction){
|
||
return S_dev_vectorNotInUse;
|
||
}
|
||
|
||
switch(intType){
|
||
case intCPU:
|
||
case intVME:
|
||
case intVXI:
|
||
status = intConnect(
|
||
(void *)INUM_TO_IVEC(vectorNumber),
|
||
unsolicitedHandlerEPICS,
|
||
(int) vectorNumber);
|
||
if(status<0){
|
||
return S_dev_vxWorksVecInstlFail;
|
||
}
|
||
break;
|
||
default:
|
||
return S_dev_uknIntType;
|
||
}
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
|
||
/*
|
||
*
|
||
* devEnableInterruptLevel()
|
||
*
|
||
* wrapper to minimize driver dependency on vxWorks
|
||
*
|
||
*/
|
||
long devEnableInterruptLevel(
|
||
epicsInterruptType intType,
|
||
unsigned level)
|
||
{
|
||
int s;
|
||
|
||
switch(intType){
|
||
case intCPU:
|
||
case intVME:
|
||
case intVXI:
|
||
s = sysIntEnable(level);
|
||
if(s<0){
|
||
return S_dev_vxWorksIntEnFail;
|
||
}
|
||
break;
|
||
default:
|
||
return S_dev_uknIntType;
|
||
}
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
|
||
/*
|
||
*
|
||
* devDisableInterruptLevel()
|
||
*
|
||
* wrapper to minimize driver dependency on vxWorks
|
||
*
|
||
*/
|
||
long devDisableInterruptLevel(
|
||
epicsInterruptType intType,
|
||
unsigned level)
|
||
{
|
||
int s;
|
||
|
||
switch(intType){
|
||
case intCPU:
|
||
case intVME:
|
||
case intVXI:
|
||
s = sysIntDisable(level);
|
||
if(s<0){
|
||
return S_dev_vxWorksIntDissFail;
|
||
}
|
||
break;
|
||
default:
|
||
return S_dev_uknIntType;
|
||
}
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
|
||
/*
|
||
*
|
||
* devRegisterAddress()
|
||
*
|
||
*
|
||
*/
|
||
long devRegisterAddress(
|
||
const char *pOwnerName,
|
||
epicsAddressType addrType,
|
||
void *baseAddress,
|
||
unsigned long size,
|
||
void **pLocalAddress)
|
||
{
|
||
char *pFirst;
|
||
char *pLast;
|
||
rangeItem *pRange;
|
||
long s;
|
||
|
||
if(!addrListInit){
|
||
s = initAddrList();
|
||
if(s){
|
||
return s;
|
||
}
|
||
}
|
||
|
||
s = addrVerify(addrType, (void *) size);
|
||
if(s){
|
||
return s;
|
||
}
|
||
|
||
if(size == 0){
|
||
return S_dev_lowValue;
|
||
}
|
||
|
||
pFirst = (char *) baseAddress;
|
||
pLast = pFirst + size - 1;
|
||
|
||
FASTLOCK(&addrListLock);
|
||
pRange = (rangeItem *) addrFree[addrType].node.next;
|
||
while(pRange){
|
||
|
||
if(pRange->pFirst > pLast){
|
||
pRange = NULL;
|
||
break;
|
||
}
|
||
|
||
if(pRange->pFirst <= pFirst && pRange->pLast >= pLast){
|
||
break;
|
||
}
|
||
|
||
pRange = (rangeItem *) pRange->node.next;
|
||
}
|
||
FASTUNLOCK(&addrListLock);
|
||
|
||
if(!pRange){
|
||
s = report_conflict(addrType, pFirst, pLast, pOwnerName);
|
||
if(s){
|
||
return s;
|
||
}
|
||
else{
|
||
return S_dev_internal;
|
||
}
|
||
}
|
||
|
||
s = devInstallAddr(
|
||
pRange,
|
||
pOwnerName,
|
||
addrType,
|
||
pFirst,
|
||
pLast,
|
||
pLocalAddress);
|
||
return s;
|
||
}
|
||
|
||
|
||
/*
|
||
*
|
||
* devInstallAddr()
|
||
*
|
||
*/
|
||
LOCAL long devInstallAddr(
|
||
rangeItem *pRange, /* item on the free list to be split */
|
||
const char *pOwnerName,
|
||
epicsAddressType addrType,
|
||
char *pFirst,
|
||
char *pLast,
|
||
void **ppLocalAddress)
|
||
{
|
||
rangeItem *pNewRange;
|
||
int s;
|
||
|
||
if(ppLocalAddress){
|
||
char *pAddr;
|
||
int s1;
|
||
int s2;
|
||
|
||
if (EPICStovxWorksAddrType[addrType] == EPICSAddrTypeNoConvert)
|
||
{
|
||
*ppLocalAddress = pFirst;
|
||
}
|
||
else
|
||
{
|
||
s1 = sysBusToLocalAdrs(
|
||
EPICStovxWorksAddrType[addrType],
|
||
pLast,
|
||
&pAddr);
|
||
s2 = sysBusToLocalAdrs(
|
||
EPICStovxWorksAddrType[addrType],
|
||
pFirst,
|
||
&pAddr);
|
||
if(s1 || s2){
|
||
errPrintf(
|
||
S_dev_vxWorksAddrMapFail,
|
||
__FILE__,
|
||
__LINE__,
|
||
"%s base=0X %X size = 0X %X",
|
||
epicsAddressTypeName[addrType],
|
||
pFirst,
|
||
pLast-pFirst+1);
|
||
return S_dev_vxWorksAddrMapFail;
|
||
}
|
||
|
||
*ppLocalAddress = (void *) pAddr;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* split the item on the free list
|
||
* (when required)
|
||
*/
|
||
if(pRange->pFirst == pFirst && pRange->pLast == pLast){
|
||
FASTLOCK(&addrListLock);
|
||
lstDelete(&addrFree[addrType], &pRange->node);
|
||
FASTUNLOCK(&addrListLock);
|
||
free((void *)pRange);
|
||
}
|
||
else if(pRange->pFirst == pFirst){
|
||
pRange->pFirst = pLast+1;
|
||
}
|
||
else if(pRange->pLast == pLast){
|
||
pRange->pLast = pFirst-1;
|
||
}
|
||
else{
|
||
|
||
pNewRange = (rangeItem *) malloc(sizeof(*pRange));
|
||
if(!pNewRange){
|
||
return S_dev_noMemory;
|
||
}
|
||
pNewRange->pFirst = pLast+1;
|
||
pNewRange->pLast = pRange->pLast;
|
||
pNewRange->pOwnerName = "<fragmented block>";
|
||
pRange->pLast = pFirst-1;
|
||
/*
|
||
* add the node after the old item on the free list
|
||
* (blocks end up ordered by address)
|
||
*/
|
||
FASTLOCK(&addrListLock);
|
||
lstInsert(&addrFree[addrType], &pRange->node, &pNewRange->node);
|
||
FASTUNLOCK(&addrListLock);
|
||
}
|
||
|
||
/*
|
||
* allocate a new address range entry and add it to
|
||
* the list
|
||
*/
|
||
pNewRange = (rangeItem *)calloc(1,sizeof(*pRange));
|
||
if(!pNewRange){
|
||
return S_dev_noMemory;
|
||
}
|
||
|
||
pNewRange->pFirst = pFirst;
|
||
pNewRange->pLast = pLast;
|
||
pNewRange->pOwnerName = pOwnerName;
|
||
|
||
s = devInsertAddress(&addrAlloc[addrType], pNewRange);
|
||
if(s){
|
||
free((void *)pNewRange);
|
||
return s;
|
||
}
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
|
||
/*
|
||
*
|
||
* report_conflict()
|
||
*
|
||
*
|
||
*/
|
||
LOCAL long report_conflict(
|
||
epicsAddressType addrType,
|
||
char *pFirst,
|
||
char *pLast,
|
||
const char *pOwnerName
|
||
)
|
||
{
|
||
rangeItem *pRange;
|
||
|
||
pRange = (rangeItem *) addrAlloc[addrType].node.next;
|
||
while(pRange){
|
||
|
||
if(pRange->pFirst <= pFirst && pRange->pLast >= pFirst){
|
||
break;
|
||
}
|
||
if(pRange->pFirst <= pLast && pRange->pLast >= pLast){
|
||
break;
|
||
}
|
||
if(pRange->pFirst > pLast){
|
||
pRange = NULL;
|
||
break;
|
||
}
|
||
|
||
pRange = (rangeItem *) pRange->node.next;
|
||
}
|
||
|
||
if(pRange){
|
||
errPrintf(
|
||
S_dev_addressOverlap,
|
||
__FILE__,
|
||
__LINE__,
|
||
"%10s 0X %08X - %08X Requested by %s",
|
||
epicsAddressTypeName[addrType],
|
||
pFirst,
|
||
pLast,
|
||
pOwnerName);
|
||
|
||
errPrintf(
|
||
S_dev_identifyOverlap,
|
||
__FILE__,
|
||
__LINE__,
|
||
"%10s 0X %08X - %08X Owned by %s",
|
||
epicsAddressTypeName[addrType],
|
||
pRange->pFirst,
|
||
pRange->pLast,
|
||
pRange->pOwnerName);
|
||
|
||
return S_dev_addressOverlap;
|
||
}
|
||
|
||
return S_dev_internal;
|
||
}
|
||
|
||
|
||
/*
|
||
*
|
||
* devUnregisterAddress()
|
||
*
|
||
*/
|
||
long devUnregisterAddress(
|
||
epicsAddressType addrType,
|
||
void *baseAddress,
|
||
const char *pOwnerName)
|
||
{
|
||
char *charAddress = (char *) baseAddress;
|
||
rangeItem *pRange;
|
||
int s;
|
||
|
||
if(!addrListInit){
|
||
s = initAddrList();
|
||
if(s){
|
||
return s;
|
||
}
|
||
}
|
||
|
||
s = addrVerify(addrType, charAddress);
|
||
if(s != SUCCESS){
|
||
return s;
|
||
}
|
||
|
||
FASTLOCK(&addrListLock);
|
||
pRange = (rangeItem *) addrAlloc[addrType].node.next;
|
||
while(pRange){
|
||
if(pRange->pFirst == charAddress){
|
||
break;
|
||
}
|
||
if(pRange->pFirst > charAddress){
|
||
pRange = NULL;
|
||
break;
|
||
}
|
||
pRange = (rangeItem *) pRange->node.next;
|
||
}
|
||
FASTUNLOCK(&addrListLock);
|
||
|
||
if(!pRange){
|
||
return S_dev_addressNotFound;
|
||
}
|
||
|
||
if(strcmp(pOwnerName,pRange->pOwnerName)){
|
||
s = S_dev_addressOverlap;
|
||
errPrintf(
|
||
s,
|
||
__FILE__,
|
||
__LINE__,
|
||
"unregister address for %s at 0X %X failed because %s owns it",
|
||
pOwnerName,
|
||
charAddress,
|
||
pRange->pOwnerName);
|
||
return s;
|
||
}
|
||
|
||
FASTLOCK(&addrListLock);
|
||
lstDelete(
|
||
&addrAlloc[addrType],
|
||
&pRange->node);
|
||
FASTUNLOCK(&addrListLock);
|
||
|
||
pRange->pOwnerName = "<released fragment>";
|
||
s = devInsertAddress(&addrFree[addrType], pRange);
|
||
if(s){
|
||
free((void *)pRange);
|
||
errMessage(s, "Allocated Device Address Leak");
|
||
return s;
|
||
}
|
||
s = devCombineAdjacentBlocks(&addrFree[addrType], pRange);
|
||
if(s){
|
||
errMessage(s, NULL);
|
||
return s;
|
||
}
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
|
||
/*
|
||
*
|
||
* devCombineAdjacentBlocks()
|
||
*
|
||
*
|
||
*/
|
||
LOCAL long devCombineAdjacentBlocks(
|
||
LIST *pRangeList,
|
||
rangeItem *pRange)
|
||
{
|
||
rangeItem *pBefore;
|
||
rangeItem *pAfter;
|
||
|
||
pBefore = (rangeItem *) pRange->node.previous;
|
||
pAfter = (rangeItem *) pRange->node.next;
|
||
|
||
/*
|
||
* combine adjacent blocks
|
||
*/
|
||
if(pBefore){
|
||
if(pBefore->pLast == pRange->pFirst-1){
|
||
FASTLOCK(&addrListLock);
|
||
pRange->pFirst = pBefore->pFirst;
|
||
lstDelete(pRangeList, &pBefore->node);
|
||
FASTUNLOCK(&addrListLock);
|
||
free((void *)pBefore);
|
||
}
|
||
}
|
||
|
||
if(pAfter){
|
||
if(pAfter->pFirst-1 == pRange->pLast){
|
||
FASTLOCK(&addrListLock);
|
||
pRange->pLast = pAfter->pLast;
|
||
lstDelete(pRangeList, &pAfter->node);
|
||
FASTUNLOCK(&addrListLock);
|
||
free((void *)pAfter);
|
||
}
|
||
}
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
|
||
/*
|
||
*
|
||
* devInsertAddress()
|
||
*
|
||
*
|
||
*/
|
||
LOCAL long devInsertAddress(
|
||
LIST *pRangeList,
|
||
rangeItem *pNewRange)
|
||
{
|
||
rangeItem *pBefore;
|
||
rangeItem *pAfter;
|
||
|
||
FASTLOCK(&addrListLock);
|
||
pAfter = (rangeItem *) pRangeList->node.next;
|
||
while(pAfter){
|
||
if(pNewRange->pLast < pAfter->pFirst){
|
||
break;
|
||
}
|
||
pAfter = (rangeItem *) pAfter->node.next;
|
||
}
|
||
|
||
if(pAfter){
|
||
pBefore = (rangeItem *) pAfter->node.previous;
|
||
lstInsert(pRangeList, &pBefore->node, &pNewRange->node);
|
||
}
|
||
else{
|
||
lstAdd(pRangeList, &pNewRange->node);
|
||
}
|
||
FASTUNLOCK(&addrListLock);
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
*
|
||
* devAllocAddress()
|
||
*
|
||
*
|
||
*/
|
||
long devAllocAddress(
|
||
const char *pOwnerName,
|
||
epicsAddressType addrType,
|
||
unsigned long size,
|
||
unsigned alignment, /* n ls bits zero in base addr*/
|
||
void **pLocalAddress)
|
||
{
|
||
int s;
|
||
rangeItem *pRange;
|
||
char *pBase;
|
||
|
||
s = addrVerify(addrType, (void *)size);
|
||
if(s){
|
||
return s;
|
||
}
|
||
|
||
if(size == 0){
|
||
return S_dev_lowValue;
|
||
}
|
||
|
||
FASTLOCK(&addrListLock);
|
||
pRange = (rangeItem *) addrFree[addrType].node.next;
|
||
while(pRange){
|
||
if(pRange->pLast-pRange->pFirst>=size-1){
|
||
s = blockFind(
|
||
addrType,
|
||
pRange->pFirst,
|
||
pRange->pLast,
|
||
size,
|
||
alignment,
|
||
&pBase);
|
||
if(!s){
|
||
break;
|
||
}
|
||
}
|
||
pRange = (rangeItem *) pRange->node.next;
|
||
}
|
||
FASTUNLOCK(&addrListLock);
|
||
|
||
if(!pRange){
|
||
s = S_dev_deviceDoesNotFit;
|
||
errMessage(s, epicsAddressTypeName[addrType]);
|
||
return s;
|
||
}
|
||
|
||
|
||
s = devInstallAddr(
|
||
pRange,
|
||
pOwnerName,
|
||
addrType,
|
||
pBase,
|
||
pBase + size - 1,
|
||
pLocalAddress);
|
||
return s;
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* addrVerify()
|
||
*/
|
||
LOCAL long addrVerify(
|
||
epicsAddressType addrType,
|
||
void *address)
|
||
{
|
||
if(addrType>=atLast){
|
||
return S_dev_uknAddrType;
|
||
}
|
||
|
||
if(address > addrLast[addrType]){
|
||
return addrFail[addrType];
|
||
}
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* initAddrList()
|
||
*/
|
||
LOCAL long initAddrList(void)
|
||
{
|
||
rangeItem *pRange;
|
||
|
||
if(NELEMENTS(addrAlloc) != NELEMENTS(addrFree)){
|
||
return S_dev_internal;
|
||
}
|
||
|
||
if(!addrListInit){
|
||
int i;
|
||
|
||
FASTLOCKINIT(&addrListLock);
|
||
|
||
FASTLOCK(&addrListLock);
|
||
for(i=0; i<NELEMENTS(addrAlloc); i++){
|
||
lstInit(&addrAlloc[i]);
|
||
lstInit(&addrFree[i]);
|
||
}
|
||
|
||
addrListInit = TRUE;
|
||
|
||
for(i=0; i<NELEMENTS(addrAlloc); i++){
|
||
pRange = (rangeItem *)malloc(sizeof *pRange);
|
||
if(!pRange){
|
||
return S_dev_noMemory;
|
||
}
|
||
pRange->pOwnerName = "<Vacant>";
|
||
pRange->pFirst = 0;
|
||
pRange->pLast = addrLast[i];
|
||
lstAdd(&addrFree[i], &pRange->node);
|
||
}
|
||
FASTUNLOCK(&addrListLock);
|
||
}
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
|
||
/*
|
||
* devAddressMap()
|
||
*/
|
||
long devAddressMap(void)
|
||
{
|
||
return devListAddressMap(addrAlloc);
|
||
}
|
||
|
||
|
||
/*
|
||
* devListAddressMap()
|
||
*/
|
||
LOCAL long devListAddressMap(LIST *pRangeList)
|
||
{
|
||
rangeItem *pri;
|
||
int i;
|
||
long s;
|
||
|
||
if(!addrListInit){
|
||
s = initAddrList();
|
||
if(s){
|
||
return s;
|
||
}
|
||
}
|
||
|
||
FASTLOCK(&addrListLock);
|
||
for(i=0; i<NELEMENTS(addrAlloc); i++){
|
||
pri = (rangeItem *) lstFirst(&pRangeList[i]);
|
||
if(pri){
|
||
printf("%s Address Map\n", epicsAddressTypeName[i]);
|
||
}
|
||
while(pri){
|
||
printf("0X %0*lX - %0*lX %s\n",
|
||
(int) (sizeof (pri->pFirst) * 2U),
|
||
(unsigned long) pri->pFirst,
|
||
(int) (sizeof (pri->pFirst) * 2U),
|
||
(unsigned long) pri->pLast,
|
||
pri->pOwnerName);
|
||
pri = (rangeItem *) lstNext(&pri->node);
|
||
}
|
||
}
|
||
FASTUNLOCK(&addrListLock);
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
|
||
/*
|
||
*
|
||
* unsolicitedHandlerEPICS()
|
||
* what gets called if they disconnect from an
|
||
* interrupt and an interrupt arrives on the
|
||
* disconnected vector
|
||
*
|
||
*/
|
||
void unsolicitedHandlerEPICS(int vectorNumber)
|
||
{
|
||
/*
|
||
* call logMsg() and not errMessage()
|
||
* so we are certain that printf()
|
||
* does not get called at interrupt level
|
||
*/
|
||
logMsg(
|
||
"%s: line=%d: Interrupt to EPICS disconnected vector = 0X %X",
|
||
(int)__FILE__,
|
||
__LINE__,
|
||
vectorNumber,
|
||
NULL,
|
||
NULL,
|
||
NULL);
|
||
}
|
||
|
||
|
||
/*
|
||
*
|
||
* initHandlerAddrList()
|
||
* init list of interrupt handlers to ignore
|
||
*
|
||
*/
|
||
LOCAL
|
||
void initHandlerAddrList(void)
|
||
{
|
||
int i;
|
||
SYM_TYPE type;
|
||
int status;
|
||
|
||
for(i=0; i<NELEMENTS(defaultHandlerNames); i++){
|
||
status =
|
||
symFindByName( sysSymTbl,
|
||
defaultHandlerNames[i],
|
||
(char **)&defaultHandlerAddr[i],
|
||
&type);
|
||
if(status != OK){
|
||
errPrintf(
|
||
S_dev_internal,
|
||
__FILE__,
|
||
__LINE__,
|
||
"initHandlerAddrList() %s not in sym table",
|
||
defaultHandlerNames[i]);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
*
|
||
* isrFetch()
|
||
*
|
||
*
|
||
*/
|
||
LOCAL myISR *isrFetch(unsigned vectorNumber)
|
||
{
|
||
myISR *psub;
|
||
myISR *pCISR;
|
||
void *pParam;
|
||
int s;
|
||
|
||
/*
|
||
* fetch the handler or C stub attached at this vector
|
||
*/
|
||
psub = (myISR *) intVecGet((FUNCPTR *)INUM_TO_IVEC(vectorNumber));
|
||
|
||
/*
|
||
* from libvxWorks/veclist.c
|
||
*
|
||
* checks to see if it is a C ISR
|
||
* and if so finds the function pointer and
|
||
* the parameter passed
|
||
*/
|
||
s = cISRTest(psub, &pCISR, &pParam);
|
||
if(!s){
|
||
psub = pCISR;
|
||
}
|
||
|
||
return psub;
|
||
}
|
||
|
||
|
||
/*
|
||
*
|
||
* vectorInUse()
|
||
*
|
||
*
|
||
*/
|
||
LOCAL int
|
||
vectorInUse(
|
||
unsigned vectorNumber
|
||
)
|
||
{
|
||
static int init;
|
||
int i;
|
||
myISR *psub;
|
||
|
||
if(!init){
|
||
initHandlerAddrList();
|
||
init = TRUE;
|
||
}
|
||
|
||
psub = isrFetch(vectorNumber);
|
||
|
||
/*
|
||
* its a C routine. Does it match a default handler?
|
||
*/
|
||
for(i=0; i<NELEMENTS(defaultHandlerAddr); i++){
|
||
if(defaultHandlerAddr[i] == psub){
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
|
||
/*
|
||
*
|
||
* blockFind()
|
||
*
|
||
* Find unoccupied block in a large block
|
||
*
|
||
*/
|
||
LOCAL long blockFind(
|
||
epicsAddressType addrType,
|
||
char *pBlockFirst,
|
||
char *pBlockLast,
|
||
unsigned long size, /* size needed */
|
||
unsigned alignment, /* n ls bits zero in base addr */
|
||
char **ppBase /* base address found */
|
||
)
|
||
{
|
||
int s;
|
||
unsigned long mask;
|
||
|
||
/*
|
||
* align the block base
|
||
*/
|
||
mask = devCreateMask(alignment);
|
||
if(mask&(long)pBlockFirst){
|
||
pBlockFirst = (char *) (mask | (unsigned long) pBlockFirst);
|
||
pBlockFirst++;
|
||
}
|
||
|
||
if(pBlockFirst == 0){
|
||
return S_dev_badRequest;
|
||
}
|
||
|
||
if(pBlockLast < pBlockFirst){
|
||
return S_dev_badRequest;
|
||
}
|
||
|
||
/*
|
||
* align size of block
|
||
*/
|
||
if(mask & size){
|
||
size |= mask;
|
||
size++;
|
||
}
|
||
|
||
if(size == 0){
|
||
return S_dev_badRequest;
|
||
}
|
||
|
||
if(pBlockLast-pBlockFirst < size-1){
|
||
return S_dev_badRequest;
|
||
}
|
||
|
||
s = blockDivide(
|
||
addrType,
|
||
pBlockFirst,
|
||
pBlockFirst + (size-1),
|
||
ppBase,
|
||
size);
|
||
|
||
return s;
|
||
}
|
||
|
||
|
||
/*
|
||
* blockDivide()
|
||
* (binary search within a block)
|
||
* End up at a valid block without stepping through
|
||
* the entire address range.
|
||
*/
|
||
LOCAL long blockDivide(
|
||
epicsAddressType addrType,
|
||
char *pBlockFirst,
|
||
char *pBlockLast,
|
||
char **ppBase, /* base address found */
|
||
unsigned long requestSize
|
||
)
|
||
{
|
||
char *pBlock;
|
||
unsigned long bs;
|
||
int s;
|
||
|
||
s = blockProbe(addrType, pBlockFirst, pBlockFirst+(requestSize-1));
|
||
if(!s){
|
||
*ppBase = pBlockFirst;
|
||
return SUCCESS;
|
||
}
|
||
|
||
/*
|
||
* prevent unsigned long overflow
|
||
*/
|
||
bs = pBlockLast - pBlockFirst + 1;
|
||
if(bs == 0){
|
||
bs = 0x80000000;
|
||
}
|
||
else{
|
||
bs = bs >> 1;
|
||
}
|
||
|
||
while(bs > requestSize){
|
||
pBlock = pBlockFirst;
|
||
while(pBlock <= pBlockLast-bs+1){
|
||
pBlock += bs;
|
||
s = blockProbe(addrType, pBlock, pBlock+(requestSize-1));
|
||
if(!s){
|
||
*ppBase = pBlock;
|
||
return SUCCESS;
|
||
}
|
||
pBlock += bs;
|
||
}
|
||
bs = bs>>1;
|
||
}
|
||
return S_dev_deviceDoesNotFit;
|
||
}
|
||
|
||
|
||
/*
|
||
* blockProbe()
|
||
*/
|
||
LOCAL long blockProbe(
|
||
epicsAddressType addrType,
|
||
char *pFirst,
|
||
char *pLast
|
||
)
|
||
{
|
||
char *pProbe;
|
||
int s;
|
||
|
||
pProbe = pFirst;
|
||
while(pProbe <= pLast){
|
||
s = locationProbe(addrType, pProbe);
|
||
if(s){
|
||
return s;
|
||
}
|
||
pProbe++;
|
||
}
|
||
return SUCCESS;
|
||
}
|
||
|
||
|
||
/*
|
||
* locationProbe
|
||
*/
|
||
long locationProbe(
|
||
epicsAddressType addrType,
|
||
char *pLocation
|
||
)
|
||
{
|
||
char *pPhysical;
|
||
int s;
|
||
|
||
/*
|
||
* every byte in the block must
|
||
* map to a physical address
|
||
*/
|
||
if (EPICStovxWorksAddrType[addrType] == EPICSAddrTypeNoConvert)
|
||
{
|
||
pPhysical = pLocation;
|
||
}
|
||
else
|
||
{
|
||
s = sysBusToLocalAdrs(
|
||
EPICStovxWorksAddrType[addrType],
|
||
pLocation,
|
||
&pPhysical);
|
||
if(s<0){
|
||
return S_dev_vxWorksAddrMapFail;
|
||
}
|
||
}
|
||
|
||
|
||
{
|
||
int8_t *pChar;
|
||
int8_t byte;
|
||
|
||
pChar = (int8_t *) pPhysical;
|
||
if(devPtrAlignTest(pChar)){
|
||
s = vxMemProbe(
|
||
(char *) pChar,
|
||
READ,
|
||
sizeof(byte),
|
||
(char *) &byte);
|
||
if(s!=ERROR){
|
||
return S_dev_addressOverlap;
|
||
}
|
||
}
|
||
}
|
||
{
|
||
int16_t *pWord;
|
||
int16_t word;
|
||
|
||
pWord = (int16_t *)pPhysical;
|
||
if(devPtrAlignTest(pWord)){
|
||
s = vxMemProbe(
|
||
(char *)pWord,
|
||
READ,
|
||
sizeof(word),
|
||
(char *) &word);
|
||
if(s!=ERROR){
|
||
return S_dev_addressOverlap;
|
||
}
|
||
}
|
||
}
|
||
{
|
||
int32_t *pLongWord;
|
||
int32_t longWord;
|
||
|
||
pLongWord = (int32_t *) pPhysical;
|
||
if(devPtrAlignTest(pLongWord)){
|
||
s = vxMemProbe(
|
||
(char *)pLongWord,
|
||
READ,
|
||
sizeof(longWord),
|
||
(char *)&longWord);
|
||
if(s!=ERROR){
|
||
return S_dev_addressOverlap;
|
||
}
|
||
}
|
||
}
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
/******************************************************************************
|
||
*
|
||
* The follwing may, or may not be present in the BSP for the CPU in use.
|
||
*
|
||
*/
|
||
void *sysA24Malloc(unsigned long size);
|
||
STATUS sysA24Free(void *pBlock);
|
||
|
||
/******************************************************************************
|
||
*
|
||
* Routines to use to allocate and free memory present in the A24 region.
|
||
*
|
||
******************************************************************************/
|
||
|
||
static void * (*A24MallocFunc)(size_t) = NULL;
|
||
static void (*A24FreeFunc)(void *) = NULL;
|
||
int devLibA24Debug = 0; /* Debugging flag */
|
||
|
||
void *devLibA24Calloc(size_t size)
|
||
{
|
||
void *ret;
|
||
|
||
ret = devLibA24Malloc(size);
|
||
|
||
if (ret == NULL)
|
||
return (NULL);
|
||
|
||
memset(ret, 0x00, size);
|
||
return(ret);
|
||
}
|
||
|
||
void *devLibA24Malloc(size_t size)
|
||
{
|
||
SYM_TYPE stype;
|
||
static int UsingBSP = 0;
|
||
void *ret;
|
||
|
||
if (devLibA24Debug)
|
||
logMsg("devLibA24Malloc(%d) entered\n", size, 0,0,0,0,0);
|
||
|
||
if (A24MallocFunc == NULL)
|
||
{
|
||
/* See if the sysA24Malloc() function is present. */
|
||
if(symFindByName(sysSymTbl,"_sysA24Malloc", (char**)&A24MallocFunc,&stype)==ERROR)
|
||
{ /* Could not find sysA24Malloc... use the malloc one and hope we are OK */
|
||
if (devLibA24Debug)
|
||
logMsg("devLibA24Malloc() using regular malloc\n",0,0,0,0,0,0);
|
||
A24MallocFunc = malloc;
|
||
A24FreeFunc = free;
|
||
}
|
||
else
|
||
{
|
||
if(symFindByName(sysSymTbl,"_sysA24Free", (char**)&A24FreeFunc, &stype) == ERROR)
|
||
{ /* That's strange... we have malloc, but no free! */
|
||
if (devLibA24Debug)
|
||
logMsg("devLibA24Malloc() using regular malloc\n",0,0,0,0,0,0);
|
||
A24MallocFunc = malloc;
|
||
A24FreeFunc = free;
|
||
}
|
||
else
|
||
UsingBSP = 1;
|
||
}
|
||
}
|
||
ret = A24MallocFunc(size);
|
||
|
||
if ((ret == NULL) && (UsingBSP))
|
||
errMessage(S_dev_noMemory, "devLibA24Malloc ran out of A24 memory, try sysA24MapRam(size)");
|
||
|
||
return(ret);
|
||
}
|
||
|
||
void devLibA24Free(void *pBlock)
|
||
{
|
||
if (devLibA24Debug)
|
||
logMsg("devLibA24Free(%p) entered\n", (unsigned long)pBlock,0,0,0,0,0);
|
||
|
||
A24FreeFunc(pBlock);
|
||
}
|