This document describes the software interface to a generic Industry Pack (IPAC) driver module for vxWorks, 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. On VMEbus, carrier drivers are available for the SBS VIPC310, 610 and 616 boards, and a driver for the Motorola MVME162 that also works on the MVME172. On ISAbus the SBS ATC40 carrier is now supported by a driver from Jeff Hill.
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. Although designed primarily to be used from within an EPICS system, the software has been written to allow it to be used independent of the presence of EPICS in other vxWorks-based applications.
From version 2.0 onwards the drvIpac subsystem has been separated from the CANbus driver but provided within 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.3 and later). Two steps are then required to install and build the software:
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. If all accesses occur using 16-bit read/write cycles then the problem disappears. This is usually done by changing the structure that declares the structure of a module's registers to use short instead of char and removing the `padding' char members that separate the registers (this change has been made to the ipac_idProm_t structure which is declared in drvIpac.h). This done the other changes are generally minor, usually consisting of masking 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.
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 header #includes the vxWorks ANSI header file types.h thus a -I option to the C pre-processor must be used to indicate the location of the vxWorks header files.
If it is necessary to build a copy of the driver for use without EPICS, the drvIpac.c file should be compiled with the -DNO_EPICS compiler switch to disable the EPICS-specific code.
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);
This routine will usually be called from the vxWorks (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.
Symbol/Value | Meaning |
---|---|
0 | OK |
S_IPAC_tooMany | Carrier Info Table full |
S_IPAC_badTable | Carrier Table invalid |
(others values) | from carrier initialisation routine. |
ipacAddCarrier(&vipc610_01, "0x6000,256"); ipacAddCarrier(NULL, ""); ipacAddCarrier(&vipc310, "0x6800");
Prints a report on stdout giving the status of all known IPAC carriers.
int ipacReport(int interest);
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.
Symbol/Value | Meaning |
---|---|
0 | OK. |
Initialise the IPAC driver.
int ipacInitialise(int after);
Symbol/Value | Meaning |
---|---|
0 | OK. |
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.
Returns Base CPU address of selected IP address space
void *ipmBaseAddr(ushort_t carrier, ushort_t slot, ipac_addr_t space);
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.
IP Address Space space ID Prom Space ipac_addrID Register Space ipac_addrIO 32-bit Register Space ipac_addrIO32 Memory Space ipac_addrMem
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.
Check on the presence of an IPAC module at the given carrier and slot number.
int ipmCheck(ushort_t carrier, ushort_t slot);
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" or "IPAH" identifier.
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 | "IPAC" identifier not found |
Validates a particular IPAC module type at the given carrier & slot number.
int ipmValidate(ushort_t carrier, ushort_t slot, uchar_t manufacturerId, uchar_t modelId);
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.
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 | "IPAC" or "IPAH" identifiers not found |
Manipulate the carrier board interrupt controller.
int ipmIrqCmd(ushort_t carrier, ushort_t slot, ushort_t irqNumber, ipac_irqCmd_t cmd);
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
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.
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.
Connects a module driver Interrupt Service Routine to a particular interrupt vector number.
int ipmIntConnect (ushort_t carrier, ushort_t slot, ushort_t vecNum, void (*routine)(int parameter), int parameter);
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.
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.
char *ipmReport(ushort_t carrier, ushort_t slot);
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 single internal static character array to hold the report string, thus the value will be corrupted if two tasks use this routine simultaneously.
"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. Finally if the Carrier Driver contains a report function it is called and the string it returns is appended after the hyphen.
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)
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.
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
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.
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.
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
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.
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.
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
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 source file drvIpac/drvAtc40.c will only compile for Pentium CPUs.
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);
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
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:
Other characters will be ignored without affecting the parsing of the remainder of the parameter string.
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.
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 calls 0 = OK
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 */ ushort_t 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 board is totally dumb, and thus provides the simplest possible example of a carrier driver.