Compaq Information Technologies Group, L.P.inthe United States and other countries.
UNIX and X/Open are trademarks of The Open Group in the United States and other countries. All other
product names mentioned herein may be trademarks of their respective companies.
Confidential computer software. Valid license from Compaq required for possession, use, or copying.
Consistent with FAR 12.211 and 12.212, Commercial Computer Software, Computer Software
Documentation, and Technical Data for Commercial Items are licensed to the U.S. Government under
vendor’s standard commercial license.
Compaq shall not be liable for technical or editorial errors or omissions contained herein. The information
in this document is provided “as is” without warranty of any kind and is subject to change without
notice. The warranties for Compaq products are set forth in the express limited warranty statements
accompanying such products. Nothing herein should be construed as constituting an additional warranty.
About This Manual
1Network Device Driver Environment
1.1
1.2
1.2.1
1.2.2
1.2.3
1.2.4
1.3
1.4
1.5
1.6
1.7
1.8
1.9
1.10
1.11
Include Files Section for a Network Driver .......................1–3
Declarations Section for a Network Driver .......................1–4
External and Forward Declarations ..........................1–5
Declaring softc and controller Data Structure Arrays ......1–6
Declaring and Initializing the driver Data Structure ......1–7
This manual discusses how to write network device drivers for computer
systems that run the Compaq Tru64™ UNIX operating system.
Audience
This manual is intended for systems engineers who:
•Use standard library routines to develop programs in the C language
•Know the Bourne shell or some other shell that is based on the UNIX
•Understand basic Tru64 UNIX concepts such as kernel, shell, process,
•Understand how to use the Tru64 UNIX programming tools, compilers,
•Develop programs in an environment that involves dynamic memory
•Understand the hardware device for which the driver is being written
•Understand the basics of the CPU hardware architecture, including
About This Manual
operating system
configuration, and autoconfiguration
and debuggers
allocation, linked list data structures, and multitasking
interrupts, direct memory access (DMA) operations, and I/O
Before you write a network device driver, we recommend that you be familiar
with the networking subsystem that the Tru64 UNIX operating system
provides. This manual assumes that you are familiar with the following
network interface types:
•Ethernet
•Fiber Distributed Data Interface (FDDI)
•Token Ring
See the Tru64 UNIX Technical Overview for descriptions of the data link
media.
This manual also assumes that you have some knowledge of the Tru64 UNIX
network programming environment, particularly:
•Data link provider interface
•X/Open transport interface
•Sockets
About This Manual xi
•Socket and XTI programming examples
•TCP specific programming information
•Information for Token Ring driver developers
•Data link interface
See the Tru64 UNIX Network Programmer’s Guide for descriptions of these
topics.
Scope of this Manual
This manual builds on the concepts and topics that are presented in Writing
Device Drivers, which is the core manual for developing device drivers on
Tru64 UNIX. It introduces topics that are specific to writing a device driver
for a local area network (LAN) device and that are beyond the scope of the
core manual.
In this manual, you can study a network driver called if_el. The if_el
driver supports the driver interface requirements for a LAN device,
specifically the 3Com 3C589C series PCMCIA adapter. The if_el driver
was implemented according to the specifications detailed in Ethernet III
Parallel Tasking ISA, EISA, Micro Channel, and PCMCIA Adapter Drivers
Technical Reference . This specification is published by 3Com Corporation,
and the manual part number is 09-0398-002B.
You can access the if_el source code in the device driver examples directory
(if you have installed it on your system). Ethernet is the network interface
type that is associated with the if_el driver. However, the explanations
point out where differences exist between Ethernet and other network
interfaces, including fiber distributed data interface (FDDI) and Token Ring.
The example network driver operates on multiple buses (specifically, the
PCMCIA bus and the ISA bus). It uses the common ifnet interface to
communicate with the upper layers of the Tru64 UNIX operating system.
The example does not emphasize any specific types of network device
drivers. However, mastering the concepts presented in this manual is useful
preparation for writing network device drivers that operate on a variety
of buses.
The manual does not discuss:
•How to write STREAMS network device drivers
•Topics associated with wide area networks (WANs)
•How to write an asynchronous transfer mode (ATM) device driver
•Details related to the network programming environment
xii About This Manual
New and Changed Features
This revision of the manual documents the following new features:
•Enabling support for enhanced hardware management
Enhanced hardware management (EHM) allows you to modify hardware
attributes, such as the type of LAN device, on either a local or a remote
system. See
Section 3.2 for more information about how a network device
driver uses routines to define and export hardware attributes.
•The unattach( ) routine
The unattach( ) routine stops the network device and frees resources
prior to unloading the device driver or powering off the bus to which the
device is attached. See Chapter 7 for more information.
Organization
This manual is organized as follows:
Chapter 1Describes the sections that make up a
Chapter 2Describes the device register offset
Chapter 3Describes how to define a softc data
Chapter 4Describes how to implement a
Chapter 5Describes how to implement a probe
Chapter 6Describes how to implement an attach
Chapter 7Describes how to implement an
network driver and compares them to
the sections that are associated with
block and character drivers.
definitions for the if_el device driver’s
associated LAN device, the 3Com 3C5x9
series Ethernet adapter.
structure, usingthe if_el devicedriver’s
el_softc structure as an example.
configure interface, using the if_el
device driver’s el_configure( )
routine as an example.
interface and associated routines, using
the if_el device driver’s el_probe( )
routine as an example.
interface, using the if_el device driver’s
el_attach( ) routine as an example.
unattach( ) routine to stop the device.
About This Manual xiii
Chapter 8Describes how to implement an init
interface and associated routines, using
the if_el device driver’s el_init( )
routine as an example.
Chapter 9Describes how to implement a start
interface and associated routines, using
the if_el device driver’s el_start( )
routine as an example.
Chapter 10Describes how to implement a watchdog
Chapter 11Describes how to implement a reset
Chapter 12Describes how to implement an ioctl
Chapter 13
Chapter 14Describes the sysconfigtab option
interface, using the if_el device driver’s
el_watch( ) routine as an example.
interface and associated routines, using
the if_el device driver’s el_reset( )
routine as an example.
interface, using the if_el device driver’s
el_ioctl( ) routine as an example.
Describes how to implement an
interrupt handler, using the if_el
device driver’s el_intr interrupt
handler as an example.
entries necessary for configuring network
device drivers on different bus types.
Related Documentation
The following examples and documents supplement information in this
manual.
Examples
The directory /usr/examples/ddk/src/network includes the example
source files that are used throughout this manual: if_el.c, if_elreg.h,
files, and sysconfigtab.
Manuals
The following documents provide important information that supplements
the information in this manual:
•Installation Instructions and Release Notes contains instructions on how
to install the Device Driver Kit Version 2.0 product, including source
code with examples and user manuals. It also describes changes to the
product and documentation since the Device Driver Kit Release 1.0.
xiv About This Manual
•Writing Device Drivers contains information that you need to develop
device drivers on the Compaq Tru64 UNIX operating system.
•Writing Kernel Modules describes topics for all kernel modules
such as kernel threads and writing kernel modules in a symmetric
multiprocessing (SMP) environment.
•Writing PCI Bus Device Drivers describes PCI bus-specific topics,
including PCI bus architecture and data structures that PCI bus device
drivers use.
•Writing VMEbus Device Drivers describes VMEbus-specific topics,
including VMEbus architecture and routines that VMEbus device
drivers use.
•The Guide to Preparing Product Kits describes how to create kernel
(device driver) product kits and layered product kits.
•Kernel Debugging describes how to use the
debuggers to find problems in kernel code. It also describes how to write
a kdbx utility extension and how to create and analyze a crash dump file.
•Programming Support Tools describes several commands and utilities in
the Tru64UNIX system, including facilities for text manipulation, macro
and program generation, and source file management.
•The Programmer’s Guide describes the programming environment of the
Tru64 UNIX operating system, with an emphasis on the C programming
language.
dbx, kdbx, and kdebug
•The Network Programmer’s Guide describes the Tru64 UNIX network
programming environment and provides information on STREAMS
programming.
•System Administration describes how to configure, use, and maintain
the Tru64 UNIX operating system.
Reference Pages
Tru64 UNIX reference pages (also called manpages) contain descriptions of
the routines (Section 9r), data structures (Section 9s), loadable services
routines (Section 9u), and global variables (Section 9v) that apply to device
drivers.
Reader’s Comments
Compaq welcomes any comments and suggestions you have on this and
other Tru64 UNIX manuals.
•Internet electronic mail: readers_comment@zk3.dec.com
A Reader’s Comment form is located on your system in the following
location:
/usr/doc/readers_comment.txt
Please include the following information along with your comments:
•The full title of the book and the order number. (The order number is
printed on the title page of this book and on its back cover.)
•The section numbers and page numbers of the information on which
you are commenting.
•The version of Tru64 UNIX that you are using.
•If known, the type of processor that is running the Tru64 UNIX software.
The Tru64 UNIX Publications group cannot respond to system problems
or technical support inquiries. Please address technical questions to your
local system vendor or to the appropriate Compaq technical support office.
Information provided with the software media explains how to send problem
reports to Compaq.
Conventions
This manual uses the following conventions:
.
.
.
...
file
buf
[]
xvi About This Manual
A vertical ellipsis indicates that a portion of an
example that would normally be present is not
shown.
In syntax definitions, a horizontal ellipsis indicates
that the preceding item can be repeated one or
more times.
Italic (slanted) type indicates variable values,
placeholders, and function parameter names.
In function definitions and syntax definitions used in
driver configuration, this typeface indicates names
that you must type exactly as shown.
In formal parameter declarations in function
definitions and in structure declarations, brackets
indicate arrays. Brackets also specify ranges for
device minor numbers and device special files in
file fragments. However, for the syntax definitions
that are used in driver configuration, these brackets
indicate items that are optional.
|Vertical bars separating items that appear in the
syntax definitions used in driver configuration
indicate that you choose one item from among those
listed.
About This Manual xvii
1
Network Device Driver Environment
A network device is responsible for both transmitting and receiving frames
over the network media. Network devices have network device drivers
associated with them. A network device driver attaches a network subsystem
to a network interface, prepares the network interface for operation, and
governs the transmission and reception of network frames over the network
interface. Examples of network interface types include Ethernet, Fiber
Distributed Data Interface (FDDI), and Token Ring.
Similar to the character and block device drivers that are discussed in
Writing Device Drivers, a network device driver has the following sections:
•An include files section (Section 1.1)
•A declarations section (Section 1.2)
•A configure section (Section 1.3)
•An autoconfiguration support section (Section 1.4)
•An ioctl section (Section 1.9)
•An interrupt section (Section 1.10)
Similar to a character device driver, a network device driver can also have a
reset section (Section 1.8).
Unlike a character or block device driver, a network device driver contains
the following network driver-specific sections:
•An initialization section (Section 1.5)
•A start transmit section (Section 1.6)
•A watchdog section (Section 1.7)
•An output section (Section 1.11)
Figure 1–1 shows the sections that a typical network device driver can
contain. Network device drivers are not required to have all of these
sections, and more complex network drivers can have additional sections.
However, all network drivers must have a configure section, and because
network device drivers are associated with some device, they also must have
a device register header file.
Network Device Driver Environment 1–1
Figure 1–1: Sections of a Network Device Driver
Network Device Driver
/* Include Files Section */
/* Declarations Section */
/* Configure Section */
/* Initialization Section */
/* Autoconfiguration Support Section */
/* Start Transmit Section */
/* Ioctl Section */
/* Interrupt Section */
/* Reset Section */
/* Watchdog Section */
Unlike for block and character drivers, you do not specify network driver
entry points in the dsent data structure. This means that a network
driver has no exposure into the file system and, therefore, has no entry in
the /dev directory. Thus, network drivers do not have block and character
driver-specific interfaces such as open, close, read, write, and strategy.
1–2 Network Device Driver Environment
ZK-0818U-AI
Instead of registering its entry points in a dsent data structure, a network
driver registers its entry points with the upper layers of the Tru64 UNIX
operating system in an ifnet data structure. For example, a network driver
registers entry points for queueing data for transmission and for starting
data transmission.
In addition to storing the entry points for a network driver’s associated
interfaces, the ifnet data structure stores parameter-related information
such as the transmission medium and statistics to track the performance of
the interface and network.
The ifnet data structure also contains a queue of data packets that the
network driver sends to the network device. These packets are linked lists
of mbuf data structures. Each such linked list represents one data packet.
Depending on how a network driver fills in certain members of the ifnet
data structure, the upper-level network code fragments the data to be sent
out over a network. In the case of the Ethernet network interface, the
upper-level code never hands off to the driver a single packet that exceeds
1514 bytes.
1.1 Include Files Section for a Network Driver
A network device driver includes header files that define data structures
and constant values that the driver references. A network device driver
includes some of the same files as a block or character device driver, such as
errno.h. It can also include the header files that are specific to network
device drivers. For example:
1Includes the ioctl.h include file, which defines common ioctl com-
3
4
5
6
7
mands. The ioctl.h file is located in /usr/include/sys/ioctl.h.
2Includes the sysconfig.h header file, which defines the constants that
all device drivers use during configuration. The sysconfig.h file is
located in /usr/include/sys/sysconfig.h.
3Includes the if_ether.h header file, which defines the ether_header
data structure. All network drivers typically include this file.
If you are writing the network driver for FDDI media, you also include
the header file if_fddi.h. If you are writing the network driver for
Token Ring media, you also include the header file if_trn.h.
4Includes the devdriver.h header file, which defines common device
driver data structures and constants. The devdriver.h file is located
in /usr/include/io/common/devdriver.h.
5Includes the header file eisa.h, which is associated with the ISA bus.
If you are writing the driver to operate on multiple bus architectures,
you must include the bus-specific header file. The if_el device driver
is implemented to operate on two buses: the ISA and the PCMCIA.
6Includes the header files pcmcia.h and cardinfo.h, which are
associated with the PCMCIA bus.
7Includes the lan_common.h file, which contains definitions that all
local area network (LAN) device drivers need.
8Includes the device register header file. The directory specification you
make here depends on where you put the device register header file.
1.2 Declarations Section for a Network Driver
The declarations section for a network device driver contains the following
categories of information:
1–4 Network Device Driver Environment
•External and forward declarations (Section 1.2.1)
•Declaration of softc and controller data structure arrays
(Section 1.2.2)
•Declaration of the driver data structure (Section 1.2.3)
•Definitions of driver-specific macros (Section 1.2.4)
The following sections discuss each of these categories of declarations, using
the if_el device driver as an example.
The declarations section also contains the definition of the softc data
structure and declarations for configure-related variables and data
structures. Chapter 3 discusses the definition of a network driver’s softc
data structure. Section 4.1 discusses the declarations that are related to
configuration.
1.2.1 External and Forward Declarations
The following code shows the external and forward declarations for the
if_el device driver:
int el_configure(cfg_op_t, cfg_attr_t *, size_t, cfg_attr_t *, size_t); 1
1Declares the function prototype definitions for all exported functions.
2Declares the driver interfaces for the if_el device driver.
3Declares the external timeval data structure called time. Various
ioctl commands use this data structure.
Network Device Driver Environment 1–5
4Declares a pointer to the external task_t data structure called
first_task. The task_t data structure is an opaque data structure;
that is, all of its associated members are referenced and manipulated by
the Tru64 UNIX operating system and not by the user of kernel threads.
Every kernel thread must be part of a task.
The if_el driver’s el_probe interface uses this data structure when
it creates a kernel thread.
1.2.2 Declaring softc and controller Data Structure Arrays
The following code shows the declarations for the el_softc and
controller data structure arrays. The system uses these arrays to find out
which softc and controller data structures are associated with a specific
3Com 3C5x9 device. The driver’s el_probe interface initializes these arrays
if the probe operation is successful.
The arrays of el_softc and controller data structures need to be static
for the if_el device driver. Be aware that static arrays fix the maximum
number of devices that the user can configure on the system.
static int el_isa_tag = 0; 4
static int el_isa_reset = 0; 5
decl_simple_lock_info(static, el_lock_info); 6
1Defines a constant called el_MAXDEV, which allocates data structures
that the if_el device driver needs. A maximum of seven instances of
the 3C5x9 controller can be on the system. This means that el_MAXDEV
is the maximum number of controllers that the if_el driver can
support. This is a small number of instances of the driver, and the data
structures themselves are not large, so it is acceptable to allocate for the
maximum configuration.
2Declares an array of pointers to el_softc data structures and calls it
el_softc. The el_MAXDEV constant specifies the size of this array.
3Declares an array of pointers to controller data structures and calls
it el_info. The el_MAXDEV constant specifies the size of this array.
4Declares a variable called el_isa_tag and initializes it to the value
0 (zero). The if_el driver’s el_isa_activate interface uses this
variable.
5Declares a variable called el_isa_reset and initializes it to the value
0 (zero). The if_el driver’s el_probe interface uses this variable.
6Uses the decl_simple_lock_info( ) routine to declare a simple lock
data structure called el_lock_info.
1–6 Network Device Driver Environment
1.2.3 Declaring and Initializing the driver Data Structure
The following code shows how the if_el device driver declares and
initializes the driver data structure with the names of its entry points:
1Declares and initializes the driver data structure called eldriver.
Because a network device driver does not have exposure to the file
system, it does not provide open, close, read, write, and strategy
interfaces. The members of the driver data structure that specify
these entry points are initialized to 0 (zero).
The if_el driver initializes the following members to nonzero values:
•probe, which specifies the driver’s probe interface, el_probe
•cattach, which specifies the driver’s controller attach interface,
el_attach
•ctlr_name, which specifies the controller name, el
•ctlr_list, which specifies a pointer to the array of pointers to
controller data structures, el_info
•ctlr_unattach, which specifies the driver’s controller unattach
interface, el_unattach
1.2.4 Defining Driver-Specific Macros
To help you write more portable device drivers, Tru64 UNIX provides the
following kernel routines, which allow you to read from and write to a
control status register (CSR) address without directly accessing its device
registers. These macros call the read_io_port( ) or write_io_port( )
generic routines.
Network Device Driver Environment 1–7
READ_BUS_D8
READ_BUS_D16
READ_BUS_D32
READ_BUS_D64
WRITE_BUS_D8
WRITE_BUS_D16
WRITE_BUS_D32
WRITE_BUS_D64
Reads a byte (8 bits) from a device register.
Reads a word (16 bits) from a device register.
Reads a longword (32 bits) from a device register.
Reads a quadword (64 bits) from a device register.
Writes a byte (8 bits) to a device register.
Writes a word (16 bits) to a device register.
Writes a longword (32 bits) to a device register.
Writes a quadword (64 bits) to a device register.
The following code shows how the if_el driver uses the READ_BUS_D16,
READ_BUS_D32, WRITE_BUS_D16, and WRITE_BUS_D32 kernel routines to
construct driver-specific macros to perform read and write operations on the
3Com 3C5x9 device:
1Constructs driver-specific macros to read from and write to the 3Com
3C5x9 device’s CSRs.
The first argument to these macros specifies an I/O handle that
references a device register or memory that is located in bus address
space (either I/O space or memory space). You can perform standard
C mathematical operations (addition and subtraction only) on the I/O
handle. The READ_CCR, WRITE_CCR, and the other macros construct
the first argument by referencing the I/O handle that is defined in the
el_softc data structure.
1–8 Network Device Driver Environment
The second argument to the WRITE_CCR and the other write macros
specifies the data to be written to the device register in bus address
space. These write macros construct the second argument by referencing
the val variable. For the if_el driver, this data is typically one of the
device register offsets that is defined in the if_elreg.h file.
The read and write driver-specific macros call the mb( ) kernel routine
to perform a memory barrier. The mb( ) kernel routine ensures that
the read or write operation is issued before the CPU executes any
subsequent code. See Section 7.5 of the Tru64 UNIX
Writing Device
Drivers manual for more information about the mb( ) routine and
when to use it.
Table 1–1 provides information on the driver-specific macros.
Table 1–1: Driver-Specific Macros
MacroDescription
READ_CCR and WRITE_CCR Read from and write to the 3Com 3C5x9 device’s
configuration control register.
READ_ACR and WRITE_ACR Read from and write to the 3Com 3C5x9 device’s
address control register.
WRITE_RCR
WRITE_ECR
READ_EDR
WRITE_CMD
READ_STS
READ_DATA and
WRITE_DATA
READ_ND and WRITE_NDRead from and write to the 3Com 3C5x9 device’s
READ_MD and WRITE_MDRead from and write to the 3Com 3C5x9 device’s media
READ_TXF and READ_RXFRead from the 3Com 3C5x9 device’s transmit and
WRITE_AD1, WRITE_AD2,
and WRITE_AD3
READ_TXS and WRITE_TXS Read from and write to the 3Com 3C5x9 device’s
Write to the 3Com 3C5x9 device’s resource
configuration register.
Write to the 3Com 3C5x9 device’s EEPROM command
register.
Read from the 3Com 3C5x9 device’s EEPROM data
register.
Write to the 3Com 3C5x9 device’s command port
registers.
Read from the 3Com 3C5x9 device’s I/O status register.
Read from and write to the 3Com 3C5x9 device’s
receive data and transmit data registers.
network diagnostic register.
type and status register.
receive FIFO registers.
Set the LAN physical address for the 3Com 3C5x9
device.
transmit status register.
Network Device Driver Environment 1–9
Table 1–1: Driver-Specific Macros (cont.)
MacroDescription
READ_RXS
READ_FDP
Read from the 3Com 3C5x9 device’s receive status
register.
Read from the 3Com 3C5x9 device’s FIFO diagnostic
port register.
1.3 Configure Section for a Network Driver
The configure section for a network device driver contains a configure
interface. The cfgmgr framework calls the driver’s configure interface
at system startup to handle static configuration requests. The cfgmgr
framework can also call the driver’s configure interface to handle
user-level requests to dynamically configure, unconfigure, query, and
reconfigure a device driver at run time. If you implement the driver as a
single binary module, the configure interface can handle both static and
dynamic configuration.
1.4 Autoconfiguration Support Section for a Network Driver
The autoconfiguration support section for a network device driver contains
the following entry points:
•A probe interface, which determines if the network device exists and is
functional on the system
•An attach interface, which establishes communication with the device
and initializes the driver’s ifnet data structure.
You define the entry point for each of these interfaces in the driver data
structure.
1.5 Initialization Section for a Network Driver
The initialization section for a network device driver prepares the network
to transmit and receive data packets.
1.6 Start Section for a Network Driver
The start section for a network device driver contains a start interface,
which transmits data packets on the network interface. You define the
entry point for the start interface in the ifnet data structure. However,
before this interface can be called, the network adapter must be enabled for
data packet transmission and reception. You enable the network adapter
by invoking the SIOCSIFADDR ioctl command.
1–10 Network Device Driver Environment
1.7 Watchdog Section for a Network Driver
The watchdog section for a network device driver contains a watchdog
interface, which attempts to restart the adapter. The watchdog interface is
optional in a network device driver. If the network device driver implements
it, watchdog is called by a kernel thread if the driver’s interrupt handler has
not shut down the countdown timer within a certain number of seconds of
queueing a data packet for transmission from the upper layer. This indicates
that the adapter is no longer on line.
1.8 Reset Section for a Network Driver
The reset section for a network device driver contains a reset interface.
The reset interface resets the LAN adapter. This interface is called to
restart the device following a network failure. This interface resets all of the
counters and local variables. It can also free up and reallocate all of the
buffers that the network driver uses.
1.9 ioctl Section for a Network Driver
The ioctl section for network device drivers performs miscellaneous tasks
that have nothing to do with data packet transmission and reception.
Typically, these tasks relate to turning specific features of the hardware
on or off.
The ioctl section contains an ioctl interface. You define this entry point in
the ifnet data structure.
1.10 Interrupt Section for a Network Driver
The interrupt section for a network device driver contains an interrupt
handler. The interrupt handler processes network device interrupts. You
define the entry point for the interrupt handler by calling the handler
interfaces. The interrupt handler is called each time that the network
interface receives an interrupt. After identifying which type of interrupt was
received — transmit or receive — the interrupt handler calls the appropriate
routine to process the interrupt.
1.11 Output Section for a Network Driver
The output section for a network device driver formats a data packet for
transmission on the network. The ether_output( ) routine formats
data packets for Tru64 UNIX network drivers. Despite its name,
ether_output( ) handles the frame formats for Ethernet, token ring, and
FDDI. After it has properly formatted the data packet, ether_output( )
enqueues the packet on the driver’s send queue and calls the driver’s start
Network Device Driver Environment 1–11
interface to transmit the data. All network drivers must set the output
member of the ifnet data structure to ether_output.
1–12 Network Device Driver Environment
2
Defining Device Register Offsets
The device register header file defines the device register offsets for the
device. The if_elreg.h file is the device register header file for the if_el
device driver. It defines the device register offsets for the 3Com 3C5x9 series
Ethernet adapter. Specifically, the if_elreg.h file contains the following
categories of device registers:
•Interrupt and status register (Section 2.1)
•Command port registers (Section 2.2)
•Window 0 configuration registers (Section 2.3)
•Window 3 configuration registers (Section 2.4)
•Window 1 operational registers (Section 2.5)
•Window 4 diagnostic registers (Section 2.6)
•EEPROM data structure definition (Section 2.7)
Your network device might have different device registers. However, this
device register header file can serve as an example of how to set up device
register offset definitions. See your network device documentation to learn
about control and status registers for your device.
2.1 Interrupt and Status Register Offset Definitions
The following code shows the offset definitions for the interrupt and status
register. The if_el device driver reads these offsets from the interrupt
and status register. The CMD_ACKINT, CMD_SINTMASK, and CMD_ZINTMASK
commands either set or clear the bits.
1Defines the offset for the I/O port of the interrupt and status register.
This register can be set to one or more of the bit values.
Defining Device Register Offsets 2–1
2Defines the interrupt latch bit position.
3Defines the adapter failure bit position.
4Defines the transmit complete bit position.
5Defines the transmit available bit position.
6Defines the receive complete bit position.
7Defines the receive early bit position.
8Defines the interrupt request bit position.
9Defines the update statistics bit position.
10Defines the command in-progress bit position.
11Defines the current window number bit position.
2.2 Command Port Register Offset Definitions
The following code shows the offset definitions for the command port
register. Bits 0:10 contain optional parameter bits and bits 11:15 contain
the command.
1Defines the offset for the I/O port of the command port register.
2Defines the reset command bit position.
3Defines the window selector for commands that are used to set up the
device.
4Defines the window selector for commands that control the operation of
the device.
5Defines the window selector for specifying the hardware address of
the device.
6Defines the window selector for the device’s first-in/first-out (FIFO)
buffer.
7Defines the window selector for commands that are used for diagnostic
purposes.
8Defines a second window selector for commands that are used for
diagnostic purposes.
9Defines the window selector for commands that are related to gathering
device statistics.
10Defines the start 10Base2 Ethernet cable command.
11Defines the receive (RX) disable command.
12Defines the receive (RX) enable command.
13Defines the receive (RX) reset command.
14Defines the receive (RX) discard top packet command.
15Defines the transmit (TX) enable command.
16Defines the transmit (TX) disable command.
17Defines the transmit (TX) reset command.
18Defines the request interrupt command.
19Defines the acknowledge interrupt command.
20Defines the set interrupt mask command.
21Defines the clear interrupt command.
22Defines the receive (RX) filter command.
Defining Device Register Offsets 2–3
23Defines an enumerated data type called rx_filter. The if_el device
driver can assign one of the following values to CMD_FILTER:
RF_IND
RF_GRP
RF_BRD
RF_PRM
24Defines the receive (RX) early threshold command.
25Defines the transmit (TX) available threshold command.
26Defines the transmit (TX) start threshold command.
27Defines the statistics enable command.
28Defines the statistics disable command.
29Defines the stop 10Base2 Ethernet cable command.
30Defines the receive (RX) reclaim threshold command.
31Defines the power-up command.
32Defines the power-down command.
33Defines the power-auto command.
Individual address
Group address
Broadcast address
Promiscuous address
1Defines the offset for the manufacturer ID register.
2Defines the offset for the adapter ID register.
3Defines the offset for the configuration control register.
4Defines an enumerated data type called w0_ccr. The if_el
11
device driver can assign one of the following values to W0_CCR (the
configuration control register):
CCR_PCMCIA
CCR_AUI
CCR_10B2
CCR_ENDEC
Ifset, this isa PCMCIAbus. Otherwise,it is anISA bus.
If set, the attachment unit interface (AUI) is available.
If set, the 10Base2 receiver is available.
If set, the internal encode/decode (ENDEC)
loopback is used.
CCR_RESET
CCR_ENA
5Defines the offset for the address control register.
6Defines an enumerated data type called w0_acr. The if_el device
Reset adapter.
Enable adapter.
driver can assign one of the following values to W0_ACR (the address
control register):
ACR_10BT
ACR_10B5
ACR_10B2
ACR_ROMS
ACR_ROMB
ACR_ASE
ACR_BASE
If set, the information transmission rate is at
10 Mb/sec for the Ethernet unshielded
twisted-pair cable wires.
If set, the information transmission rate is at
10 Mb/sec for the Ethernet thick coaxial cable wire.
The length between repeaters is 500 meters.
If set, the information transmission rate is at 10
Mb/sec for the Ethernet thin coaxial cable wire. The
length between repeaters is 200 meters.
Represents the read-only memory size for the ISA bus.
Represents the read-only memory base for the ISA bus.
Represents the autoselect mode.
Represents the I/O base address.
7Defines the offset for the resource configuration register.
2–6 Defining Device Register Offsets
8Defines an enumerated data type called w0_rcr. The if_el device
driver can assign one of the following bits to W0_RCR (the resource
configuration register):
RCR_IRQ
RCR_RSV
9Defines the offset for the EEPROM command register.
10Defines an enumerated data type called w0_ecr. The if_el device
Represents the interrupt request (IRQ).
Represents a reserved field.
driver can assign one of the following bits to W0_ECR (the EEPROM
command register):
ECR_EBY
ECR_TST
ECR_CMD
ECR_READ
ECR_WRITE
ECR_ERASE
ECR_EWENA
ECR_EWDIS
ECR_EAR
ECR_WAR
Indicates that the EEPROM is busy.
Indicates that the EEPROM is in test mode.
Represents EEPROM command bits.
Represents an EEPROM read command.
Represents an EEPROM write command.
Represents an EEPROM erase command.
Represents an EEPROM enable erase or
write command.
Represents an EEPROM disable erase or
write command.
Represents an EEPROM erase all registers command.
Represents an EEPROM write all registers command.
11Defines the offset for the EEPROM data register.
1Defines the offset for the additional setup information register 2.
2Defines the offset for the additional setup information register 0.
3Defines an enumerated data type called w3_asi. The if_el device
driver can assign one of the following values to w3_ASI2 and w3_ASI0
(the additional setup information registers):
ASI_IAS_ISA
ASI_IAS_PNP
ASI_IAS_BOT
ASI_IAS_NON
ASI_PAR_35
ASI_PAR_13
ASI_PAR_11
ASI_RS
ASI_RW
2–8 Defining Device Register Offsets
Activates ISA bus contention.
Activates ISA bus PNP.
Activates ISA bus contention and PNP.
Indicates neither ISA nor PNP activation.
Uses the RAM partition 3 TX to 5 RX (3:5).
Uses the RAM partition 1 TX to 3 RX (1:3).
Uses the RAM partition 1 TX to 1 RX (1:1).
Indicates the RAM speed.
Indicates the RAM width (which will always
be 0 to 8 bits).
ASI_RSIZE8
ASI_RSIZE32
Indicates a RAM size of 8 kilobytes (the default).
Indicates a RAM size of 32 kilobytes.
The window 1 operational registers include such registers as the receive
status, the transmit status, and the request interrupt registers, as shown in
Figure 2–3.
Figure 2–3: Window 1 Operational Registers
Register
Receive Status Register
Transmit Status Register
Request Interrupt After
Transmit Completion Register
Receive Data Register
Transmit Data Register
Free Transmit Bytes Register
Constant
W1_RXSTAT
W1_TXSTAT
TX_INT
W1_RXDATA
W1_TXDATA
W1_FREETX
ZK-1269U-AI
The following code shows the offset definitions for the window 1 operational
registers:
1Defines the offset for the receive status register.
2Defines an enumerated data type called w1_rxstat. The if_el device
5
driver can assign one of the following values to W1_RXSTAT (the receive
status register):
RX_IC
RX_ER
RX_EM
Indicates an incomplete operation.
Indicates an error in the operation.
If any of the bits are set in the mask, indicates
that an error has occurred.
RX_EOR
RX_ERT
RX_EAL
RX_ECR
RX_EOS
RX_BYTES
3Defines the offset for the transmit status register.
4Defines an enumerated data type called w1_txstat. The if_el
Indicates an overrun error in the operation.
Indicates a run-time error.
Indicates an alignment error.
Indicates a CRC error.
Indicates an oversize error.
Mask used to determine the number of bytes received.
device driver can assign one of the following values to W1_TXSTAT (the
transmit status register):
TX_CM
TX_IS
TX_JB
TX_UN
TX_MC
TX_OF
TX_RE
Indicates that the transmission completed.
Indicates that the device should interrupt when a
transmission is successfully completed.
Indicates a jabber error.
Indicates an underrun. This is a serious error
that requires a reset.
Indicates the maximum number of colli-
sions that occurred.
Indicates an overflow error.
Not currently used.
5Defines the offset for the request interrupt after completion register.
6Defines the offset for the receive data register.
7Defines the offset for the transmit data register.
2–10 Defining Device Register Offsets
8Defines the offset for the free transmit bytes register.
The window 4 operational registers include such registers as the media type
and status register and the network diagnostic port register, as shown in
Figure 2–4.
Figure 2–4: Window 4 Diagnostic Registers
Register
Media Type and Status Register
Network Diagnostic and
Constant
W4_MEDIA
W4_NET
Status Register
ZK-1270U-AI
The following code shows the definitions for the window 4 diagnostic
registers:
1Defines the offset for the media type and status register.
Defining Device Register Offsets 2–11
2Defines an enumerated data type called w4_media. The if_el device
driver can assign one of the following values to W4_MEDIA (the media
type and status register):
MD_TPE
MD_COAXE
MD_RES1
MD_SQE
MD_VLB
MD_PRD
MD_JAB
MD_UNSQ
MD_LBE
MD_JABE
MD_CS
MD_COLL
MD_SQEE
MD_NCRC
3Defines the offset for the network diagnostic port register.
4Defines an enumerated data type called w4_net. The if_el device
Indicates that 10BaseT cable is enabled.
Indicates that 10Base2 cable is enabled.
Reserved.
Indicates that SQE is present.
Indicates that a valid link beat was detected.
Indicates that polarity reversal was detected.
Indicates that jabber was detected.
Indicates unsequelch.
Indicates that link beat was enabled.
Indicates that jabber was enabled.
Indicates that carrier sense was detected.
Indicates that collisions occurred.
Indicates that SQE stats were enabled.
Indicates that the CRC strip was disabled.
driver can assign one of the following values to W4_NET (the network
diagnostic port register):
ND_EXT
ND_ENDEC
ND_ECL
ND_LOOP
ND_TXE
ND_RXE
ND_TXB
ND_TXRR
ND_STATE
ND_REV
ND_LOW
2–12 Defining Device Register Offsets
Indicates external loopback.
Indicates encode/decode (ENDEC) loopback.
Indicates Ethernet controller loopback.
Indicates FIFO loopback.
Indicates that TX is enabled.
Indicates that RX is enabled.
Indicates that TX is busy.
Indicates that TX reset is required.
Indicates that statistics are enabled.
Indicates the ASIC revision.
Not currently used.
2.7 EEPROM Data Structure Definition
The following code shows the definition for the w3_eeprom data structure.
This data structure stores information about the 3Com 3C5x9 device.
struct w3_eeprom { 1
unsigned short addr[3];
unsigned short pid;
unsigned short mandata[3];
unsigned short mid;
unsigned short addrconf;
unsigned short resconf;
unsigned short oem[3];
unsigned short swinfo;
unsigned short compat;
unsigned short cs1;
unsigned short cw2;
unsigned short res1;
unsigned inticw;
unsigned short swinfo2;
unsigned short res[2];
unsigned short cs2;
unsigned short pnp[40];
};
1Defines an EEPROM data structure called w3_eeprom. This data
structure has the following members:
addr
pid
mandata
mid
addrconf
resconf
oem
swinfo
compat
cs1
cw2
res1
icw
swinfo2
res
cs2
pnp
Contains the local area network (LAN) address.
Contains the product ID.
Contains manufacturing data.
Contains the manufacturer ID.
Contains the address configuration.
Contains the resource configuration.
Contains original equipment manufacturer
(OEM) address fields.
Contains software information.
Contains a compatibility word.
Contains the first part of the checksum.
Contains a second compatibility word.
Reserved.
Contains an internal configuration word.
Contains secondary software information.
Reserved.
Contains the second part of the checksum.
Contains plug-and-play data.
Defining Device Register Offsets 2–13
Defining the softc Data Structure
All network device drivers define a softc data structure to contain the
software context of the network device driver and to allow the driver
interfaces to share information.
A softc data structure contains the following information:
•Common information (Section 3.1)
•Enhanced hardware management (EHM) support (Section 3.2)
•Media state information (Section 3.3)
•Base register definition (Section 3.4)
•Multicast table information (Section 3.5)
•Interrupt handler ID declaration (Section 3.6)
•CSR pointer information (Section 3.7)
•FIFO maintenance information (Section 3.8)
•Bus-specific information (Section 3.9)
•Broadcast flag definition (Section 3.10)
3
•Debug flag definition (Section 3.11)
•Interrupt and timeout statistics (Section 3.12)
•Autosense kernel thread context information (Section 3.13)
•Polling context flag definition (Section 3.14)
•w3_eeprom data structure definition (Section 3.15)
•Simple lock data structure declaration (Section 3.16)Figure 3–1 shows a typical softc data structure.
Defining the softc Data Structure 3–1
Figure 3–1: Typical softc Data Structure
Common Information
*
Enhanced Hardware Management Information
*
Media State Information
**
Base Register
*
Multicast T ab le Information
*
Interrupt Handler ID
*
CSR Pointer Information
*
FIFO Maintenance Information
**
Bus-Specific Information
**
Broadcast Flag
**
Debug Flag
**
Interrupt and Timeout Information
**
Autosense Kernel Thread
**
Context Information
Polling Context Flag
**
w3_eeprom Structure
**
Simple Lock Structure
*
A single asterisk denotes information that all network device drivers provide
in the associated softc data structure, and a double asterisk denotes
information that is specific to the hardware or bus.
3.1 Defining Common Information
The common information in a local area network driver’s softc data
structure is contained in the ether_driver data structure, which consists
of information such as counter blocks, media state, media values, and so
forth. The following code shows the declaration and definition of the common
information in the if_el device driver’s el_softc data structure. Make
sure that the common part of your softc data structure has the same
declaration and definitions.
1Declares an instance of the ether_driver data structure and calls
it is_ed. All network drivers must have an ether_driver data
structure. By convention, a pointer to this data structure is the first
element in the softc data structure.
2Maps the ess_ac member of the ether_driver data structure to
the alternate name is_ac. The ess_ac member is referred to as the
“Ethernet common part” and is actually an instance of the arpcom data
structure. Figure 3–2 shows the is_ac alternate name and associated
mapping.
3Maps the ess_ztime member of the ether_driver data structure to
the alternate name ztime. The ess_ztime member stores the time
counters that were last zeroed. Figure 3–2 shows the ztime alternate
name and associated mapping.
4Maps the ess_ctrblk member of the ether_driver data structure
to the alternate name ctrblk. The ess_ctrblk member is referred
to as the “counter block” and is actually an instance of the estat data
structure. Figure 3–2 shows the ctrblk alternate name and associated
mapping.
You must define this line in your network device driver if you plan to
use ADD_RECV_MPACKET, ADD_RECV_PACKET, ADD_XMIT_MPACKET,
and ADD_XMIT_PACKET for maintaining LAN device counters. Each of
these macros references the ctrblk alternate name.
5Maps the ac_if member of the arpcom data structure to the alternate
name is_if. The ac_if member is referred to as the “network-visible
interface” and is actually an instance of the ifnet data structure.
Figure 3–2 shows the is_if alternate name and associated mapping.
6Maps the ac_enaddr member of the arpcom data structure to the
alternate name is_addr. The name ac_enaddr is actually an alternate
name for ac_hwaddr, which is the name of the actual member of
the arpcom data structure that stores the hardware address. The
if_ether.h file defines the ac_enaddr alternate name. Figure 3–2
shows the is_addr alternate name and associated mapping.
Defining the softc Data Structure 3–3
Figure 3–2: Mapping Alternate Names
#define is_ac
#define ztime
#define ctrblk
#define is_addr
ether_driver
.
.
.
ess_ac
ess_ztime
ess_ctrblk
.
.
.
arpcom
.
.
.
ac_if
ac_hwaddr
.
.
.
#define is_if
#define ac_enaddr
ZK-1274U-AI
3.2 Enabling Support for Enhanced Hardware Management
Enhanced hardware management (EHM) is a feature of Tru64 UNIX
Version 5.0 that allows a system administrator to view, and possibly modify,
various attributes of the hardware on either a local or a remote system.
To support this facility, device drivers and bus drivers must provide their
specific, predefined attributes to a centralized management entity. Examples
of these attributes for network drivers include the type of LAN device, its
hardware address, the type of media it is attached to, and how fast it can
operate. The LAN subsystem supplies access routines for defining and
exporting these attributes.
To use these routines, a network driver must declare a net_hw_mgmt data
structure as shown by the following code:
struct net_hw_mgmtehm; 1
1Declares a net_hw_mgmt data structure and calls it ehm.
3.3 Defining Media State Information
The media state information contained in a network driver’s softc data
structure consists of information about the lan_media data structure.
The following code shows the declaration and definition of the media state
information in the if_el device driver’s el_softc data structure:
1Declares a lan_media data structure and calls it lan_media. The
lan_media data structure contains media state values.
2Defines an alternate name for referencing the lan_media_mode
member of the lan_media data structure. The value that is stored in
3–4 Defining the softc Data Structure
lan_media_mode usually reflects how the media is to be selected. (In
contrast, the value that is stored in the lan_media member reflects the
current setting of the device.) Typically, you set this member in the
driver’s probe interface to the media mode constant that identifies the
mode for the media.
The lan_common.h file defines two enumerated data types called
media_types and media_modes. You can set the lan_media_mode
member to one of the following values, which are defined by the
media_types and media_modes enumerated data types:
LAN_MEDIA_UTP
LAN_MEDIA_BNC
LAN_MEDIA_STP
LAN_MEDIA_FIBER
LAN_MEDIA_AUI
LAN_MEDIA_4PAIR
LAN_MODE_AUTOSENSE
3Defines an alternate name for referencing the lan_media_state
The mode for the media is unshielded
twisted-pair cable.
The mode for the media is thin wire.
The mode for the media is shielded
twisted pair cable.
The mode for the media is any
fiber-based media.
The mode for the media is the attachment
unit interface (AUI).
The mode for the media is four-pair cable.
The hardware determines the media.
member of the lan_media data structure. The lan_media_state
member will be set only if lan_media_mode has the value
LAN_MODE_AUTOSENSE. This member is typically set in the driver’s
probe( ) routine.
The lan_media_state member can be set to one of the following
constants, which are defined in the lan_common.h file:
LAN_MEDIA_STATE_SENSING
LAN_MEDIA_STATE_DETERMINED
Themedia is currently inthe autosensing state.
The media state has been determined.
4Defines an alternate name for referencing the lan_media member
of the lan_media data structure. The lan_media member specifies
the currently set media.
The value that is stored in the lan_media member is valid in the
autosense mode only if the lan_media_state member is set to the
constant LAN_MEDIA_STATE_DETERMINED. The value that is stored in
lan_media reflects the current setting of the device. (In contrast, the
value that is stored in the lan_media_mode member usually reflects
how the media is to be selected.) Typically, you set the lan_media
Defining the softc Data Structure 3–5
member in the driver’s probe interface to the media state constant that
identifies the state for the media.
You can set the lan_media member to the same constants that are
listed for the lan_media_mode member in item 2.
3.4 Defining the Base Register
The base register in a network driver’s softc data structure is a member
that represents the base register of the device. The following code shows
the declaration of the base register in the if_el device driver’s el_softc
data structure. Most network device drivers declare a variable to store the
device’s base register.
vm_offset_t basereg; 1
1Declares a base register member and calls it basereg.
3.5 Defining Multicast Table Information
All multicast address information in a network driver’s softc data structure
is encapsulated in the lan_multi data structure. The following code shows
the declaration of the lan_multi data structure in the if_el device driver’s
el_softc data structure. Most network device drivers declare this data
structure in their softc data structure.
struct lan_multi is_multi;
1
1Declares a lan_multi data structure and calls it is_multi.
3.6 Defining the Interrupt Handler ID
The interrupt handler ID in a network driver’s softc data structure is a
variable that stores the interrupt handler ID that the handler_add( )
routine returns. The following code shows the declaration of the interrupt
handler ID in the if_el device driver’s el_softc data structure. Make
sure that the interrupt handler ID part of your softc data structure has
a similar declaration.
ihandler_id_t *hid;
1Declares a pointer to an ID that deregisters the interrupt handlers.
1
3.7 Defining CSR Pointer Information
The control and status register (CSR) addresses in a network driver’s
softc data structure consist of specific adapter register addresses. These
registers generally consist of the base register plus some offset, as defined
by the network adapter’s hardware specification. Make sure that you never
3–6 Defining the softc Data Structure
access a CSR directly. The driver-specific macros handle the read and write
operations that are made on these device registers.
The following code shows the declarations of the CSR addresses in the if_el
device driver’s el_softc data structure. Make sure that the CSR pointer
information part of your softc data structure has similar declarations.
io_handle_t regE; 1
io_handle_t regC;
io_handle_t regA;
io_handle_t reg8;
io_handle_t reg6;
io_handle_t reg4;
io_handle_t reg2;
io_handle_t reg0;
io_handle_t data;
1Declares the CSR addresses for the if_el driver. These addresses are
computed during the probe( ) routine by adding the specified offset
(0xE, 0xC, 0xA, and so forth) to the base address.
3.8 Defining FIFO Maintenance Information
The first-in/first-out (FIFO) maintenance information in the if_el driver’s
el_softc data structure consists of a variable that stores a value that
the device keeps on board. The following code shows its declaration. This
information is hardware-specific, so you can omit it from your network
device driver’s softc data structure.
unsigned long txfree;
3.9 Defining Bus-Specific Information
The bus-specific information in a network driver’s softc data structure
consists of information about the bus or buses on which the driver operates.
The if_el driver operates on the PCMCIA and ISA buses, so that the
information in this section reflects these buses.
The following code shows the bus-specific declarations in the if_el device
driver’s el_softc data structure. The bus-specific information that is
described here may not apply to your network device driver. However, the
declarations do give you an idea of some of the information that a network
driver needs to keep when operating on the PCMCIA and ISA buses.
intirq;
intiobase; 2
intisa_tag; 3
intcardout; 4
intreprobe; 5
intispcmcia; 6
structcard_info *cinfop; 7
1Contains the interrupt request (IRQ) to use.
1
Defining the softc Data Structure 3–7
2Contains the I/O base address.
3Contains a tag value that identifies 3Com 3C5x9 devices on an ISA bus.
4Contains a value that indicates whether the user has ejected the
PCMCIA card.
5Contains a value that indicates whether the user has reloaded the
PCMCIA card.
6Contains a value that indicates whether the card is a PCMCIA card.
7Declares a pointer to the card_info data structure and calls it cinfop.
The card_info data structure contains information that is necessary
to communicate with the kernel PCMCIA subsystem.
3.10 Defining the Broadcast Flag
The broadcast flag in the if_el driver’s el_softc data structure indicates
whether the device should receive broadcast traffic. This flag is specific to
the if_el driver and, therefore, is optional in most network device drivers.
The following code shows the declaration of the broadcast flag in the if_el
device driver’s el_softc data structure:
intis_broadcast; 1
1Contains a boolean value. If true, the broadcast address flag is set.
3.11 Defining the Debug Flag
The debug flag in a network driver’s softc data structure indicates whether
debug mode is on. The following code shows the declaration of the debug
flag in the if_el device driver’s el_softc data structure. The debug flag
is optional.
intdebug;
1Contains the status of the debug flag. If the if_flags member of
1
the ifnet data structure pointer is set to IFF_DEBUG, debug is on.
Otherwise, debug is off.
3.12 Defining Interrupt and Timeout Statistics
The interrupt and timeout statistics in the if_el driver’s el_softc data
structure consists of information about timeout and interrupt events.
3–8 Defining the softc Data Structure
The following code shows the declarations of the timeout and interrupt
information in the if_el device driver’s el_softc data structure:
unsigned long txreset; 1
unsigned long xmit_tmo; 2
unsigned long tint; 3
unsigned long rint; 4
1
Contains the number of transmitter error resets.
2Contains the number of times that transmit timeouts occurred. The
el_watch( ) routine increments this member.
3Contains the count of transmit interrupts.
4Contains the count of receive interrupts.
3.13 Defining Autosense Kernel Thread Context Information
The autosense kernel thread context information in the if_el driver’s
el_softc data structure consists of information about the kernel thread
that performs the autosense operation. For the if_el driver, this kernel
thread is called el_autosense_thread.
The following code shows the declarations of the autosense kernel thread
variables in the if_el device driver’s el_softc data structure. The if_el
device driver uses kernel threads to perform the tasks that are related to
autosensing the media. However, you can choose other methods instead of
kernel threads.
thread_tautosense_thread;
intautosense_flag; 2
1
1Contains the autosense kernel thread ID.
2Contains the autosense kernel thread blocking flag.
3.14 Defining the Polling Context Flag
A LAN driver typically does not need to perform polling operations. However,
the if_el driver provides an example of how polling operations might be
accomplished.
The polling context flag in a network driver’s softc data structure indicates
whether polling is on or off. The following code shows the declaration of the
polling member in the if_el device driver’s el_softc data structure:
intpolling_flag; 1
1Declares a polling context flag member called polling_flag. This
member stores a boolean value of 1 (polling context is on) or 0 (polling
context is off).
Defining the softc Data Structure 3–9
3.15 Defining a Copy of the w3_eeprom Data Structure
The w3_eeprom data structure copy in the if_el driver’s el_softc
data structure consists of information about the hardware-specific
w3_eeprom data structure. The following code shows the declaration of this
device-specific data structure. If your device has an EEPROM, you might
want to save some or all of its contents in your softc data structure.
struct w3_eeprom eeprom; 1
1Declares a copy of the w3_eeprom data structure and calls it eeprom.
3.16 Declaring the Simple Lock Data Structure
A network driver’s softc data structure contains the declaration of a
simple lock data structure. The if_el driver uses a simple lock to protect
the data integrity of the el_softc data structure on multiprocessor
systems. It also guarantees the sequence of register accesses that a CPU in
a multiprocessor system makes to the adapter. See
for more information about locking in an SMP environment.
The following code shows the declaration of the simple lock data structure
in the if_el driver’s el_softc data structure:
decl_simple_lock_data(, el_softc_lock)
1Uses the decl_simple_lock_data( ) routine to declare a simple lock
1
data structure as a member of the el_softc data structure. The simple
lock data structure is called el_softc_lock.
Writing Kernel Modules
3–10 Defining the softc Data Structure
4
Implementing the Configure Section
The configure section of a network device driver contains the code
that incorporates the device driver into the kernel, either statically or
dynamically. In a static configuration, the device driver’s
interface registers callback routines, which allow the cfgmgr framework
to configure the driver into the kernel at a specified point during system
startup. In a dynamic configuration, the configure interface cooperates
with the cfgmgr framework to handle user-level requests to dynamically
configure, reconfigure, and query a network device driver at run time.
Because these tasks are common to all network drivers, the code has been
consolidated into a single routine called lan_configure( ). Routines with
the prefix lan_ reside in the lan_common.c source file. A network driver’s
configure( ) routine can simply call lan_configure( ) to carry out the
following tasks:
•CFG_OP_CONFIGURE
•CFG_OP_RECONFIGURE
•CFG_OP_UNCONFIGURE
•CFG_OP_QUERY
configure
The if_el driver’s configure section contains an attributes data structure
and the el_configure( ) routine.
The following sections describe how to initialize the cfg_subsys_attr_t
data structure and how to set up the el_configure( ) routine:
•Declaring configure-related variables and initializing the
cfg_subsys_attr_t data structure (Section 4.1)
•Setting up the el_configure( ) routine (Section 4.2)
4.1 Declaring Configure-Related Variables and the
cfg_subsys_attr_t Data Structure
As part of implementing a device driver’s configure interface, you declare a
number of variables and initialize the cfg_subsys_attr_t data structure.
Implementing the Configure Section 4–1
The following code shows the declaration of the variables and the
initialization of the cfg_subsys_attr_t data structure for the if_el
device driver:
1Declares a character array called pcmcia_optiondata and initializes
3
7
(caddr_t)el_pcmcia_optiondata, 0, 400, 0},
(caddr_t)el_isa_optiondata, 0, 300, 0},
(caddr_t)&el_polling, 0, 1, sizeof(int)},
(caddr_t)&el_pollint, 10, 100, sizeof(int)},
9
8
10
11
it to the null string. The pcmcia_optiondata character array is
where the cfgmgr framework stores the value for the PCMCIA_Option
attribute. The cfgmgr framework obtains this value from the
/etc/sysconfigtab database.
2Declares a character array called isa_optiondata and initializes it
to the null string. The isa_optiondata character array is where the
cfgmgr framework stores the value for the ISA_Option attribute. The
cfgmgr framework obtains this value from the /etc/sysconfigtab
database.
3Declares an integer variable called el_polling and initializes it to
the value 0 (zero). The el_polling variable is where the cfgmgr
framework stores the style of interrupt processing for the Polling
attribute. The cfgmgr framework obtains this value from the
/etc/sysconfigtab database.
4Declares an integer variable called el_pollint and initializes it to the
value 16. The el_pollint variable is where the cfgmgr framework
stores the polls per second for the Polls_Per_Second attribute. The
cfgmgr framework obtains this value from the /etc/sysconfigtab
database.
5Declares an integer variable called el_configured and initializes it
to the value 0 (zero). The driver must increment this variable for each
successfully configured el device.
4–2 Implementing the Configure Section
6Declares the lan_config_data structure, which contains all
information specific to the el driver. The lan_configure common
code uses this structure.
7Declares an array of cfg_subsys_attr_t data structures and calls
it el_attributes.
8Describes the PCMCIA_Option attribute, which specifies the option
data for the PCMCIA bus.
9Describes the ISA_Option attribute, which specifies the option data
for the ISA bus.
10Describes the Polling attribute, which is specific to this device driver.
It indicates the style of interrupt processing. The operation code
specifies CFG_OP_CONFIGURE and CFG_OP_QUERY. This means that the
attribute can only be set at configuration time and, after that, only
queried. You can specify a value in the sysconfigtab file fragment
(which is appended to the /etc/sysconfigtab database). The cfgmgr
framework obtains this value from the /etc/sysconfigtab database
and stores it in the el_polling variable.
11Describes the Polls_Per_Second attribute, which is specific to this
device driver. It indicates the polls per second for interrupt processing.
Similar to the Polling attribute, you can only specify a value for
this attribute at configuration time. The cfgmgr framework obtains
this value from the /etc/sysconfigtab database and stores it in
the el_pollint variable.
12Ends the array by specifying the null string.
4.2 Setting Up the el_configure Routine
The following code shows how to set up the el_configure( ) routine:
int el_configure(cfg_op_t op, 1
{
return (lan_configure (op, &el_data));
}
1Declares an argument called op to contain a constant that describes the
configuration operation to be performed on the driver. This argument
evaluates to one of the following valid constants: CFG_OP_CONFIGURE,
CFG_OP_UNCONFIGURE, CFG_OP_QUERY,orCFG_OP_RECONFIGURE.
2Declares a pointer to a cfg_attr_t data structure called indata,
which consists of input to the el_configure( ) routine. The cfgmgr
framework fills in this data structure. The cfg_attr_t data structure
represents a variety of information, including the if_el driver’s
interrupt polling requirements.
3
Declares an argument called indatalen to store the size of this input
data structure. This argument represents the number of cfg_attr_t
data structures included in indata.
4Declares an argument for user-defined configuration operations, which
can occur when the cfgmgr framework calls the driver’s configure
interface with the CFG_OP_USERDEFINED operation code. Typically,
this argument is not used.
5Declares the size of the outdata argument. Typically, this argument
is not used.
6Calls the LAN common driver code to configure the device (either
statically or dynamically).
4–4 Implementing the Configure Section
5
Implementing the Autoconfiguration
Support Section (probe)
The autoconfiguration support section contains the code that implements a
network device driver’s probe interface. A network device driver’s probe
interface determines whether the network device exists and is functional on
a given system. The bus configuration code calls the driver’sprobe interface.
The if_el driver operates on the ISA and PCMCIA bus. For the PCMCIA
bus, it provides a driver-specific routine that is called when a user removes
the card from the slot. For the ISA bus, the driver provides routines to reset,
activate, and read from hardware registers. These routines are specific to
the if_el device driver. To learn how the driver handles these tasks, see
the source listing in the examples directory that is installed with the device
driver kit.
The following sections describe how to use the probe interface:
•Implementing the el_probe( ) routine (Section 5.1)
•Implementing the el_shutdown( ) routine (Section 5.2)
•Implementing the el_autosense_thread( ) routine (Section 5.3)
5.1 Implementing the el_probe Routine
The el_probe( ) routine performs the following tasks:
•Checks the maximum number of devices that the driver supports
(Section 5.1.2)
•Performs bus-specific tasks (Section 5.1.3)
•Allocates memory for the softc and ether_driver data structures
(Section 5.1.4 and Section 5.1.5)
•Initializes the enhanced hardware management data structure
(Section 5.1.6)
•Computes the control and status register addresses (Section 5.1.7)
•Sets bus-specific data structure members (Section 5.1.8)
•If this is the first time the device has been probed, copies data from the
EEPROM, reads and saves the device’s physical address and starts the
autosense kernel thread to determine the media type (Section 5.1.9)
Implementing the Autoconfiguration Support Section (probe) 5–1
•For subsequent probe operations, reads the EEPROM to determine if the
hardware address (and thus the adapter) has changed (Section 5.1.10)
•Registers the interrupt handler (Section 5.1.11)
•Saves the
controller and softc data structure pointers
(Section 5.1.12)
•Tries to allocate another controller data structure (Section 5.1.13)
•Registers the shutdown routine (Section 5.1.14)
5.1.1 Setting Up the el_probe Routine
The following code shows how to set up the el_probe( ) routine:
1Declares an argument that specifies an I/O handle that you can use to
reference a device register or memory that is located in bus address
space (either I/O space or memory space). This I/O handle references
the device’s I/O address space for the bus where the read operation
originates (in calls to the read_io_port( ) routine) and where the
write operation occurs (in calls to the write_io_port( ) routine). The
bus configuration code passes this I/O handle to the driver’s probe
interface during device autoconfiguration.
struct controller *ctlr) 2
3
11
2Declares a pointer to a controller data structure for this controller.
This data structure contains such information as the controller type,
the controller name, and the current status of the controller. The bus
configuration code passes this initialized controller data structure
to the driver’s probe and attach interfaces. A device driver typically
uses the ctlr_num member of the controller data structure as an
index to identify the instance of the controller a request is for.
3Declares a pointer to the el_softc data structure and calls it sc.
4Declares a unit variable and initializes it to the controller number for
this controller. This controller number identifies the specific 3Com
3C5x9 controller that is being probed. The controller number is
5–2 Implementing the Autoconfiguration Support Section (probe)
contained in the ctlr_num member of the controller data structure
for this 3Com 3C5x9 device.
5
Declares a handler_intr_info data structure called el_intr_info.
The handler_intr_info data structure is a generic data structure
that contains interrupt handler information for buses that are connected
to a device controller. Using the handler_intr_info data structure
makes the driver more portable across different bus architectures.
6Declares an ihandler_t data structure called el_ihandle to contain
information for the if_el device driver’s interrupt service routine
registration.
7Declares a pointer to a card_info data structure called card_infop
and initializes it to the specific card_info data structure for this
controller. This data structure is associated with PCMCIA devices only.
The bus configuration code passes this card_info data structure
through the controller data structure’s conn_priv[2] member. The
pcmcia.h file defines card_info_ptr as conn_priv[2].
8Declares a variable called reg that stores the I/O handle that is passed
to the driver’s el_probe( ) routine.
9Declares an e_port data structure called port_sel. This data
structure is associated with the EISA and ISA buses. The e_port data
structure describes bus I/O port information. The bus configuration
code initializes the members of the e_port data structure during device
autoconfiguration. Device drivers call the get_config( ) routine to
obtain information from the members of the e_port data structure.
10Declares an irq data structure called irq_sel. The irq data structure
specifies EISA/ISA bus interrupt channel characteristics that are
assigned to a device. The bus configuration code initializes the members
of the irq data structure during device autoconfiguration. Device
drivers call the get_config( ) routine to obtain information from the
members of the irq data structure.
11Declares the tuple_* data structures. For more information and
definitions of the tuple_info and tuple_data_info data structures,
see the /usr/sys/include/io/dec/pcmcia/cardinfo.h file and
tuple_info( ) and tuple_data_info( ).
Implementing the Autoconfiguration Support Section (probe) 5–3
5.1.2 Checking the Maximum Number of Devices That the Driver
Supports
The following code shows how to check for the maximum number of devices
that the if_el device driver supports:
if (unit >= el_MAXDEV) { 1
printf("el%d: el_probe: unit exceeds max supported devices\n",
unit);
return(0);
}
1If the unit variable exceeds the maximum number of devices that
2
the if_el driver supports, calls the printf( ) routine to display
an appropriate message on the console terminal. The printf( )
routine also displays the controller number that is stored in the unit
variable. The el_probe( ) routine stores the controller number in
this variable by referencing the ctlr_num member of the controller
data structure pointer.
The el_MAXDEV constant defines the maximum number of controllers
that the if_el driver can support.
2Returns the value 0 (zero) to indicate that the probe operation failed.
5.1.3 Performing Bus-Specific Tasks
The following code shows how the el_probe( ) routine performs tasks that
are specific to the PCMCIA and ISA buses. Only network device drivers
that operate on the PCMCIA and ISA buses perform these tasks. Your
probe interface performs tasks that are related to the bus on which your
network driver operates. See the bus-specific manual for information on
data structures for that bus.
printf("el%d: EtherLink III not found on bus\n", unit);
return(0);
}
}
}
break;
7
1
5
6
5–4 Implementing the Autoconfiguration Support Section (probe)
case BUS_ISA: 8
if (get_config(ctlr, RES_PORT, NULL, &port_sel, 0) >= 0) { 9
reg = port_sel.base_address; 10
} else { 11
printf("el%d: Can’t get assigned IOBASE\n",unit);
return(0);
}
if (get_config(ctlr, RES_IRQ, NULL, &irq_sel, 0) < 0) {
printf("el%d: Can’t get assigned IRQ\n", unit);
return(0);
}
if (el_isa_reset++ == 0)
el_isa_reset_all(reg, &isatag, ctlr);
if (el_isa_activate(reg, &isatag, ctlr)) {
printf("el%d: 3C509 not present or not responding at 0x%x\n",
unit, reg);
return(0);
}
break;
default:
}
1Determines which bus the if_el driver operates on by examining the
15
printf("el%d: Unrecognized bus type\n", unit);
return(0);
break;
13
14
12
constant that the bus configuration code has stored in the bus_type
member. The el_probe( ) routine references this value through the
controller data structure pointer’s bus_hd member. This pointer is
the data structure that is associated with this 3Com 3C5x9 device.
2Performs tasks related to the PCMCIA bus if bus_type evaluates to
the constant BUS_PCMCIA.
3Adds the I/O handle to the base address of the card and stores it in the
reg variable. The reg variable becomes an argument in subsequent
calls to the read and write macros.
4Determines whether the card is a multifunction card or a single-function
card.
5Calls the READ_BUS_D16 macro to read a word (16 bits) from a device
register that is located in the bus I/O address space. This read operation
verifies that the EtherLink III card is attached.
If the data that READ_BUS_D16 returns is not equal to 0x6d50, calls
the WRITE_BUS_D16 and DELAY macros. The WRITE_BUS_D16 macro
writes a word (16 bits) to a device register that is located in the bus
I/O address space. This specific write operation resets the card. The
DELAY macro spins, waiting the specified number of microseconds before
continuing execution.
Implementing the Autoconfiguration Support Section (probe) 5–5
6Calls the READ_BUS_D16 macro a second time to determine whether
the EtherLink III is attached. If the data returned by READ_BUS_D16
is not 0x6d50, calls the printf( ) routine to display an appropriate
message on the console terminal.
7Returns the value 0 (zero) to indicate that the probe operation failed.
8Performs tasks related to the ISA bus if bus_type evaluates to the
constant BUS_ISA.
9Calls the get_config( ) routine to obtain the base I/O address for
the device.
10If get_config( ) is successful, stores the base I/O address in the reg
variable.
11If get_config( ) is unsuccessful, calls the printf( ) routine to
display an appropriate message on the console terminal, then returns
the value 0 (zero) to indicate that the probe operation failed.
12Calls the get_config( ) routine to obtain the interrupt request (IRQ)
line for the device. If get_config( ) is not successful, el_probe( )
calls the printf( ) routine to display an appropriate message on the
console terminal, then returns the value 0 (zero) to indicate that the
probe operation failed.
13If this is the first ISA 3Com 3C5x9 adapter seen in the system, calls the
el_isa_reset_all( ) routine to reset all 3Com 3C5x9 adapters on
the ISA bus once to clear any bad state data.
14Calls the el_isa_activate( ) routine to attempt to activate the
lowest addressed adapter on the bus and to configure it with the given
base address. If the attempt fails, el_probe( ) calls the printf( )
routine to display an appropriate message on the console terminal, then
returns the value 0 (zero) to indicate that the probe operation failed. See
the if_el source file (in the examples directory that is installed with
the device driver kit) for a listing of the el_isa_activate( ) routine.
15If the driver is not operating on either the PCMCIA or ISA bus, calls
the printf( ) routine to display an appropriate message on the console
terminal, then returns the value 0 (zero) to indicate that the probe
operation failed.
5.1.4 Allocating Memory for the softc Data Structure
The following code shows how the el_probe( ) routine allocates memory
for the if_el device driver’s softc data structure. If the device has already
been probed, the driver does not need to allocate the data structure. This
can happen if the user removed and then reinserted the device, an operation
that is only possible for PCMCIA versions of the adapter.
5–6 Implementing the Autoconfiguration Support Section (probe)
printf("el%d: el_probe: failed to get buffer memory for softc\n",
unit);
return(0);
4
•Locates the existing el_softc data structure for this device. The
controller number (which is stored in the unit variable) is used as
an index into the array of el_softc data structures to determine
which el_softc data structure is associated with this 3Com 3C5x9
device.
•Sets the cardout member of the el_softc data structure to the
value 0 (zero) to indicate that the PCMCIA card is not currently
removed from its slot.
•Sets the reprobe member of the el_softc data structure to the
value 1 to indicate that the PCMCIA card was reinserted into its slot.
2If this is an ISA device or if the user did not remove and replace the
card, calls the MALLOC macro to allocate memory for the el_softc
data structure.
3If MALLOC could not allocate the memory, calls the printf( ) routine to
display an appropriate message on the console terminal. The printf( )
routine also displays the controller number for the device.
4Returns the value 0 (zero) to the bus configuration code to indicate
that the probe operation failed.
5.1.5 Allocating the ether_driver Data Structure
The following code shows how the el_probe( ) routine calls if_alloc( )
to allocate the ether_driver data structure for this device. if_alloc( )
returns an ether_driver data structure, which contains the ifnet data
structure, and initializes the if_name, if_unit, and if_index fields.
Make sure that your driver allocates its ether_driver data structure in
the same way.
sc->is_ed = if_alloc("el", unit, sizeof(struct ether_driver));
CLEAR_LAN_COUNTERS(sc->is_ed); 2
1Calls a routine that returns an ether_driver data structure and
initializes the ifnet portion of it.
Implementing the Autoconfiguration Support Section (probe) 5–7
1
2Initializes all Ethernet statistics counters in the ether_driver data
structure to 0 (zero).
5.1.6 Initializing the Enhanced Hardware Management Data Structure
The following code shows how the el_probe( ) routine initializes the data
structure for enhanced hardware management (EHM) support:
lan_ehm_init(&sc->ehm, NET_EHM_VERSION_ID); 1
}
1Initializes the net_hw_mgmt data structure. This data structure
contains the current and default attribute values for this device as well
as other information that EHM requires. The lan_ehm_init( ) routine
allocates all necessary storage and performs basic initialization of the
EHM data structure. Make sure that your driver makes this call as well.
5.1.7 Computing the CSR Addresses
The following code shows how the el_probe( ) routine determines the
addresses of the if_el device’s control and status (CSR) registers:
1Fills in the regE member of the el_softc data structure for this 3Com
3C5x9 device. The value that is stored in regE consists of the I/O handle
plus a byte offset. The el_probe( ) routine computes this address
according to the requirements of the PCMCIA bus and the ISA bus.
2This line and the subsequent lines compute and save other if_el device
register addresses in the el_softc data structure.
3Stores the I/O handle in the basereg member of the el_softc data
structure for this 3Com 3C5x9 device.
5.1.8 Setting Bus-Specific Data Structure Members
The following code shows how the el_probe( ) routine sets members for
the bus-specific data structures that are associated with the PCMCIA and
ISA buses. See the bus-specific manual for information on data structures
for the bus on which your driver operates.
switch (ctlr->bus_hd->bus_type) { 1
case BUS_PCMCIA: 2
5–8 Implementing the Autoconfiguration Support Section (probe)
1Evaluates the bus_type member of the bus data structure for this
3Com 3C5x9 device.
2Performs tasks that are related to the PCMCIA bus if bus_type
evaluates to BUS_PCMCIA.
3Sets the interrupt request (IRQ) to the value 3.
4Sets the I/O base of the program card to the value 0 (zero).
5Indicates that this is a PCMCIA unit and saves the card information
pointer.
6Calls the pcmcia_register_event_callback( ) routine. See the
if_el source file (in the examples directory that is installed with the
device driver kit) for a listing of this routine.
7Sets the model identification attribute for enhanced hardware
management support.
8Performs tasks that are related to the ISA bus.
9Saves the interrupt request (IRQ) from the ISA bus configuration code.
10Saves the tag from the activation process.
11Computes the I/O base to give to the device.
12Sets the model identification attribute for enhanced hardware
management support.
Implementing the Autoconfiguration Support Section (probe) 5–9
5.1.9 Handling First-Time Probe Operations
If the device has not already been probed, the el_probe( ) routine performs
the following tasks:
•Reads the EEPROM and saves it to a temporary data structure
•Reads and saves the device’s physical address
•Starts the autosense thread to determine the media type
The following code shows how the el_probe( ) routine performs these
tasks:
1Determines whether the device has already been probed, which
indicates that the device is operating on a PCMCIA bus and that the
user has put the card back into the slot. In this case, the driver does
not need to redo much of the initial probe work and will skip to the code
shown in Section 5.1.10.
2If this is a multifunction card, reads the EEPROM data and saves it in
sc->eeprom. If this is a multifunction PC card, the EEPROM data is
located in the card information data structure.
3If this is not a multifunction PC card, the EEPROM data is read directly
from the card and saved in the el_softc data structure.
4Saves the 48-bit physical address of the device into the is_addr
member of the el_softc data structure for this 3Com 3C5x9 device.
5Sets the media mode to the constant LAN_MODE_AUTOSENSE. This
constant indicates that the driver hardware determines the media
automatically.
6Sets the media state to the constant LAN_MEDIA_STATE_SENSING. This
constant indicates that the media is currently in the autosensing state.
7Sets the currently set media to the constant LAN_MEDIA_UTP.
This constant indicates that the mode for the media is unshielded
twisted-pair cable.
Implementing the Autoconfiguration Support Section (probe) 5–11
8Calls the kernel_thread_w_arg( ) routine to create and start a
kernel thread with timeshare scheduling. A kernel thread that is
created with timeshare scheduling means that its priority degrades if it
consumes an inordinate amount of CPU resources. Make sure that your
device driver calls kernel_thread_w_arg( ) only for long-running
tasks and always attaches a kernel thread to the first task.
The kernel_thread_w_arg( ) routine returns a pointer to the thread
data structure for the newly created thread. The device driver stores
this pointer in the autosense_thread member of the el_softc data
structure.
9If the value that kernel_thread_w_arg( ) returns is NULL, then the
thread could not be created. At this point, the el_probe( ) routine
must undo previous work and return a failure indication to the caller.
10For PCMCIA versions of the card, unregisters the callback routine that
was previously registered.
11Deallocates the ether_driver data structure for this device.
12Frees up any memory that was allocated for enhanced hardware
management and unregisters this card from the hardware management
database.
13Calls the FREE macro, which frees the memory that was previously
allocated for the el_softc data structure.
14Returns the value 0 (zero) to indicate that the probe operation failed.
5.1.10 Handling Subsequent Probe Operations
If the device had already been probed, the if_el device driver reads the
EEPROM to determine whether the hardware address has changed. The
following code shows how the el_probe( ) routine performs these tasks:
1If this is a multifunction card, reads the EEPROM data and saves
it in a temporary data structure, ee_copy. If this is a 3Com 3C562
multifunction PC card, the EEPROM data is located in the card
information data structure.
2If this is not a multifunction PC card, the EEPROM data is read directly
from the card and saved in the el_sofc data structure.
3Calls the bcmp( ) routine to compare the EEPROM address from the
first probe operation to the EEPROM address of the current probe
operation.
4If the EEPROM address has changed, converts the original EEPROM
address to its canonical form.
5Compares the original EEPROM address to the hardware address that
is currently in effect. If they are different, then a previously specified
hardware address was used that was different from the address that
was found in the EEPROM. In this case, the alternate address is still in
effect and no further action needs to be taken.
6If the original EEPROM address is the same as the hardware address
that is currently in effect, uses the hardware address that was found
in the EEPROM. Because the EEPROM has changed (because the
old if_el adapter was removed and a new one inserted), it will be
necessary to broadcast the new EEPROM hardware address onto
the network to inform the network that there has been a change.
This section of code converts the hardware address from the current
EEPROM to canonical form in preparation for the broadcast message.
7Saves the new hardware address in the is_addr member of the
el_softc data structure.
8If an IP address has been configured for this interface, informs the
network that there is a new hardware address for the IP address by
sending out an ARP packet.
9Marks this new hardware address as the link address for this interface.
10Informs the packet filter of the new hardware address.
11Saves the EEPROM contents in the el_softc data structure.
5.1.11 Registering the Interrupt Handler
The following code shows how the el_probe( ) routine registers the
interrupt handler. The Writing Device Drivers manual provides detailed
information on the data structures and routines that relate to the
5–14 Implementing the Autoconfiguration Support Section (probe)
registration of interrupt handlers. All network device drivers are required to
register interrupt handlers.
1Sets the configuration_st member of the el_intr_info data
6
7
CARD_REMOVAL_EVENT,
(caddr_t)el_card_remove);
structure to the pointer to the controller data structure for this
3Com 3C5x9 device.
2Sets the intr member of the el_intr_info data structure to
el_intr, which is the if_el device driver’s interrupt handler.
3Sets the param member of the el_intr_info data structure to the
controller number for the controller data structure for this 3Com
3C5x9 device.
4Sets the config_type member of the el_intr_info data structure to
the constant CONTROLLER_CONFIG_TYPE, which identifies the if_el
driver type as a controller driver.
5If the if_el driver operates on the PCMCIA bus, indicates that the
if_el driver can handle shared interrupts.
6Sets the ih_bus member of the el_ihandle data structure to the bus
data structure for the if_el device driver. The bus data structure
is referenced through the bus_hd member of the controller data
structure for this 3Com 3C5x9 device.
7Sets the ih_bus_info member of the el_ihandle data structure to the
address of the bus-specific information data structure, el_intr_info.
8Calls the handler_add( ) routine to register the device driver’s
interrupt handler and its associated ihandler_t data structure with
the bus-specific interrupt-dispatching algorithm.
Implementing the Autoconfiguration Support Section (probe) 5–15
This routine returns an opaque ihandler_id_t key, which is a
unique number that identifies the interrupt handler to be acted
on by subsequent calls to handler_del, handler_disable, and
handler_enable. The hid member of the el_softc data structure
stores this key.
9
If the return value from handler_add equals NULL, the if_el driver
failed to register an interrupt handler for the if_el device. This is a
fatal error, and the if_el driver will undo all previous operations and
return an error to the caller.
5.1.12 Saving the controller and softc Data Structure Pointers
The following code shows how the el_probe( ) routine saves the
controller and el_softc data structure pointers. All probe interfaces
perform this task.
el_softc[unit] = sc; 1
el_info[unit] = ctlr; 2
1Saves the el_softc data structure pointer for this instance of the
3Com 3C5x9 device in the array of el_softc data structures. The unit
number is the offset to the data structure within the el_softc array.
2Saves the controller data structure pointer for this instance of the
3Com 3C5x9 device in the array of controller data structures.
5.1.13 Trying to Allocate Another controller Data Structure
The following code shows how the el_probe( ) routine attempts to allocate
another controller data structure. You make this call so that a driver
can support multiple devices.
if (!sc->reprobe && lan_create_controller(&el_data) != ESUCCESS) {
1Registers the shutdown( ) routine and directs the kernel to pass
a pointer to the driver’s softc data structure to the routine. The
shutdown( ) routine is important for those devices that perform
DMA-related operations.
5.2 Implementing the el_shutdown Routine
The driver’s shutdown( ) routine shuts down the controller. The kernel
calls all registered shutdown( ) routines when the system shuts down.
The el_probe( ) routine registers a shutdown( ) routine called
el_shutdown( ). The if_el device driver implements the routine as
follows:
static void el_shutdown(struct el_softc *sc)
{
WRITE_CMD(sc, CMD_RESET);
DELAY(1000); 3
}
2
1
1
1Specifies the argument that the kernel passes to the routine, which is a
pointer to the driver’s el_softc data structure. The driver specifies
this argument when it registers the shutdown( ) routine in its probe
interface.
2Calls the WRITE_CMD macro to write data to the command port register.
In this call, the el_softc data structure for this 3Com 3C5x9 device
contains the I/O handle to reference the device’s command register. The
data to be written is the CMD_RESET bit, which resets the device.
3Calls the DELAY macro to delay the execution of el_shutdown( ) for 1
millisecond before continuing execution. This gives the reset command
time to complete.
5.3 Implementing the el_autosense_thread Routine
The if_el device driver implements a driver-specific routine called
el_autosense_thread( ) to determine the mode of the network interface.
The el_probe( ) routine calls el_autosense_thread( ) during device
autoconfiguration.
Implementing the Autoconfiguration Support Section (probe) 5–17
To determine the mode, el_autosense_thread( ) tries to send a test data
packet in each of the possible modes. When it successfully transmits the data
packet, it sets the network interface to that mode. The lm_media_mode,
lm_media, and lm_media_state members of the el_softc data structure
keep track of the progress of the autosensing procedure, as follows:
•The value of the lm_media_mode member determines whether the
el_autosense_thread( ) will automatically determine the network
interface, or whether the user specified the type of media.
•The lm_media member specifies the current media. This member
changes each time that the driver uses a different medium to try to
transmit a packet. The if_el device driver can set this member to any
of the following values:
LAN_MEDIA_UTP
LAN_MEDIA_BNC
LAN_MEDIA_AUI
The media is unshielded twisted-pair cable.
The media is thin wire.
The media is the attachment unit
interface (AUI).
•The lm_media_state member specifies the current state of the
autosensing procedure, as follows:
LAN_MEDIA_STATE_SENSING
LAN_MEDIA_STATE_DETERMINED
The driver is trying to determine
the media mode.
The media state has been determined.
The el_autosense_thread( ) routine is implemented as a kernel thread.
It performs the following tasks:
•Blocks until awakened (Section 5.3.2)
•Tests for the termination flag (Section 5.3.3)
•Starts up statistics (Section 5.3.4)
•Enters the packet transmit loop (Section 5.3.5)
•Saves counters prior to the transmit operation (Section 5.3.6)
•Allocates memory for a test packet (Section 5.3.7)
•Uses the default from the ROM (Section 5.3.8)
•Sets the media setting in the hardware (Section 5.3.9)
•Builds a test packet to transmit (Section 5.3.10)
•Transmits the test packet (Section 5.3.11)
•Sets a timer for the current kernel thread (Section 5.3.12)
•Tests for loss of carrier (Section 5.3.13)
5–18 Implementing the Autoconfiguration Support Section (probe)
•Determines whether packets were transmitted successfully
(Section 5.3.14)
•Prints debug information (Section 5.3.15)
•Sets up new media to try if transmit was unsuccessful (Section 5.3.16)
•Establishes media if transmit was successful (Section 5.3.17)
5.3.1 Setting Up the el_autosense_thread Routine
The following code shows how to set up the el_autosense_thread( )
routine:
struct ifnet *ifp = &sc->is_if;
unsigned long prev_tint, prev_tmo, prev_err;
struct mbuf *m;
int good_xmits, wait, s, i, link_beat, passes;
unsigned long wait_flag=0;
1Defines the message to transmit when trying to determine the mode of
3
the device.
2
2Declares a pointer to the el_softc data structure and calls it sc.
3Declares a pointer to an ifnet data structure and calls it ifp. This line
also initializes ifp to the address of the ifnet data structure for this
3Com 3C5x9 device. The ifnet data structure is referenced through
the is_if member of the el_softc data structure pointer. The is_if
name is an alternate name for the ac_if member of the arpcom data
structure. The ac_if member is referred to as the network-visible
interface and is actually the instance of the ifnet data structure for
this 3Com 3C5x9 device.
5.3.2 Blocking Until Awakened
The following code shows how the el_autosense_thread( ) routine blocks
until awakened:
1Performs an initial test for the termination flag. The termination
2
flag would have been set if another kernel thread had called the
thread_terminate( ) routine for the el_autosense_thread( )
routine.
2The thread_halt_self( ) routine performs the work that is
associated with a variety of asynchronous traps (ASTs) for a kernel
thread that terminates itself. A kernel thread terminates itself by
calling the thread_halt_self( ) routine. The thread_halt_self( )
routine does not return to the caller.
5.3.4 Starting Up Statistics
The following code shows how the el_autosense_thread( ) routine starts
up statistics:
s = splimp();
simple_lock(&sc->el_softc_lock);
WRITE_CMD(sc, CMD_STATSENA);
simple_unlock(&sc->el_softc_lock);
splx(s);
1
1Starts up statistics to test for the loss of the carrier during the transmit
operation.
5.3.5 Entering the Packet Transmit Loop
The following code shows how the el_autosense_thread( ) routine enters
the packet transmit loop:
printf("el%d: Use lan_config to configure if necessary\n",
} else {
}
ifp->if_unit);
printf("el%d: Autosense thread cannot get xmit buffer\n",
ifp->if_unit);
5.3.8 Using the Default from the ROM
The following code shows how the el_autosense_thread( ) routine uses
the default media setting from ROM. This code sequence signifies a last
resort if the driver is unable to determine the media.
switch (sc->eeprom.addrconf & 0xc) {
case ACR_10B5:
if (sc->lm_media_mode == LAN_MODE_AUTOSENSE)
sc->lm_media = LAN_MEDIA_AUI;
break;
case ACR_10B2:
if (sc->lm_media_mode == LAN_MODE_AUTOSENSE)
sc->lm_media = LAN_MEDIA_BNC;
break;
case ACR_10BT:
default:
if (sc->lm_media_mode == LAN_MODE_AUTOSENSE)
sc->lm_media = LAN_MEDIA_UTP;
break;
}
printf("el%d: Used %s setting from eeprom\n",
Implementing the Autoconfiguration Support Section (probe) 5–21
1Loads the junk message into the mbuf data structure.
2Sets the destination address as the address of the adapter.
3Sets the source address as the address of the adapter.
5.3.11 Transmitting the Test Packet
The following code shows how the el_autosense_thread( ) routine
transmits the test packet:
s = splimp();
simple_lock(&sc->el_softc_lock);
IF_ENQUEUE(&ifp->if_snd, m);
el_start_locked(sc, ifp);
simple_unlock(&sc->el_softc_lock);
splx(s);
5–22 Implementing the Autoconfiguration Support Section (probe)
5.3.12 Setting a Timer for the Current Kernel Thread
The following code shows how the el_autosense_thread( ) routine sets a
timer for the current kernel thread:
1Sets the lm_media_state member of the softc data structure to
LAN_MEDIA_STATE_DETERMINED. This indicates that the driver has
successfully selected a media mode.
2Calls the splimp( ) routine to mask all LAN hardware interrupts.
Upon successful completion, splimp( ) stores an integer value in the
s variable. This value represents the CPU priority level that existedbefore the call to splimp( ).
3Calls the simple_lock( ) routine to assert a lock with exclusive
access for the resource that is associated with the el_softc_lock
data structure. This means that no other kernel thread can gain access
to the locked resource until you call simple_unlock( ) to release it.
Implementing the Autoconfiguration Support Section (probe) 5–25
Because simple locks are spin locks, simple_lock( ) does not return
until the lock has been obtained.
The el_softc_lock member of the el_softc data structure points to
a simple lock data structure. The if_el device driver declares this data
structure by calling the decl_simple_lock_data( ) routine.
4
Calls the WRITE_CMD macro to write data to the command port register.
In this call, el_autosense_thread( ) passes the if_el driver’s
el_softc data structure pointer. The data to be written is the statistics
disable command (CMD_STATDIS).
5Releases the simple lock and resets the IPL.
6Calls the splx( ) routine to reset the CPU priority to the level that is
stored in the s variable.
5–26 Implementing the Autoconfiguration Support Section (probe)
6
Implementing the Autoconfiguration
Support Section (attach)
The autoconfiguration support section implements a network device driver’s
attach interface. A network device driver’s attach interface establishes
communication with the device. The interface initializes the pointer to the
ifnet data structure and attaches the network interface to the packet filter.
The bus configuration code calls the driver’s attach interface.
The if_el device driver implements an attach( ) routine called
el_attach( ). The el_attach( ) routine performs the following tasks:
•Initializes the media address and media header lengths (Section 6.2)
•Sets up the media (Section 6.3)
•Initializes simple lock information (Section 6.4)
•Prints a success message (Section 6.5)
•Specifies the network driver interfaces (Section 6.6)
•Sets the baud rate (Section 6.7)
•Attaches to the packet filter and the network layer (Section 6.8)
•Sets network attributes and registers the adapter (Section 6.9)
•Handles reinsertion operations (Section 6.10)
•Enables the interrupt handler (Section 6.11)
•Starts the polling process (Section 6.12)
6.1 Setting Up the el_attach Routine
The following code shows how to set up the el_attach( ) routine:
1Declares as an argument a pointer to a controller data structure
for this controller. This data structure contains such information
as the controller type, the controller name, and the current status
Implementing the Autoconfiguration Support Section (attach) 6–1
2
of the controller. The bus configuration code passes this initialized
controller data structure to the driver’s probe and attach
interfaces.
2
Declares a unit variable and initializes it to the controller number for
this controller. This controller number identifies the specific 3Com
3C5x9 controller that is being attached. The controller number is
contained in the ctlr_num member of the controller data structure
for this device.
3Declares a pointer to the el_softc data structure called sc and
initializes it to the el_softc data structure for this device. The
controller number (which is stored in the unit variable) is used as an
index into the array of el_softc data structures to determine which
el_softc data structure is associated with this device.
4Declares a pointer to an ifnet data structure called ifp and initializes
it to the address of the ifnet data structure for this device.
5Declares a pointer to a sockaddr_in data structure called sin.
6.2 Initializing the Media Address and Media Header
Lengths
The el_attach( ) routine sets up the media’s address length and header
length, as follows:
sin = (struct sockaddr_in *)&ifp->if_addr; 7
sin->sin_family = AF_INET; 8
1Sets the ac_bcastaddr member of the softc data structure for this
device to the Ethernet broadcast address. The system stores the
Ethernet broadcast address in the etherbroadcastaddr character
array. Tru64 UNIX defines the etherbroadcastaddr character array
in the if_ether.h file.
The media header structure for Ethernet-related
media. The if_ether.h file defines the
ether_header structure.
The media header structure for FDDI-related
media. The if_fddi.h file defines the
fddi_header structure.
The media header structure for Token Ring-related
media. The if_trn.h file defines the
trn_header structure.
The name is_ac is an alternate name for the ess_ac member of the
ether_driver data structure. The ess_ac member is referred to as
the Ethernet common part and is actually an instance of the arpcom
data structure.
2Sets the ac_arphrd member of the softc data structure for this
device to the constant ARPHRD_ETHER, which represents the Ethernet
hardware address. The if_arp.h file defines this constant.
For the Token Ring interface, set the ac_arphrd member to the
constant ARPHRD_802. The if_arp.h file also defines this constant.
For the FDDI interface, set the ac_arphrd member to the constant
ARPHRD_ETHER, which represents the Ethernet hardware address. See
RFC 826 for more details.
Implementing the Autoconfiguration Support Section (attach) 6–3
3Sets the if_mtu member of the ifnet data structure for this device to
the maximum transmission unit, which for Ethernet-related media is
represented by the constant ETHERMTU.
The following media-specific constants represent the maximum
transmission unit:
ETHERMTU
FDDIMTU
TRN4_RFC1042_IP_MTU
TRN16_RFC1042_IP_MTU
4Sets the if_mediamtu member of the ifnet data structure for this
The maximum transmission unit for
Ethernet media. The if_ether.h file
defines the ETHERMTU constant.
The maximum transmission unit for
FDDI media. The if_fddi.h file
defines the FDDIMTU constant.
The maximum transmission unit for
the 4 megabit-per-second Token Ring
media. The if_trn.h file defines the
TRN4_RFC1042_IP_MTU constant.
The maximum transmission unit for
the 16 megabit-per-second Token Ring
media. The if_trn.h file defines the
TRN16_RFC1042_IP_MTU constant.
device to the maximum transmission unit for the media, which for
Ethernet-related media is represented by the constant ETHERMTU.
Typically, you set this member to the same constant that is used for
the if_mtu member.
5Sets the if_type member of the ifnet data structure for this device
to the type of network interface, which is represented by the constant
IFT_ETHER (Ethernet I or II interface).
The following describes some of the valid interface types that are
defined in the if_types.h file:
IFT_ETHER
IFT_FDDI
IFT_ISO88025
6Sets the ac_flag member of the arpcom data structure for this device
Ethernet I or II interface
FDDI interface
Token Ring interface
to the value 0 (zero). This indicates that an IP address is currently
not configured for this interface.
7Sets the sockaddr_in data structure pointer to the address of the
network interface. The address of the network interface is referenced
through the if_addr member of the ifnet data structure for this
device.
6–4 Implementing the Autoconfiguration Support Section (attach)
8Sets the sin_family member of the sockaddr_in data structure to
the address family, which in this case is represented by the constant
AF_INET. The socket.h file defines this and other address family
constants.
6.4 Initializing Simple Lock Information
The following code shows how the el_attach( ) routine sets up simple
lock information:
1Sets the if_affinity member of the ifnet data structure for this
device to the constant NETALLCPU. The if_affinity member specifies
which CPU to run on. You can set this member to one of the following
constants defined in if.h:
NETMASTERCPU
NETALLCPU
Specifies that you want to funnel the network device
driver because you have not made it symmetric
multiprocessor (SMP) safe. This means that the
network driver is forced to execute on a single (the
master) CPU. This setting is
are encouraged to make your driver SMP safe.
Specifies that you do not want to funnel the network
device driver because you have made it SMP safe.
This means that the network driver can execute
on multiple CPUs. You make a network device
driver SMP safe by using the simple or complex lock
mechanism in all critical sections of the driver.
not recommended. You
The if_el driver uses the simple lock mechanism and is, therefore,
SMP safe.
2Sets the lk_softc member of the ifnet data structure for this device
to the address of the el_softc_lock. Both the if_el driver and the
network software above the driver use this lock whenever modifications
are made to the shared members of the ifnet data structure. Make
sure to supply a lock for the shared portion of the ifnet structure also.
3Calls the simple_lock_init( ) routine to initialize the simple lock
structure called el_softc_lock. You need to initialize the simple
lock structure only once.
Implementing the Autoconfiguration Support Section (attach) 6–5
6.5 Printing a Success Message
The following code shows how the el_attach( ) routine prints a success
message:
printf("el%d: %s, hardware address: %s\n", unit,
ifp->if_version, ether_sprintf(sc->is_addr));
1
Calls the printf( ) routine to display the following information
message on the console terminal:
•The controller number that is stored in the unit variable.
•The version of the network interface that is stored in the
if_version member of the ifnet data structure pointer.
•The hardware address that is accessed through the is_addr
member of the el_softc data structure for this device. The if_el
device driver maps the ac_enaddr member of the arpcom data
structure to the alternate name is_addr.
The argument list that is passed to printf( ) contains a call to the
ether_sprintf( ) routine. The ether_sprintf( ) routine converts
an Ethernet address to a printable ASCII string representation.
Make sure that your driver prints a similar message during its attach( )
routine.
1
6.6 Specifying the Network Driver Interfaces
The following code shows how the el_attach( ) routine specifies the
network driver interfaces for the if_el driver:
1Sets the if_ioctl member of the ifnet data structure for this device
to el_ioctl, which is the if_el device driver’s ioctl interface.
2Sets the if_watchdog member of the ifnet data structure for this
device to el_watch, which is the if_el device driver’s watchdog
interface.
6–6 Implementing the Autoconfiguration Support Section (attach)
1
4
5
3Sets the if_start member of the ifnet data structure for this device
to el_start, which is the if_el device driver’s start transmit for
output interface.
4Sets the if_output member of the ifnet data structure for this
device to ether_output, which is the if_el device driver’s output
interface. Tru64 UNIX provides this kernel routine. All network device
drivers, including Token Ring and FDDI drivers, must set if_output
to ether_output, rather than implementing a driver-specific output
interface.
An mb( ) (memory barrier) preceeds the setting of the if_output
member. Members of the ifnet structure
must be initialized in the
order shown. The mb( ) ensures that all other function pointers are set
before the if_output function pointer is set. This order is necessary
because the if_el device can be unattached and later attached again.
5Sets the if_flags member of the ifnet data structure for this device
to the bitwise inclusive OR of the following status bits that are defined
in the if.h file:
IFF_BROADCAST
IFF_MULTICAST
IFF_NOTRAILERS
IFF_SIMPLEX
Signifies that the network interface supports
broadcasting and that the associated broadcast
address is valid.
Signifies thatthe network interface supports multicast.
Signifies that the transmission avoids the use of
trailers. The term trailers refers to the IP trailer
encapsulation protocol, which is obsolete.
Signifies that the interface cannot identify
its own transmissions.
An mb( ) (memory barrier) precedes the setting of the if_flags
member. All the function pointers must be initialized before the
if_flags field is set, in case the if_el device has been unattached
and then attached again.
6Sets the if_timer member of the ifnet data structure for this device
to the value 0 (zero). This is the number of seconds to wait until the
driver’s watchdog interface is called. Setting the if_timer member to
0 (zero) disables the timer.
7Sets the if_sysid_type member of the ifnet data structure for
this device to the value 0 (zero). This optional member specifies a
unique number that identifies the bus adapter hardware to the network
management software. This unique number is referred to as the MOP
system ID device code.
Implementing the Autoconfiguration Support Section (attach) 6–7
8Sets the if_version member of the ifnet data structure for this
device to the string 3Com EtherLink III.
6.7 Setting the Baud Rate
The following code shows how the el_attach( ) routine sets the baud rate:
ifp->if_baudrate = ETHER_BANDWIDTH_10MB; 1
1Sets the if_baudrate member of the ifnet data structure for this
device to the constant ETHER_BANDWIDTH_10MB. The if_baudrate
member specifies the line speed.
You can use the following media-specific constants:
ETHER_BANDWIDTH_10MB
Ethernet line speed is 10 megabits per second.
The if_ether.h file defines the ETHER_BAND-
WIDTH_10MB constant.
ETHER_BANDWIDTH_100MB
Fast Ethernet line speed is 100 megabits per second.
The if_ether.h file defines the ETHER_BAND-
WIDTH_100MB constant.
FDDI_BANDWIDTH_100MB
FDDI line speed is 100 megabits per second. The if_fddi.h
file defines the FDDI_BANDWIDTH_100MB constant.
TRN_BANDWIDTH_4MB
Token Ring line speed is 4 megabits per second. The if_trn.h
file defines the TRN_BANDWIDTH_4MB constant.
TRN_BANDWIDTH_16MB
Token Ring line speed is 16 megabits per second. The
if_trn.h file defines the TRN_BANDWIDTH_16MB constant.
6.8 Attaching to the Packet Filter and the Network Layer
The following code shows how the el_attach( ) routine attaches to the
packet filter and the network layer:
attachpfilter(&(sc->is_ed));
if_attach(ifp); 2
el_configured ++; 3
1Calls the attachpfilter( ) routine to inform the packet filter driver
about this network driver. The attachpfilter( ) routine is passed
a pointer to the ether_driver data structure for this network device
driver.
6–8 Implementing the Autoconfiguration Support Section (attach)
1
2Calls the if_attach( ) routine to attach an interface to the list of
active interfaces. The argument to the if_attach( ) routine is a
pointer to the ifnet data structure for with this device.
3If the probe and attach operations were successful, increments the
number of successfully configured el devices. You must do this if you
are using lan_configure( ).
6.9 Setting Network Attributes and Registering the Adapter
The following code shows how the if_attach( ) routine sets the known
nonzero network attributes for the enhanced hardware management (EHM)
facility and registers the adapter:
1Sets any known nonzero network attributes for the enhanced hardware
net_method_automatic);
2
management facility. Make sure that this function call is made only
after the call to if_attach( ).
2Registers the adapter with EHM.
6.10 Handling the Reinsert Operation
If the user has reinserted the PCMCIA card, the if_el device driver does
not need to initialize the media address and media length. It does not need
to set up the media, specify the network driver interfaces, set the baud rate,
or initialize simple lock information. These tasks are done during the first
attach operation. The el_attach( ) routine needs only to initialize the
device, as follows:
} else {
printf("el%d: %s, reloaded -- current lan address: %s\n", unit,
ifp->if_version, ether_sprintf(sc->is_addr));
if (ifp->if_flags & IFF_RUNNING) 2
el_init(unit);
}
1
1If the adapter was reinserted, calls the printf( ) routine to display the
following information on the console terminal:
•The controller number (which is stored in the unit variable).
•The version of the network interface (which is stored in the
if_version member of the ifnet data structure).
•The hardware address of the device.
2Calls the driver’s el_init( ) routine if the resources that are
associated with the network interface were previously allocated.
Implementing the Autoconfiguration Support Section (attach) 6–9
6.11 Enabling the Interrupt Handler
The following code shows how the el_attach( ) routine enables the
interrupt handler:
handler_enable(sc->hid); 1
1
Calls the handler_enable( ) routine to enable a previously registered
interrupt handler. The el_probe( ) routine calls handler_add to
register the interrupt handler and it stores the handler ID in the hid
member of the el_softc data structure for this device.
6.12 Starting the Polling Process
The following code shows how the el_attach( ) routine starts the polling
process:
1Starts the polling process if the el_polling attribute specifies that
2
polling is to be done.
1
To start the polling process, el_attach( ) sets the polling_flag
member to 1 (true), then calls the timeout( ) routine to schedule the
interrupt handler to run at some point in the future. timeout( ) is
called with the following arguments:
•A pointer to the el_intr( ) routine, which is the if_el device
driver’s interrupt handler.
•The unit variable, which contains the controller number associated
with this device. This argument is passed to the el_intr( ) routine.
•The el_pollint variable, which specifies the amount of time to
delay before calling the el_intr( ) routine.
2If the user requests that polling be disabled, el_attach( ) sets the
polling_flag member to 0 (false).
6–10 Implementing the Autoconfiguration Support Section (attach)
7
Implementing the unattach Routine
The el_unattach( ) routine is called to stop the device and to free memory
and other resources prior to unloading the driver or powering off the bus
to which the device is attached. The el_unattach( ) routine undoes
everything that was performed by the el_probe( ) and el_attach( )
routines.
______________________Note_______________________
The PCMCIA bus does not support the el_unattach( ) routine.
The el_unattach( ) routine performs the following tasks:
•Verifies that the interface has shut down (Section 7.2)
•Obtains and releases the simple lock (Section 7.3)
•Disables the interrupt handler (Section 7.4)
•Terminates the autosense thread (Section 7.5)
•Unregisters the PCMCIA event callback routine (Section 7.6)
•Stops the polling process (Section 7.7)
•Unregisters the shutdown interface (Section 7.8)
•Terminates the simple lock (Section 7.9)
•Unregisters the card from the hardware management database
(Section 7.10)
•Frees data structures and resources used by the adapter (Section 7.11)
7.1 Setting Up the el_unattach Routine
The following code shows how to set up the el_unattach( ) routine:
1Declares as an argument a pointer to a bus data structure and a
controller data structure for this controller. The controller data
structure contains such information as the controller type, the controller
name, and the current status of the controller. This completely identifies
the adapter that is being unattached.
2Declares a unit variable and initializes it to the controller number for
this controller. This controller number identifies the specific 3Com
3C5x9 controller that is being unattached. The controller number is
contained in the ctlr_num member of the controller data structure
for this device.
7.2 Verifying That the Interface Has Shut Down
The following code verifies that the interface is down. Make sure that other
errors returned by if_detach do not stop interface shutdown.
status = if_detach(ifp);
if (status == EBUSY) 2
return(status);
else if (status == ESUCCESS)
detachpfilter(sc->is_ed);
ifp->if_flags &= ~IFF_RUNNING;
1Calls if_detach to remove this interface from the list of active
interfaces.
2If the interface is still in use, it cannot be detached, so failure is
returned.
1
3
4
3If the interface is not in use, detaches it from the list of those that the
packet filter monitors.
4Marks the interface as no longer running.
7.3 Obtaining the Simple Lock and Shutting Down the
Device
The following code shows how the el_unattach( ) routine obtains the
simple lock, shuts down the device, and releases the simple lock:
s = splimp();
simple_lock(&sc->el_softc_lock); 2
el_shutdown(sc); 3
simple_unlock(&sc->el_softc_lock); 4
splx(s); 5
1Calls the splimp( ) routine to mask all LAN hardware interrupts.
Upon successful completion, splimp( ) stores an integer value in the
7–2 Implementing the unattach Routine
1
s variable. This value represents the CPU priority level that existed
before the call to splimp( ).
2
Calls the simple_lock( ) routine to assert a lock with exclusive
access for the resource that is associated with the el_softc_lock
data structure. This means that no other kernel thread can gain access
to the locked resource until you call simple_unlock( ) to release it.
Because simple locks are spin locks, simple_lock( ) does not return
until the lock has been obtained.
3Stops the device and puts it in a reset state.
4Calls the simple_unlock( ) routine to release the simple lock.
5Calls the splx( ) routine to reset the CPU priority to the level that is
stored in the s variable.
7.4 Disabling the Interrupt Handler
The following code shows how the el_unattach( ) routine disables and
deletes the interrupt handler: