drvIpac - Industry Pack Driver

Version 2.9
Andrew Johnson
  1. Introduction
  2. IPAC Driver Usage
  3. Calls for use by IPAC Module Drivers
  4. IPAC Carrier Drivers
  5. Interface to IPAC Carrier Drivers
  6. See also the following Module Drivers which are included with drvIpac:

    1. Introduction

    This document describes the software interface to a generic Industry Pack (IPAC) driver module for EPICS, which was originaly written as part of a CANbus EPICS device driver for the Gemini and UKIRT telescopes. The original purpose of the generic IPAC driver was to ensure that the CANbus driver would not be restricted to use with a single carrier board but could be used with different carriers as required, including with more than one type of carrier board simultaneously. The use of the generic driver also ensures that additional IPAC modules and drivers for other interfaces can be added without affecting the functioning of the CANbus driver.

    To provide a generic IPAC carrier board interface for each IPAC module driver, all control of or requests for information about the carrier board goes via the IPAC driver which in turn calls the IPAC Carrier driver written for the particular type of carrier board. This carrier driver should be simple to write, comprising three or four short subroutines and an interface structure. Carrier drivers are available for most of the common IP carrier boards.

    At present the IPAC driver is limited (by the size of an internal array) to controlling a maximum of 21 carrier boards, but this limitation should be easy to dispense with completely without altering any of its interfaces.

    Installation

    The drvIpac subsystem is an EPICS <supporttop> application which can also be used to build IPAC module drivers. To install and use the the ipac support, obtain a copy of the tar file or (if you have remote CVS permissions at APS) export the software from the CVS repository where it resides as epics/modules/bus/ipac - CVS tags of the form `V2-1' mark the particular file versions required for each release. These instructions assume you already have EPICS R3.14.x installed and built (this software should work with EPICS R3.14.4 and later). Two steps are then required to install and build the software:

    1. Edit the configure/RELEASE file and set the correct path for EPICS_BASE at your site.
    2. If you don't need all of the module drivers included with the distribution, edit the top level Makefile and comment out the lines mentioning driver directories you don't need.
    3. Edit the drvIpac/drvIpac.dbd file to include the set of IPAC Carrier drivers that you will be using at your site. This step can also be performed later by copying the drvIpac.dbd file to an IOC application and modifying it there instead.
    4. Run gnumake in the top level directory.

    Bus Issues

    From version 2-1 this software supports little-endian as well as big-endian busses, and provides a means of isolating module drivers from some of the differences between interrrupt handling on different busses.

    The endian problem only exists when accessing I/O registers and the IPAC ID PROM using byte addresses. In drvIpac all accesses are made using 16-bit read/write cycles, so there are no known issues with endianness. This is done by declaring the structure of a module's registers using short variables instead of char. With this done the only other requirement is to mask off the top 8 bits of every value read from the hardware.

    Some busses such as ISAbus do not support interrupt vectors and require a different approach to connecting Interrupt Service Routines up to the relevent hardware interrupts, although the IndustryPack standard does require that any IP module that generates interrupts should provide a vector. On ISA bus carriers this vector can be read by the carrier driver to work out which module caused the interrupt. A module driver should not need to know about the particular bus type its carrier is on, thus Ipac now provides the routine ipmIntConnect() to allow it to pass such issues off to the carrier driver to handle. The interface to this is very similar to the standard vxWorks intConnect() routine.


    2. IPAC Driver Usage

    The driver provides a C header file drvIpac.h for use by both module and carrier drivers.

    #include "drvIpac.h"

    This header file declares the necessary structures, enumerated types and functions provided by the driver. These are individually documented below.

    This software can no longer be built for use without EPICS.


    ipacAddCarrier

    Used to register a carrier board and the appropriate carrier driver software for it with the IPAC Driver. Up to release 2.5 this call was used directly inside IOC startup scripts, but from release 2.6 onwards the carrier drivers provided with drvIpac all contain their own routines for use in startup scripts, which allows initialization from the EPICS ioc shell as well as from the vxWorks shell. See the documentation for the specific carrier board in section 4 below for the name of the new initialization routine.

    int ipacAddCarrier(ipac_carrier_t *pcarrier, const char *cardParams);

    Parameters

    ipac_carrier_t *pcarrier
    Pointer to the carrier driver structure which is the only interface to the IPAC Carrier driver. The same structure is used for every instance of the same type of carrier board.
    const char *cardParams
    String containing board-specific initialisation parameters which is passed to the carrier driver. For carrier boards which rely on jumpers to set the board address (e.g. the SBS carrier boards), the settings for each particular board will be reflected in the parameter settings given here when registering that carrier. For boards such as the MVME162 where the addresses can be changed by the driver, this string may be used to indicate how the board should be initialised. See the specific documentation for each carrier driver (section 4 below) for the parameter string syntax.

    Description

    This routine will usually be called from the EPICS start-up script. Some types of carrier may need additional initialisation before or after registering, but this method using the card parameter string should be sufficient for most carriers. Note that only the carrier initialise() routine is called at this stage. The order in which carriers are registered with this routine defines the carrier number which they will be allocated, starting from zero for the first board registered.

    The code checks that the carrier descriptor table looks sensible, calls the initialise routine with the given card parameters, then saves the carrier private pointer and carrier table address in an internal array. The card number allows the same descriptor table to be used for all carriers of the same type.

    It may be necessary to remove a carrier temporarily from a system in some circumstances without wanting to have to change the carrier number allocated to higher numbered carriers. To allow this, it is legal to call this routine with a NULL (zero) carrier table address, which switches in the null carrier table instead. When this facility is used any module driver which attempts to access a slot on this carrier will be given error status returns by the module interface routines.

    As long as the carrier table is not full, ipacAddCarrier() will always increment its internal carrier number on every call, thus a carrier driver failure will not cause all subsequent carriers to silently move down by one. In the event of an error, the null carrier table is used for the current carrier number instead of the requested table.

    Returns

    int
    Symbol/Value Meaning
    0 OK
    S_IPAC_tooMany Carrier Info Table full
    S_IPAC_badTable Carrier Table invalid
    (others values) from carrier initialisation routine.

    Examples

    ipacAddCarrier(&vipc610_01, "0x6000,256");
    ipacAddCarrier(NULL, "");
    ipacAddCarrier(&vipc310, "0x6800");

    ipacLatestCarrier

    Gets the carrier number of the most recently added carrier board.

    int ipacLatestCarrier(void);

    Description

    Returns the index into the carrier table of the most recently added carrier board, or USHRT_MAX if the most recent call to ipacAddCarrier could not be fulfilled because the carrier table was already full. The value returned can always be used as the carrier argument to any drvIpac routine without checking it first; if the carrier board was not properly initialized for any reason then these routines will return a failure status of some kind.

    Returns

    int
    Symbol/Value Meaning
    0 thru 20 Carrier number of latest board added
    USHRT_MAX Carrier table was full

    ipacReport

    Prints a report on stdout giving the status of all known IPAC carriers.

    int ipacReport(int interest);

    Parameters

    int interest
    Interest level, defines how much information to provide in the report.

    Description

    Prints information on each known carrier board and slot according to the specified interest level. Level 0 lists all the carriers defined, with the number of IPAC slots each one supports. Level 1 gives details on each slot on the carriers: the Manufacturer and Model ID bytes of the installed module if one is present, and the Carrier Driver's report for that slot (see ipmReport below). Level 2 adds the CPU address of each memory space for the slot.

    Returns

    int
    Symbol/Value Meaning
    0 OK.

    ipacInitialise

    Initialise the IPAC driver.

    int ipacInitialise(int after);

    Parameters

    int after
    Not currently used, provided for compatibility with EPICS driver initialisation routine.

    Description

    Null routine, does nothing.

    Returns

    int
    Symbol/Value Meaning
    0 OK.

    3. Calls for use by IPAC Module Drivers

    The routines documented below are provided for use by the module drivers which use the services of the generic IPAC driver. In general it is expected that these routines will only be used at initialisation time. The module driver should be informed by other means which carrier and slot the particular IPAC module it is to control is installed in, although it should be possible to search each carrier and slot number in turn for the module using the Manufacturer and Model ID codes.

    ipmBaseAddr

    Returns Base CPU address of selected IP address space

    void *ipmBaseAddr(int carrier, int slot, ipac_addr_t space);

    Parameters

    int carrier
    Carrier number; identifies a particular carrier board in the system. The carriers are given numbers sequentially starting from zero according to the order in which they were registered by calling ipacAddCarrier.
    int slot
    Slot number; identifies the particular IP slot on the carrier board, starting from zero. The number of slots available varies with the type of the carrier board - the VIPC310 and MVME172 provide 2, the VIPC610, VIPC616, ATC40 and MVME162 each have four slots.

    Together these two parameters uniquely identify a specific IPAC module in the system, and these are used in this way by all of the following routines.

    ipac_addr_t space
    Value identifying the IP address space to be queried. This parameter is an enumerated type, and must be one of the following values which are defined in the header file:
    IP Address Space space
    ID Prom Space ipac_addrID
    Register Space ipac_addrIO
    32-bit Register Space ipac_addrIO32
    Memory Space ipac_addrMem

    Description

    Checks its input parameters, then calls the carrier driver. This will return a pointer to the location of the address space indicated by the space parameter.

    All IP modules must provide an ID prom to indicate the module type (space = ipac_addrID). Most modules need register I/O locations, which are in the I/O space (space = ipac_addrIO). Some types of module also provide memory (space = ipac_addrMem), but if this is not required the carrier may allow it to be disabled, in which case the carrier driver will return a NULL for this address space. Some carriers also provide a 32-bit wide I/O space for accessing 32-bit registers on Dual-slot IP modules (space = ipac_addrIO32); carriers which do not support this will return NULL for this space.

    Returns

    void *
    Pointer to the beginning of the IP address space for the given carrier/slot, or NULL pointer.

    ipmCheck

    Check on the presence of an IPAC module at the given carrier and slot number.

    int ipmCheck(int carrier, int slot);

    Parameters

    int carrier, int slot
    Module identification - see above

    Description

    Does a quick check to make sure the carrier and slot numbers are legal, probes the IDprom space to ensure an IPAC is installed, and checks that the IDprom starts with an "IPAC", "IPAH" or "VITA4" identifier.

    Returns

    int
    Symbol/Value Meaning
    0 OK
    S_IPAC_badAddress Bad carrier or slot number
    S_IPAC_badDriver Carrier driver returned NULL ID address
    S_IPAC_noModule No IP module installed
    S_IPAC_noIpacId IP Module identifier not found

    ipmValidate

    Validates a particular IPAC module type at the given carrier & slot number.

    int ipmValidate(int carrier, int slot,
                    int manufacturerId, int modelId);

    Parameters

    int carrier, int slot
    Module identification - see above
    int manufacturerId
    IPAC Manufacturer Identification Number, as allocated by SBS. This number should be given in the Programmer's Documentation for the IPAC module.
    int modelId
    IPAC Model Identification Number, as allocated by the module manufacturer. This number should be given in the Programmer's Documentation for the IPAC module.

    Description

    Uses ipmCheck to ensure the carrier and slot numbers are legal, probe the IDprom and check that the IDprom looks like an IPAC module. Then calculates and verifies the CRC for the ID Prom, and compares the manufacturer and model ID values in the Prom to the ones given.

    The manufacturer and model identification numbers allow a Module Driver to ensure that the correct hardware has been installed in the particular slot which the driver has been told to control. If a driver supports more than one type of module, it should check each module type individually by calling ipmValidate with each manufacturer/model pair it can control until it finds a match.

    Releases of drvIpac before 2-9 did not recognize Format-2 ID PROMS as defined in the VITA spec. From release 2-9 on this software should be compatible with modules having either Format-1 or Format-2 ID PROMS. In the newer format the PROM is specified to be 16 bits wide rather than 8, and various fields including the Manufacturer and Model numbers have been made wider. The calculated CRC is also wider, but some IP Module manufacturers are setting the CRC field to all zeros rather than calculating the correct CRC value for it. As a result, the ipmValidate routine will not check the CRC of a Format-2 ID Prom if its CRC field is zero.

    Returns

    int
    Symbol/Value Meaning
    0 OK
    S_IPAC_badCRC CRC Check failed
    S_IPAC_badModule Manufacturer or model IDs wrong
    S_IPAC_badAddress Bad carrier or slot number
    S_IPAC_badDriver Carrier driver returned NULL ID address
    S_IPAC_noModule No IP module installed
    S_IPAC_noIpacId IP Module identifier not found

    ipmIrqCmd

    Manipulate the carrier board interrupt controller.

    int ipmIrqCmd(int carrier, int slot,
                  int irqNumber, ipac_irqCmd_t cmd);

    Parameters

    int carrier, int slot
    Module identification - see above
    int irqNumber
    The IPAC specification provides two interrupt lines for each module. This parameter identifies the interrupt to the Carrier Driver. It should have the value 0 or 1 only.
    ipac_irqCmd_t cmd
    This parameter gives the action required (see table in Description below), and is an enumerated type defined in the header file. Because some carrier boards do not provide software access to their interrupt controllers most of the commands are optional. Module Drivers may be written to utilise the additional functions if they are available.

    Description

    Checks input parameters, then passes the interrupt command request to the equivalent Carrier Driver routine. The driver is only required to support the command ipac_irqEnable; for other commands it may return the status code S_IPAC_notImplemented and do nothing. Commands available are as follows:

    Command Description cmd
    Selects Interrupt Priority 0 (disabled) ipac_irqLevel0
    Selects Interrupt Priority 1 ipac_irqLevel1
    Selects Interrupt Priority 2 ipac_irqLevel2
    Selects Interrupt Priority 3 ipac_irqLevel3
    Selects Interrupt Priority 4 ipac_irqLevel4
    Selects Interrupt Priority 5 ipac_irqLevel5
    Selects Interrupt Priority 6 ipac_irqLevel6
    Selects Interrupt Priority 7 (non-maskable) ipac_irqLevel7
    Returns current Interrupt Priority, 0 to 7 ipac_irqGetLevel
    Enable interrupts from module ipac_irqEnable
    Disable interrupts from module ipac_irqDisable
    Returns current interrupt signal state ipac_irqPoll
    Sets LED indicator to Empty/Unused ipac_statUnused
    Sets LED indicator to Active ipac_statActive
    Resets this IP slot only ipac_slotReset

    The Interrupt Priority (often also known as interrupt level) commands are defined to be numerically the same as the level number they select. Level 0 effectively disables the interrupt. Level 7 is not recommended within vxWorks as it is non-maskable, and may only be used for an ISR that does not call any vxWorks routines. The ipac_irqGetLevel command returns the level currently set. Carrier boards which have fixed interrupt levels will not support setting the interrupt level but the driver may still able to return the level number.

    The ipac_irqEnable command must be supported by all Carrier Drivers, and must be called by any Module Driver that uses interrupts. The Carrier Driver routine is responsible for calling the vxWorks sysIntEnable() routine if this is required to allow IPAC interrupts to be seen by the CPU. The corresponding ipac_irqDisable command is not necessarily supported by all carriers however - the module driver must disable interrupts using the control registers on the IP module itself if this is necessary. A Carrier Driver cannot implement the ipac_irqDisable command with a call to the vxWorks sysIntDisable() routine because this would stop any other devices which still need this interrupt level from working.

    The ipac_slotReset command should only be implemented on carrier boards that can reset IP slots individually without affecting any IP modules in neighboring slots. This command must not return until the reset process has completed, so any driver using this may immediately proceed to reinitialize the IP module as required.

    Returns

    int
    Symbol/Value Meaning
    0 OK
    S_IPAC_badAddress No such carrier or slot
    S_IPAC_notImplemented Driver does not support that command

    Other values may also be returned depending on the Driver and command used.


    ipmIntConnect

    Connects a module driver Interrupt Service Routine to a particular interrupt vector number.

    int ipmIntConnect (int carrier, int slot, int vecNum, 
                       void (*routine)(int parameter), int parameter);

    Parameters

    int carrier, int slot
    Module identification - see above
    int vecNum
    Interrupt vector number
    void (*routine)(int parameter)
    Modules Interrupt Service Routine to be connected
    int parameter
    Context parameter passed to Interrupt Service Routine

    Description

    Checks input parameters, then passes the request to the carrier driver routine. If no carrier routine is provided it uses the standard vxWorks intConnect() routine instead. This is not quite a direct replacement for the vxWorks intConnect() call; as well as providing the carrier and slot numbers the module driver does not use the INUM_TO_IVEC(vecNum) macro but just passes the vector number to this routine.

    VxWorks' interrupt vectoring mechanism varies between bus types, and ipmIntConnect() allows a module driver to connect its routine to an interrupt vector from a particular IPAC module without knowing the requirements of the particular bus type. Some carrier drivers will need to maintain a private interrupt dispatch table if the bus type (i.e. ISA) does not support interrupt vectoring.

    Returns

    int
    Symbol/Value Meaning
    0 OK
    S_IPAC_badAddress No such carrier, slot or vector

    Other values may also be returned depending on the Driver and vector used.


    ipmReport

    Returns a printable string giving the status/settings of the given slot.
    char *ipmReport(int carrier, int slot);

    Parameters

    int carrier, int slot
    Module identification - see above

    Description

    Generates a report string describing the given IPAC slot. If a module is installed, it includes the manufacturer and model ID numbers. If the report function is supported by the carrier driver this report string is appended. This function is uses a static character array to hold the report string, thus the value will be corrupted if two tasks use this routine simultaneously. The string returned by the carrier driver's report routine will be clipped if longer than IPAC_REPORT_LEN characters.

    Returns

    char *
    Pointer to a static, printable string.

    Sample Output

    C0 S0 : 0x23ae80/0x8d49 - M0 L3,3
    C0 S1 : 0xB1/0x01 - M0 L4,5

    This string is made up of three parts. The first two elements before the colon give the carrier and slot number of the slot. If a module is installed, the manufacturer and model IDs follow as two hex numbers (2 digits each for Format-1 ID PROMS, 6+4 digits for Format-2 ID PROMS). Finally if the Carrier Driver contains a report function it is called and the string it returns is appended after a hyphen.


    4. IPAC Carrier Drivers

    SBS VIPC310

    This board is probably the simplest possible VME-based IPAC Carrier available. A 3U VME card, it provides two IP slots (although it cannot support 32-bit accesses to dual-slot IP modules), and allows no control over the slot interrupt controllers from software. The base addresses for the card are set using a series of jumpers on the board which select both the VME short I/O base address (used for the IPAC ID Prom and Register spaces) and the VME Standard base address (used for the IPAC Memory space if required). Additional jumpers allow the size of the IPAC Memory to be selected. The interrupts are at priority levels fixed by the hardware.

    The IPAC Carrier Driver for this board is found in the file drvVipc310.c which implements the command ipacAddVIPC310 to add a VIPC310 board to the system, and provides the registrar routine vipc310Registrar to add the above command to the iocsh and link the driver into a final IOC executable, for which it must be listed in the IOC's .dbd file thus:

    registrar(vipc310Registrar)

    Configuration Command and Parameter

    int ipacAddVIPC310(const char *cardParams);

    The parameter string should comprise a hexadecimal number (an 0x or 0X at the start is optional) optionally followed by a comma and a decimal integer. The first number is the I/O Base Address of the card in the VME A16 address space. The factory default setting for the card gives an I/O Base Address of 0x6000, and this value will be used if the string is empty or NULL. If supplied the second number in the parameter string gives the size in Kbytes of the memory space allocated to each IP module.

    The Memory Base Address of the VIPC310 card is set using the same jumpers as the I/O base address and is always 256 times the I/O base address, but in the VME A24 address space. The factory default for the memory base address is thus 0x600000.

    If the memory size parameter is omitted or set to zero then neither IP module provides any memory space. Legal memory size values are 0, 64, 128, 256, 512, 1024 or 2048. The memory size interacts with the memory base address such that it is possible to set the existence of memory in either slot independently by suitable adjustment of the base address.

    Configuration Examples

    ipacAddVIPC310("0x6000")
    This indicates that the carrier has its I/O base set to 0x6000, and neither slot uses any memory space.
    ipacAddVIPC310("1000,512")
    Here the I/O base is set to 0x1000, and there is 512 Kbytes of memory on each module, with the IP module A memory at 0x100000 and module B at 0x180000.
    ipacAddVIPC310("0xfe00, 128")
    The I/O Base is at 0xfe00, and hence the carrier board Memory Base address is 0xfe0000. However because the memory size is set to give each module 128 Kbytes of memory space, module A cannot be selected (128 K = 0x020000, so the module Memory Base would be decoded at 0xfc0000 but can't be accessed there because this is below the Memory Base address for the board).

    Interrupt Commands Supported

    The board uses fixed interrupt levels, and provides no software control over the interrupt generator. The only commands thus supported are a request of the interrupt level associated with a particular slot and interrupt number, or to enable interrupts by making sure the CPU's VMEbus interrupter is listening on the necessary level.

    cmd Value Returned
    ipac_irqGetLevel slot interrupt level (1, 2, 4 or 5)
    ipac_irqEnable 0 = OK
    (other commands) S_IPAC_notImplemented

    SBS VIPC610

    This board is a four-slot, 6U carrier, but otherwise very similar to the VIPC310. A seperate driver is also included for the VIPC610-01 option which changes the Interrupt Priority levels for the IP slots so they are equivalent to a pair of VIPC310 carrier boards, different to the interrupt levels for a standard VIPC610 board.

    The IPAC Carrier Drivers for both board versions are found in the file drvVipc610.c which implements the commands ipacAddVIPC610 and ipacAddVIPC610_01 for adding a VIPC610 board of the relevent type to the system, and provides the registrar routine vipc610Registrar to add the above commands to the iocsh and link the driver into a final IOC executable, for which it must be listed in the IOC's .dbd file thus:

    registrar(vipc610Registrar)

    Warning: As delivered by SBS the VIPC610 has IRQ0 of slot D connected to the VMEbus level 7 interrupt, and IRQ1 of slot D does not cause a VMEbus interrupt at all. Under vxWorks on the MC680x0 family a level 7 interrupt level may only be connected to a service routine that does not make any calls to vxWorks routines. Thus with a VIPC610 board slot D should not be used for modules that generate interrupts. The VIPC610-01 board option is free of this problem.

    Configuration Commands and Parameter

    int ipacAddVIPC610(const char *cardParams);
    int ipacAddVIPC610_01(const char *cardParams);

    The parameter string should comprise a hexadecimal number (an 0x or 0X at the start is optional) optionally followed by a comma and a decimal integer. The first number is the I/O Base Address of the card in the VME A16 address space. The factory default setting for the card gives an I/O Base Address of 0x6000, and this value will be used if the string is empty or NULL. If supplied the second number in the parameter string gives the size of the memory space in Kbytes allocated to each IP module.

    The Memory Base Address of the VIPC610 card is set using the same jumpers as the I/O Base Address and is always 256 times the I/O Base Address, but in the VME A24 address space. The factory default for the Memory Base address is thus 0x600000.

    If the memory size parameter is omitted or set to zero then none of the IP modules on the carrier provide any memory space. Legal memory size values are 0, 64?, 128, 256, 512, 1024 or 2048. The memory size interacts with the Memory Base Address setting such that it is possible to exclude memory from the lower slots while still providing access to memory in the later slots by suitable adjustment of the base address.

    Configuration Examples

    ipacAddVIPC610("0x6000")
    This indicates that the VIPC610 carrier board has its I/O base set to 0x6000, and none of the slots provide memory space.
    ipacAddVIPC610_01("1000,128")
    Here the I/O base is set to 0x1000, and there is 128Kbytes of memory on each module, with the IP module A memory at 0x100000, module B at 0x120000, module C at 0x140000 and D at 0x160000. The board is actually a VIPC610-01.
    ipacAddVIPC610("7000,1024")
    The I/O base is at 0x7000, and hence the carrier memory base is 0x700000. However because the memory size is set to 1024 Kbytes, modules A, B and C cannot be selected (1024 K = 0x100000, so they are decoded at 0x400000, 0x500000 and 0x600000 but can't be accessed because these are below the base address for the board).

    Interrupt Commands Supported

    The board uses fixed interrupt levels, and provides no software control over the interrupt generator. The only commands thus supported are a request of the interrupt level associated with a particular slot and interrupt number, or to enable interrupts by making sure the CPU's VMEbus interrupter is listening on the necessary level. Note that the VIPC610-01 uses different interrupt levels to the straight VIPC610, you must use the correct driver!

    cmd Value Returned
    ipac_irqGetLevel slot interrupt level
    ipac_irqEnable 0 = OK
    (other commands) S_IPAC_notImplemented

    SBS VIPC616

    This board is a four-slot, 6U carrier, but otherwise very similar to the VIPC310. A seperate driver is also included for the VIPC616-01 option which changes the Interrupt Priority levels for the IP slots so they are equivalent to a pair of VIPC310 carrier boards, different to the interrupt levels for a standard VIPC616 board.

    The only differences between this carrier and the VIPC610 relate to the VME addressing capabilities, the VIPC616 supports access to memory IP modules in the VME A32 address space. It is possible to use the VIP610 driver to control a VIPC616 board, but the use of this specific driver is recommended. This driver should also be used for the VIPC618 carrier which is schematically identical to the VIPC616 but uses different I/O connectors for the IP module signals.

    The IPAC Carrier Drivers for both board versions are found in the file drvVipc616.c which implements the commands ipacAddVIPC616 and ipacAddVIPC616_01 to add a VIPC616 board of the relevent type to the system, and provides the registrar routine vipc616Registrar to add the above commands to the iocsh and link the driver into a final IOC executable, for which it must be listed in the IOC's .dbd file thus:

    registrar(vipc616Registrar)

    Warning: As delivered by SBS the VIPC616 has IRQ0 of slot D connected to the VMEbus level 7 interrupt, and IRQ1 of slot D does not cause a VMEbus interrupt at all. Under vxWorks on the MC680x0 family a level 7 interrupt level may only be connected to a service routine that does not make any calls to vxWorks routines. Thus with a VIPC616 board slot D should not be used for modules that generate interrupts. The VIPC616-01 board option is free of this problem.

    Configuration Commands and Parameter

    int ipacAddVIPC616(const char *cardParams);
    int ipacAddVIPC616_01(const char *cardParams);

    The parameter string should comprise a hexadecimal number (an 0x or 0X at the start is not required) optionally followed by a comma and another hexadecimal number, and then possibly another comma and a decimal integer. The first number is the I/O Base Address of the card in the VME A16 address space. The factory default setting for the card gives an I/O Base Address of 0x6000, and this value will be used if the string is empty or NULL.

    The meaning of the second number depends upon whether the third (decimal) integer is present in the string or not. If there is no third number then the second number gives the Memory Base Address of the card in the VME A32 space. In this case each module is allocated a fixed 8 Mbytes of memory space by the carrier.

    If all three numbers are given then the second number is the Memory Base Address of the card in VME A24 address space, and the third number gives the size of the memory space in Kbytes allocated to each IP module. This is the VIPC610 compatibility mode, and the Memory Base Address and Memory Size parameters are used and interact in exactly the same way as with the VIPC610.

    Configuration Examples

    ipacAddVIPC616("")
    This indicates that the board is configured as delivered by the manufacturer, with the I/O base set to 0x6000 and the memory base address to 0xd0000000 in the VME A32 space, with 8MB of memory space available for each slot.
    ipacAddVIPC616("0x9000")
    This indicates that the board has its I/O base set to 0x9000, and none of the slots provide memory space.
    ipacAddVIPC616_01("1000,8000000")
    Here the I/O base is set to 0x1000, and each module is allocated 8Mb of VME A32 memory space starting at 0x80000000. This puts IP module A memory at 0x80000000, module B at 0x80800000, module C at 0x81000000 and D at 0x81800000.
    ipacAddVIPC616("7000,700000,1024")
    The I/O base is at 0x7000 and the carrier memory base is at 0x700000 in the VME A24 address space. However because the memory size is set to 1024 Kbytes, modules A, B and C cannot be selected (1024 K = 0x100000, so they are decoded at 0x400000, 0x500000 and 0x600000 but can't be accessed because these are below the base address).

    Interrupt Commands Supported

    The board uses fixed interrupt levels, and provides no software control over the interrupt generator. The only commands thus supported are a request of the interrupt level associated with a particular slot and interrupt number, or to enable interrupts by making sure the CPU's VMEbus interrupter is listening on the necessary level. Note that the VIPC616-01 uses different interrupt levels to the straight VIPC616, you must use the correct driver!

    cmd Value Returned
    ipac_irqGetLevel slot interrupt level
    ipac_irqEnable 0 = OK
    (other commands) S_IPAC_notImplemented

    Tews TVME-200

    This board is a four-slot, 6U carrier which is also sold by SBS as the VIPC626 and was also available from XYCOM VME. The configuration of the board is much simpler than the VIPC boards it replaces as there are only 6 rotary hexadecimal switches which completely configure the board. There are also a pair of registers provided for each slot, which allow the interrupt levels to be read and configured in software and permit individual slots to be reset.

    It is possible to use the VIP610 or VIPC616 drivers to control an appropriately configured TVME-200 board, but the use of this specific driver is strongly recommended if possible.

    The IPAC Carrier Driver is found in the file drvTvme200.c which implements the command ipacAddTVME200 that registers a TVME-200 board with drvIpac. It also exports the registrar routine tvme200Registrar to add the above command to the iocsh and link the driver into a final IOC executable, for which it must be listed in the IOC's .dbd file thus:

    registrar(tvme200Registrar)

    Configuration Commands and Parameter

    int ipacAddTVME200(const char *cardParams);

    The parameter string must contain exactly 6 hexadecimal digits (without any leading 0x or 0X) which are the settings of the six rotary switches on the board, in order from S1 through S6. The board's silk-screen printing shows the possible values and meaning for each switch position. The carrier initialization routine checks the switch settings for legality and will return an error if it finds an unsupported (undocumented) setting, as there are some combinations of switch settings that are reserved or not permitted.

    Configuration Examples

    ipacAddTVME200("6010D0")
    This indicates that the board is configured as delivered by the manufacturer, with the I/O base set to 0x6000, interrupt levels matching the VIPC610 or 616, and all module memory spaces disabled.
    ipacAddTVME200("100580")
    This indicates that the board has its I/O base address at 0x1000, all interrupts are disabled, and each IP module is allocated 2MB of memory space with the memory base address in VME A24 space starting at 0x800000.
    ipacAddTVME200("602FB0")
    Here the I/O base address is set to 0x6000, and interrupts are configured to match a pair of VIPC310 boards. Each IP module is allocated 8MB of VME A32 memory space starting at 0xB0000000, which puts IP module A's memory at 0xB0000000, module B at 0xB0800000, module C at 0xB1000000 and D at 0xB1800000. This particular setting is commonly used at APS.

    Interrupt Commands Supported

    The board provides a configuration switch to select from 5 different fixed VME interrupt level configurations, but it also provides software control over the interrupt generator which allows these levels to be changed under program control as needed. The commands supported therefore include the ability to get or set the interrupt level, and also to poll whether the interrupt line is currenly active or not. A control register bit also permits each slot to be reset individually.

    cmd Value Returned
    ipac_irqLevelN 0 = OK
    ipac_irqGetLevel slot interrupt level
    ipac_irqEnable 0 = OK
    ipac_irqPoll >0 if the interrupt line is active, else 0
    ipac_slotReset 0 = OK
    (other commands) S_IPAC_notImplemented

    SBS ATC40

    The SBS ATC40 is an IP carrier board for the ISAbus, which is a little-endian architecture unlike the VMEbus. Providing support for this board has required some changes to the drvIpac software which are described in the Bus Issues section above. Unless similar precautions are taken when writing module drivers these will not be compatible with little-endian systems. This carrier driver was written by Peregrine McGehee and Jeff Hill, who should be approached directly for support. Note that the carrier driver will probably only run on an Intel CPU, and has not been tested with recent drvIpac releases.

    The registrar entry for this driver should be:

    registrar(atc40Registrar)

    The configuration command is shown below. See the source code for the format of the parameter string.

    int ipacAddATC40(const char *cardParams);

    Motorola MVME162 and MVME172

    The Motorola MVME162 and MVME172 CPU boards provide either two or four IP slots in addition to the MC68040 CPU, memory and I/O. Slot pairs can be used with 32-bit dual-slot IP modules, and the IPIC chip which controls the interface supports all of the IPAC Driver interrupter commands. This carrier driver can be used with either board; non-existant slots will always appear to be empty.

    When this CPU board is used the IPAC carrier driver drvIpMv162.c can control the IP slots on the board. It implements the command ipacAddMVME162 to add the MVME162 or MVME172 carrier to the system, and provides the registrar routine mv162ipRegistrar to add the above command to the iocsh and link the driver into a final IOC executable, for which it must be listed in the IOC's .dbd file thus:

    registrar(mv162ipRegistrar)

    The carrier initialisation routine has the following additional return-code meanings (see also ipacInitialise() above):

    Symbol/Value Meaning
    S_IPAC_tooMany IpMv162 carrier already registered
    S_IPAC_badDriver IPIC chip not found
    S_IPAC_badAddress Parameter string error, or address not reachable

    Configuration Commands and Parameter

    int ipacAddMVME162(const char *cardParams)

    The parameter string is used to initialise the IPIC registers which allow detailed control of several settings for each slot. The string consists of a series of single characters to determine the slot and setting to be controlled and one or more numeric parameters for each setting. The string is parsed sequentially from left to right, and the characters and their parameters have the following meanings:

    R
    If used this must be the first character of the string, and will cause a hardware reset pulse to be sent to all the IP modules. This is useful if any module is found to need a hardware reset on a vxWorks soft reboot.
    A, B, C and D
    These select the IP slot (also identified as slots 0 through 3) which is to be controlled by the following commands, up to the appearance of the next of these slot selection characters.
    l=level1[,level2]
    Sets the interrupt level for the slot interrupters to the decimal values given by level1 and level2 respectively. If the second IP interrupt is not used by the particular module the ,level2 part may be omitted and this interrupt will be disabled. The default setting is for both interrupts to be disabled.
    m=base,size
    Enables the slot memory space and sets the base address for the slot to the hexadecimal value given by base, with extent given by the size parameter in kilobytes. NB size cannot be omitted.
    r=recovery
    This programs the slot recovery timer on the IPIC chip to be at least recovery microseconds (legal values are between 0 and 8 inclusive). This option should only be required with some early IP module designs.
    w=width
    The IPIC chip can alter the way in which the IP module memory space is addressed and is controlled using this option. By default or with a w=16 setting the memory will be initialised to be 16 bits wide with direct mapping of CPU addresses to IP memory addresses. By using the setting w=8 it is possible to access only the odd bytes of the IP memory space, i.e. only the 8 least significant bits of the data bus are used (other carrier boards may not support this type of operation so this facility should be used with care). The w=32 setting permits the memory space on double-width IP modules to be accessed using 32-bit transfers; this should be used on the even-numbered slot of the pair only.

    Other characters will be ignored without affecting the parsing of the remainder of the parameter string.

    Configuration Example

    ipacAddMVME162("A:m=0x90000000,1024 l=5,3 w=8 r=2 B:l=2")

    The above example initialises slots 0 and 1 only - slots 2 and 3 are not used or their modules require register and ID Prom access only in this particular application.

    Slot 0 is set up for a slow (recovery time 2µs) memory board with 1 Mbyte of 8-bit wide RAM, addressed at 0x90000000 and with interrupt priorities set for levels 5 and 3.

    Slot 1 has no memory space, and just a single interrupt at priority level 2.

    Interrupt Commands Supported

    The IPIC chip allows a lot of control over the IP interrupters, thus all commands perform the requested action. The ipmIrqCmd return values for the commands are:

    cmd Value Returned
    ipac_irqGetLevel current slot interrupt level
    ipac_irqPoll >0 if the interrupt line is active, else 0
    Other ipac_irq commands 0 = OK
    Other commands S_IPAC_notImplemented

    Acromag AVME-9660/9668/9670

    These boards are four-slot, 6U VME carriers, two of which were once sold by Xycom as the XVME-9660/9670. On the 9660 board the IP module signal wiring is brought out through front panel connectors, whereas the 9670 boards make signal wiring available through the VME64x P2 and P0 connectors. The AVME-9668 is like the 9660 but can operate IP modules at 8MHz or 32MHz, whereas the other boards only support 8MHz operation. A single bank of jumpers provides the only hardware configuration, setting the base address of the board in VME A16 space; module memory locations in VME A24 space and the module clock speeds for the 9668 are configured in software using the board registers.

    The IPAC Carrier driver is found in the file drvXy9660.c and implements the commands ipacAddAvme96XX and ipacAddXy9660 that register a single carrier board (of any of the supported models) with drvIpac. The driver also exports a registrar routine xy9660Registrar that adds the above command to the iocsh and will link the driver into a final IOC executable, for which it must be listed in the IOC's .dbd file thus:

    registrar(xy9660Registrar)

    Configuration Commands and Parameter

    int ipacAddXy9660(const char *cardParams);
    int ipacAddAvme96XX(const char *cardParams);

    The parameter string starts with a hex number (a leading 0x is optional) which sets the I/O base address of the card in the VME A16 address space (the factory default is 0x0000). Next must come a comma, followed by the VME interrupt level (0 through 7, although 0 means all interrupts are disabled) to be used for this carrier (all module interrupts share the same interrupt level from this board).

    A letter R may appear at this point, which causes a carrier soft reset to be generated before any further configuration occurs.

    Finally if any module drivers need to access the memory space on their module, the relevent slots must have their memory size and base address configured, which is done like this for each slot:

    slot = size, address
    Configures one slot on the card, setting the size and base address of the slot's memory space in VME A24 space. The slot parameter is one of the letters A through D and selects which slot is to be configured. The size is a single digit 1, 2, 4 or 8 which gives the memory size to be used, expressed in MegaBytes. The address is a 6-digit hexadecimal number (a leading 0x is optional) which must be compatible with the selected memory size. Slots may be configured in any order, but cannot be programmed to overlap.

    Configuration Examples

    ipacAddXy9660("0x6000,4 R")

    This indicates that the carrier board has its I/O base set to A16:6000 and that it generates interrupts on VME IRQ4. None of the slots are configured for memory, and modules are reset at initialization.

    ipacAddAvme96XX("C000,3 A=2,800000 C=1,A00000")

    The carrier is at A16:C000 and generates level 3 interrupts. Slot A is configured for 2MB of memory space at A24:800000 and Slot C for 1MB of memory space at A24:A00000.

    5. Interface to IPAC Carrier Drivers

    Writing a new Carrier Driver is quite simple, and requires just three subroutines to be produced (the report function is optional). The driver will need some of the definitions in the drvIpac.h file.

    #include "drvIpac.h"

    All routines must be re-entrant, and no static variables should be used unless (like the mv162) only one carrier board of this type is possible in a particular system. In this case re-entrancy is still necessary, but static variables may be used to hold information about the carrier provided these are protected from simultaneous updates by different tasks.

    The sole interface between the Carrier Driver and the IPAC driver is through the ipac_carrier_t typedef structure given in the header file. Note that this has changed slightly since version 2.0 with the addition of the carrier parameter to the initialise() routine, and the new intConnect() routine. This is defined as follows:

    typedef struct {
        char *carrierType;                 /* String describing carrier board type */
        int numberSlots;                   /* Number of IPAC devices this carrier can hold */
        int (*initialise)(char *cardParams, void **cPrivate, ushort_t carrier);
                                           /* Initialise carrier and return *cPrivate */
        char *(*report)(void *cPrivate, ushort_t slot);
                                           /* Return string giving status of this slot */
        void *(*baseAddr)(void *cPrivate, ushort_t slot, ipac_addr_t space);
                                           /* Return base addresses for this slot */
        int (*irqCmd)(void *cPrivate, ushort_t slot, ushort_t irqNumber,
                      ipac_irqCmd_t cmd);  /* Interrupt control */
        int (*intConnect)(void *cPrivate, ushort_t slot, ushort_t vecNum,
                          void (*routine)(int parameter), int parameter);
                                           /* Connect routine to interrupt vector */
    } ipac_carrier_t;

    The first two structure members provide fixed information about the carrier to the IPAC driver. carrierType is a string which is printed by the report function to identify the type of carrier board, and numberSlots indicates how many IPAC slots this particular type of carrier provides.

    The remaining structure members are function pointers to the routines which control the carrier board. The cPrivate parameter passed to these functions points to a structure which must be defined and allocated by the carrier driver and can be used to hold information about a particular carrier board (for example the board base address). The IPAC driver stores the cPrivate pointer which is returned by the initialise() routine, and passes the same pointer back to the other routines when referring to that particular carrier board at a later stage.

    The intConnect() function pointer may be set to NULL if the standard vxWorks intConnect() provides all the funtionality needed to install an interrupt vector - this will probably only be needed for ISA bus carriers.

    The other parameters to the routines are identical to those described in detail in the corresponding IPAC Driver routines above. The IPAC Driver performs parameter checking on the slot and irqNumber parameters before calling the Carrier Driver routine, so these values can be used with confidence.

    The simplest way to write a carrier driver is to copy the VIPC310 or MVME162 driver and modify one of these for the new board type. The MVME162 driver interfaces to the IPIC chip and can be used as a basis for carrier drivers which provide extensive control over the IPAC slots. The VIPC310 and VIPC610 boards are totally dumb, and thus provide the simplest possible example of a carrier driver.


    Andrew Johnson <anj@aps.anl.gov>