4 THE LCU DRIVER COMMON MODULES - lcudrv and lculog
4.1 lcudrv - Driver Common Functions
This chapter describes the LCU part of the module in its version 1.17.
It shall provide a general description of the functions contained in this module. For detailed parameters etc. see section 4.6, examples are given in section 3.3.
A Driver Channel Table (DCT) is used to keep track of the channels opened to the devices controlled by the driver. By means of this table the other routines can check if a specific channel has been opened and if the open-mode allows access to a device through that channel. The index into the DCT is used to distinguish between channels opened to a device at the same time. It is therefore similar to a file-descriptor inside the driver. See section 2.5 also.
A mode-specifier defining the access rights must be given when opening a channel to a device:
· lcudrvOPEN_SHARED
Shareable read and write mode. Write access is granted to a defined number of processes to use this open mode. Exceeding this number or requesting this mode for a device already opened in Exclusive write mode returns an error.
· lcudrvOPEN_EXCLUSIVE
Exclusive read and write mode. Write access is granted to the process using this open mode. Requesting this mode for a device already opened in Exclusive or Shareable write mode returns an error.
· lcudrvOPEN_TEST
Test read and write mode. Write access is granted to the process using this open mode regardless of the status of the device. Requesting this mode for a device already opened in Test mode returns an error.
The common lcudrvInitDCT routine should be called from the driver specific xxxDrv function (see section 3.3.1). It performs the following actions:
The routine returns lcudrvOK if successful or a negative error code if there is no memory available.
Several inline-functions are provided in the include-file lcudrvCheckDev.h, which should be used in the device-install function xxxDevCreate as shown in section 3.3.2 (simply to avoid duplication of code). All function return lcudrvOK on success or the appropriate lcudrv error-code:
· lcudrvCheckDevBaseAddrA16 - converts a VMEbus-address in the short address space into a local address as seen from the CPU.
· lcudrvCheckDevBaseAddrA24 - converts a VMEbus-address in the standard address space into a local address as seen from the CPU.
The common lcudrvInitDevice routine should be called from the driver specific xxxDevCreate function (see section 3.3.2). It performs the following actions:
The routine returns lcudrvOK if successful or a negative error code if the device already exists.
The common lcudrvOpen routine should be called from the driver specific xxxOpen function (see section 3.3.3). It performs the following actions:
The routine returns in a provided ststus variable lcudrvOK if successful or a negative error code if any problem occured.
The common lcudrvClose routine should be called from the driver specific xxxClose function (see section 3.3.4). It performs the following actions:
The routine returns lcudrvOK if successful or a negative error code if any problem occured.
The common lcudrvCheckAccess routine should be called from the driver specific xxxIoctl function (see section 3.3.5). It performs the following actions:
lcudrvCheckChannel can be used instead, if an access rights check is not required. The routine returns lcudrvOK if successful or a negative error code if any problem occured.
The lcudrvProbeAddress routine is a tool-function which checks whether a device exists at the specified address or not. The routine returns lcudrvOK if the address exists or lcudrvERROR if not. It should be called from xxxDevCreate to make sure that a device is actually present.
The lcudrvPrintError routine is a tool-function which prints an error-message for the corresponding error-number to the standard output. The lcudrvErrorGet function returns a pointer to the same error-description string.
The macros defined in lcudrvDevice.h can be used to access hardware registers directly. They use assembler directives, what normally - but not necessarily - results in more efficient code. At present the macros are supported only for GNU-gcc and the 68000 CPU family!
4.2 The Device Descriptor Table
The Device Descriptor usually consists of three parts:
The declaration of a Device Descriptor structure should therefore include the lcudrvDEVICE_HEADER as first item, appended by as much further data as required by a device, for instance:
/*
* Device Descriptor
*/
typedef struct xxxDEVICE_DESCRIPTOR
{
lcudrvDEVICE_HEADER header; /* standard header (must be on top!) */
/* installation parameters: */
void *baseAddrA24; /* standard VMEbus base-address */
void *baseAddrA16; /* short VMEbus base-address */
int intrNumber; /* interrupt-vector-number */
int intrLevel; /* interrupt-level */
/* derived/computed values: */
void *dpramAddr; /* board DPRAM base address */
SEM_ID semAccess; /* access protection mutex-semaphore */
WDOG_ID wd; /* timeout watchdog */
} xxxDEVICE_DESCRIPTOR;
This declaration should be included in the header file xxxPrivate.h. The memory allocation of the whole Device Descriptor Table of a driver should be done in xxxDrv. The device-specific initialization should be done in xxxDevCreate. In doing so, the function lcudrvInitDevice can be used for the initialization of the lcudrv-specific part.
4.3 The Command Descriptor Table
This table is optional. It could be used inside xxxIoctl (see section 3.3.5) to determine which handler-routine shall be invoked to execute a requested command-code etc.
To achieve this, the table should contain:
· The access rights for this command, which have to be checked by xxxIoctl,
e.g. the value (lcudrvOPEN_SHARED | lcudrvOPEN_EXCLUSIVE) would reject accesses in the modes Read-Only and Test (see section 4.1 for information about open-modes).
· If semaphore protection is necessary for this command (only commands without any write-accesses are allowed to execute without semaphore-protection!)
/*
* Command Descriptor Table
*/
typedef const struct xxxCMD_DESCRIPTOR
{
int code; /* Cmd passed to controller */
int access; /* Access rights of the command */
BOOL protected; /* For exclusive access to the board */
/* Device layer routine executing the command: */
int (*handler)(const xxxDEVICE_DESCRIPTOR *devPtr, void *argPtr);
} xxxCMD_DESCRIPTOR;
This declaration should be included in the header file xxxPrivate.h. The memory allocation and initialization of the whole Command Descriptor Table of a driver should be done in xxxDrv.c.
4.4 lculog - Driver Common Logging Functions
This chapter describes the module in its version 1.9.
It shall provide a general description of the functions contained in this module. For detailed parameters etc. see section 4.6.
Several logging calls are available which are very similar to the normal VxWorks logMsg function, i.e. they take the same parameters and they can be used from interrupt level. The additional features are severity-specific logging and - if necessary - message handling by a special lculog-Task.
Corresponding to the message-severity the following calls should be used:1
These calls are normally implemented as macros. This requires that the first parameter (the format string) must be a constant string, not a variable!
If this is too restrictive then macro-expansion can be inhibited, which means that normal function-calls are used instead (with more function-call overhead). This can be requested by:
Passing of pointers to volatile entities must be avoided, only pointers to static data (constant strings etc.) are allowed. The following example shows an allowed construction with two constant strings and an integer as parameters for LCU_LOG_error:
#define FNAME "xxxDevCreate"
int error = 99;
LCU_LOG_error("%s: error condition (%d)", (int)FNAME, error, 0, 0, 0, 0);
Output => "ERROR: xxxDevCreate: error condition (99)\n"
There are also preprocessor options to exclude logging calls completely from the compilation, for example to omit debugging-logs in the final version of a driver.
All log messages are handled by the normal VxWorks logging task, except when the routine lculogTask has been spawned as a task, in which case all messages are processed by this function instead.
All LCU logging outputs can be turned off by setting the variable lculogDisable to TRUE (1). This applies to all message-severities!
4.5 Errors Reference
See section 7.1 in the Reference chapter.
4.6 Functions Reference
See section 7.2 in the Reference chapter.
Quadralay Corporation http://www.webworks.com Voice: (512) 719-3399 Fax: (512) 719-3606 sales@webworks.com |