431 lines
16 KiB
C
431 lines
16 KiB
C
/*************************************************************************\
|
|
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
|
|
* National Laboratory.
|
|
* Copyright (c) 2002 The Regents of the University of California, as
|
|
* Operator of Los Alamos National Laboratory.
|
|
* EPICS BASE is distributed subject to a Software License Agreement found
|
|
* in file LICENSE that is included with this distribution.
|
|
\*************************************************************************/
|
|
|
|
/**
|
|
* \file devLibVME.h
|
|
* \author Marty Kraimer, Jeff Hill
|
|
* \brief API for accessing hardware devices, mosty over VMEbus.
|
|
*
|
|
* API for accessing hardware devices. The original APIs here were for
|
|
* written for use with VMEbus but additional routines were added for
|
|
* ISA-bus (but not fully implemented inside EPICS Base and may never
|
|
* have been actually used).
|
|
*
|
|
* If all VMEbus drivers register with these routines then addressing
|
|
* conflicts caused by multiple device/drivers trying to use the same
|
|
* VME addresses will be detected. This API also makes it easy for a
|
|
* single driver to be written that works on both VxWorks and RTEMS.
|
|
*/
|
|
|
|
#ifndef INCdevLibh
|
|
#define INCdevLibh 1
|
|
|
|
#include "dbDefs.h"
|
|
#include "osdVME.h"
|
|
#include "errMdef.h"
|
|
#include "libComAPI.h"
|
|
#include "devLib.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/** \brief The available bus address types */
|
|
typedef enum {
|
|
atVMEA16, /**< \brief VME short I/O. */
|
|
atVMEA24, /**< \brief VME standard I/O. */
|
|
atVMEA32, /**< \brief VME extended I/O. */
|
|
atISA, /**< \brief Memory mapped ISA access. */
|
|
atVMECSR, /**< \brief VME-64 CR/CSR address space. */
|
|
atLast /**< \brief Invalid, must be the last entry. */
|
|
} epicsAddressType;
|
|
|
|
/** \brief A string representation of each of the bus address types */
|
|
LIBCOM_API extern const char *epicsAddressTypeName[];
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* To retain compatibility include everything by default
|
|
*/
|
|
#ifndef NO_DEVLIB_COMPAT
|
|
# include "devLibVMEImpl.h"
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/** \brief Print a map of registered bus addresses.
|
|
*
|
|
* Display a table of registsred bus address ranges, including the owner of
|
|
* each registered address.
|
|
* \return 0, or an error status value
|
|
*/
|
|
LIBCOM_API long devAddressMap(void);
|
|
|
|
/** \brief Translate a bus address to a pointer the CPU can use.
|
|
*
|
|
* Given a bus address, returns a pointer to that location in the CPU's
|
|
* memory map, or an error if direct access isn't currently possible.
|
|
* \param addrType The bus address type.
|
|
* \param busAddr Bus address to be translated.
|
|
* \param *ppLocalAddr Where to put the CPU pointer.
|
|
* \return 0, or an error status value.
|
|
*/
|
|
LIBCOM_API long devBusToLocalAddr (
|
|
epicsAddressType addrType,
|
|
size_t busAddr,
|
|
volatile void **ppLocalAddr);
|
|
|
|
/** \brief Probe the bus for reading from a specific address.
|
|
*
|
|
* Performs a bus-error-safe \c wordSize atomic read from a specific
|
|
* address and returns an error if this caused a bus error.
|
|
* \param wordSize The word size to read: 1, 2, 4 or 8 bytes.
|
|
* \param ptr Pointer to the location in the CPU's memory map to read.
|
|
* \param pValueRead Where to put the value read.
|
|
* \return 0, or an error status value if the location could not be
|
|
* accessed or the read caused a bus error.
|
|
*/
|
|
LIBCOM_API long devReadProbe (
|
|
unsigned wordSize, volatile const void *ptr, void *pValueRead);
|
|
|
|
/** \brief Read-probe a range of bus addresses, looking for empty space.
|
|
*
|
|
* Verifies that no device responds at any naturally aligned addresses
|
|
* within the given range. Tries to read every aligned address at every
|
|
* word size between char and long over the entire range, returning
|
|
* success only if none of the reads succeed.
|
|
* \warning This routine may be slow and have a very bad effect on a busy
|
|
* VMEbus. Every read probe of an unused address will hold onto the VMEbus
|
|
* for the global bus timeout period.
|
|
* \param addrType The bus address type.
|
|
* \param base First address base to probe.
|
|
* \param size Range of bus addresses to test, in bytes.
|
|
* \return 0 if no devices respond, or an error status value.
|
|
*/
|
|
LIBCOM_API long devNoResponseProbe(
|
|
epicsAddressType addrType,
|
|
size_t base,
|
|
size_t size
|
|
);
|
|
|
|
/** \brief Probe the bus for writing to a specific address.
|
|
*
|
|
* Performs a bus-error-safe \c wordSize atomic write to a specific
|
|
* address and returns an error if this caused a bus error.
|
|
* \param wordSize The word size to write: 1, 2, 4 or 8 bytes.
|
|
* \param ptr Pointer to the location in the CPU's memory map to write to.
|
|
* \param pValueWritten The value to write.
|
|
* \return 0, or an error status value if the location could not be
|
|
* accessed or the write caused a bus error.
|
|
*/
|
|
LIBCOM_API long devWriteProbe (
|
|
unsigned wordSize, volatile void *ptr, const void *pValueWritten);
|
|
|
|
/** \brief Register a bus address range with a name.
|
|
*
|
|
* The devLib code keeps a list of all bus address ranges registered with
|
|
* this routine and returns an error if a later call attempts to register
|
|
* any addresses that overlap with a range already registered. The call to
|
|
* registering a range also converts the given base address into a pointer
|
|
* in the CPU address space for the driver to use (see devBusToLocalAddr()).
|
|
* \param pOwnerName Name of a driver that will own this range.
|
|
* \param addrType The bus address type.
|
|
* \param logicalBaseAddress The bus start address.
|
|
* \param size Number of bytes to reserve.
|
|
* \param pPhysicalAddress Where to put the converted CPU pointer.
|
|
* \return 0, or an error status.
|
|
*/
|
|
LIBCOM_API long devRegisterAddress(
|
|
const char *pOwnerName,
|
|
epicsAddressType addrType,
|
|
size_t logicalBaseAddress,
|
|
size_t size,
|
|
volatile void **pPhysicalAddress);
|
|
|
|
/** \brief Release a bus address range previously registered.
|
|
*
|
|
* Release an address range that was previously registered by a call to
|
|
* devRegisterAddress() or devAllocAddress().
|
|
* \param addrType The bus address type.
|
|
* \param logicalBaseAddress The bus start address.
|
|
* \param pOwnerName The name of the driver that owns this range.
|
|
* \return 0, or an error status.
|
|
*/
|
|
LIBCOM_API long devUnregisterAddress(
|
|
epicsAddressType addrType,
|
|
size_t logicalBaseAddress,
|
|
const char *pOwnerName);
|
|
|
|
/** \brief Allocate and register an unoccupied address block.
|
|
*
|
|
* Asks devLib to allocate an address block of a particular address type.
|
|
* This is useful for devices that appear in more than one address space
|
|
* and can program the base address of one window using registers found
|
|
* in another window. As with devRegisterAddress() this call also converts
|
|
* the new base address into a pointer in the CPU address space for the
|
|
* driver to use (see devBusToLocalAddr()).
|
|
* \note This routine calls devNoResponseProbe() to find an unoccupied
|
|
* block in the bus address space, so using it may have a bad effect on a
|
|
* busy VMEbus at allocation time; see the warning above.
|
|
* \param pOwnerName Name of a driver that will own this range.
|
|
* \param addrType The bus address type.
|
|
* \param size Number of bytes to be allocated.
|
|
* \param alignment How many low bits in the address must all be zero.
|
|
* \param pLocalAddress Where to put the CPU pointer.
|
|
* \return 0, or an error status value.
|
|
*/
|
|
LIBCOM_API long devAllocAddress(
|
|
const char *pOwnerName,
|
|
epicsAddressType addrType,
|
|
size_t size,
|
|
unsigned alignment, /*n ls bits zero in addr*/
|
|
volatile void **pLocalAddress);
|
|
|
|
/** \name VME Interrupt Management
|
|
* Routines to manage VME interrupts.
|
|
* @{
|
|
*/
|
|
/** \brief Connect an ISR up to a VME interrupt vector.
|
|
*
|
|
* Interrupt Service Routines (ISRs) are normally written in C, and get
|
|
* passed a context parameter given with them to this connection routine.
|
|
*
|
|
* There are many restrictions on the routines that an ISR may call; see
|
|
* epicsEvent.h, epicsInterrupt.h, epicsMessageQueue.h, epicsRingBytes.h,
|
|
* epicsRingPointer.h and epicsTime.h for some APIs known to be suitable.
|
|
* It is safest just to trigger a high-priority task to handle any
|
|
* complex work that must happen as a result of the interrupt.
|
|
* \param vectorNumber VME interrupt vector number.
|
|
* \param pFunction The ISR to be called.
|
|
* \param parameter Context parameter for the ISR.
|
|
* \return 0, or an error status value.
|
|
*/
|
|
LIBCOM_API long devConnectInterruptVME(
|
|
unsigned vectorNumber,
|
|
void (*pFunction)(void *),
|
|
void *parameter);
|
|
|
|
/** \brief Disconnect an ISR from its VME interrupt vector.
|
|
*
|
|
* Device drivers may disconnect an ISR they connected earlier using this
|
|
* routine. In addition to taking the \c vectorNumber the ISR itself is
|
|
* required and used as a check to prevent a driver from inadvertently
|
|
* removing an interrupt handler that it didn't install.
|
|
*
|
|
* On a PowerPC target running VxWorks, this routine will always return
|
|
* with an error status.
|
|
* \param vectorNumber VME interrupt vector number.
|
|
* \param pFunction The ISR to be disconnected.
|
|
* \return 0, or an error status value.
|
|
*/
|
|
LIBCOM_API long devDisconnectInterruptVME(
|
|
unsigned vectorNumber,
|
|
void (*pFunction)(void *));
|
|
|
|
/** \brief Determine if a VME interrupt vector is in use.
|
|
*
|
|
* On a PowerPC target running VxWorks this routine will always return
|
|
* false, indicating that a vector is unused.
|
|
* \param vectorNumber Interrupt vector number.
|
|
* \return True if vector has an ISR attached, otherwise false.
|
|
*/
|
|
LIBCOM_API int devInterruptInUseVME (unsigned vectorNumber);
|
|
|
|
/** \brief Enable a VME interrupt level onto the CPU.
|
|
*
|
|
* The VMEbus allows multiple CPU boards to be installed in the same
|
|
* backplane. When this is done, the differente VME interrupt levels
|
|
* must be assigned to the CPUs since they cannot be shared. This
|
|
* routine tells the VME interface that it should connect interrupts
|
|
* from the indicated interrupt level to a CPU interrupt line.
|
|
* \param level VMEbus interrupt level to enable, 1-7.
|
|
* \return 0, or an error status value.
|
|
*/
|
|
LIBCOM_API long devEnableInterruptLevelVME (unsigned level);
|
|
|
|
/** \brief Disable a VME interrupt level.
|
|
*
|
|
* This routine is the reverse of devEnableInterruptLevelVME().
|
|
* \note This routine should not normally be used, even by a
|
|
* driver that enabled the interrupt level. Disabling a VME
|
|
* interrupt level should only be done by software that knows
|
|
* for certain that no other interrupting device is also using
|
|
* that VME interrupt level.
|
|
* \param level VMEbus interrupt level to disable, 1-7.
|
|
* \return 0, or an error status value.
|
|
*/
|
|
LIBCOM_API long devDisableInterruptLevelVME (unsigned level);
|
|
/** @} */
|
|
|
|
/** \name Memory for VME DMA Operations
|
|
* These routines manage memory that can be directly accessed
|
|
* from the VMEbus in the A24 address space by another bus master
|
|
* such as a DMA controller.
|
|
* @{
|
|
*/
|
|
/** \brief malloc() for VME drivers that support DMA.
|
|
*
|
|
* Allocate memory of a given size from a region that can be
|
|
* accessed from the VMEbus in the A24 address space.
|
|
* \param size How many bytes to allocate
|
|
* \return A pointer to the memory allocated, or NULL.
|
|
*/
|
|
LIBCOM_API void *devLibA24Malloc(size_t size);
|
|
|
|
/** \brief calloc() for VME drivers that support DMA.
|
|
*
|
|
* Allocate and zero-fill a block of memory of a given size from
|
|
* a region that can be accessed from the VMEbus in the A24
|
|
* address space.
|
|
* \param size How many bytes to allocate and zero.
|
|
* \return A pointer to the memory allocated, or NULL.
|
|
*/
|
|
LIBCOM_API void *devLibA24Calloc(size_t size);
|
|
|
|
/** \brief free() for VME drivers that support DMA.
|
|
*
|
|
* Free a block of memory that was allocated using either
|
|
* devLibA24Malloc() or devLibA24Calloc().
|
|
* \param pBlock Block to be released.
|
|
*/
|
|
LIBCOM_API void devLibA24Free(void *pBlock);
|
|
/** @} */
|
|
|
|
/** \name ISA Interrupt Management
|
|
* Routines to manage ISAbus interrupts.
|
|
* \note These routines may not have been used for a very long time;
|
|
* some appear to have never been implemented at all. They may vanish
|
|
* with no notice from future versions of EPICS Base. Nobody is using
|
|
* the PC's ISA-bus any more are they?
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Connect ISR to a ISA interrupt.
|
|
* \warning Not implemented!
|
|
* \param interruptLevel Bus interrupt level to connect to.
|
|
* \param pFunction C function pointer to connect to.
|
|
* \param parameter Parameter to the called function.
|
|
* \return Returns success or error.
|
|
*/
|
|
LIBCOM_API long devConnectInterruptISA(
|
|
unsigned interruptLevel,
|
|
void (*pFunction)(void *),
|
|
void *parameter);
|
|
|
|
/**
|
|
* Disconnect ISR from a ISA interrupt level.
|
|
* \warning Not implemented!
|
|
* \param interruptLevel Interrupt level.
|
|
* \param pFunction C function pointer that was connected.
|
|
* \return returns success or error.
|
|
*/
|
|
LIBCOM_API long devDisconnectInterruptISA(
|
|
unsigned interruptLevel,
|
|
void (*pFunction)(void *));
|
|
|
|
/**
|
|
* Determine if an ISA interrupt level is in use
|
|
* \warning Not implemented!
|
|
* \param interruptLevel Interrupt level.
|
|
* \return Returns True/False.
|
|
*/
|
|
LIBCOM_API int devInterruptLevelInUseISA (unsigned interruptLevel);
|
|
|
|
/**
|
|
* Enable ISA interrupt level
|
|
* \param level Interrupt level.
|
|
* \return Returns True/False.
|
|
*/
|
|
LIBCOM_API long devEnableInterruptLevelISA (unsigned level);
|
|
|
|
/**
|
|
* Disable ISA interrupt level
|
|
* \param level Interrupt level.
|
|
* \return Returns True/False.
|
|
*/
|
|
LIBCOM_API long devDisableInterruptLevelISA (unsigned level);
|
|
/** @} */
|
|
|
|
#ifndef NO_DEVLIB_OLD_INTERFACE
|
|
|
|
/**
|
|
* \name Deprecated Interfaces
|
|
* @{
|
|
*/
|
|
typedef enum {intVME, intVXI, intISA} epicsInterruptType;
|
|
|
|
/**
|
|
* \note This routine has been deprecated. It exists
|
|
* for backwards compatibility purposes only.
|
|
* Please use one of devConnectInterruptVME(), devConnectInterruptPCI(),
|
|
* devConnectInterruptISA() instead. devConnectInterrupt() will be removed
|
|
* in a future release.
|
|
*/
|
|
LIBCOM_API long devConnectInterrupt(
|
|
epicsInterruptType intType,
|
|
unsigned vectorNumber,
|
|
void (*pFunction)(void *),
|
|
void *parameter);
|
|
|
|
/**
|
|
* \note This routine has been deprecated. It exists
|
|
* for backwards compatibility purposes only.
|
|
* Please use one of devDisconnectInterruptVME(), devDisconnectInterruptPCI(),
|
|
* devDisconnectInterruptISA() instead. devDisconnectInterrupt() will
|
|
* be removed in a future release.
|
|
*/
|
|
LIBCOM_API long devDisconnectInterrupt(
|
|
epicsInterruptType intType,
|
|
unsigned vectorNumber,
|
|
void (*pFunction)(void *));
|
|
|
|
/**
|
|
* \note This routine has been deprecated. It exists
|
|
* for backwards compatibility purposes only.
|
|
* Please use one of devEnableInterruptLevelVME(), devEnableInterruptLevelPCI(),
|
|
* devEnableInterruptLevelISA() instead. devEnableInterruptLevel() will
|
|
* be removed in a future release.
|
|
*/
|
|
LIBCOM_API long devEnableInterruptLevel(
|
|
epicsInterruptType intType, unsigned level);
|
|
|
|
/**
|
|
* \note This routine has been deprecated. It exists
|
|
* for backwards compatibility purposes only.
|
|
* Please use one of devDisableInterruptLevelVME(), devDisableInterruptLevelISA(),
|
|
* devDisableInterruptLevelPCI() instead. devDisableInterruptLevel() will
|
|
* be removed in a future release.
|
|
*/
|
|
LIBCOM_API long devDisableInterruptLevel (
|
|
epicsInterruptType intType, unsigned level);
|
|
|
|
/**
|
|
* \note This routine has been deprecated. It exists
|
|
* for backwards compatibility purposes only.
|
|
* Please use devNoResponseProbe() instead. locationProbe() will be removed
|
|
* in a future release.
|
|
*/
|
|
LIBCOM_API long locationProbe (epicsAddressType addrType, char *pLocation);
|
|
|
|
/** @} */
|
|
|
|
#endif /* NO_DEVLIB_OLD_INTERFACE */
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* INCdevLibh.h*/
|