Documente Academic
Documente Profesional
Documente Cultură
VxWorks
6.6
Corporate Headquarters
Wind River Systems, Inc.
500 Wind River Way
Alameda, CA 94501-1153
U.S.A.
toll free (U.S.): (800) 545-WIND
telephone: (510) 748-4100
facsimile: (510) 749-2010
For additional contact information, please visit the Wind River URL:
http://www.windriver.com
For information on how to contact Customer Support, please visit the following URL:
http://www.windriver.com/support
VxWorks Device Driver Developer's Guide, Volume 1: Fundamentals of Writing Device Drivers, 6.6
9 Nov 07
Part #: DOC-16098-ND-00
Contents
1.1
1.2
1.2.1
1.2.2
3
4
2.1
Introduction .............................................................................................................
2.2
2.3
2.4
13
2.4.1
Performance ..............................................................................................
13
2.4.2
14
1.2.3
1.3
iii
VxWorks
Device Driver Developer's Guide, 6.6
2.4.3
14
2.4.4
14
2.4.5
14
Introduction .............................................................................................................
15
3.2
16
3.2.1
16
17
17
17
18
18
19
19
20
20
20
21
21
22
22
23
3.3.1
23
24
24
25
27
34
36
36
38
3.4.1
38
3.2.2
3.3
3.3.2
3.4
iv
Contents
3.5
3.6
3.4.2
39
3.4.3
39
3.4.4
40
3.4.5
42
42
3.5.1
42
43
44
44
45
45
46
46
46
3.5.2
46
3.5.3
47
47
47
48
3.5.4
48
3.5.5
48
3.5.6
49
3.5.7
50
PLB ............................................................................................................
Other Bus Types ........................................................................................
51
51
52
3.6.1
Configuration ...........................................................................................
53
53
56
57
57
58
58
3.6.2
VxWorks
Device Driver Developer's Guide, 6.6
3.6.3
59
3.6.4
59
59
62
63
63
64
64
65
Synchronization .......................................................................................
66
67
68
70
vxbDmaBufLib ..........................................................................................
DMA Considerations ...............................................................................
Allocating External DMA Engines .......................................................
70
71
75
77
79
3.7.1
79
3.7.2
82
82
3.8.1
83
3.8.2
84
3.8.3
84
3.8.4
84
3.6.5
3.6.6
3.6.7
3.6.8
3.7
3.8
Introduction .............................................................................................................
89
4.2
90
vi
Contents
4.2.1
4.3
90
90
90
91
91
92
4.2.2
93
4.2.3
94
4.2.4
95
4.2.5
95
96
4.3.1
96
vxBusShow( ) ............................................................................................ 96
vxbDevStructShow( ) ............................................................................... 99
vxbDevPathShow( ) ................................................................................. 100
4.3.2
4.4
101
101
102
103
104
104
4.3.3
4.3.4
4.4.2
4.4.3
4.4.4
4.4.5
4.4.6
vii
VxWorks
Device Driver Developer's Guide, 6.6
5.2
5.3
5.4
5.5
5.6
viii
1
Getting Started with
Device Driver Development
The preferred method for new development uses the VxBus device driver
infrastructure. This infrastructure supports device drivers by defining
standard interfaces for the driver to interact with the operating system and
device hardware.
VxWorks
Device Driver Developer's Guide, 6.6
The term legacy device drivers is used to describe pre-VxBus device drivers as
implemented in early VxWorks 6.x and in VxWorks 5.x releases. Legacy
drivers do not share a common interface to the operating system or hardware.
NOTE: In VxWorks 6.6, the legacy device driver implementation is valid only
for uniprocessor (UP) systems. (For information on SMP and UP systems, see
the VxWorks Kernel Programmers Guide).
Wind River strongly recommends that you develop new VxWorks device drivers
according to the VxBus model whenever possible. The VxWorks Device Driver
Developers Guide (Vol. 3): Migrating to VxBus includes information on migrating an
existing legacy-model driver to the VxBus model.
Your level of experience with VxWorks device driver development will influence
how you approach Volume 1 (this document). If your experience is limited to
legacy model VxWorks device driver development, the majority of the concepts
described in this document will be new to you. Understanding these concepts is
critical before beginning any VxBus model driver development. If you are an
experienced VxBus device driver developer, some of the information in Volume 1
is likely to be familiar to you. However, you may still need to carefully review the
requirements for your driver class in Volume 2 and may even need to review
certain concepts in Volume 1.
VxWorks
Device Driver Developer's Guide, 6.6
If you are an experienced legacy model device driver developer, the early chapters
of Volume 3 are likely to be familiar to you. However, if you plan to migrate any
existing drivers to the VxBus model, or you have plans to use the optional
VxWorks symmetric multiprocessing model (SMP) product, you should carefully
review the migration information in Volume 3. It is also critical that you carefully
examine Volume 1 (this document) and relevant chapters of VxWorks Device Driver
Developers Guide, Volume 2: Writing Class-Specific Drivers before beginning any
VxBus model driver development.
If you are fairly new to VxWorks device driver development and you are not
interested in migrating an existing device driver, you should focus your attention
on Volume 1 (this document) and Volume 2 of this documentation set. The
fundamentals presented in Volume 1 are critical for most VxBus model device
drivers. Once you have a basic understanding of these fundamentals, you can
move on to the class-specific information in Volume 2 that is appropriate for your
device class.
If you are new to device driver development in general (not specific to VxWorks),
you may need to consult some third-party information in order to better
understand the basic concepts associated with all device driver development.
However, if you are fairly experienced with embedded development and have
some hardware experience, you should find that the information in Volume 1 is
sufficient to get you started.
class
Drivers for specific devices are grouped by device class. For example, serial
drivers are located at installDir/vxworks-6.x/target/src/hwif/sio. For the
general case, class represents the device type:
installDir/vxworks-6.x/target/src/hwif/class.
dev
Where this document refers to devices in general, these devices are generically
referred to as dev. In such cases, substitute the name of each device or device
type for dev. For example, if your driver supports ncr810, the general file
devInit.c becomes ncr810Init.c.
VxWorks
Device Driver Developer's Guide, 6.6
2
VxBus and
VxBus Device Drivers
2.1 Introduction 7
2.2 About VxBus 8
2.3 VxBus Device Drivers 9
2.4 Design Goals 13
2.1 Introduction
This chapter explains some of the key concepts and terms associated with VxBus
and VxBus device drivers including the term VxBus itself, instances, and driver
method advertisement. This chapter is intended as a system overview only. The
concepts and terms introduced here are explained further in 3. Device Driver
Fundamentals.
Class-specific driver information for all supported VxBus classes is provided in
VxWorks Device Driver Developers Guide, Volume 2: Writing Class-Specific Device
Drivers.
VxWorks
Device Driver Developer's Guide, 6.6
VxBus Instance
A driver and a
ns16550.c
register( )
together to form
an instance.
}
.
.
.
Driver
Serial
Port
Network
Port
USB
Port
Serial
Port
Devices
Driver methods make up the mechanism for other parts of the software
environment to gain access to device functionality.
VxWorks
Device Driver Developer's Guide, 6.6
When using a driver method, the module making the request can query a single
instance or all instances. And the query can either ask for information on how to
accomplish an action or it can be a request for the driver to perform some action.
At the top level, then, the query can consist of a question of whether a specific
instance can support an action, a question of what instances can support an action,
or a request to perform an action.
Figure 2-2 illustrates device/driver/operating system communication in a subset
of a VxWorks system. The system shown includes two middleware modules or
VxWorks subsystems (in this case, the network stack and the auxiliary timer)
which are attempting to communicate with a hardware device on the system. Note
that an actual system is likely to have several instances and many middleware
modules, Figure 2-2 is a subset only.
An instance makes itself available to the overall VxWorks system by advertising
the driver methods it supports. In Figure 2-2, the network stack uses the
vxbDevMethodGet( ) routine to query each instance (device/driver pairing)
known to the system. In the example, the network stack module is searching for an
instance that supports the {muxDevConnect}( ) driver method. If the instance
supports the method, it returns a pointer to the drivers routine implementing that
method. If an instance does not support the requested method, it returns NULL. In
the example shown, the stack finds a Yukon II network interface advertising
support for the required method.
The system also shows an auxiliary timer making a similar query. In this case, the
timer looks for the {vxbTimerFuncGet}( ) method and gets a positive response
from the OpenPic timer instance in the system.
Note that although this example shows only a single instance making a positive
response in each case, any number of instances (or none at all) can include the
necessary support.
10
Figure 2-2
Method Advertising
Middleware Module
Middleware Module
Network Stack
...
Auxiliary Clock
Interrupt Controller
vxbDevMethodGet( )
{vxbIntCtlrConnect}( )
vxbDevMethodGet( )
{vxbIntCtlrEnable}( )
...
Support for
{muxDevConnect}( )
?
Support for
{vxbTimerFuncGet}( )
?
{sioChanGet}( )
Yes
Yes
{sioChanConnect}( )
OpenPic Timer
{vxbTimerFuncGet}( )
other modules...
other modules...
11
VxWorks
Device Driver Developer's Guide, 6.6
Figure 2-3 shows the OpenPic timer instance (as seen in Figure 2-2) querying the
interrupt controller instance directly. The interrupt controller includes support for
{vxbIntCtlrEnable}( ) and therefore responds to the timer request.
Figure 2-3
Interrupt Controller
{vxbIntCtlrConnect}( )
{vxbIntCtlrEnable}( )
...
{sioChanGet}( )
{sioChanConnect}( )
OpenPic Timer
Yes
{vxbTimerFuncGet}( )
vxbDevMethodGet( )
other instances ...
12
Support for
{vxbIntCtlrEnable}( )
?
2.4.1 Performance
Drivers must perform well enough to match the real-time kernel's abilities.
Designing for performance implies many things. First, it requires using direct
memory access (DMA) and interrupts in an efficient manner. This requires you to
keep your routine nesting at an optimum level. For example, too many routine
calls and restore operations can increase process dispatch latency and reduce
performance. However, performance requirements must be balanced against
proper use of routines for keeping code size small and making your driver design
easy to follow and understand.
Designing for performance also means keeping interrupt latency to a minimum.
Interrupt handlers must receive the greatest care in any design. Overall system
performance is just as important as the specific driver's performance.
For specific applications, you may consider it acceptable to write a VxWorks driver
that sacrifices one or more of these goals. For example, when writing a driver for a
system that is expected to be used only for a specific non-real-time application, you
may be tempted to sacrifice real-time system performance in your driver design.
However, because of issues such as code re-use, Wind River strongly discourages
this approach. Real-time performance and memory footprint are an important
concern for all VxWorks drivers.
13
VxWorks
Device Driver Developer's Guide, 6.6
14
3
Device Driver Fundamentals
3.1 Introduction 15
3.2 Driver Classes 16
3.3 Driver Organization 23
3.4 VxBus Driver Methods 38
3.5 Driver Run-time Life Cycle 42
3.6 Services Available to Drivers 52
3.7 BSP Configuration 79
3.8 SMP Considerations 82
3.1 Introduction
This chapter discusses the key concepts related to VxWorks device drivers that use
the VxBus driver model. In particular, it provides detailed information about the
anatomy of the VxBus device driver ecosystem including information on
driver-related file locations and directory structure, an explanation of VxBus
methods, a description of the services available to VxBus device drivers, and the
general life cycle of a VxBus device driver. In addition, this chapter provides
guidelines for developing device drivers for use with the optional VxWorks
symmetric multiprocessing (SMP) product.
15
VxWorks
Device Driver Developer's Guide, 6.6
In general the concepts explained in this chapter apply to many (or all) types of
device-specific drivers. Volume 2 of the VxWorks Device Driver Developers Guide
provides information about specific driver classes and is intended to supplement
the information provided in this volume.
16
Serial Drivers
Serial drivers manage interfaces to terminals and other devices with serial
interface such as RS-232 or RS-422. These devices are connected to the I/O system,
and may be configured as the VxWorks system console. Software can gain access
to these devices by making a call to open( ), read( ), write( ), ioctl( ), and so forth.
Within the VxBus framework, serial driver source files are located in
installDir/vxworks-6.x/target/src/hwif/sio. The primary operations they support
are connection to the I/O system and fetching channel-specific data.
Storage Drivers
Storage drivers manage interfaces to magnetic disks, tape drives, flash disks (also
known as flash keys), and on-board flash devices. Some general characteristics of
these devices are:
These devices include ATA disks, Serial ATA disks, SCSI disks, USB flash disks,
floppy disks, and so forth.
Within the VxBus framework, storage driver source files are located in
installDir/vxworks-6.x/target/src/hwif/storage. The primary operation they
support is connecting to an extended block device (XBD), which occurs during the
instConnect( ) phase of VxBus initialization. (For information on device driver
initialization phases, see 3.5 Driver Run-time Life Cycle, p.42.)
For more information on XBD, see VxWorks Device Driver Developers Guide (Vol. 2):
Storage Drivers.
17
VxWorks
Device Driver Developer's Guide, 6.6
Non-Volatile RAM (NVRAM) devices provide data storage that is not erased when
power is turned off. There is some overlap between NVRAM devices and storage
devices (see Storage Drivers, p.17). The primary distinction is that NVRAM devices
generally allow random byte-sized access to the data, while storage devices
typically do not allow random byte-sized access to the data. However, this is not
always the case and exceptions occur in both directions. Functionally, NVRAM
devices store small amounts of data for use during system configuration, and
storage devices store application data.
Within the VxBus framework, NVRAM driver source files are located in
installDir/vxworks-6.x/target/src/hwif/nvram. The primary operations supported
by these drivers are reading and writing to and from the media according to
specified allocation.
Timer Drivers
Timer devices can provide two services. They provide a counter that increments or
decrements periodically that an application can read to determine elapsed time.
They can also provide a mechanism to notify the CPU that a given time period has
elapsed. This is done using an interrupt.
Within the VxBus framework, timer driver source files are located in
installDir/vxworks-6.x/target/src/hwif/timer. The primary operations supported
are allocation of a timer to a specific purpose, attaching an interrupt service routine
(ISR) to the timer interrupt, reading the current value of the timer, and enabling or
disabling counting and interrupt generation.
18
DMA engines allow data to be copied from one location in RAM to another
without the overhead of using the CPU to perform the data copy. They are
typically used to copy data between a device buffer and system RAM.
Many devices have built-in DMA engines to help increase performance. This is
typical in devices such as network interfaces (MACs) and storage devices.
However, many systems include DMA engines available for general purpose use.
With respect to VxWorks device drivers, devices with built-in DMA engines are
not considered to be DMA controller drivers. Rather, they are part of another class
such as network or storage. Only drivers for the general-purpose DMA engines are
considered to be in the DMA controller driver class.
Within the VxBus framework, DMA controller driver source files are located in
installDir/vxworks-6.x/target/src/hwif/dma. The primary operations supported
are allocation of a DMA engine to a specific purpose, and copying data.
19
VxWorks
Device Driver Developer's Guide, 6.6
USB Drivers
USB functionality is split into two different types. USB host adaptors are a kind of
bus controller device, usually providing a bridge between the PLB or a PCI bus and
a USB bus. USB class drivers provide the functionality of storage drivers, network
drivers, and so on.
Within the VxBus framework, USB host adaptor drivers are located in
subdirectories under installDir/vxworks-6.x/target/src/hwif/busCtlr/usb/hcd.
As of VxWorks 6.6, USB class drivers are not integrated with the VxBus
framework, so their source files are located in
installDir/vxworks-6.x/target/src/drv/usb. For more information on USB class
drivers, see Wind River USB Programmers Guide: USB Class Drivers.
Multifunction Drivers
Many physical devices contain multiple logical devices. That is, a single chip can
include several timers, several DMA engines, one or more network interfaces, a
USB host adaptor, a PCI bus controller device, and various other devices.
Because many of the devices on a chip are identical copies of devices available
elsewhere, it is not practical to create a single driver that supports all the functions
of a chip. A single driver targeted at a specific device can be used to control a
device on a given multifunction chip or a device that is not on the chip. This
eliminates duplication of code.
20
Having a single driver to manage the entire chip also reduces your ability to
configure the final system. For example, if you do not require USB for your
application, using a single driver to manage an entire multifunction chip
containing a USB host adaptor results in the entire USB stack being included in
your application. This can cost several hundred kilobytes of unnecessary memory
overhead.
Because of this, the recommended device driver development strategy for
multifunction devices is to have multiple drivers to support a single chip, one
driver for each functional component. In addition, you should create a
multifunction driver that manages the functional blocks on the chip. The
multifunction driver leaves management of the functional blocks to the individual
drivers for each functional block. The multifunction drivers job to announce to
VxBus that each functional component part is available, what the register base
address of each functional component is, and manages other high level
information about the chip as a whole and about how it is divided into the
individual functional components.
Many modern computers provide general purpose processors other than the
primary CPU. These processors can be similar to the primary CPU, or a different
processor type. They can also be custom processing elements such as digital signal
processors (DSPs). These remote processing elements can be dedicated to specific
tasks, depending on the application, and controlled by the primary CPU, or they
can be autonomous or semi-autonomous systems running their own operating
system.
Within the VxBus framework, processing element driver source code is kept in
installDir/vxworks-6.x/target/src/hwif/cpu. Processing element drivers are
responsible for establishing communication with the remote processing element.
Each VxBus processing element instance (see 2.3 VxBus Device Drivers, p.9) is
responsible for establishing and maintaining communication with one remote
processor.
Console Drivers
Console devices are those devices that can be used as a graphical system console
when the console is not a terminal connected to a serial port. This includes
keyboards, mouse devices, and display devices.
21
VxWorks
Device Driver Developer's Guide, 6.6
Resource Drivers
Many modern processor designs include hardware resources that are used by, and
shared among, several peripheral devices. The types of services provided by these
resources include things such as data routing and address translation. Sometimes,
each peripheral device has enough dedicated resources, that those resources can be
considered part of the device. However, when the available resources must be
shared among several peripheral devices, there may not be enough of these
resources available in the running system to enable full functionality of all the
peripheral devices available. In this case, you must create a resource management
driver to allocate the resources to other peripheral devices.
Within the VxBus framework, resource driver source code is kept in
installDir/vxworks-6.x/target/src/hwif/resource. The primary function of resource
drivers is allocation of the available resources to other peripheral devices. It can
also be used for configuring the resources.
22
23
VxWorks
Device Driver Developer's Guide, 6.6
Third-Party Drivers
Third-party drivers are organized in a way that allows individual driver vendors
and developers to create third-party drivers without worrying about namespace
collisions between files created by different vendors. Each vendor wishing to write
a device driver for VxWorks should first create a vendor-specific subdirectory in
installDir/vxworks-6.x/target/3rdparty. For example, if a developer for the Acme
Corporation plans to create a third-party driver for VxWorks, the first step for the
driver developer is to create a new subdirectory,
installDir/vxworks-6.x/target/3rdparty/acme, to store the new driver files. Within
this subdirectory, each individual driver is created within its own subdirectory. For
example, use the subdirectory
installDir/vxworks-6.x/target/3rdparty/acme/acmeFoo to store the foo driver
provided by the Acme Corporation.
24
The driver source file contains the logic that implements the functionality of the
device driver. As stated previously, VxWorks device drivers are found under
installDir/vxworks-6.x/target/src/hwif, while third-party drivers are found under
installDir/vxworks-6.x/target/3rdparty. The example in this section discusses the
file locations for a Wind River driver.
While many VxWorks device drivers consist of a single source file, this is not a
requirement. A driver can include one or more optional header files in order to
allow for a cleaner presentation of the driver source code. A driver can also include
multiple source files, with makefile rules to build a single driver object module for
installation in the VxWorks library.
In the following example, fragments from the Wind River device driver file
vxbCn3xxxTimer.c are used to illustrate the structure of a VxWorks device driver.
Example 3-1
The first part of a device driver (following the driver header lines) is a data
structure describing the routines that VxWorks must call during the VxBus
initialization phases. (For more information on VxBus initialization phases, see
3.5.1 Driver Initialization Sequence, p.42.)
NOTE: The bold items in this example code are intended to emphasize certain
content. The bold highlighting does not represent any actual syntax in the source
code.
/* data structures used by the driver to register itself
* with Vxworks
*/
/* drvBusFuncs provides a set of entry points into the
* driver that are called during various phases of the
* boot process. Drivers can choose to implement 1 or
* more of these entry point, according to the needs of
* the driver during its initialization phases.
*/
LOCAL struct drvBusFuncs
{
cn3xxxTimerInstInit,
cn3xxxTimerInstInit2,
cn3xxxTimerInstConnect
};
cn3xxxTimerDrvFuncs =
/* devInstanceInit */
/* devInstanceInit2 */
/* devConnect */
25
VxWorks
Device Driver Developer's Guide, 6.6
Following this registration data structure, there is a data structure describing the
driver methods that the driver supports. (Drivers that belong to a specific class
always implement the driver methods that are required for that class.)
/* cn3xxxTimerDrv_methods provides the list of driver
* methods that this driver supports. For each driver
* class supported by Wind River, one or more methods
* are expected to be defined for the driver. For
* timer driver class, the 'vxbTimerFuncGet' method
* is required to be supported.
*/
LOCAL struct vxbDeviceMethod cn3xxxTimerDrv_methods[] =
{
DEVMETHOD(vxbTimerFuncGet, cn3xxxTimerFuncGet),
{0,NULL}
};
Following the list of driver methods, the driver includes a data structure to
describe the driver registration information.
/* The cnxxxTimerDrvRegistration structure provides a
* description of the driver to VxWorks, so that VxWorks
* can connect this driver to appropriate hardware during
* the boot process.
*/
After the registration information, the driver provides a routine to register with
VxBus.
/* The vxbCn3xxxTimerDrvRegister function contains the
* first instructions of the device driver that are
* ever executed within a VxWorks system. This function
* registers the driver with VxBus by providing pointers
* to the data structures listed previously. Once this
* step is complete, VxWorks is able to associate this
* driver with appropriate hardware within the system
* to form an instance.
*/
26
Because the driver registration routine is used as the first entry point into the
driver, VxWorks needs to be configured so that it knows to call this entry point
when it is registering the driver with VxBus. To do this, VxWorks uses information
that is found in the driver configuration files: driverName.cdf, driverName.dc, and
driverName.dr. For information on these driver configuration files, see Component
Description File, p.27 and Driver Configuration Stub Files, p.34.
NOTE: VxBus model VxWorks device drivers require the registration routine to be
a global symbol. Most drivers do not require any other global symbols therefore
other routines and data variables should be declared LOCAL.
VxBus model VxWorks device drivers are easily integrated into a BSP. VxWorks
device drivers that are developed according to the VxBus standard are compiled
as stand-alone object files that can be included in a BSP using the VxWorks
configuration tools. To do this, you must create a VxWorks component for your
device driver.
A component is a basic unit of functionality that can be configured into a VxWorks
image. In order for VxWorks to include or exclude individual device drivers, the
drivers must be written so that they appear to the VxWorks configuration tools as
individual components.
In order for a device driver to be configurable in Workbench or vxprj, you must
create a component description file (CDF) that describes the driver to these
configuration tools. This done by creating a configuration file named
40driverName.cdf.
NOTE: Component description files are briefly described in this chapter for the
benefit of the device driver developer. However, this is not an exhaustive
discussion. For more detailed information on CDFs, see the VxWorks Kernel
Programmer's Guide: Kernel.
For device drivers distributed by Wind River, the 40driverName.cdf file is located in
installDir/vxworks-6.x/target/config/comps/vxWorks. For these Wind River
drivers, there may be a single configuration file that contains component
27
VxWorks
Device Driver Developer's Guide, 6.6
descriptions for multiple drivers. This is because Wind River drivers are shipped
as a collection.
For third-party drivers, the 40driverName.cdf files are located in the same directory
as the driver itself (for example, installDir/vxworks-6.x/3rdparty/vendor/
driver/40driverName.cdf). For these drivers, each third-party CDF should contain
only a single component description.
Writing a CDF File
To create a CDF file for a new driver, copy an existing CDF (extension for this file
type is .cdf) from the standard VxWorks installation tree to the directory where you
are creating your driver and then modify the CDF to suit the needs of your driver.
The CDFs for device drivers shipped with VxWorks are located in installDir/
vxworks-6.x/target/config/comps/vxWorks.
Example 3-2 shows the contents of a CDF for a PCI bus controller. This file is
located in installDir/vxworks-6.x/target/config/comps/VxWorks/40m85xxPci.cdf.
Example 3-2
28
The MODULES field lists the names of the object files that are created when the
driver is built. In this example, only a single module is included. When a driver
is included in a project, the VxWorks configuration services parse the contents
of the object files that are listed on the MODULES line in order to determine
what other components are needed in order to build this driver into the
VxWorks image.
For example, if a driver makes use of the routine strlen( ), the symbol name
strlen appears as an unresolved external in the driver's object file. Using this
information, the VxWorks project configuration services automatically create
a dependency on the component that provides strlen( ). This simplifies the
REQUIRES field, because many of the dependencies that a driver has on other
components are inferred from the direct dependencies parsed from the object
modules.
29
VxWorks
Device Driver Developer's Guide, 6.6
Figure 3-1
COMPONENT field
SYNOPSIS field
The MODULES field and the files listed in MODULES, in conjunction with the
REQUIRES field, provide all of the information necessary for VxWorks to
determine which components need to be included in order to support a given
driver.
_CHILDREN FOLDER_DRIVERS
30
NOTE: Be sure to include the leading underscore on the keywords of the CDF
file (where shown in the example above). The underscore reverses the
meaning. For example, a _CHILDREN entry indicates that this component (in
this case, your driver) is a child of the specified folder. If the underscore is not
present, the folder (FOLDER_DRIVERS) is configured as a child of your driver,
which is not correct.
_INIT_ORDER hardWareInterFaceBusInit
The _INIT_ORDER field is used to describe when in the VxWorks boot process
this driver needs to be initialized. All VxBus device drivers must be initialized
in the hardWareInterFaceBusInit initialization group. Therefore, copy this
line into your driver without change.
INIT_RTN m85xxPciRegister();
The REQUIRES field lists the components that must also be used in order for
this driver to work correctly within VxWorks.
This field is necessary because not all device driver dependencies can be
determined by examining the unresolved externals that are present in a driver.
The REQUIRES field, in conjunction with the MODULES field, is used to
determine the set of components that must be included to support the driver.
For example, the PowerPC 85XX PCI bus controller driver requires services
from the CCSR resource driver. (For more information on resource drivers, see
Resource Drivers, p.22.) In this case, none of the public symbols of the CCSR
driver appear as unresolved references in the network driver. Therefore, the
MODULES method of determining component dependencies does not work.
Instead, you must use explicit entries in the REQUIRES field of your CDF to
describe the indirect dependencies.
31
VxWorks
Device Driver Developer's Guide, 6.6
Another more common example of this, is the use of PHY driver services from
some network drivers. Some network drivers can use one of several PHY
drivers, but others require a specific PHY driver. The network driver uses
driver lookup services to locate the PHY instance to which it is attached.
Again, no public symbols of the PHY driver are used by the network driver.
Therefore, if a specific PHY driver is required, that PHY driver must be
explicitly listed in REQUIRES field.
INIT_AFTER INCLUDE_PCI_BUS
The INIT_AFTER and INIT_BEFORE (not shown in the example) fields are used
to indicate any initialization dependencies within the initialization group
specified by _INIT_ORDER. The component listed here must belong to the
same initialization group as specified by _INIT_ORDER. In this example, this
line indicates that this driver should not be initialized until after the PCI bus
driver is initialized.
HDR_FILES $(WIND_BASE)/target/src/hwif/h/end/fei8255xVxbEnd.h
The above line is not shown in the example. However, your driver may require
a HDR_FILES field. This field is used to list the driver header file that provides
the routine prototype for the driver registration routine. This field works in
conjunction with the INIT_RTN field. When VxWorks is configured, the header
file provided by HDR_FILES is added to the generated C code for the VxWorks
image. This allows the C code provided by INIT_RTN to compile without
errors such as undefined references. By default, the project facility searches for
HDR_FILES in the directory installDir/vxworks-6.x/target/h. To access files that
are located in directories outside of installDir/vxworks-6.x/target/h, the
complete path to the desired header file should be used, starting with the
installation directory (installDir).
For a complete description of the component description language (CDL) used to
create CDFs, see the VxWorks Kernel Programmers Guide: Kernel.
CFG_PARAMS
32
For example, a driver for a network device that supports jumbo frames might use
a parameter to specify the maximum size of the jumbo frames that the driver can
accept. An example of the relevant fields of the Component and Parameter blocks
is:
Component
DRV_NET_SAMPLE {
NAME
network device supporting jumbo frames
...
CFG_PARAMS
SAMPLE_JUMBO_MTU_VALUE
}
Parameter SAMPLE_JUMBO_MTU_VALUE {
NAME
Jumbo frame MTU size
SYNOPSIS
max num of bytes in a jumbo MTU
TYPE
int
DEFAULT
9000
}
The NAME and SYNOPSIS fields in a parameter are similar to the same fields
in a component.
TYPE
int
The TYPE keyword describes the type of data in the parameter. The valid types
include any valid C language type, as well as the string, bool, and exists types.
The string type is a NULL terminated ASCII string.
The bool type indicates a logical true/false variable. This can be either all
uppercase or all lowercase, bool or BOOL.
The exists type is used when the parameter name, as a C macro, is either
defined or not defined. When used, the default value can be TRUE or FALSE.
DEFAULT
9000
The DEFAULT keyword indicates the default value if the user does not change
it.
For more information about driver parameters, see Configuring Resources, p.54 and
Configuring Parameters, p.54.
33
VxWorks
Device Driver Developer's Guide, 6.6
For some BSPs, VxWorks supports two distinct ways of building run-time images:
The first method (using Workbench or vxprj) is supported for all BSPs.
The second method allows you to create a VxWorks image by invoking the make
command from within a BSP directory.
NOTE: Although the facility for building your BSP using the make command is
available for most BSPs, it is not supported for all VxWorks development scenarios
or for the optional VxWorks SMP product. For more information, see the VxWorks
Command-Line Tools Users Guide.
When a BSP is built directly from its makefile, the information that is contained in
the driver component (.cdf file) is not used to configure the BSP. Instead, the BSP
author includes or excludes components directly within the source files of the BSP,
by creating lines in the BSP config.h file that specify which components to include
or exclude.
For example, if you want to include the Cn3xxx timer driver in the run-time image
created using your BSP, you can add the following line to your BSP config.h file:
#define DRV_TIMER_CN3XXX
NOTE: For simplicity, this example ignores the fact that the Cn3xxx timer driver
has dependencies on other components, and that these other components must
also be added to the BSP config.h file in order to satisfy the device driver
dependencies.
After adding the appropriate define to the BSP config.h file, you can invoke make
in the BSP directory to rebuild the BSP. Once the BSP is rebuilt, the component (in
this case, the timer driver) is included in the VxWorks run-time image generated
using this BSP.
NOTE: BSP builds are not supported for VxWorks SMP BSPs. For more information
on working with the optional VxWorks SMP product, see the VxWorks Kernel
Programmers Guide: VxWorks SMP.
34
To support direct BSP builds for your driver, you must create two additional
configuration stub files, the driverName.dc and driverName.dr file. These files
connect the device driver to the BSP command-line build.
The driverName.dc file is created using the same base name as the driver source file,
but with a .dc extension instead of a .c extension. Again, using the Cn3xxx timer
driver as an example, here is the vxbCn3xxxTimer.dc file:
IMPORT void vxbCn3xxxTimerDrvRegister();
The purpose of the driverName.dc file is to provide a function prototype for the
device driver registration routine. The prototype may be surrounded in an
#ifdef/#endif construct using the driver component identifier
(DRV_CLASS_NAME) but this is not required.
The vxbCn3xxTimer.dr file is similarly brief:
#ifdef DRV_TIMER_CN3XXX
vxbCn3xxxTimerDrvRegister ();
#endif /* DRV_TIMER_CN3XXX */
The purpose of the driverName.dr file is to call the driver registration routine that
announces the driver to the VxWorks operating system. This code must be
surrounded in an #ifdef/#endif construct in order to ensure that the registration
routine for the driver is run only when the component is included using the BSP
config.h file.
NOTE: The macro used on the #ifdef line must match the component name used
in the CDF file (see Component Description File, p.27).
For Wind River drivers, both the driverName.dc and driverName.dr files are located
in installDir/vxworks-6.x/target/config/comps/src/hwif. For third-party drivers,
these files are located in the same directory as the driver source file.
For these files to be useful, they must be merged into an initialization file that is
linked into a VxWorks run-time image. The VxWorks makefile environment
contains all of the necessary commands to create this initialization file. If a new
driver is added to the VxWorks source tree, the initialization file must be recreated
as follows:
% cd installDir/vxworks-6.x/target/config/comps/src/hwif
% make vxbUsrCmdLine.c
When these commands are run, the VxWorks makefile environment searches all of
the locations where driver configuration stub files are found, and merges the files
into the initialization file vxbUsrCmdLine.c.
35
VxWorks
Device Driver Developer's Guide, 6.6
README File
While not required by the makefile environment, each device driver should
include a README file that describes the driver to a user. Third-party vendors may
wish to include driver version information, a list of all files that make up the driver
(source files, configuration files, and so forth), any known bugs, driver version
information, and perhaps even a URL where an end user might go to find an
updated copy of the driver.
The driver README includes three sections of data as well as separation lines as
follows:
a one-line statement that this is the README file for a VxWorks driver and
stating the device for which the driver is intended. For example:
README: VxWorks/VxBus driver for device device
one or more paragraphs showing what devices the driver is suitable for, as
well as the specific devices that have been tested with the driver. This section
also lists which version of VxWorks and VxBus the driver has been developed
for. This section may also list the files that make up the driver, provide a list of
known bugs, or provide other information to the user.
Optionally, you can include instructions for the installation procedure in this
section. (For more information, see 5.6 Driver Release Procedure, p.120.)
a list of version numbers, along with a description of the changes between each
version.
NOTE: Driver version numbers consist of two parts (for example, 7.4). Do not
use three-part version numbers, and do not use slashes to separate version
fields.
An example README file is available as part of the wrsample driver (see
installDir/vxworks-6.x/target/3rdparty/windriver/wrsample).
Driver Makefile
In order for a device driver to build correctly under VxWorks, you must provide
the appropriate makefiles so that your device driver can be incorporated into an
36
object file that can be linked into a VxWorks image. There are two makefiles that
are used to address this issue. These files are:
The contents of these makefiles can be complex because the makefiles need to be
correctly integrated into the overall makefile hierarchy used by VxWorks. To create
these makefiles properly, copy the appropriate sample makefiles from
installDir/vxworks-6.x/target/3rdparty/windriver and installDir/vxworks-6.x/
target/3rdparty/windriver/wrsample. Modify the sample files to match your
vendor and driver names as needed.
Vendor Makefile
37
VxWorks
Device Driver Developer's Guide, 6.6
38
The routine associated with a driver method must be a valid executable routine.
Every routine for a given driver method must use the same prototype.
Most driver methods use a standard prototype because there are mechanisms to
call driver methods in VxWorks that assume that the driver method routine being
called conforms to this standard.
The standard driver method prototype is as follows:
STATUS func{driverMethod}
(
VXB_DEVICE_ID devID,
void * pArg
)
For more information on these calling mechanisms, see 3.4.3 Calling Driver
Methods, p.39.
39
VxWorks
Device Driver Developer's Guide, 6.6
METHOD_DECL( )
To avoid iterating through all instances on the system, you must know the device
ID for every instance containing the desired driver method. However, given the
device ID of an instance, vxbDevMethodGet( ) can be used to discover the driver
routine associated with the desired driver method, so that it can then be invoked.
The routine vxbDevMethodGet( ) returns either a pointer to the function within
the driver, func{driverMethod}( ), or NULL if the driver does not publish the
specified method.
When the func{driverMethod}( ) is known, it can be called directly. For example:
STATUS (*methodFunc)(VXB_DEVICE_ID devID, void * pArg);
methodFunc = vxbDevMethodGet(devID, DEVMETHOD_CALL(driverMethod));
if ( methodFunc != NULL )
(*methodFunc)(devID, pArg);
40
pointer to call when invoking the driver method. You can choose to have a separate
method table for each instance on the system, a single method table for all
instances involving your driver, or a combination of both.
Drivers can choose to replace the table dynamically to change what methods are
advertised.
Most often, a driver includes only a single method table, which is allocated
statically by the compiler. There is a macro available in installDir/vxworks-6.x/
target/h/hwif/vxBus.h that you must use when creating the method table at
compile time. The macro is DEVMETHOD( ). This macro accepts two arguments:
the method ID of the method, and the routine associated with the method in the
driver. In addition, your driver must use DEVMETHOD_END to terminate the
table.
The following is an example of a statically defined method table. (This is a
modified version of a table from the NS16550 SIO driver.)
LOCAL device_method_t ns16550vxb_methods[] =
{
DEVMETHOD(sioChanGet, ns16550vxbSioChanGet),
DEVMETHOD(sioChanConnect, ns16550vxbSioChanConnect),
#ifdef NS16550_DEBUG_ON
DEVMETHOD(busDevShow, ns16550vxbSioShow),
#endif /* NS16550_DEBUG_ON */
DEVMETHOD_END
};
To make the driver methods available to the rest of the system, there are two places
that the driver can put a pointer to its method table. Each device in a VxWorks
system, in the device structure, provides a field called pMethods that contains a
pointer to a table of methods relevant to the instance. This is the preferred location
to advertise driver methods. As mentioned previously, the driver can have a single
table pointed to by each instance, or it can allocate a separate table for each
instance, or it can set up groups of instances sharing a table each.
Although Wind River does not recommend this option, you can also advertise
methods in the driver's registration structure. This method table is intended to be
used for methods that do not require the driver to be paired with a device. Putting
a pointer to the same table in both places does not cause the system to fail, but it
doubles the time to perform method calls.
41
VxWorks
Device Driver Developer's Guide, 6.6
how to configure the driver into a VxWorks bootable image. For more information
on the device driver development cycle, see 4. Development Strategies. For more
information on configuring a driver into a bootable image, see Component
Description File, p.27.
42
NOTE: This version of VxWorks continues to support legacy device drivers as well
as BSPs that are not enabled to support VxBus. Note that the initialization sequence
described in this section does not represent the initialization sequence for legacy
drivers or BSPs that do not support VxBus.
Device Driver
Phase
Description
Comments
Match/Probe
Optional.
Phase 1
devInstanceInit( )
Pre-kernel initialization.
Phase 2
devInstanceInit2( )
Post-kernel initialization.
Phase 3
devInstanceConnect( )
Asynchronous initialization.
Registration
The following sections provide more information about each of these phases, along
with context of what the overall system is doing during each phase. The overall
initialization process includes the following states:
At each phase of initialization, VxBus executes this initialization phase level for all
instances before moving to the next phase. The order in which instances are
initialized within a phase is not specified. The only assumption your driver can
make is that its parent bus controller instance has initialized to the point where the
driver can get access to the hardware.
43
VxWorks
Device Driver Developer's Guide, 6.6
Device drivers do not play any role in the early boot process. Depending on which
processor architecture you are working with, the CPU typically jumps to a
specified address at power-on and starts executing instructions. Those instructions
typically come from ROM or flash.
These early instructions initialize the memory controller and CPU, then start the
procedure for initializing VxWorks.
44
NOTE: Bus controller hardware is managed by the VxWorks device drivers for the
bus controller class. For more information on bus controller device drivers, see
VxWorks Device Driver Developer's Guide (Vol. 2): Bus Controller Drivers.
3
Driver Registration
Immediately after the driver and device are associated to form an instance,
VxWorks examines the registration structure that is provided when the driver calls
vxbDevRegister( ) (see Driver Registration, p.45).
This structure contains several initialization entry points into the driver. The first
of these is the devInstanceInit( ) routine.
The devInstanceInit( ) routine that is called during phase 1 of VxBus initialization,
is the first chance the driver has to initialize the hardware in any meaningful way.
However, there are severe restrictions on what can be performed because no
operating system services of any kind are available at this point.
Some driver classes, such as interrupt controller drivers and serial drivers, have
special requirements for what must be ready after the devInstanceInit( ) routine is
complete. However, for most drivers, the devInstanceInit( ) routine is relatively
simple. At a minimum, your driver devInstanceInit( ) routine should ensure that
the device interrupts are disabled.
45
VxWorks
Device Driver Developer's Guide, 6.6
Kernel Startup
In sysHwInit2( ), the BSP calls vxbDevInit( ). From the point of view of a driver,
this is the next available window for additional initialization. At this second phase
of VxBus initialization, the devInstanceInit2( ) routine for each instance is called.
By this point, kernel services are initialized and are accessible to your driver.
However, middleware services (such as network MUX) may not be available.
At the end of sysHwInit2( ), a task is created that runs the third and final phase of
VxBus driver initialization. During phase 3, the devInstanceConnect( ) routine for
each instance is called.
This phase is available for drivers that take a long time to perform their
initialization, and where it is not appropriate to slow the system boot time in order
to wait for a driver to initialize.
Execution of devInstanceConnect( ) can occur simultaneously with additional
system and application configuration and startup.
46
Unloading a Driver
Call vxbDriverUnregister( ).
2.
3.
Normally, bus controller drivers are responsible for managing device discovery
and device removal. Wind River does not currently support a bus-independent
high-level interface for device removal while the system is running. This
functionality is one aspect of the feature known as hot swap.
When an application handles removal of a device, it must know the exact VxBus
device ID of the device being removed. The application makes a call to
vxbDevRemovalAnnounce( ). This routine requires a VxBus device ID as a
parameter. The application can find the VxBus device ID by using
vxbDevIterate( ). The helper routine passed to vxbDevIterate( ) can look at any
parameter of each device or instance, and choose the one (or more) that should be
removed, based on criteria defined by the application.
47
VxWorks
Device Driver Developer's Guide, 6.6
NOTE: Drivers supporting device removal must not make use of the
u.pDevPrivate field of the device structure.
Unlinking a device from a device driver is handled by the VxBus driver method,
{vxbDrvUnlink}( ).
The func{vxbDrvUnlink}( ) routine shuts down a device instance in response to an
unlink event from VxBus. This event occurs when a VxBus instance is terminated,
or when an associated device driver is unloaded. When an unlink event occurs,
your driver must shut down and unload any connection to the operating system,
middleware, or an application that is associated with the affected device instance.
You must also release all of the resources that were allocated during the instance
creation.
48
In addition, you can use deferred registration in the debug version of your driver.
This allows the driver to be included in the VxWorks image, but not started
automatically. One way to enable deferred registration is to split the driver's
registration routine. When debugging is enabled in the early version of the driver,
the second level of the registration routinewhich actually calls
vxbDevRegister( )is not called. The following is a sample from the early phases
of development for the NS16550 SIO driver.
void ns16550sioRegister2(void)
{
vxbDevRegister((struct vxbDevRegInfo *)&ns16550vxbDevRegistration);
}
void ns16550sioRegister(void)
{
#ifdef NS16550_DEBUG_ON
ns16550sioRegister2();
#endif /* NS16550_DEBUG_ON */
}
NOTE: This split level of function call should be removed before releasing the
driver.
49
VxWorks
Device Driver Developer's Guide, 6.6
However, despite the general lack of requirements, the order of device discovery
can sometimes affect driver behavior for devices downstream from the bus
controller.
During hardware discovery and driver match (see sysHwInit( ), PLB, and Hardware
Discovery, p.44), the bus controller driver is responsible for discovery of devices
located on its bus. One implication of this is that devices located downstream from
the bus controller do not show up in the system until after the bus controller driver
is associated with the device, and the instance is given a chance to initialize the
device and discover the devices located on the bus.
For this reason, while PLB devices may be associated with the driver during the
devInstanceInit( ) phase of initialization (immediately after the driver registers),
devices on any other bus may not be available this early in the boot process.
When developing a new driver, this behavior can result in insufficient testing. For
example, if the bus controller driver used on the board initializes the bus during
the devInstanceInit2( ) initialization phase, the downstream driver's initialization
code is not called until after the operating system is running. However, other bus
controller drivers for the same bus type may initialize the device and discover
devices during the devInstanceInit( ) phase (when operating system services are
not yet available). Therefore, moving a driver that has been tested only on a
late-configuration system can crash the system. The solution to this issue is to
avoid using services that are not always available in an initialization phase (see
3.5.1 Driver Initialization Sequence, p.42).
First, VxBus verifies that the driver's registered bus type is the same as the bus
on which the device actually resides.
2.
Second, VxBus runs a match routine provided by the code specific to the bus
type.
3.
Third, if a driver has provided a probe routine, this routine is called to give the
driver a chance to verify that it will work correctly with the discovered
hardware.
50
The first and third stages are always followed with no variation. However, what
happens during the second phase of driver-to-device matching varies depending
on the bus type. This is based on the fact that the driver registration information
includes a component that is specific to the bus type for which the driver registers.
PLB
The most basic mechanism used to match a driver and a device is used when the
bus type does not support dynamic discovery of devices present on the bus. In this
case, a BSP-provided table is used to determine what devices are present. The table
contains an identifier for each device, and the driver provides an identifier for
those devices it can manage. When a bus type match is identified, the bus-specific
match code compares the two identifiers and succeeds or fails depending on
whether or not they match.
For other bus types, the device provides a mechanism to identify hardware. The
driver must provide bus-specific information in its registration structure that can
be compared against the information provided by the device (for example, PCI
vendor and device registers).
PCI
The information used to match a driver and device consists of the 16-bit device ID
and the 16-bit vendor ID. The device driver registration structure contains a
pointer to a table containing these value-pairs.
Note that PCI provides additional configuration space fields that can be helpful to
the driver when deciding whether to accept or reject a device. These fields include
the class field and subclass field, the sub vendor ID and sub system ID, as well as
other fields.
The driver can include valid information in its registration structure and also
provide a match or probe routine that checks these additional fields. Alternatively,
the driver can specify values of all-ones (0xFFFF) for both the device ID and the
vendor ID fields of the registration structure and provide a match or probe routine
that checks all of the configuration space fields.
51
VxWorks
Device Driver Developer's Guide, 6.6
RapidIO
Handling the exchange of data between a driver and its device, including
routines to read and write data to device registers, routines to probe memory
within the address space of a device, routines to transfer blocks of data to and
from drivers through DMA channels, and so forth.
Allocating and freeing memory buffers, both during system startup and
during normal system operation.
Handling data management within the driver, such as singly linked lists,
doubly linked lists, and lock-free ring buffers.
52
This section provides an overview of these services in order to give you a feel for
the type of services that are available to you as a device driver developer. Because
this information is designed as an overview, it is necessarily brief, and favors
simplicity and brevity over detail. For detailed information about any of the
services described in this section, see the related reference documentation.
3.6.1 Configuration
When a driver is initialized in VxWorks, the driver sometimes needs to learn about
the properties of the hardware and software run-time environment. For example,
a serial driver for the NS16550 serial port can to be written to support densely
packed device registers, or to support registers that have 2, 4, 8, or more bytes of
offset between them. Because this type of information cannot always be
determined by inspecting the hardware itself, the driver must determine the
information for itself during initialization. This allows the driver to conform to the
exact hardware and software requirements of the system.
Drivers within VxWorks are configured using two broad types of driver
configuration information, resources and parameters. Resources provide the
information that the driver needs about its hardware run-time environment, such
as hardware register spacing, availability of optional hardware services within a
device, and so forth. Parameters provide the information that the driver needs to
know about its software run-time environment, such as the size of memory buffers
to allocate for transmit and receive, whether or not to support Ethernet jumbo
frames, and so forth.
VxWorks provides routines that are used to determine both the hardware and
software configuration information required by the driver at runtime. The routines
that are used to query (and in some cases modify) the configuration information
are described later in this section.
VxWorks driver resources and driver parameters are easily confused because both
deal with querying configuration information from outside the driver. In general,
a driver uses resources when the property being configured determines whether
or not the driver functions correctly in a given run-time system, and uses
parameters when the property being configured has more to do with driver
performance, memory usage, or other software properties.
53
VxWorks
Device Driver Developer's Guide, 6.6
Both resources and parameters can be set in a file in the BSP directory called
hwconf.c. This file lists all devices that reside on the PLB bus, resource information
about each such device, and, potentially, parameter information about all devices
on any bus type. For more information, see 3.7 BSP Configuration, p.79 and the
VxWorks BSP Developer's Guide.
Configuring Resources
In this call, the device driver queries the BSP to determine what value to use for
register width. Elsewhere in the driver, the driver uses the queried value for the
register width when performing register I/O operations, rather than using a
hard-coded assumed value for the register width.
Well written drivers make judicious use of devResourceGet( ) to maximize the
portability of the driver. However, if a driver requires an excessive number of
resources from the BSP, the driver becomes less portable because the work required
by the BSP developer to incorporate the driver into the BSP increases significantly.
For information on creating BSP resource entries, see the VxWorks BSP Developers
Guide. For further information on using devResourceGet( ), refer to the reference
entry for the routine.
Configuring Parameters
To retrieve parameter information from its environment, the driver uses the
vxbInstParamByNameGet( ) routine. Use of this routine is similar to
devResourceGet( ), as shown in the following example:
vxbInstParamByNameGet (pInst, "jumboEnable", VXB_PARAM_INT32, &val);
54
In this table, the rtl8169VxbEnd driver declares that it supports three parameters,
named rxQueue00, txQueue00, and jumboEnable. When the driver registers with
VxWorks, it provides a pointer to these parameters as part of its driver registration
data structure. For example:
LOCAL struct vxbPciRegister rtgDevPciRegistration =
{
{
/* . */
rtgParamDefaults
/* pParamDefaults */
/* . */
}
};
Using this information, VxWorks stores the driver's default values for each of its
parameters. Unless the parameters are changed by the BSP or application, the
default driver values are the values that are returned when the driver calls
vxbInstParamByNameGet( ).
There are two methods that can be used to override the default value of a
parameter for a driver:
The BSP can provide a different default value in its hwconf.c file.
or
55
VxWorks
Device Driver Developer's Guide, 6.6
When the BSP provides a different default value for a parameter, the BSP default
value replaces the driver-provided value for the parameter. This replacement
occurs as soon as the driver registers with VxWorks, therefore there is no period of
time where the driver default can be returned using vxbInstParamByNameGet( ).
In addition to the BSP override method, the default value of a parameter can also
be changed at runtime through a call to vxbInstParamSet( ). vxbInstParamSet( )
can be used to modify the default values for a driver parameter.
For complete information on vxbInstParamByNameGet( ) and
vxbInstParamSet( ), see the reference entries for these routines.
The driver registers with VxWorks, its default parameter values are stored by
VxWorks.
2.
The driver is bound to a device, creating a hardware instance. The driver uses
the stored values for its parameters to configure the instance.
3.
To address this scenario, device drivers are given the option to be informed of any
changes to their parameter list that occur through a call to vxbInstParamSet( ).
VxWorks provides a special driver method that can be implemented for any device
driver that needs to monitor changes to its parameter list. To implement this
method in your driver, the driver must publish the {instParamModify}( ) driver
method. If the driver publishes this method, the method's callback function is
invoked whenever a change occurs to the driver parameters.
Support for the {instParamModify}( ) method is optional, and is not required for
most drivers. In practice, driver parameters are generally expected to be
overridden by the BSP hwconf.c file, rather than at runtime.
56
While a driver can use this method to reserve the memory for its instance data, this
method is not recommended for two reasons:
The number of simultaneous instances that the driver can support is artificially
restricted.
When the driver is used fewer less than the maximum number of instances, the
memory for the unused instances is wasted.
Well-written drivers should utilize one of the two memory allocation strategies
that are available to dynamically allocate instance data structures, to avoid the
problems listed above.
When the VxWorks operating system is booting, some device drivers must
initialize themselves early in the boot process. For example, a serial driver is
initialized early in the VxWorks bootstrap process so that it can be used for console
messages during the remainder of system startup. This early initialization also
allows the serial driver to be used with WDB before the kernel is initialized. When
a driver instance is initialized early in system startup, the standard
application-level memory allocation strategiessuch as malloc( ), calloc( ),
memPartAlloc( ), and so forthcannot be used because these routines use
semaphores, which are not available for use until the operating system is booted,
to protect the memory allocation data area.
To allow device drivers to allocate memory during system boot, a special set of
memory allocation services are provided to device drivers. This includes:
hwMemAlloc( )
Allocate n bytes of storage from a static pool.
57
VxWorks
Device Driver Developer's Guide, 6.6
hwMemFree( )
Return allocated storage to the static pool.
As their names imply, hwMemAlloc( ) and hwMemFree( ) perform memory
allocation services. These routines are useful to driver writers because they can be
called at any time during system startup, even when the multitasking services of
VxWorks are not available.
hwMemAlloc( ) allocates its memory from a pool of memory that is reserved for
hwMemAlloc( ). The size of this pool of memory defaults to 50,000 bytes for most
BSPs, and is configurable by adjusting the HWMEM_POOL_SIZE parameter
associated with the INCLUDE_HWMEM_ALLOC component.
Because this pool size is adjustable, the size can be configured downward on
systems that want to minimize wasted memory. For this reason, device drivers
must always check the return value of hwMemAlloc( ) to ensure that any
requested memory allocation is successful. Even on systems with large amounts of
available memory, the pool of memory that is reserved for hwMemAlloc( ) may
not be sufficient to support all of the requirements for all of the device drivers that
are configured in a VxWorks image.
NOTE: hwMemAlloc( ) can only allocate blocks of 2012 bytes or smaller.
Drivers that utilize both hwMemAlloc( ) and the standard memory allocation
routines must be sure to use the corresponding memory free routine. For example,
do not use hwMemFree( ) to free memory that has been allocated using the
standard memory allocation routines, and do not use the standard memory free
routine to free memory that has been allocated using hwMemAlloc( ).
To eliminate potential mismatching of memory allocation and memory free
routines in your driver, you may wish to use the same type of memory allocation
58
routine for each example of a particular data type. For example, if your driver
allocates some objects of type FOO before the standard memory allocation routines
are available, and other objects of type FOO after the system is up and those
routines are available, continue using hwMemAlloc( ) for all objects of type FOO,
regardless of when they are allocated.
However, if the driver also allocates objects of type BAR, but not until the standard
memory allocation routines are available, then all objects of type BAR should be
allocated using the standard memory allocation routines, and not hwMemAlloc( ).
59
VxWorks
Device Driver Developer's Guide, 6.6
The VXB_DEVICE data structure contains information that is useful for a specific
instance of the driver (that is, a specific device and driver pairing). In order for the
driver to learn where its hardware registers are located within the system address
space, the driver refers to the regBase[ ] array of pointers that is located within the
pInst structure, and uses the corresponding regBaseFlags[ ] array to determine
what type of address space is present at each location. Figure 3-2 illustrates the
regBase[ ] and regBaseFlags[ ] data structures.
Figure 3-2
VXB_REG_IO
VXB_REG_MEM
regBaseFlags[ ]
.
.
.
entry 0
entry 1
NULL
regBase[ ]
.
.
.
60
Device Memory-Mapped
Registers
(VXB_REG_MEM)
In Figure 3-2, VxWorks provides the driver with two windows into the hardware
address space. The first window is defined by the base address contained within
pInst->regBase[0], and is used for I/O mapped transactions, as shown in
Figure 3-2 by the value of VXB_REG_IO found in pInst->regBaseFlags[0]. In
addition, a second window is defined by the base address contained within
pInst->regBase[1]. This second address range is used for memory-mapped
register access, as shown in Figure 3-2 by the value of VXB_REG_MEM in
pInst->regBaseFlags[1].
When a device driver initializes itself, it must inspect the various register windows
that are provided by the device and then determine which windows must be used
and which windows can be safely ignored. For example, if a hardware device
provides two windows into its hardware registers, one that is mapped into the I/O
space of the system and another symmetric window that is mapped into the
memory space of the system, the device driver can choose to utilize only the I/O
space for its interaction with the hardware.
Once the driver decides which of the available windows to use for its interaction
with the hardware, the instance must create a mapping between the driver and the
hardware so that transactions in this memory window are performed correctly in
the system. This mapping is created by a call to vxbRegMap( ). The following
example is from the fei8255xVxbEnd.c driver:
/* find the memory mapped window for the device registers */
for (i = 0; i < VXB_MAXBARS; i++)
{
if (pInst->regBaseFlags[i] == VXB_REG_MEM)
break;
}
pDrvCtrl->feiBar = pInst->pRegBase[i];
vxbRegMap (pInst, i, &pDrvCtrl->feiHandle);
In this example, the device driver searches the available register windows until it
finds a register window of type VXB_REG_MEM. Once the window is located, the
driver stores the base address of the window in its driver control structure
(pDrvCtrl), and then maps in the address space using vxbRegMap( ).
vxbRegMap( ) performs the necessary operations to ensure that subsequent writes
to, or reads from, this window of the address space are performed correctly. It also
returns a handle for the address space that the driver can use for subsequent reads
and writes to the device.
61
VxWorks
Device Driver Developer's Guide, 6.6
Once the hardware registers are located and mapped by the driver, the driver can
perform read and write transactions to the register space using any of the
following routines:
vxbRead8( )
vxbRead16( )
vxbRead32( )
vxbRead64( )
vxbWrite8( )
vxbWrite16( )
vxbWrite32( )
vxbWrite64( )
All of the read routines have essentially identical semantics, differing only in the
size of the data element read during the transaction. Likewise, all of the write
routines have equivalently identical semantics.
In later sections, the interfaces to these routines are described collectively because
the concepts are the same for all of the read routines, and for all of the write
routines.
Reading from the Hardware Registers
A device driver can read either 8, 16, 32, or 64 bit quantities from a hardware
register using a single function call. The interface to each of the vxbReadxx( )
routines is essentially the same. For example:
UINT8 value = vxbRead8 (handle, UINT8 *);
UINT16 value = vxbRead16 (handle, UINT16 *);
UINT32 value = vxbRead32 (handle, UINT32 *);
UINT64 value = vxbRead64 (handle, UINT64 *);
In this example, handle is used to hold a handle to a portion of the device address
space. This handle is generated when the driver calls vxbRegMap( ). The address
represents the absolute address of the hardware register to be read. For example, if
a device provides three 32-bit registers in one of its mapped areas, a device driver
can read the middle 32-bit value by performing pointer arithmetic to generate the
address for the register as follows:
value = vxbRead32 (handle, (UINT32 *) (pDrvCtrl->feiBar + sizeof(UINT32)));
When making calls into any of the vxbReadxx( ) routines, use a base address value
for the appropriate register window, and then add the appropriate offset into the
register window to access the desired hardware register. The handle value does not
62
encode any type of pointer offset for the window therefore the pointer arithmetic
must always be performed explicitly by the driver.
Writing to the Hardware Registers
A device driver can write either 8, 16, 32, or 64 bit quantities to a hardware register
using a single function call. The interface to each of the vxbWritexx( ) routines is
essentially the same. The only significant difference is the data types for the
parameter values. For example:
void
void
void
void
As with read routines, you are responsible for any pointer arithmetic required to
access registers located in the mapped register window.
When a device driver writes to or reads from a hardware register, the vxbReadxx( )
and vxbWritexx( ) routines perform whatever memory or I/O transactions are
required in order to deliver the data to (or read the data from) the underlying
hardware. On some processor architectures, this task involves the execution of
special instructions (such as eieio on PowerPC processors), or a read-after-write
transaction to flush any write buffers that exist between the CPU and the target
hardware. The special operations that are required for each memory region are
encoded as part of the state that is contained in the handle for each of the memory
regions that are mapped by vxbDevMap( ). Because of this, you do not need to
perform any additional operations in your driver in order to ensure that data that
is read or written is transferred correctly.
63
VxWorks
Device Driver Developer's Guide, 6.6
Interrupt Indexes
VxWorks provides a set of services that you can use to manage interrupts from
devices. These services allow you to:
64
65
VxWorks
Device Driver Developer's Guide, 6.6
One method for minimizing the time spent in an ISR is to defer any processing so
that it is performed within a task context instead of within an interrupt context
using the functionality provided by isrDeferLib. When an ISR is structured to
support ISR deferral, the ISR does the following:
1.
processing after the ISR exits because the original interrupt is still pending.
2.
Prepares a data structure to describe the work that needs to be deferred. This
data structure is then provided as an input parameter to the routine that
performs the deferred work at task level.
3.
Unblocks a task that is waiting on a semaphore. This task handles the deferred
work once the ISR completes execution.
4.
Returns from the ISR. This signals the operating system to schedule the task to
handle the deferred work.
3.6.6 Synchronization
VxWorks device drivers have unique synchronization requirements when
compared with VxWorks application code. A typical device driver receives
requests from user tasks to perform various forms of I/O. In addition, the driver
66
must service device interrupts from the hardware that the driver is controlling.
These requests create a fairly chaotic environment within the driver because it
must ensure that all of the individual threads and interrupts that are competing for
the driver's resources do not corrupt the driver's data structures. Simultaneous
access to shared data structures can lead to data corruption, incorrect driver
behavior, and possibly system crashes. As a driver developer, you must take active
steps to ensure that the data structures maintained by your driver are protected
from corruption by these competing threads of execution.
Task-Level Synchronization
When a driver is running in task context, it can use the full suite of available
operating system services to perform synchronization operations. These services
include:
You can choose any of these synchronization methods, depending on the data flow
needs of your device and the I/O interface between your device driver and its
calling tasks. However, your overall goal is to ensure that the data structures that
are maintained by the driver remain consistent.
For example, a common task-level synchronization scenario would be to have a
single driver instance allocate and initialize a semaphore then store that
semaphore as part of the per-instance data structure maintained by the driver. The
semaphore can then be used to protect all access to the shared data structures that
the driver maintains.
However, while semaphores provide a useful method to protect driver data
structures from corruption by competing tasks, they have a significant drawback
that prevents them from being a good general-purpose solutionthey cannot be
used from the interrupt context. If your device driver maintains data structures
that must be accessed from both task context and interrupt context, you must
employ a different synchronization method.
67
VxWorks
Device Driver Developer's Guide, 6.6
Interrupt-Level Synchronization
Take a mutex.
Because these operations are not allowed in interrupt context, another method to
provide mutual exclusion is required to resolve the shared data contention issues
between task context and interrupt context.
In interrupt context, there are two methods you can employ to gain exclusive
access to a shared resource:
Interrupt locking is the traditional method used to protect device driver data
structures from being modified simultaneously in both task and interrupt context,
and this method works well in uniprocessor VxWorks environments, provided the
code executed while interrupts are locked is short. Using interrupt locking, any
piece of code running in task context that wants to gain access to a shared data
structure must surround the code in an intCpuLock( ) and intCpuUnlock( ) pair
of function calls. For example:
key = intCpuLock ();
/* access shared data structures. */
intCpuUnlock (key);
By locking out interrupts for the duration of the access to any shared data
structures, you can guarantee that no interrupts occur while the driver shared data
structures are accessed in task context.
Within the interrupt service routine of your driver, the driver shared data
structures can be accessed without explicitly locking interrupts in a UP
environment. Because an ISR cannot be preempted in order to run any task-level
68
code, explicit locking is not required within the ISR. An ISR can infer from the very
fact that it is running that no tasks are executing in any regions bracketed by
intCpuLock( ) and intCpuUnlock( ).
Despite the simplicity and efficiency offered by interrupt locking, Wind River
discourages the use of interrupt locking in modern device drivers. There are two
reasons for this:
Interrupt locking does not work if more than one processor is present in the
system, as is the case for the optional VxWorks SMP product.
In place of interrupt locking, you can use spinlocks in modern device drivers that
need to provide protection between task and interrupt context. This service is
available in both uniprocessor VxWorks and VxWorks SMP systems (see
Interrupt-Level Synchronization Using Spinlocks, p.69).
Interrupt-Level Synchronization Using Spinlocks
NOTE: A complete discussion of spinlocks is beyond the scope of this document.
For more information on spinlocks, see the VxWorks Kernel Programmers Guide:
VxWorks SMP.
When you use interrupt locking to protect a shared data structure, each task that
wants to access the shared data structure must first lock interrupts, and then access
the shared data. In a uniprocessor VxWorks system, your driver can safely access
shared data in this context because it knows that it will not be preempted, whether
by another task of higher priority, or by any type of ISR. This is guaranteed in
uniprocessor systems because only one processing unit is available to execute
instructions.
However, in a symmetric multiprocessing (SMP) system, more than one
processing unit is available, and instructions that access shared data can be
executed on any (or even all) cores in the system. As a result, a core in a VxWorks
SMP system that executes intCpuLock( ) cannot make any assumptions about
code that is running on any other core in the system. A second core could be
executing code that is accessing the shared driver resources, while a third core
could be executing an ISR for the driver. Unless you take positive steps in your
driver to ensure that only one of these entities can gain access to the driver shared
data structures, data corruption of the shared data structures is inevitable.
69
VxWorks
Device Driver Developer's Guide, 6.6
To address this need, VxWorks SMP provides spinlocks that can be used to provide
exclusive access to a shared resource, even when the resource is being contended
for by multiple cores in a multiprocessor system.
Spinlocks can be taken and given. After spinlock is taken, the driver that holds the
spinlock can access any data structures that are protected by the spinlock. For
example:
isrSpinLockTake (pSpinlock);
/* access shared data structures */
isrSpinLockGive (pSpinLock);
Unlike interrupt locking, spinlocks must be used in both task context and in
interrupt context to ensure exclusive access to a driver shared resource. An ISR
must use a spinlock because it cannot know whether or not a task on another core
in the system will try to access the driver shared resources while the ISR is running.
That is, an ISR cannot depend upon the implicit locking that is available in a
uniprocessor system. You must use an explicit lock to ensure data integrity.
vxbDmaBufLib
70
NOTE: When writing data to a disk, the disk controller device reads the data from
RAM as the first step. Similarly, when reading data from a disk, the last step for
the disk controller device is to write the data into RAM. Thus, the terms read and
write are ambiguous, depending on whether the application or the device is
performing the operation. In this documentation, unless otherwise noted, these
terms should be considered relative to the application.
When setting up for a write operation (where the CPU writes to RAM and the
device reads the data), the driver calls vxbDmaBufMapLoad( ) or a variant of it4.
At the appropriate time, the driver calls vxbDmaBufSync( ) with appropriate
arguments to cause cache flush or invalidate. For more information on these
routines, see the corresponding reference entries and the reference entry for
vxbDmaBufLib.
When processing incoming data, the driver first finds what buffers contain data,
the DMA tag, and the DMA map associated with each buffer. For each buffer, the
driver calls vxbDmaBufSync( ) to invalidate any cache entries, followed by
vxbDmaBufMapLoad( ), followed by another call to vxbDmaBufSync( ) with a
different operation flag. At this point, it is safe to read the data from the buffer.
When processing outgoing data already in a buffer, the driver calls
vxbDmaBufMapLoad( ) followed by vxbDmaBufSync( ). Once this occurs, it is
safe to initiate the write operation.
For more information on vxbDmaBufLib, see the library reference entry as well as
the reference entries for vxbDmaBufTagCreate( ) and other routines provided by
vxbDmaBufLib.
DMA Considerations
There are several issues related to these operations. Both data operations and
operations on descriptors have similar issues, and the same mechanism is used to
manage both types. The mechanisms used to manage these operations are address
translation and cache.
that multiple buffers can be mapped with the same call. The basic version maps a
single buffer. Unless otherwise noted, references to vxbDmaBufMapLoad( )
indicate all variants.
71
VxWorks
Device Driver Developer's Guide, 6.6
Address Translation
First, the memory address used by the device may not be the same as the memory
address used by the CPU. That is, if the bus controller performs address
translation, the same memory addresses are known by one address from the CPU
and a different address from the device. Figure 3-3 illustrates this situation. In this
example, the driver allocates a buffer from RAM at 0xC0001000. The CPU uses this
address to read and write the buffer. However, because the bus controller
translates the address, the device must read and write at 0x00001000 in order to
manipulate the same RAM locations.
Figure 3-3
CPU
0xc0001000
RAM
0xc0001000
bus controller
0x00001000
device
Bus Controller Address Conversion
There are two types of address conversion that are relevant to device drivers. These
are the conversion of device register addresses and the conversion of buffer
addresses.
In most cases, drivers do not need to handle address conversion directly because
utility routines perform the mapping on behalf of the driver. However, as a driver
writer, you must be aware of the mappings that are performed. The following
sections discuss mappings of device register addresses and mappings of data
buffer addresses.
Device Registers
Device registers reside on the device itself, and are therefore subject to the rules
and restrictions of the bus type on which the device resides. Often, device registers
are not seen at the same address on the CPU as on the bus that the device resides
72
on. Because of this, most drivers need to use the device register management
routines to manipulate register contents. For more information on the register
management routines, see 3.6.4 Hardware Access, p.59.
3
Data Buffers
Data buffers typically reside in system RAM. In most systems, there is a bus
controller device of some sort between the device and RAM. The bus controller
device performs address conversion between the CPU and the downstream
devices, as shown in Figure 3-3. The driver, which is running on the CPU, needs to
use one address to access a particular location in RAM. However, the device on the
downstream bus needs to use a different address to access the same location in
RAM.
In most cases, drivers for devices that use system memory rely on the routines in
vxbDmaBufLib to manage buffers, and these routines allow the driver to handle
the address translation.
The RAM addresses are passed to the appropriate vxbDmaBufLib routines, and
the converted addressesas seen by the deviceare available from the returned
structures.
Cache
Detailed cache considerations are beyond the scope of this document. Therefore,
the cache discussion in this section is presented as a simplified description of cache
operations and how they affect device drivers. Many cache configurations are
possible, and this discussion does not reflect the full range of available
configurations. For more detailed cache information, see the VxWorks Architecture
Supplement and the reference entry for cacheLib.
In Figure 3-4, the CPU has an associated cache. This introduces another layer of
complexity for address translation. For every memory access by the CPU, the cache
checks the memory address of the access. If the address is already in cache, the
cache responds with the data stored in cache. Depending on the cache
configuration, the cache may respond to the CPU request by reading data from, or
writing data to, its cache memory, completely avoiding any transactions with
system RAM.
For example, assume a copy of RAM from a certain address is held in cache. If the
device writes to that address, the data are written to RAM. If the processor tries to
read that address, the cache responds to the CPU with the cached data and
prevents it from accessing the data in RAM. The result is that the data received by
the CPU does not contain the updated data written by the device.
73
VxWorks
Device Driver Developer's Guide, 6.6
Figure 3-4
CPU
0xC0001000
cache
0xC0001000
RAM
0xC0001000
bus controller
no translation
0xC0001000
device
Similarly, if the CPU writes to an address, the cache will intercept the write request
and store the data in cache, but it will not necessarily store the data in RAM. If the
device then attempts to read data from the address, the device reads old data from
RAM rather than the current data from cache.
To resolve these cache issues, the processor must perform operations known as
cache invalidate and cache flush. When reading from cached RAM addresses, the
CPU configures the device to write to RAM. However, before doing so, the CPU
invalidates the cache addresses being written to. When the CPU next tries to read
the address, the cache does not respond directly. Instead, it reads the data from
RAM, stores the data in cache, and sends the data to the CPU.
Provided the CPU does not read from the address until after the device writes to
it, the operation is performed as expected.
In the second situation, the CPU writes into an address and then notifies the device
that the device should read the data there. Before notifying the device to perform
the read, the CPU flushes the cache. This instructs the cache to write any pending
data from cache into RAM. After this has happened, the device can read the latest
information directly from RAM.
Recall that before configuring the device to write into the buffer, the cache
invalidate operation is performed, which causes the entire contents of the cache
74
line to be discarded. However, in some cases, it is possible that valid data have
been written into the cache line but not written to RAM. In this case, the valid data
are discarded along with the invalid cached buffer contents.
To prevent this, driver writers must ensure that all data buffers used for DMA are
cache aligned.
Most devices that manipulate large amounts of data have DMA engines included
in the device. This allows data to be copied without requiring the CPU to perform
the copies, resulting in better overall system performance. However, some devices
that manage large amounts of data do not include built-in DMA hardware.
VxWorks provides a way for device drivers for such devices to allocate an external
DMA engine, also known as a slave DMA engine, if one is available. This allows
drivers to eliminate the CPU data copy operations.
This functionality is achieved with vxbDmaLib. The driver calls
vxbDmaChanAlloc( ) to allocate a DMA channel, and then calls one of the data
copy routines made available when you allocate the channel. There are two
variants of the copy. One variant copies the data and waits for the copy operation
to complete before returning to the caller, the other variant initiates the copy
operation and returns immediately. When the copy is complete, the caller is
notified. Both variants are called through function pointers made available when
a DMA channel is allocated.
By default, when vxbDmaChanAlloc( ) is called and no DMA engine is available,
the routine allocates a software entity that performs the operations using CPU
cycles. This allows a driver to request a DMA channel, but use the same interface
whether one is available or not. The driver can specify not to use software copy by
specifying the DMA_COPY_MODE_NO_SOFT flag.
vxbDmaChanAlloc( )
This routine allocates and initializes a DMA channel for use by a device instance.
It searches the system for DMA controller drivers that have dedicated channels,
and if found, calls the {vxbDmaResDedicatedGet}( ) method to allocate the
dedicated channel. If no dedicated channels are available, this routine searches
through the system for any DMA controller drivers that can allocate a channel
satisfying the parameters passed to the routine. If a channel is allocated, the routine
returns an ID for the channel.
75
VxWorks
Device Driver Developer's Guide, 6.6
VXB_DMA_RESOURCE_ID vxbDmaChanAlloc
(
VXB_DEVICE_ID
pInst,
UINT32
minQueueDepth,
UINT32
flags,
void *
pDedicatedChanInfo
)
pInst refers to the VXB_DEVICE_ID associated with the device requesting the
DMA channel. DMA device drivers normally select a DMA channel based upon
minQueueDepth and flags. Device drivers can optionally pass a pointer to DMA
device-specific information in pDedicatedChanInfo, which signals the DMA
library to call the {vxbDmaResDedicatedGet}( ) method.
minQueueDepth refers the minimum queue depth required by the device, in
transaction units. The DMA model expects a chained DMA command mode,
where multiple DMA transactions can be initiated and a single interrupt occurs
when the DMA command chain is completed and no further transactions are
available to be performed. If the device uses a direct mode, where one transaction
is performed at a time, then the DMA driver should reject requests containing a
minQueueDepth of any value other than 1.
flags allows drivers to specify any options in configuring the DMA channel. The
acceptable values for flags are defined in vxbDmaLib.h and are described as
follows:
mechanism used by the device for presenting its data buffers is a register.
Successive reads or writes to this register are required to complete a transfer to
or from CPU memory.
developer wishes to use the API, but knows that there will not be adequate
DMA hardware to provide appropriate performance, this flag can be specified.
It indicates that the library should return a software copy routine to the driver.
driver that the DMA channel is requested for read operations, that is, data is
read from the device into memory.
76
driver that the DMA channel is requested for write operations, that is, data is
written to the device from memory.
3
vxbDmaChanFree( )
This routine frees the DMA channel identified by dmaChan, by calling the DMA
device driver through the {vxbDmaResourceRelease}( ) method.
void vxbDmaChanFree
(
VXB_DMA_RESOURCE_ID dmaChan
)
semaphores
spinlocks
interrupt locking
In this release, atomic operators have been added to this set of synchronization
primitives. As their name implies, atomic operators can be used to atomically
modify a data structure. Atomic operators guarantee that their update to a data
structure is atomic, even when more than one thread of execution is contending for
the shared data structure. In VxWorks, atomic operators are divided into four
logical groups:
arithmetic
logical
read/write
compare/swap
All of the atomic operators act upon a variable of type atomic_t. The atomic_t type
is an architecture-dependent integral type, guaranteed to be at least 32 bits in size.
77
VxWorks
Device Driver Developer's Guide, 6.6
vxAtomicAdd
vxAtomicDec
vxAtomicInc
vxAtomicSub
(atomic_t
(atomic_t
(atomic_t
(atomic_t
*
*
*
*
Each of the logical operators take as input a pointer to a variable of type atomic_t,
which is atomically updated by the operator. In all cases, the atomic logical
operators return the original value of *pTarget.
The atomic read/write operators are:
atomicVal_t vxAtomicClear (atomic_t * target);
atomicVal_t vxAtomicGet (atomic_t * target);
atomicVal_t vxAtomicSet (atomic_t * target, atomicVal_t value);
The vxCas operator is the most complex of the atomic operators. It is designed to
be used to update a data structure by:
Writing the value back, but only if the data structure has been left unchanged
singe the original read from the data structure occurred.
78
If atomic operators are used within a device driver, they must be used consistently.
Data elements of type atomic_t should never be directly accessed using simple
pointer indirection. The atomic operators perform other operations aside from
simple memory operations to ensure that the atomic operations occur as designed.
If the atomic operators are not used consistently, correct behavior is not assured.
For further information about the atomic operators, see reference entry for
vxAtomicLib.
79
VxWorks
Device Driver Developer's Guide, 6.6
BSP hwconf.c file in order to incorporate a D1643 timer driver into the BSP, and to
configure the timer driver so that it is accessible through the PLB:
const struct hcfResource d16430Resources[] = {
/* entries describing resources tailored to the D1643 timer on PLB */
};
const struct hcfDevice hcfDeviceList[] = {
{"d1643", 0, VXB_BUSID_PLB, 0, d16430Num, d16430Resources},
};
const int hcfDeviceNum = NELEMENTS(hcfDeviceList);
intrNLevel
txInt
rxInt
errInt
txIntLevel
rxIntLevel
errIntLevel
regInterval
regWidth
regDelay
Device drivers may also require resources that have not been previously named by
another driver. In this case, you can assign a name to the resource.
The one required resource is regBase, which is of type HCF_RES_INT. This resource
represents the base address of the device registers, or the base address of the first
bank of device registers. It must be present and non-zero in order for a device to be
associated with a driver. Other regBase entries can optionally exist as well. These
entries are identified as regBaseN, where N is a value between 1 and 9. Drivers do
not need to read the regBase and regBaseN entries. The system reads those entries
and stores the results in the pRegBase[ ] entries in the VXB_DEVICE structure.
When your system is configured with interrupt controller support provided by a
VxBus model device driver, interrupt routing information is provided with the
interrupt controller driver resources. However, when the BSP provides the code to
manage the interrupt controller devices, interrupt information is listed as a
resource for each device. In this case, there are two required interrupt resources for
each interrupt the device can generate.
80
Each interrupt requires two resources, an interrupt number and an interrupt level.
To ease BSP development, the resources have several aliases. These aliases are:
irq and irqLevel
These aliases can be used to represent the first interrupt that a device
generates.
intrN and intrNLevel
These aliases can be used to represent multiple interrupts. The character N is
replaced either by a decimal number, or it is deleted. For example, valid values
can include intr, intr0, intr1, intr27, and so on, along with the corresponding
intrLevel, intr0Level, and so on.
txInt, rxInt, and errInt
txIntLevel, rxIntLevel, and errIntLevel
These resource names can be used for a device that generates three interrupts
for transmit events, receive events, and error events. Note that txInt always
refers to interrupt 0, rxInt always refers to interrupt 1, and errInt always refers
to interrupt 2.
There are two additional generic resources that are required in some cases and may
be used by your driver:
regInterval
Describes the amount of space between registers. For example, sometimes a
device uses four 8-bit registers, and the board maps the register addresses so
that they appear to be located at 32-bit boundaries. In this case, the value of
regInterval must be specified as 4.
regWidth
Describes the size that must be used to access a register. For example,
sometimes a device uses four 8-bit registers, and the board maps the register
addresses so that they appear to be located at 32-bit boundaries, and in
addition, the device is located on a bus that allows only 32-bit transactions. In
this case, the driver needs to access each register with 32-bit transactions or a
bus error results. Therefore, the value of regWidth must be specified as 4.
regDelay
Describes the delay required between accesses to registers, in milliseconds.
clkFreq
Describes the frequency of an oscillator in Hz.
Wind River provides a general naming convention as part of the coding
convention described in Wind River Coding Conventions. Resource names should
follow the conventions for variable names. For example, if you need to represent a
81
VxWorks
Device Driver Developer's Guide, 6.6
Parameters are driver specific. There may be conventions for a given driver class,
but many parameters are specific to an individual device. Unlike resources, which
have required generic entries for all device classes, there are no generic parameters.
Wind River provides a general naming convention as part of the coding
convention described in Wind River Coding Conventions. Parameter names should
follow the conventions for variable names.
82
system, you can save yourself a great deal of time in the future by writing a driver
to be SMP-ready when compared with the cost of retrofitting SMP support into
a previously uniprocessor-only driver.
This section describes some of the unique device driver challenges posed by an
SMP system, and provides you with some possible solutions to the challenges.
For more information on VxWorks SMP, see the VxWorks Kernel Programmers
Guide: VxWorks SMP.
If a driver for a uniprocessor system is executing in task context, the driver can
lock interrupts in order to prevent any other thread of execution or ISR from
gaining control of the CPU, and thus guarantee itself exclusive access to device
driver resources.
Given this knowledge, you can construct small areas in the driver where interrupts
must be locked, and can guarantee that within these locked regions any driver
shared resources cannot be accessed simultaneously by more than one thread of
execution.
In a VxWorks SMP system, the simple mutual exclusion model used for a
uniprocessor system does not work because multiple cores within the system can
execute instructions simultaneously on more than one core. Because of this true
multiprocessing, your driver must use explicit locking to ensure that the driver's
shared data structures are protected from corruption by competing threads of
execution.
For details about methods than can be used to protect data structures against
simultaneous access on VxWorks SMP systems, see 3.6.6 Synchronization, p.66.
83
VxWorks
Device Driver Developer's Guide, 6.6
ISR-callable spinlocks
ISR deferral of work to a task context
84
In a VxWorks SMP system, you cannot always use a spinlock within an ISR to
protect a driver shared resource. For example, this can be because the driver's data
structures are part of a protocol stack, and access to the protocol stack is protected
using a semaphore. Because your driver cannot take a semaphore within an ISR,
the ISR must find another way to manipulate the shared data structures.
ISRs commonly use a deferral task to modify data that is protected by a semaphore.
A deferral task is a dedicated task within VxWorks that pends on a binary
semaphore, waiting to be unblocked by an ISR. Within an interrupt service routine,
if your driver needs to defer work, you can perform a set of steps to defer the
necessary work to task context:
1.
Block further interrupt delivery from the hardware. This is necessary because
the driver may not be able to clear the interrupt condition from the
interrupting device. If your device driver's interrupt service routine returns
while the device interrupt is still pending, the pending interrupt is serviced
immediately following the ISR return which causes an infinite loop of
interrupt processing.
2.
Prepare a data buffer that describes the work to be performed. This data buffer
needs to be private to the ISR so that it can modify its contents without
worrying about contention with other threads of execution.
3.
Deliver the data buffer to a waiting deferral task so that the task knows what
required work to perform.
4.
Unblock the deferral task so that it can then perform the deferred work.
The choice of deferral model is made when VxWorks is configured. The ISR
deferral library (INCLUDE_ISR_DEFER) is typically included in a VxWorks system
when a driver that uses the library is included. This is because the driver's use of
the deferral library creates a dependency on the deferral library that causes the
component to be pulled into the VxWorks system. The deferral library uses its
85
VxWorks
Device Driver Developer's Guide, 6.6
follows:
When device drivers defer interrupts, it is much more efficient to defer interrupts
to a task that is running on the same CPU as the CPU where the interrupt is first
received. When VxWorks first boots, all interrupts are delivered to CPU 0, but this
can be changed at run time by reconfiguring the routing of interrupts through the
various interrupt controllers. If an interrupt is migrated from CPU 0 to another
CPU in the SMP system, the deferral library must be informed of the change, so
that it can adapt to the new interrupt routing. The library uses two methods to
adapt to the change in routing:
For shared deferral tasks, the ISR deferral library locates a preexisting deferral
task (or creates one, if necessary) running on the CPU receiving the rerouted
interrupt. The deferral library returns a handle to this new queue. The driver
that receives the new handle should use this handle for all subsequent deferral
operations.
For individual deferral tasks, the ISR deferral library changes the CPU affinity
of the deferral task to correspond to the CPU where the interrupt has been
routed. A handle to the deferral task is still returned, but in this situation the
handle is unchanged, because no new deferral task is used for interrupt
processing.
86
87
VxWorks
Device Driver Developer's Guide, 6.6
88
4
Development Strategies
4.1 Introduction 89
4.2 Writing New VxBus Drivers 90
4.3 VxBus Show Routines 96
4.4 Debugging 110
4.1 Introduction
This chapter outlines development strategies for creating a VxBus model device
driver. The chapter presents an overall methodology for creating a new device
driver (where no previous VxWorks driver exists). It also presents several
suggestions for debugging those aspects of a device driver that are relevant to the
interface between the device driver and other modules such as the VxBus core
features and middleware.
89
VxWorks
Device Driver Developer's Guide, 6.6
2.
3.
4.
5.
To create the driver source file, start with a template file or an existing driver from
the same driver class. Templates, if available, are kept in the same directory as
other drivers of the same class.
Many VxBus device drivers have all source code located in a single source file, with
no external header file. However, if your driver includes a number of
device-specific macros or other driver-specific information, you can put this
information in an optional header file.
90
4 Development Strategies
4.2 Writing New VxBus Drivers
The component description file (CDF) for your driver allows the driver to be
configured and included in a project using standard Wind River tools (Workbench
and the vxprj command-line utility).
4
NOTE: This section provides an overview of the component description file
Many drivers have configuration options. For more information on how the driver
manages configuration options internally, see VxWorks Kernel Programmers Guide:
Kernel. Configuration options that are specified as parameters should be
configurable from within Workbench and in vxprj. To do this, provide Parameter
entries for each parameter and link the parameters to your Component with the
CFG_PARAMS keyword. For more information, see CFG_PARAMS, p.32.
Configuration stub files provide similar functionality to the CDF file, but are used
when building the VxWorks image from the BSP directory using the make
command (this is known as the bspDir/config.h build method).
91
VxWorks
Device Driver Developer's Guide, 6.6
NOTE: In general, you should build your project files using Workbench or the
vxprj command-line utility. However, the BSP build method described in this
section may be useful in certain development scenarios including early BSP and
driver development. For more information on this build method, see the VxWorks
Command-Line Tools Users Guide.
In most cases, each driver requires two stub files. The stub files are named
according to the convention for your driver, with the extensions .dc and .dr.
The driverName.dc file usually contains a forward reference to the driver
registration routine, and nothing else. Use the Wind River macro IMPORT to
declare this routine. (Note that all registration routines return a void value.)
The following is a sample driver .dc file:
IMPORT void sampleDriverRegister(void);
The .dr file contains a call to the driver registration routine. This call must be
surrounded by #ifdef and #endif.
The last line must be terminated with a newline (be sure that your editor does not
strip it off).
The following is a sample driver .dr file:
#ifdef DRV_CLASS_NAME
sampleDriverRegister();
#endif /* DRV_CLASS_NAME */
Wind River driver .dc and .dr files are located in installDir/vxworks-6.x/
target/config/comps/src/hwif. Third-party driver .dc and .dr files are located in
installDir/vxworks-6.x/target/3rdparty/vendor/driver.
Once you have created your driver, compiled it, added it to a library, and
configured your BSP, verify that what you have done so far is correct.
To do this, first build the VxWorks image from the BSP directory. Verify that the
driver file is included by using the nmarch command and searching for the
registration routine.
Next, verify that the CDF file is correct by starting Workbench and configuring the
VxWorks image. If everything is correct, your driver should be available in the
drivers folder (not greyed out).
92
4 Development Strategies
4.2 Writing New VxBus Drivers
Finally, boot the image and run vxBusShow( ). Your driver should show up in the
list of drivers and the target device should show up in the list of devices.
One common problemfrequently encountered when creating drivers for PLB
devicesis that the name of the driver does not match the name you provided in
the hcfDeviceList[ ] table. When this happens, the output of vxBusShow( )
displays the entry as an orphan rather than a device. If this happens, you must get
the driver and device to match up before proceeding.
VxBus matches a driver to its hardware by using strcmp( ) to compare the driver
name with the hcfDeviceList[ ] entries. The comparison is case sensitive, and the
match must be exact. Check that the driver name and the name listed in the
hcfDeviceList[ ] table in hwconf.c are identical and correct as necessary.
The second most common problem at this stage is related to the device's register
base address. For PLB devices, the first register base address must be non-null. You
can verify this by running vxBusShow( ) with a verbose level argument greater
than 1. This displays the full set of pRegBase[ ] entries for each device (instance
and orphan) known by VxBus. If the pRegBase[0] entry for your device is zero,
correct the problem by supplying the correct base address.
NOTE: In some cases, you may not want to supply the register base address in
hwconf.c. In this is the case for your driver, use ERROR or TRUE, both of which are
non-null. If you choose this option, your driver must not attempt to read or write
registers using the VxBus register access mechanism.
Before moving on to the next step, be sure that your device and driver are
connected to each other.
Depending on the bus type, VxBus may be able to discover your device
automatically. For example, when the device is on a PCI bus or variant of PCI,
information about the device is available from PCI configuration space. VxBus
reads this information and compares it against PCI configuration information
provided by a driver for a PCI device. If the information matches, the driver is
paired with the device.
93
VxWorks
Device Driver Developer's Guide, 6.6
However, with the PLB bus type, devices are not discovered automatically. In this
case, you must add an entry for your device in the hcfDeviceList[ ] array in the
BSP hwconf.c file.
For easier debugging, configure your VxWorks Image Project so that the show
routines are included. Be sure to include the VxBus show routines in addition to
the standard show routines. For example, add the following components:
INCLUDE_SHOW_ROUTINES
INCLUDE_VXBUS_SHOW
DRV_CLASS_NAME
For most new driver development, you should defer registration of your driver
with VxBus. You can manually run your driver registration routine after the
system has booted and you are ready to debug your driver. This allows the system
to come up without your driver, and you can use the debug facilities from a
fully-functional VxWorks image for debugging.
The type of debug information that can be added to a driver is discussed in
4.4 Debugging, p.110.
94
4 Development Strategies
4.2 Writing New VxBus Drivers
95
VxWorks
Device Driver Developer's Guide, 6.6
vxBusShow( )
The most basic show routine in the VxBus framework is vxBusShow( ). This
routine provides a list of information related to drivers and devices.
There are several levels of detail available when using this routine. The level of
detail is specified by the value of the argument. A value of 0 provides the following
basic information:
Example 4-1 shows the output for a typical vxBusShow( ) routine run on a
Pentium target.
Example 4-1
96
4 Development Strategies
4.3 VxBus Show Routines
97
VxWorks
Device Driver Developer's Guide, 6.6
Higher verbose level values result in the display of additional information. Each
driver can publish a show routine that is integrated into vxBusShow( ) (see
4.4.1 Configuring Show Routines, p.110). The amount and format of the information
that is displayed depends on the driver and the information that the driver chooses
to display based upon a given verbose level.
NOTE: The remainder of this section discusses only the generic format used when
the driver does not publish a show routine.
98
4 Development Strategies
4.3 VxBus Show Routines
...
vxbDevStructShow( )
99
VxWorks
Device Driver Developer's Guide, 6.6
NOTE: When pRegBase[0] is NULL on PLB devices, the device is not matched with
a driver, but instead remains an orphan.
vxbDevPathShow( )
The vxbDevPathShow( ) routine indicates the bus controllers upstream from the
specified device to the PLB. For example:
-> sio3 = 0x00468c50
-> vxbDevPathShow(sio3)
device ns16550 @ 0x00468c50
device pentiumPci @ 0x00467a50
device plbCtlr @ 0x0044f9f4
100
4 Development Strategies
4.3 VxBus Show Routines
pciDevShow( )
The pciDevShow( ) routine displays PCI information about the specified device.
This includes the [bus,device,function] triple, and the device ID and vendor ID, that
were read from PCI configuration space when the device was created. For
example:
-> yn0 = 0x00468350
-> pciDevShow(yn0)
pDev @ 0x00468350
[3,0,0]
devID
= 0x4b00
vendID = 0x1186
The devID and vendID fields shown by pciDevShow( ) are used when matching
PCI devices and drivers. If the information displayed by pciDevShow( ) does not
match the values listed in your driver, you may need to modify your driver to get
an exact match.
vxbPciDeviceShow( )
101
VxWorks
Device Driver Developer's Guide, 6.6
bus
0
0
0
0
0
0
0
0
0
device
0
2
4
6
28
30
31
31
31
function
0
0
0
0
0
0
0
1
3
vendorID
0x8086
0x8086
0x8086
0x8086
0x8086
0x8086
0x8086
0x8086
0x8086
deviceID
0x3590
0x3595
0x3597
0x3599
0x25ae
0x244e
0x25a1
0x25a2
0x25a4
class/rev
0x0600000c
0x0604000c
0x0604000c
0x0604000c
0x06040002
0x0604000a
0x06010002
0x01018a02
0x0c050002
vxbPciHeaderShow( )
The vxbPciHeaderShow( ) routine displays the full contents of the PCI header for
an individual device. Note that the device is specified by four values: the bus
controller device, and the PCI triple [bus,device,function]. This means that
vxbPciHeaderShow( ) is usable even when the BSP excludes a particular device
from being configured. (For information about excluding a particular device
within the BSP, see the reference entry for vxbPciAutoConfig( ).)
The following sample shows the PCI header for the Yukon II network interface
device. Notice that the VxBus device ID for the yn0 device is not used as an
argument to vxbPciHeaderShow( ). Instead, use the [bus,device,function] triple as
provided in the output of pciDevShow( ).
-> yn0 = 0x00468350
-> pciDevShow(yn0)
pDev @ 0x00468350
[3,0,0]
devID
= 0x4b00
vendID = 0x1186
-> pciCtlr = 0x004669d0
-> vxbPciHeaderShow pciCtlr,3,0,0
vendor ID =
0x1186
device ID =
0x4b00
command register =
0x0007
status register =
0x4010
revision ID =
0x11
class code =
0x02
102
4 Development Strategies
4.3 VxBus Show Routines
vxbPciFindDeviceShow( )
103
VxWorks
Device Driver Developer's Guide, 6.6
vxbPciFindClassShow( )
vxbPciConfigTopoShow( )
104
4 Development Strategies
4.3 VxBus Show Routines
105
VxWorks
Device Driver Developer's Guide, 6.6
Obviously, this is not enough information to know much about the device.
Ideally, when debugging a driver for PCI devices, you should know the
[bus,device,function] triple. You can get this by providing a routine that prints
information about the devices it sees and then using vxbDevIterate( ) to call the
routine for every device. For example, you could provide the following routine:
STATUS pciShowHelper
(
VXB_DEVICE_ID devID,
void * pArg
)
{
struct vxbPciDevice * pPci;
if ( devID->busID != VXB_BUSID_PCI )
/* wrong bus type, just return */
return(OK);
pPci = (struct vxbPciDevice *)devID->pBusSpecificDevInfo;
106
4 Development Strategies
4.3 VxBus Show Routines
if ( devID->pName == NULL )
printf("PCI device orphan 0x%08x devID 0x%04x vendID 0x%04x at
[%d,%d,%d]\n",
devID, pPci->pciDevId, pPci->pciVendId,
pPci->pciBus, pPci->pciDev, pPci->pciFunc);
else
printf("PCI device %s%d devID 0x%04x vendID 0x%04x at
[%d,%d,%d]\n",
devID->pName, devID->unitNumber,
pPci->pciDevId, pPci->pciVendId,
pPci->pciBus, pPci->pciDev, pPci->pciFunc);
return(OK);
}
Then, use this routine with vxbDevIterate( ). When using vxbDevIterate( ), you
can indicate that the routine should only be run on orphan devices by specifying
the value 2 as the third argument.
NOTE: The following output is displayed from a different system than other
output examples in this section.
-> vxbDevIterate(pciShowHelper,0,2)
PCI device orphan 0x0042d348 devID 0x3590
PCI device orphan 0x0042d448 devID 0x3595
PCI device orphan 0x0042d548 devID 0x3597
PCI device orphan 0x0042d648 devID 0x3599
PCI device orphan 0x0042d748 devID 0x25ae
PCI device orphan 0x0042d948 devID 0x244e
PCI device orphan 0x0042da48 devID 0x4c52
PCI device orphan 0x0042db48 devID 0x25a1
PCI device orphan 0x0042fc48 devID 0x25a2
PCI device orphan 0x0042fd48 devID 0x25a4
vendID
vendID
vendID
vendID
vendID
vendID
vendID
vendID
vendID
vendID
0x8086
0x8086
0x8086
0x8086
0x8086
0x8086
0x1002
0x8086
0x8086
0x8086
at
at
at
at
at
at
at
at
at
at
[0,0,0]
[0,2,0]
[0,4,0]
[0,6,0]
[0,28,0]
[0,30,0]
[5,1,0]
[0,31,0]
[0,31,1]
[0,31,3]
It is possible to use the show routines from test code or other software. However,
to do this, your code needs to find the VxBus device ID of the desired device. This
can be accomplished by requiring that the user to provide the VxBus device ID.
However, it may be more convenient to provide the driver name and unit number.
struct devNameAndUnit
{
VXB_DEVICE_ID devID;
char * devName;
int devUnit;
};
STATUS pciDevByNameUnitHelper
(
VXB_DEVICE_ID devID,
struct devNameAndUnit * pDev
)
{
struct vxbPciDevice * pPci;
107
VxWorks
Device Driver Developer's Guide, 6.6
if ( pDev->devID != NULL )
/* already found, just return */
return(OK);
if ( ( strcmp(devID->pName,pDev->devName) == 0 ) &&
( devID->unitNumber == pDev->devUnit ) )
/* found it */
pDev->devID = devID;
return(OK);
}
VXB_DEVICE_ID pciDevByNameUnitFind(char * devName, int devUnit)
{
struct devNameAndUnit nmUnit;
nmUnit.devID = NULL;
nmUnit.devName = devName;
nmUnit.devUnit = devUnit;
vxbDevIterate(pciDevByNameUnitHelper, &nmUnit, 1)
return(nmUnit.devID);
}
The pciDevByNameUnitFind( ) routine can be used within the code to find the
VxBus device ID of the desired device.
-> pciDevByNameUnitFind("fei",0)
value = 4623952 = 0x00468e50
To include the generic Vxbus show routines, include the following macros or
components when building your VxWorks image:
INCLUDE_SHOW_ROUTINES
INCLUDE_PCI_BUS_SHOW
INCLUDE_VXBUS_SHOW
108
4 Development Strategies
4.3 VxBus Show Routines
difficult to configure, due to the fact that interrupt controller drivers and the
interrupt controller driver support library are compiled outside the context of a
project or BSP.
Several source files need to be recompiled and archived into the driver library. The
files are all located in the installDir/vxworks-6.x/target/src/hwif/intCtlr directory.
The interrupt controller driver support library provides show routines when the
INTCTLR_LIB_SHOW macro is defined. Individual interrupt controller drivers are
configured with additional show routines by defining driver-specific macros.
To determine which macros you need to define, you must determine which
interrupt controller driver is included with your system, and check for
preprocessor macros containing any of the following strings:
_DEBUG_
_DBG_
_SHOW
For example, if the EPIC interrupt controller driver, vxbEpicIntCtlr.c is used, the
macro VXB_EPICINTCTLR_DBG_ON determines whether debug information is
included.
Once you have determined which macros need to be defined, run a make
command to build the files, specifying ADDED_CFLAGS to define the macros. You
must also specify the appropriate CPU and TOOL values for your hardware.
For example:
% make CPU=PPC32 TOOL=diab \
ADDED_CFLAGS="-DVXB_EPICINTCTLR_DBG_ON -DINTCTLR_LIB_SHOW"
NOTE: You may need to update the timestamp on the files in order to build the
object modules.
NOTE: Be sure to restore the non-debug versions of these files before creating your
109
VxWorks
Device Driver Developer's Guide, 6.6
4.4 Debugging
This section provides general information on debugging VxBus device drivers. In
addition to the information in this section, you should also review any
class-specific debugging hints which are provided in the class-specific chapters of
volume 2 of the VxWorks Device Driver Developers Guide. (For information on
debugging legacy device drivers, see volume 3 of the VxWorks Device Driver
Developers Guide.)
The general debugging hints discussed in this section include:
Including debug code in the driver. (4.4.3 Including Debug Code, p.112)
Confirming the driver and device names match for PLB devices.
(4.4.6 Confirming Device and Driver Name Matches, p.113)
110
4 Development Strategies
4.4 Debugging
Table 4-1
Level
Description
3 ... 8
10 ... 49
50
51 ... 499
500+
111
VxWorks
Device Driver Developer's Guide, 6.6
searches the list of orphan devices (devices not associated with a driver) for any
device that matches the new driver. If it finds one, it pairs the driver with the
device and runs through the normal initialization sequence.
For some driver classes, additional work may need to be done in order for the
device to be fully recognized by the available middleware modules. This is
explained further in the class-specific chapters in volume 2 of the VxWorks Device
Driver Developer's Guide.
This allows the driver to include the debug code available if required, but without
any overhead for a normal configuration.
112
4 Development Strategies
4.4 Debugging
113
VxWorks
Device Driver Developer's Guide, 6.6
114
5
Driver Release Procedure
5.1 Introduction
This chapter documents a procedure for releasing VxBus model VxWorks device
drivers. The information in this chapter applies to developers that are releasing a
device driver within their organization for use with custom hardware and
applications as well as developers releasing a VxWorks device driver for general
distribution.
Following the release procedure in this chapter allows you to integrate your driver
with Workbench and the vxprj command-line utility so that it is configurable in a
manner similar to that of a standard Wind River supplied driver. This procedure
also allows your driver to be included in a BSP command-line build (using make).
The only significant difference between this method of packaging and that done
internally at Wind River is the way the driver files are packaged.
115
VxWorks
Device Driver Developer's Guide, 6.6
If you plan to distribute your driver independently, you can consider the
instructions in this chapter as suggestions rather than as requirements. However,
if you plan to provide your driver to Wind River for distribution as a standard
product, you must follow the guidelines in this chapter as well as the checklist
provided in B. Checklist for Device Drivers.
This discussion is presented in conjunction with a sample driver, provided by
Wind River, which is located in the installDir/vxworks-6.x/target/3rdparty/
windriver/wrsample directory.
116
README
Makefile
driverName.cdf
driverName.dr
driverName.dc
In addition, one or more source or object files must be present. You may also have
header files or other supporting files included in this directory. For more
information on each of the required files, see 3.3.2 Required Files, p.24.
Without the required files, your driver cannot be correctly integrated with
Workbench, the vxprj command-line utility, or BSP command-line builds.
You can choose to release your driver as source or as binary only. The driver source
files (or binary files for a binary-only release) must be located in the driver-specific
directory.
NOTE: An binary-only driver release is possible. However, the makefile
modifications needed to release a driver this way are not supported by Wind
River. In particular, you must be sure that object files are not given a .o extension.
Otherwise, object files may be removed when a user cleans object files.
A source release is the easiest release form. When producing a source release, you
can copy and rename the files from the Wind River sample driver (installDir/
vxworks-6.x/target/3rdparty/windriver/wrsample) into your driver directory, add
your source file and any required driver-specific header files, and update the
makefile and configuration files as necessary.
To make the modifications correctly, use the wrsample driver as a reference.
Follow the instructions in README, Makefile, and in this chapter, to integrate
your driver with your installation.
117
VxWorks
Device Driver Developer's Guide, 6.6
In all the driver configuration files, change the driver registration routine from
wrsampleRegister( ) to the registration routine used by your driver.
If you choose to release in binary-only format, the filenames for your driver should
include the supported architecture and the tool used to build the driver. The driver
directory should not contain any files ending in a .o extension, as those files can be
accidentally removed when other drivers are installed. Use driverName.obj format
instead. For example, for the myDriver object file for the PowerPC architecture
using the Wind River Compiler toolchain with software floating-point (sfdiab),
you might name the file myDriver_PPC32_sfdiab.obj. You must modify the
makefile so that it copies the object files to the correct locations and causes the
correct object file archive to be updated.
cd installDir/vxworks-6.x/target/src/hwif/methods
make vxbMethodDecl.h
cd installDir/vxworks-6.x/target/config/comps/src/hwif
make vxbUsrCmdLine.c
cd installDir/vxworks-6.x/target/config/comps/vxWorks
rm CxrCat.txt
make
For each processor (CPU) and tool (TOOL) combination used by the installer, run
the following commands:
% cd installDir/vxworks-6.x/3rdparty/vendor/driver
% make CPU=cpuName TOOL=tool
118
cd installDir\vxworks-6.x\target\config\comps\src\hwif
make vxbUsrCmdLine.c
cd installDir\vxworks-6.x\target\config\comps\vxWorks
del CxrCat.txt
make
cd installDir\vxworks-6.x\target\3rdparty\vendor\driver
For each processor (CPU) and tool (TOOL) combination used by the installer, run
the commands:
C:\> make CPU=cpuName TOOL=tool
You can now release your driver in an archive such as a ZIP file or tarball.
NOTE: The packaging procedure documented in this section is an alternative to the
formal practice used within Wind River. The internal driver release procedure
uses custom tools that are not currently available outside of Wind River. When
installed with the Wind River packaging, the installation updates the setup.log file
to indicate that the driver is installed, builds the driver, and causes several files to
be updated with the contents of the driver configuration files for integration with
the build process. This packaging is currently available from the Wind River
Professional Services organization. For more information, see your Wind River
representative.
119
VxWorks
Device Driver Developer's Guide, 6.6
120
A
Glossary
access routine
The hardware device that controls signals on a bus. The bus controller hardware
must be associated with a bus controller device driver in order for VxBus to make
use of the device. The service that a bus controller device driver provides is to
support the devices downstream from the controller. The bus controller driver is
also responsible for enumerating devices present on the bus. See also device, driver,
enumeration, and instance.
bus discovery
See enumeration.
121
VxWorks
Device Driver Developer's Guide, 6.6
bus match
For DMA, a descriptor is a data structure shared by the device and driver, which
communicates the size, location, and other characteristics of data buffers used to
hold transmit and receive data. The data format is defined by the design of the
device.
device
A hardware module that performs some specific action, usually visible (in some
way) outside the processor or to the external system. See also bus, driver, and
instance.
downstream
From the perspective of a device, downstream refers to a point farther from the CPU
on the bus hierarchy. See also child.
driver
A compiled software module along with the infrastructure required to make the
driver visible to Workbench and BSPs. The software module usually includes a text
segment containing the executable driver code plus a small, static data segment
containing information that is required to recognize whether the driver can
manage a particular device. The infrastructure typically includes a CDF that allows
integration with Workbench and vxprj, and stub files for integration with a BSP.
122
A Glossary
driver method
A driver method is a published entry point into a driver made available to an API
in VxBus. Examples of methods include functionality such as connecting network
interfaces to the MUX and discovery of interrupt routing. See also method ID.
enumeration
Enumeration refers to the discovery of devices present on a bus. For some bus
types such as PCI, the bus contains information about devices that are present. For
those bus types, dynamic discovery is performed during the enumeration phase.
For bus types such as VME, which do not have such functionality, tables that
describe the devices that may be present on the system are maintained in the BSP.
See also bus discovery.
instance
A driver and device that are associated with each other. This is the minimal unit
that is accessible to higher levels of the operating system. See also bus, device, and
driver.
mBlk
The bus to which a device is attached, or the bus controller of that bus.
probe
123
VxWorks
Device Driver Developer's Guide, 6.6
probe routine
An entry point into drivers. After the system has tentatively identified a device as
being associated with a driver, VxBus gives the driver a chance to verify that the
driver is suitable to control the device. The driver registers the probe routine to
perform this comparison. This routine is optional. If specified, it is normally safe
and acceptable for the routine to simply indicate acceptance.
processor Local bus (PLB)
Serial bitbang describes a scenario where software writes the individual bits of a
word out on a serial line, often with a corresponding clock, rather than writing the
entire value into a register and allowing the underlying hardware to take care of
the delivery of the word.
service driver
A condition that occurs when a network interface device stops operating due to
momentary lack of resources.
upstream
From the perspective of a device, upstream refers to a point closer to the CPU on
the bus hierarchy. See also parent.
124
B
Checklist for Device Drivers
This appendix includes a checklist to help you determine when your driver is
ready for deployment or distribution. Successful completion of this checklist can
help you assess the quality of your driver and make decisions with respect to
deployment and distribution.
The checklist assumes you are familiar with VxBus device driver development or
you have reviewed the information in the VxWorks device driver documentation
set. (The items included in the checklist are discussed in detail throughout this
documentation set.)
125
VxWorks
Device Driver Developer's Guide, 6.6
Table B-1
Date
YYYY-MM-DD
Description
126
Status
OK | FAIL | N/A
Table B-1
Description
Date
YYYY-MM-DD
Status
OK | FAIL | N/A
12. Use the nmarch command to verify that there is only one
global symbol present. The symbol should be the registration
routine for the driver.
12. Verify that the VxBus version in the driver's registration
structure matches the current VxBus version.
13. If the VxTest test suite is available, verify that all VxTest tests
applicable to the driver class of this driver are successful.
127
VxWorks
Device Driver Developer's Guide, 6.6
128
Index
Symbols
{busDevShow}( ) 110
{instParamModify}( ) 56
{isrRerouteNotify}( ) 86
{vxbDmaResDedicatedGet}( ) 75
{vxbDmaResourceRelease}( ) 77
{vxbDrvUnlink}( ) 48
see also dissociating a device from a driver
Numerics
pRegBase 100
A
access routine 121
accessing hardware 59
adding
debug code 94
driver methods 95
address
conversion for bus controllers 72
translation, considerations for DMA
address space
mapping 61
advertise 121
advertising driver methods 40
allocating
external DMA engines 75
memory 57, 58
during system operation 58
during system startup 57
ATA 17
atomic operators 77
atomic_t 77
72
boot process 42
early phase 44
BSP
configuration 54, 79
device parameter configuration
hwconf.c 113
modifications for drivers 93
bus
definition 121
discovery 121
match 122
bus controller
address conversion 72
definition 121
drivers 19
129
82
VxWorks
Device Driver Developer's Guide, 6.6
C
cache
considerations for DMA 73
cacheLib 73
calling driver methods 39
CDF, see component description file
CFG_PARAMS 32
changes in device parameters 56
child 122
classes, see driver classes
clkFreq 81
cluster 122
command-line builds
using make 34
communication
between device, driver, and OS 10
comparing
device and driver names 113
component 8, 27
INCLUDE_ISR_DEFER 85
INCLUDE_SHOW_ROUTINES 94
INCLUDE_VXBUS_SHOW 94
parameters
ISR_DEFER_MODE 86
component description file 27, 91, 117
example 28
fields
CFG_PARAMS 32
CHILDREN 30
Component 28
HDR_FILES 32
INIT_AFTER 32
INIT_BEFORE 32
INIT_ORDER 31
INIT_RTN 31
MODULES 29
NAME 29
Parameter 32
130
PROTOTYPE 31
REQUIRES 31
SYNOPSIS 29
parameter keywords
DEFAULT 33
NAME 33
SYNOPSIS 33
TYPE 33
writing 28
components
INCLUDE_PCI_BUS_SHOW 108
INCLUDE_SHOW_ROUTINES 108
INCLUDE_VXBUS_SHOW 108
configuration
driver services 53
in hwconf.c 54
information 53
resource 54
configuration stub files 34, 91, 117
configuring
BSPs 54, 79
device parameters in a BSP 82
interrupt show routines 108
parameters 54
show routines into VxWorks 108
VxBus show routines 110
confirming register access 112
console drivers 21
creating the VxBus infrastructure 90
D
data buffers
address mapping 73
data structures
VXB_DEVICE 60
VXB_DEVICE_ID 95
debugging 94, 110, 112
register access 112
deferral task 85
deferring
driver registration 111
interrupt processing in an SMP system 84
descriptor 122
Index
design goals 13
developing new VxBus drivers 90
development life cycle 42
device
ATA 17
bus controller
definition 122
display 21
DMA engines 19
Ethernet 17
floppy disks 17
interrupt controller 20
keyboard 21
MAC 17
matching to a driver 50, 92, 93
mouse 21
multifunction 20
network interface 17
non-volatile RAM 18
parameter configuration in BSP 82
PHY 17
PLB 79
responding to changes in parameters 56
SCSI 17
serial 17
serial ATA 17
timer 18
USB 20
device driver model
legacy 2
VxBus 1
device registers
address mapping 72
devInstanceConnect( ) 43, 46
see also initialization VxBus phases
devInstanceInit( ) 43, 45
see also initialization VxBus phases
devInstanceInit2( ) 43, 46, 49
see also initialization VxBus phases
DEVMETHOD( ) 41
DEVMETHOD_CALL( ) 40
DEVMETHOD_END 41
devResourceGet( ) 54
direct memory access, see DMA
discovering hardware 50
131
Index
VxWorks
Device Driver Developer's Guide, 6.6
132
routine prototype 39
syntax 38
driverName.cdf 117
driverName.dc 35, 91, 117
driverName.dr 35, 91, 117
E
enumeration 123
errInt 81
errIntLevel 81
Ethernet 17
examples
VxBus show routine output 96
VxBus show routine verbose output
98
F
files
component description file 27, 91, 117
configuration stub files 34, 91
driver source 90
driverName.cdf 117
driverName.dc 35, 91, 117
driverName.dr 35, 91, 117
in a device driver 23
location 23
for third-party drivers 116
makefile 36, 37, 117
README 36, 117, 118
required 24
third-party drivers 23
vendor makefile 37
finding the address of hardware registers 59
floppy disks 17
G
global symbols 27
global variables
removing 95
Index
H
hardware
access 59
discovery 44, 50
memory pool size 112
registers
finding the address of 59
reading and writing 62
special requirements 63
hardWareInterFaceBusInit( ) 44, 45, 46
hardWareInterFaceInit( ) 44
HCF_RES_ADDR 54
HCF_RES_INT 54
HCF_RES_STRING 54
header files 90
hwConf.h 80
vxBus.h 39
hwconf.c 54, 55, 79
supplying a register base address 113
hwConf.h 80
HWMEM_POOL 112
hwMemAlloc( ) 57
see also memory allocation
hwMemFree( ) 58
see also memory allocation
I
INCLUDE_HWMEM_ALLOC 44
see also memory allocation
INCLUDE_ISR_DEFER 85
INCLUDE_PCI_BUS_SHOW 108
INCLUDE_SHOW_ROUTINES 94, 108
INCLUDE_VXBUS_SHOW 94, 108
including debug code 112
initialization
driver 42
driver registration 45
early boot process 44
hardware discovery 44
kernel startup 46
order 43
PLB 44
sysHwInit( ) 44
VxBus phases 43
phase 1 43, 45
phase 2 43, 46
phase 3 43, 46
instance 9
definition 123
intConnect( ) 64
intCpuLock( ) 68
intCpuUnlock( ) 68
INTCTLR_LIB_SHOW 109
integration
with vxprj 8
with Workbench 8
interrupt
deferring processing in an SMP system
handling 63
index 64
locking 68
in an SMP system 83
minimizing work in an ISR 65
routing
in an SMP system 84
vector model 64
interrupt controller drivers 20
interrupt service routine, see ISR
interrupt show routines
configuring 108
interrupt-level synchronization 68
using interrupt locking 68
using spinlocks 69
intrN 81
intrNLevel 81
invoking driver methods 46
irq 81
irqLevel 81
ISR
deferral 66
deferral library component 85
minimizing work in 65
ISR_DEFER_MODE 86
ISR_DEFER_MODE_PER_CPU 86
ISR_DEFER_MODE_PER_SOURCE 86
isrDeferIsrReroute( ) 87
isrDeferJobAdd( ) 66
133
Index
84
VxWorks
Device Driver Developer's Guide, 6.6
isrDeferLib 66, 87
isrDeferQueueGet( ) 66
K
kernel startup 46
L
late driver registration 48
ld( ) 48
legacy device driver model 2
legacy drivers
documentation 3
file location 23
LIB_BASE_NAMES 116
libraries
cacheLib 73
isrDeferLib 66, 87
vxAtomicLib 77
vxbDmaBufLib 70
vxbDmaLib 75
loading
an object module 48
drivers after boot time 48
loadModule( ) 48
loadModuleAt( ) 48
M
MAC drivers 17
see also network interface drivers
macros
DEVMETHOD( ) 41
DEVMETHOD_CALL( ) 40
DEVMETHOD_END 41
INTCTLR_LIB_SHOW 109
METHOD_DECL( ) 40
makefile 36, 37, 117
vendor 37
134
mapping
address space 61
data buffer addresses 73
device registers 72
matching
devices and drivers 50, 92, 93, 113
mBlk 123
media independent interface, see MII
memory allocation 44, 57
during system operation 58
during system startup 57
mixing methods within a driver 58
see also INCLUDE_HWMEM_ALLOC
memory pool 112
method ID 123
METHOD_DECL( ) 40
methods, see driver methods
migrating legacy drivers 3
MII 17
minimizing work in an ISR 65
modifying the BSP 93
msgQSend( ) 68
multifunction drivers 20
N
network interface drivers 17
non-volatile RAM 18, 59
drivers 18
notifying a driver of system shutdown 48
NVRAM, see non-volatile RAM
O
object module
loading 48
order of initialization
organization
driver 23
43
Index
P
packaging a driver for release 115, 119
pairing a device with a driver 50, 92, 113
parameter
configuration 54
definition 123
parent 123
PCI 19, 51
PCI triple 100
show routines 100
pciDevByNameUnitFind( ) 108
pciDevShow( ) 101
pDrvCtrl 95
performance testing 14
PHY drivers 17
see also network drivers
PLB 19, 44, 51
BSP configuration 79
definition 124
probe 123
probe routine 124
processor local bus, see PLB
Q
queue sharing 86
R
RapidIO 52
reading
hardware registers 62
README 36, 117, 118
regDelay 81
regInterval 81
register access
debugging 112
register base address
supplying in hwconf.c 113
registering
a driver 45
a driver after boot time 48
registration order 49
registration routine 45
regWidth 81
releasing
drivers 115
in binary format 117
in source format 117
providing driver installation instructions 118
third-party drivers 120
remote processing element drivers 21
removing a device from the system 47
see also vxbDevRemovalAnnounce( )
removing global variables 95
required files 24
resource
clkFreq 81
configuration 54
definition 124
drivers 22
errInt 81
errIntLevel 81
intrN 81
intrNLevel 81
irq 81
irqLevel 81
names 80
regDelay 81
regInterval 81
regWidth 81
rxInt 81
rxIntLevel 81
txInt 81
txIntLevel 81
resource types
address 54
integer 54
string 54
routines
devInstanceConnect( ) 43, 46
devInstanceInit( ) 43, 45
devInstanceInit2( ) 43, 46, 49
devResourceGet( ) 54
135
Index
VxWorks
Device Driver Developer's Guide, 6.6
driver registration 45
hardWareInterFaceBusInit( ) 44, 45, 46
hardWareInterFaceInit( ) 44
hwMemAlloc( ) 57
hwMemFree( ) 58
intConnect( ) 64
intCpuLock( ) 68
intCpuUnlock( ) 68
isrDeferIsrReroute( ) 87
isrDeferJobAdd( ) 66
isrDeferQueueGet( ) 66
msgQSend( ) 68
pciDevByNameUnitFind( ) 108
pciDevShow( ) 101
sysHwInit( ) 44, 46
sysHwInit2( ) 46
taskLock( ) 84
vxbDevInit( ) 46
vxbDevIterate( ) 47, 106
vxbDevMethodGet( ) 10, 40
vxbDevMethodRun( ) 40
vxbDevPathShow( ) 100
vxbDevRegister( ) 45
vxbDevRemovalAnnounce( ) 47
vxbDevStructShow( ) 99
vxbDmaBufMapLoad( ) 71
vxbDmaBufSync( ) 71
vxbDmaBufTagCreate( ) 70
vxbDmaChanAlloc( ) 75
vxbDmaChanFree( ) 77
vxbDriverUnregister( ) 47
vxbInstParamByNameGet( ) 54
vxbInstParamSet( ) 55, 56
vxbIntConnect( ) 49, 65
vxbIntDisable( ) 65, 66
vxbIntDisconnect( ) 65
vxbIntEnable( ) 65
vxbNonVolGet( ) 59
vxbNonVolSet( ) 59
vxbPciConfigTopoShow( ) 104
vxbPciDeviceShow( ) 101
vxbPciFindClassShow( ) 104
vxbPciFindDeviceShow( ) 103
vxbPciHeaderShow( ) 102
vxbReadxx( ) 62
136
vxbRegMap( ) 61
vxBusShow( ) 93, 96, 110
vxbWritexx( ) 63
rxInt 81
rxIntLevel 81
S
SATA, see serial ATA
SCSI 17
serial ATA 17
serial bitbang 124
serial drivers 17
service driver 124
services 52
atomic operators 77
configuration 53
DMA
hardware access 59
interrupt handling 63
memory allocation 57
synchronization 66
show routines 96, 110
configuring into VxWorks 108
generic 96
PCI 100
using from software 106
verbose level 98, 110
shutdown notification 48
SMP
see VxWorks SMP
source file 25
example 25
structure 25
stall 124
storage drivers 17
symmetric multiprocessing
see VxWorks SMP
synchronization 66
interrupt-level 68
task-level 67
sysHwInit( ) 44, 46
sysHwInit2( ) 46
Index
system startup
memory allocation at 57
T
task-level synchronization 67
taskLock( ) 84
terms
access routine 121
advertise 121
bus 121
bus controller 121
bus discovery 121
bus match 122
bus type 122
child 122
cluster 122
descriptor 122
device 9, 122
downstream 122
driver 9, 122
driver method 123
enumeration 123
instance 9, 123
mBlk 123
method ID 123
parameter 123
parent 123
PLB 124
probe 123
probe routine 124
resource 124
serial bitbang 124
service driver 124
stall 124
upstream 124
VxBus 8
third-party drivers 24, 116
file location 23
packaging for release 119
releasing 120
timer drivers 18
txInt 81
txIntLevel 81
U
u.pDevPrivate 48
unloading a driver 47
see also vxbDriverUnregister( )
upstream 124
USB drivers 20
using show routines from software
using spinlocks 69
106
Index
vendor makefile 37
verbose level 110
vxBusShow( ) 98
vxAtomicLib 77
VXB_DEVICE 60
VXB_DEVICE_ID 95
VXB_REG_MEM 61
vxbDevInit( ) 46
vxbDevIterate( ) 47, 106
vxbDevMethodGet( ) 10, 40
vxbDevMethodRun( ) 40
vxbDevPathShow( ) 100
vxbDevRegister( ) 45
vxbDevRemovalAnnounce( ) 47
see also removing a device from the system
vxbDevStructShow( ) 99
vxbDmaBufLib 70
vxbDmaBufMapLoad( ) 71
vxbDmaBufSync( ) 71
vxbDmaBufTagCreate( ) 70
vxbDmaChanAlloc( ) 75
vxbDmaChanFree( ) 77
vxbDmaLib 75
vxbDriverUnregister( ) 47
see also unloading a driver
vxbInstParamByNameGet( ) 54
vxbInstParamSet( ) 55, 56
vxbIntConnect( ) 49, 65
vxbIntDisable( ) 65, 66
vxbIntDisconnect( ) 65
vxbIntEnable( ) 65
vxbNonVolGet( ) 59
137
VxWorks
Device Driver Developer's Guide, 6.6
vxbNonVolSet( ) 59
vxbPciConfigTopoShow( ) 104
vxbPciDeviceShow( ) 101
vxbPciFindClassShow( ) 104
vxbPciFindDeviceShow( ) 103
vxbPciHeaderShow( ) 102
vxbReadxx( ) 62
vxbRegMap( ) 61
VxBus
about 8
creating infrastructure 90
driver components 8
driver model 9
initialization phases 43
instance 9
show routines 110
example 96, 98
verbose level 98
vxBus.h 39
vxBusShow( ) 93, 96, 110
vxbWritexx( ) 63
vxCas 78
vxprj
device driver integration with 8
VxWorks
components 27
VxWorks SMP 2
considerations for device drivers 82
deferring interrupt processing 84
interrupt routing 84
lack of implicit locking in 83
task-to-task contention 84
W
Workbench
device driver integration with
writing
hardware registers 62, 63
new VxBus drivers 90
138