Tru64 UNIX Writing Network Device Drivers Part Number: AA-RNG2A-TE December 2000 Product Version: Device Driver Kit Version 2.0 Operating System and Version: Tru64 UNIX Version 5.0A or higher This manual contains information that systems engineers need to write network device drivers that operate on any bus.
© 2000 Compaq Computer Corporation Compaq and the Compaq logo Registered in U.S. Patent and Trademark Office. Tru64 is a trademark of Compaq Information Technologies Group, L.P. in the 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.
Contents About This Manual 1 Network 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 2 1–3 1–4 1–5 1–6 1–7 1–7 1–10 1–10 1–10 1–10 1–11 1–11 1–11 1–11 1–11 Defining Device Register Offsets 2.1 2.2 2.3 2.4 2.5 2.6 2.7 3 Include Files Section for a Network Driver . .. . .. . .. . . .. . .. . .. . .. . Declarations Section for a Network Driver . .. . .. . .. . . .. . .. . .. . .. . External and Forward Declarations . .. . .. . .. . .. . . .. . .. . .. . ..
3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 4 3–6 3–6 3–7 3–7 3–8 3–8 3–8 3–9 3–9 3–10 3–10 Implementing the Configure Section 4.1 4.2 5 Defining the Interrupt Handler ID . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . Defining CSR Pointer Information . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . Defining FIFO Maintenance Information .. . .. . .. . .. . . .. . .. . .. . .. . Defining Bus-Specific Information . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. .
.3.5 5.3.6 5.3.7 5.3.8 5.3.9 5.3.10 5.3.11 5.3.12 5.3.13 5.3.14 5.3.15 5.3.16 5.3.17 6 5–20 5–21 5–21 5–21 5–22 5–22 5–22 5–23 5–23 5–24 5–24 5–24 5–25 Implementing the Autoconfiguration Support Section (attach) 6.1 6.2 6.3 6.4 6.5 6.6 6.7 6.8 6.9 6.10 6.11 6.12 7 Entering the Packet Transmit Loop . . .. . .. . .. . .. . . .. . .. . .. . .. . Saving Counters Prior to the Transmit Operation . .. . .. . .. . Allocating Memory for a Test Packet . .. . .. . .. . .. . . .. . .. . .. . .. .
7.10 7.11 8 Unregistering the Card from the Hardware Management Database . . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . Freeing Resources . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . Implementing the Initialization Section 8.1 Implementing the el_init Routine . . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 8.1.1 Setting Up the el_init Routine . .. . .. . . .. . .. . .. . .. . . .. . .. . .. .
9.2.3 9.2.4 9.2.5 9.2.6 Transmitting the Buffer .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . Accounting for Outgoing Bytes . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . Updating Counters, Freeing the Transmit Buffer, and Marking the Output Process as Active . .. . .. . .. . . .. . .. . .. . .. . Indicating When to Start the Watchdog Routine .. . .. . .. . .. . 9–6 9–7 9–7 9–8 10 Implementing a Watchdog Section 10.1 10.2 10.
12.15 12.16 12.17 Resetting the Device (SIOCIFRESET ioctl Command) .. . .. . .. . Setting Device Characteristics (SIOCIFSETCHAR ioctl Command) .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . Releasing the Simple Lock and Resetting the IPL . . . .. . .. . .. . .. . 12–11 12–11 12–13 13 Implementing the Interrupt Section 13.1 Implementing the el_intr Routine . . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 13.1.
2–4 3–1 3–2 Window 4 Diagnostic Registers . . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . Typical softc Data Structure . . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . Mapping Alternate Names . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . 2–11 3–2 3–4 Driver-Specific Macros . . .. . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . .. . Network ioctl Commands . . . .. . .. . .. . .. . .. . . .. . .. . .. . .. . . .. . .. . .. . ..
About This Manual This manual discusses how to write network device drivers for computer systems that run the Compaq Tru64™ UNIX operating system.
• 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.
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.
Chapter 8 Describes how to implement an init interface and associated routines, using the if_el device driver’s el_init( ) routine as an example. Chapter 9 Describes how to implement a start interface and associated routines, using the if_el device driver’s el_start( ) routine as an example. Chapter 10 Describes how to implement a watchdog interface, using the if_el device driver’s el_watch( ) routine as an example.
• 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.
• 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.
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.
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.
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 */ ZK-0818U-AI Unlike for block and character drivers, you do not specify network driver entry points in the dsent data structure.
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.
#include #include #include #include #include #include #include #include #include 3 4 #include 5 #include 6 #include #include #include 7 8 1 Includes the ioctl.h include file, which defines common ioctl commands.
• 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.
4 Declares 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.
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: static struct driver eldriver = { el_probe, 0, el_attach, 0, 0, 0, 0, 0, "el", el_info, 0, 0, 0, 0, 0, el_unattach, 0 }; 1 1 Declares and initializes the driver data structure called eldriver.
READ_BUS_D8 Reads a byte (8 bits) from a device register. READ_BUS_D16 Reads a word (16 bits) from a device register. READ_BUS_D32 Reads a longword (32 bits) from a device register. READ_BUS_D64 Reads a quadword (64 bits) from a device register. WRITE_BUS_D8 Writes a byte (8 bits) to a device register. WRITE_BUS_D16 Writes a word (16 bits) to a device register. WRITE_BUS_D32 Writes a longword (32 bits) to a device register. WRITE_BUS_D64 Writes a quadword (64 bits) to a device register.
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.
Table 1–1: Driver-Specific Macros (cont.) Macro Description READ_RXS Read from the 3Com 3C5x9 device’s receive status register. READ_FDP 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.
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.
interface to transmit the data. All network drivers must set the output member of the ifnet data structure to ether_output.
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.
2 Defines the interrupt latch bit position. 3 Defines the adapter failure bit position. 4 Defines the transmit complete bit position. 5 Defines the transmit available bit position. 6 Defines the receive complete bit position. 7 Defines the receive early bit position. 8 Defines the interrupt request bit position. 9 Defines the update statistics bit position. 10 Defines the command in-progress bit position. 11 Defines the current window number bit position. 2.
#define CMD_POWERUP #define CMD_POWERDOWN #define CMD_POWERAUTO (0x1b<<11) (0x1c<<11) (0x1d<<11) 31 32 33 1 Defines the offset for the I/O port of the command port register. 2 Defines the reset command bit position. 3 Defines the window selector for commands that are used to set up the device. 4 Defines the window selector for commands that control the operation of the device. 5 Defines the window selector for specifying the hardware address of the device.
23 Defines an enumerated data type called rx_filter. The if_el device driver can assign one of the following values to CMD_FILTER: RF_IND Individual address RF_GRP Group address RF_BRD Broadcast address RF_PRM Promiscuous address 24 Defines the receive (RX) early threshold command. 25 Defines the transmit (TX) available threshold command. 26 Defines the transmit (TX) start threshold command. 27 Defines the statistics enable command. 28 Defines the statistics disable command.
Figure 2–1: Window 0 Configuration Registers Register Constant Manufacturer ID Register W0_MID Adapter ID Register W0_AID Configuration Control Register W0_CCR Address Control Register W0_ACR Resource Configuration Register W0_RCR EEPROM Command Register W0_ECR EEPROM Data Register W0_EDR ZK-1267U-AI The following code shows the offset definitions for the registers that make up the window 0 configuration register: #define W0_MID 0x0 #define W0_AID 0x2 #define W0_CCR 0x4 enum w0_ccr { 4 CCR_P
ECR_WRITE=0x0040, ECR_ERASE=0x00c0, ECR_EWENA=0x0030, ECR_EWDIS=0x0000, ECR_EAR= 0x0020, ECR_WAR= 0x0010 }; #define W0_EDR 0xc 11 1 Defines the offset for the manufacturer ID register. 2 Defines the offset for the adapter ID register. 3 Defines the offset for the configuration control register. 4 Defines an enumerated data type called w0_ccr. The if_el device driver can assign one of the following values to W0_CCR (the configuration control register): CCR_PCMCIA If set, this is a PCMCIA bus.
8 9 10 11 Defines 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 Represents the interrupt request (IRQ). RCR_RSV Represents a reserved field. Defines the offset for the EEPROM command register. Defines an enumerated data type called w0_ecr. The if_el device driver can assign one of the following bits to W0_ECR (the EEPROM command register): ECR_EBY Indicates that the EEPROM is busy.
Figure 2–2: Window 3 Configuration Registers Register Constant Additional Setup Information 2 Register W3_ASI2 Additional Setup Information 0 Register W3_ASI0 ZK-1268U-AI The following code shows the offset definitions for the registers that are associated with the window 3 configuration registers: #define W3_ASI2 0x2 1 #define W3_ASI0 0x0 2 enum w3_asi { 3 ASI_IAS_ISA=0x00040000, ASI_IAS_PNP=0x00080000, ASI_IAS_BOT=0x000c0000, ASI_IAS_NON=0x00000000, ASI_PAR_35 =0x00000000, ASI_PAR_13 =0x00010000, A
ASI_RSIZE8 Indicates a RAM size of 8 kilobytes (the default). ASI_RSIZE32 Indicates a RAM size of 32 kilobytes. 2.5 Window 1 Operational Register Offset Definitions 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.
}; #define #define #define #define TX_INT W1_RXDATA W1_TXDATA W1_FREETX 0x8000 0x0 6 0x0 7 0xc 8 5 1 Defines the offset for the receive status register. 2 Defines an enumerated data type called w1_rxstat. The if_el device driver can assign one of the following values to W1_RXSTAT (the receive status register): RX_IC Indicates an incomplete operation. RX_ER Indicates an error in the operation. RX_EM If any of the bits are set in the mask, indicates that an error has occurred.
8 Defines the offset for the free transmit bytes register. 2.6 Window 4 Diagnostic Register Offset Definitions 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.
2 Defines 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 Indicates that 10BaseT cable is enabled. MD_COAXE Indicates that 10Base2 cable is enabled. MD_RES1 Reserved. MD_SQE Indicates that SQE is present. MD_VLB Indicates that a valid link beat was detected. MD_PRD Indicates that polarity reversal was detected. MD_JAB Indicates that jabber was detected.
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.
3 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.
Figure 3–1: Typical softc Data Structure * Common Information * Enhanced Hardware Management Information ** Media State Information * Base Register * Multicast Table 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 ZK-1273U-AI A singl
#define #define #define #define #define is_ac ztime ctrblk is_if is_addr is_ed->ess_ac 2 is_ed->ess_ztime 3 is_ed->ess_ctrblk 4 is_ac.ac_if 5 is_ac.ac_enaddr 6 1 Declares 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. 2 Maps the ess_ac member of the ether_driver data structure to the alternate name is_ac.
Figure 3–2: Mapping Alternate Names ether_driver . . . arpcom . . . #define is_ac ess_ac ac_if #define ztime ess_ztime #define ctrblk ess_ctrblk . . . ac_hwaddr . . . #define is_if #define ac_enaddr #define is_addr 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.
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.
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.
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.
2 Contains the I/O base address. 3 Contains a tag value that identifies 3Com 3C5x9 devices on an ISA bus. 4 Contains a value that indicates whether the user has ejected the PCMCIA card. 5 Contains a value that indicates whether the user has reloaded the PCMCIA card. 6 Contains a value that indicates whether the card is a PCMCIA card. 7 Declares a pointer to the card_info data structure and calls it cinfop.
The following code shows the declarations of the timeout and interrupt information in the if_el device driver’s el_softc data structure: unsigned unsigned unsigned unsigned long long long long txreset; 1 xmit_tmo; 2 tint; 3 rint; 4 1 Contains the number of transmitter error resets. 2 Contains the number of times that transmit timeouts occurred. The el_watch( ) routine increments this member. 3 Contains the count of transmit interrupts. 4 Contains the count of receive interrupts. 3.
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 1 Declares a copy of the w3_eeprom data structure and calls it eeprom. 3.
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 configure interface registers callback routines, which allow the cfgmgr framework to configure the driver into the kernel at a specified point during system startup.
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: static unsigned char el_pcmcia_optiondata[400] = ""; static unsigned char el_isa_optiondata[300] = ""; 2 static unsigned char el_unused[300] = ""; static int el_polling = 0; 3 static int el_pollint = 16; 4 static int el_configured = 0; 5 static struct lan_config_data el_data = { 6 LAN_CONFIG_VERSION_ID, 0, &eldriver, &el_configured }; 1 cfg_subsys_attr_t el_
6 Declares the lan_config_data structure, which contains all information specific to the el driver. The lan_configure common code uses this structure. 7 Declares an array of cfg_subsys_attr_t data structures and calls it el_attributes. 8 Describes the PCMCIA_Option attribute, which specifies the option data for the PCMCIA bus. 9 Describes the ISA_Option attribute, which specifies the option data for the ISA bus. 10 Describes the Polling attribute, which is specific to this device driver.
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. 4 Declares 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.
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’s probe interface. The if_el driver operates on the ISA and PCMCIA bus.
• 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.
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.
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); 2 } 1 If the unit variable exceeds the maximum number of devices that the if_el driver supports, calls the printf( ) routine to display an appropriate message on the console terminal.
case BUS_ISA: 8 if (get_config(ctlr, RES_PORT, NULL, &port_sel, 0) >= 0) { reg = port_sel.
6 Calls 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. 7 Returns the value 0 (zero) to indicate that the probe operation failed. 8 Performs tasks related to the ISA bus if bus_type evaluates to the constant BUS_ISA. 9 Calls the get_config( ) routine to obtain the base I/O address for the device.
if (el_softc[unit]) { 1 sc = el_softc[unit]; sc->cardout = 0; sc->reprobe = 1; } else { 2 MALLOC(sc, void*, sizeof(struct el_softc), M_DEVBUF, M_WAIT | M_ZERO); if (!sc) { 3 printf("el%d: el_probe: failed to get buffer memory for softc\n", unit); return(0); 4 } 1 If the user removed and returned the PCMCIA card to its slot: • Locates the existing el_softc data structure for this device.
2 Initializes 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 } 1 Initializes the net_hw_mgmt data structure.
sc->irq = 3; 3 sc->iobase = 0; 4 sc->ispcmcia = 1; 5 sc->cinfop =card_infop; pcmcia_register_event_callback(card_infop->socket_vnum, CARD_REMOVAL_EVENT, (caddr_t)el_card_remove, (caddr_t)sc); 6 if (multi_func_flag) 7 lan_set_attribute(sc->ehm.current_val, NET_MODEL_NDX, "3C562"); else lan_set_attribute(sc->ehm.current_val, NET_MODEL_NDX, "3C589"); break; case BUS_ISA: 8 sc->irq = irq_sel.channel; sc->isa_tag = isatag; 9 10 sc->iobase = ((reg-0x200)/0x10)&0x1f; 11 lan_set_attribute(sc->ehm.
5.1.
for (i=0; i<(sizeof(struct w3_eeprom)/2); i++) { WRITE_ECR(sc, ECR_READ+i); DELAY(1000); *ed = READ_EDR(sc); ed++; } } for (i=0; i<3; i++) { 4 j = sc->eeprom.
8 9 Calls 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.
if (status == SUCCESS) { ee = (unsigned char *)&ee_copy; for (i = 0; i < (sizeof(struct w3_eeprom)); i++) { *ee = tuple_data_infop->TupleData[i]; ee++; } } else { printf("el%d: Can’t read multifunction card’s eeprom.\n", unit); if (sc->ispcmcia) pcmcia_unregister_event_callback(card_infop->socket_vnum, CARD_REMOVAL_EVENT, (caddr_t)el_card_remove); return(0); } } else { printf("el%d: Can’t read multifunction card’s eeprom.
bcopy(&ee_copy, &sc->eeprom, sizeof(struct w3_eeprom)); 11 } } 1 If 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. 2 If this is not a multifunction PC card, the EEPROM data is read directly from the card and saved in the el_sofc data structure.
registration of interrupt handlers. All network device drivers are required to register interrupt handlers. el_intr_info.configuration_st = (caddr_t)ctlr; 1 el_intr_info.intr = el_intr; 2 el_intr_info.param = (caddr_t)unit; 3 el_intr_info.config_type = CONTROLLER_CONFIG_TYPE; 4 if (ctlr->bus_hd->bus_type == BUS_PCMCIA) 5 el_intr_info.config_type |= SHARED_INTR_CAPABLE; el_ihandle.ih_bus = ctlr->bus_hd; 6 el_ihandle.
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.
5.1.14 Registering the shutdown Routine The following code shows how the el_probe( ) routine registers its shutdown( ) routine. The kernel calls this routine when the system shuts down. The driver can specify an argument for the kernel to pass to the routine at that time. if (!sc->reprobe) drvr_register_shutdown(el_shutdown, (void*)sc, DRVR_REGISTER); return( ~ 0); 1 } 1 Registers the shutdown( ) routine and directs the kernel to pass a pointer to the driver’s softc data structure to the routine.
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.
• 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.
5.3.3 Testing for the Termination Flag The following code shows how the el_autosense_thread( ) routine tests for the termination flag: while (thread_should_halt(sc->autosense_thread)) { 1 printf("el%d: Autosense thread exiting\n", ifp->if_unit); thread_halt_self(); 2 } 1 Performs an initial test for the termination flag. The termination flag would have been set if another kernel thread had called the thread_terminate( ) routine for the el_autosense_thread( ) routine.
simple_unlock(&sc->el_softc_lock); splx(s); thread_halt_self(); } 1 Enters a loop for transmitting a packet and determining if it succeeds. A packet must go out twice successfully for media selection to succeed. This algorithm probably will not work in all cases. 5.3.6 Saving Counters Prior to the Transmit Operation The following code shows how the el_autosense_thread( ) routine saves counters prior to the transmit operation: prev_tint= sc->tint; prev_err = ifp->if_oerrors; prev_tmo = sc->xmit_tmo; 5.3.
ifp->if_unit, lan_media_strings_10[sc->lm_media]); good_xmits = 100; 1 Uses the default from ROM. 5.3.9 Setting the Media in the Hardware The following code shows how the el_autosense_thread( ) routine sets the media setting in the hardware: el_reset(ifp->if_unit); break; 2 } else { 1 1 Directs the hardware to use the media setting that was selected in the previous section. 2 Breaks out of the packet transmit loop because the media setting has been determined. 5.3.
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: wait = 0; while ((prev_tint == sc->tint) && 1 (prev_tmo == sc->xmit_tmo) && (wait++ < 4)) { assert_wait((vm_offset_t)&wait_flag, TRUE); thread_set_timeout(1*hz); 2 thread_block(); } 1 Waits until the transmit makes it out, a timeout occurs, or 4 seconds pass. 2 Sets the timer and puts the current thread to sleep.
WRITE_CMD(sc, CMD_WINDOW1); simple_unlock(&sc->el_softc_lock); splx(s); break; default: break; } 1 Tests for loss of carrier errors. Most network adapters give carrier errors if no cable is plugged in or if transceivers are not present. 5.3.
if (sc->lm_media_mode == LAN_MODE_AUTOSENSE) sc->lm_media = LAN_MEDIA_UTP; break; case LAN_MEDIA_BNC: if (sc->lm_media_mode == LAN_MODE_AUTOSENSE) sc->lm_media = LAN_MEDIA_AUI; break; case LAN_MEDIA_UTP: default: if (sc->lm_media_mode == LAN_MODE_AUTOSENSE) sc->lm_media = LAN_MEDIA_BNC; break; } el_reset(ifp->if_unit); 2 } } 1 Selects new media. 2 Calls the el_reset( ) routine to reset the hardware. This reset will establish the next media to try. 5.3.
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.
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( ).
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.
header length is the size of the ether_header data structure plus 8 (the size of the maximum LLC header). The media headers are represented by the following data structures: ether_header The media header structure for Ethernet-related media. The if_ether.h file defines the ether_header structure. fddi_header The media header structure for FDDI-related media. The if_fddi.h file defines the fddi_header structure. trn_header The media header structure for Token Ring-related media. The if_trn.
3 Sets 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 The maximum transmission unit for Ethernet media. The if_ether.h file defines the ETHERMTU constant. FDDIMTU The maximum transmission unit for FDDI media. The if_fddi.h file defines the FDDIMTU constant.
8 Sets 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.
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 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.
3 Sets 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. 4 Sets 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.
8 Sets 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 1 Sets 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.
2 Calls 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. 3 If 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.
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.
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.
struct el_softc *sc = el_softc[unit]; struct ifnet *ifp = &sc->is_if; 1 Declares 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. 2 Declares a unit variable and initializes it to the controller number for this controller.
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.
7.6 Unregistering the PCMCIA Event Callback Routine The following code shows how the el_unattach( ) routine unregisters the PCMCIA event callback routine: if (sc->ispcmcia) 1 pcmcia_unregister_event_callback(sc->cinfop->socket_vnum, CARD_REMOVAL_EVENT, (caddr_t)el_card_remove); 1 For PCMCIA versions of the card, directs the bus code not to return notification if the card has been removed. 7.
7.10 Unregistering the Card from the Hardware Management Database The following code shows how the el_unattach( ) routine unregisters the card from the hardware management database: lan_ehm_free(&sc->ehm); 1 1 Frees up any memory allocated for enhanced hardware management and unregisters this card from the hardware management database. 7.
8 Implementing the Initialization Section The initialization section prepares the network interface to transmit and receive data packets. It can also allocate mbuf data structures for the receive ring. The if_el device driver implements the following routines in its initialization section: • el_init (Section 8.1) • el_init_locked (Section 8.2) 8.
3 Declares a pointer to an ifnet data structure called ifp and initializes it to the address of the ifnet data structure for this 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. 4 Declares the i and s variables. The i variable stores the value that el_init_locked( ) returns.
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. 8.1.4 Calling the el_init_locked Routine The following code shows how the el_init( ) routine calls the el_init_locked( ) routine, which performs the actual initialization tasks: i = el_init_locked(sc, ifp, unit); 8.1.
• Sets the LAN media type attribute (Section 8.2.6) • Selects memory mapping (Section 8.2.7) • Resets the transmitter and receiver a second time (Section 8.2.8) • Sets the LAN address (Section 8.2.9) • Processes special flags (Section 8.2.10) • Sets the debug flag (Section 8.2.11) • Enables TX and RX (Section 8.2.12) • Enables interrupts (Section 8.2.13) • Sets the operational window (Section 8.2.14) • Marks the device as running (Section 8.2.
This task is specific to the 3Com 3C5x9 device. Make sure that you perform similar initialization tasks for the hardware device that your network driver controls. WRITE_CMD(sc, CMD_ACKINT+0xff); 1 1 Calls the WRITE_CMD macro to write data to the command port register. The data written to the command port register is the acknowledge interrupt command (CMD_ACKINT) plus a mask that specifies that all interrupts are to be acknowledged. 8.2.
8.2.5 Setting the LAN Media The following code shows how the el_init_locked( ) routine sets the LAN media. This task is specific to the 3Com 3C5x9 device. You may want to perform similar initialization tasks for the hardware device that your network driver controls.
10 For the default case, sets the lm_media member to LAN_MEDIA_UTP (media mode is unshielded twisted pair cable). 11 Determines whether lm_media evaluates to LAN_MEDIA_UTP. 12 Calls WRITE_ACR to write to the address control register. The data to be written establishes the Ethernet unshielded twisted-pair cable as the media. 13 Calls WRITE_CMD to write to the command port register. The data to be written is the window 4 diagnostic command bit (CMD_WINDOW4).
WRITE_CMD(sc, CMD_TXRESET); WRITE_CMD(sc, CMD_RXRESET); 1 2 1 Calls the WRITE_CMD macro to write data to the command port register. The data to be written is the transmit (TX) reset command (CMD_TXRESET). 2 Calls the WRITE_CMD macro to write data to the command port register. In this call, the data to be written is the receive (RX) reset command (CMD_RXRESET). 8.2.9 Setting the LAN Address The following code shows how the el_init_locked( ) routine sets the LAN address.
else { lan_set_attribute(sc->ehm.current_val, NET_PROMISC_NDX, (void *)0); } WRITE_CMD(sc, CMD_FILTER+i); 7 1 If loopback mode is requested, enables it. 2 Sets the LAN loopback attribute for EHM support. 3 Selects to receive frames that are sent to both the local address and the broadcast address. 4 If the network device receives all multicast packets, selects all group addresses. 5 If the network device receives all packets destined to all stations, selects promiscuous mode.
WRITE_CMD(sc, CMD_RXENA); WRITE_CMD(sc, CMD_TXENA); 1 2 1 Calls the WRITE_CMD macro to write data to the command port register. The data to be written is the receive (RX) enable command (CMD_RXENA). 2 Calls the WRITE_CMD macro to write data to the command port register. In this call, the data to be written is the transmit (TX) enable command (CMD_TXENA). 8.2.13 Enabling Interrupts The following code shows how the el_init_locked( ) routine enables interrupts.
ifp->if_flags |= IFF_RUNNING; 1 ifp->if_flags &= ~ IFF_OACTIVE; 2 1 Sets the IFF_RUNNING flag to mark the device as running. 2 Clears the IFF_OACTIVE flag to indicate that there is no output outstanding. 8.2.16 Starting the Autosense Kernel Thread The following code shows how the el_init_locked( ) routine starts the autosense kernel thread. Only network device drivers that implement an autosense kernel thread perform this task.
9 Implementing the Start Section The start section of a network device driver transmits data packets across the network. When the network protocol has a data packet to transmit, it prepares the packet, then calls the start interface for the appropriate network device driver. The start interface transmits the packet. When the transmission is complete, it frees up the buffers that are associated with the packet.
2 Calls the simple_lock_try( ) routine to try to assert a lock with read and write access for the resource that is associated with the specified simple lock. The el_start( ) routine calls simple_lock_try( ) rather than simple_lock( ) because simple_lock_try( ) returns immediately if the resource is already locked; simple_lock( ) spins until the lock has been obtained. Make sure that you call simple_lock_try( ) when you need a simple lock but the code cannot spin until the lock is obtained.
This simple lock was previously asserted by calling the simple_lock( ) or simple_lock_try( ) routine. 2 Calls the splx( ) routine to reset the CPU priority to the level that the s variable specifies. 9.2 Implementing the el_start_locked Routine The el_start_locked( ) routine performs the start operation. It is called by the if_el device driver’s el_init_locked( ), el_start( ), el_intr( ), and el_autosense_thread( ) routines.
IF_DEQUEUE(&ifp->if_snd, m); 3 while (m) { 4 m_freem(m); IF_DEQUEUE(&ifp->if_snd, m); } return; } 1 Declares a pointer to an ether_header data structure called eh. The ether_header data structure contains information that is associated with a 10 Mb/s and 100 Mb/s Ethernet header. 2 If the cardout member of the el_softc data structure for this device is set to 1 (true), the user removed the PCMCIA card from the slot. 3 Calls the IF_DEQUEUE macro to remove an entry from the output queue.
mp = ms; 8 mn = mp->m_next; 9 len = mp->m_len; 10 while (mn != NULL) { 11 if (mn->m_len == 0) { mp->m_next = mn->m_next; mn->m_next = NULL; m_free(mn); } else { 12 len += mn->m_len; mp = mn; } mn = mp->m_next; } 1 While true, removes packets from the pending queue and has the device transmit the packets. 2 Calls the IF_DEQUEUE macro to remove an entry from the output queue. The output queue is referenced through the if_snd member of the ifnet data structure for this device.
in the middle. The mfree( ) routine is called to free any zero-length memory buffers. Otherwise, adds the length and sets the next memory buffer in the chain to the mp mbuf pointer. 12 9.2.
2 Copies transmit data from memory to the card using 32-bit writes. Only a multiple of 4 bytes can be copied this way. 3 If some number of bytes (fewer than 4) remain in the current memory buffer, the driver either copies those bytes directly to the card (if they were the last bytes for the entire frame), or combines those bytes with bytes from the next memory buffer (if there is more data for this frame). 9.2.
9.2.6 Indicating When to Start the Watchdog Routine The following code shows how the el_start_locked( ) routine indicates the time for starting the driver’s watchdog interface. Although this task is optional, we recommend that all network drivers perform this task. ifp->if_timer = 3; 1 } 1 Sets the time (in seconds) for starting the if_el driver’s watchdog( ) routine, called el_watch( ).
10 Implementing a Watchdog Section Network device drivers can take advantage of the watchdog timer. The network layer implements this mechanism to ensure that the network device is transmitting data. The driver starts the watchdog timer when it sends a transmit request to the device. After it receives the transmit completion interrupt, the driver stops the timer. If the interrupt never happens, the timer expires and the driver’s watchdog interface is called.
2 Calls the simple_lock( ) routine to assert a lock with exclusive access for the resource that is associated with the el_softc_lock simple lock data structure pointer. 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. 10.
11 Implementing the Reset Section The reset section of a network device driver contains the code that resets the LAN adapter when there is a network failure and there is a need to restart the device. It resets all of the counters and local variables and can free up and reallocate all of the buffers that the network driver uses. The if_el device driver implements the following routines in its reset section: • el_reset( ) (Section 11.1) • el_reset_locked( ) (Section 11.2) 11.
3 Calls the el_reset_locked( ) routine, which performs the actual tasks that are associated with resetting the device. 4 Calls the simple_unlock( ) routine to release the simple lock for the el_softc data structure and then resets the CPU priority to the level that it was originally at upon entrance to this routine. 11.
12 Implementing the ioctl Section The ioctl section of a network device driver contains the code that implements a network device driver’s ioctl interface. The ioctl interface performs miscellaneous tasks that have nothing to do with data packet transmission and reception. Typically, it turns specific features of the hardware on or off. The el_ioctl( ) routine performs the following tasks: • Determines whether the user has removed the PCMCIA card from the slot (Section 12.
Table 12–1: Network ioctl Commands (cont.) ioctl Command Required Description For More Information SIOCSIFFLAGS Yes Ensures that the Section 12.12 interface is operating correctly according to the interface flags (if_flags). SIOCSIPMTU Yes Sets the IP maximum Section 12.13 transmission unit (MTU). SIOCSMACSPEED Yes Sets the media speed. Section 12.14 SIOCIFRESET No Resets the device. Section 12.
7 Casts the data argument to a data structure of type ifdevea for use with the SIOCRPHYSADDR ioctl command. 8 Casts the data argument to a data structure of type ctrreq for use with the SIOCRDCTRS and SIOCRDZCTRS ioctl commands. 9 Casts the data argument to a data structure of type ifchar for use with the SIOCIFSETCHAR ioctl command. 10 Declares a lock_on variable and sets it to the value 1 (true), which indicates that the simple lock is held.
you call simple_unlock( ) to release it. Because simple locks are spin locks, simple_lock( ) does not return until the lock has been obtained. 12.4 Enabling Loopback Mode (SIOCENABLBACK ioctl Command) The following code shows how the el_ioctl( ) routine implements the SIOCENABLBACK ioctl command to enable loopback mode when an application requests it. Support for the SIOCENABLBACK command is optional. You can choose whether or not your driver supports it.
12.6 Reading Current and Default MAC Addresses (SIOCRPHYSADDR ioctl Command) The following code shows how the el_ioctl( ) routine implements the SIOCRPHYSADDR ioctl command to read the current and default MAC addresses when an application requests them: case SIOCRPHYSADDR: 1 bcopy(sc->is_addr, ifd->current_pa, 6); 2 for (i=0; i<3; i++) { 3 j = sc->eeprom.addr[i]; ifd->default_pa[(i*2)] = (j>>8) & 0xff; ifd->default_pa[(i*2)+1] = (j) & 0xff; } break; 1 Determines whether the cmd argument is SIOCRPHYSADDR.
4 If the 3Com 3C5x9 device is running, calls the el_reset_locked( ) routine to restart the network interface with the new address. 5 Calls the simple_unlock( ) routine to release the simple lock for the resource that is associated with el_softc_lock. 6 Calls the splx( ) routine to reset the CPU priority to the level that the s variable specifies. 7 Sets the lock_on variable to 0 (false), which indicates that the simple lock is no longer held.
ether_sprintf(maddr), sc->is_multi.lan_mtable[j-1].muse); } } lan_build_mclist (mclist_buf, NET_SZ_MCLIST, &sc->is_multi); 5 lan_set_attribute(sc->ehm.current_val, NET_MCLIST_NDX, mclist_buf); break; 1 Determines whether the cmd argument is SIOCADDMULTI. 2 If the address is broadcast, indicates the presence of another broadcast user. If the address is multicast, the el_ioctl( ) routine adds the address to the table. The EtherLink III family does not support any multicast filtering.
if (sc->debug) { j = 0; printf("el%d: Dump of multicast table after DEL (%d entries)\n", unit, sc->is_multi.lan_nmulti); for (i=0; iis_multi.lan_nmulti; i++) { unsigned char *maddr; LAN_GET_MULTI(&sc->is_multi, maddr, j); printf(" %d %s (muse==%d)\n", i+1, ether_sprintf(maddr), sc->is_multi.lan_mtable[j-1].muse); } } lan_build_mclist (mclist_buf, NET_SZ_MCLIST, &sc->is_multi); 3 lan_set_attribute(sc->ehm.
2 Copies the current counters to the ctrreq data structure. 3 Indicates that these are Ethernet counters. 4 Returns the number of seconds since the counters were last zeroed. 5 If the user process requested the SIOCRDZCTRS command, zeroes the counters and sets the ztime member of the softc data structure to the current time. This indicates when the counters were zeroed. For other types of network interfaces, you can specify a different counter type and a different set of counters.
2 Marks the interface as up and calls the el_reset_locked( ) routine to start the network interface with the current settings. 3 Sets the counter cleared time (used by DECnet, netstat, clusters, and so forth). 12.
SIOCSMACSPEED and SIOCIFSETCHAR ioctl commands perform some of the same tasks.) case SIOCSMACSPEED: 1 bcopy(ifr->ifr_data, (u_char *)&speed, sizeof(u_short)); if ((speed != 0) && (speed != 10)) { status = EINVAL; break; } break; 2 1 Determines whether the cmd argument is SIOCSMACSPEED. 2 If the LAN speed passed is anything other than 10 (0 means no change), fails the request. (The if_el device can only operate at 10 Mb per second.) 12.
if (ifc->ifc_auto_sense != -1) { 5 if ((ifc->ifc_auto_sense == LAN_AUTOSENSE_ENABLE) && (sc->lm_media_mode != LAN_MODE_AUTOSENSE)) { sc->lm_media_mode = LAN_MODE_AUTOSENSE; need_reset++; } else if ((ifc->ifc_auto_sense == LAN_AUTOSENSE_DISABLE) && (sc->lm_media_mode == LAN_MODE_AUTOSENSE)) { sc->lm_media_mode = sc->lm_media; 6 need_reset++; } } if (ifc->ifc_media_type != -1) { 7 switch (ifc->ifc_media_type) { case LAN_MEDIA_UTP: case LAN_MEDIA_AUI: case LAN_MEDIA_BNC: 8 if (ifc->ifc_media_type != sc->lm
If the user sets media that the card does not have, the interface may not work. 9 Selects the new mode. 10 Resets the device to pick up the new mode (if the interface was running). 11 The default case returns an error that indicates that the caller has issued an invalid ioctl command. 12.
13 Implementing the Interrupt Section The interrupt section of a network device driver contains the code that is called whenever the network interface transmits or receives a frame. The if_el device driver implements the following routines in its interrupt section: • el_intr( ) (Section 13.1) • el_rint( ) (Section 13.2) • el_tint( ) (Section 13.3) • el_error( ) (Section 13.4) ______________________ Note _______________________ The if_el device driver implements a shared interrupt handler.
13.1.
13.1.3 Reading the Interrupt Status The following code shows how the el_intr( ) routine uses the READ_STS macro to read the interrupt status from the I/O status register: status = READ_STS(sc); 13.1.
• If the status variable has the S_AF bit set, calls the el_error( ) routine to process the error. • Calls the READ_STS macro to read the interrupt status again from the I/O status register. 13.1.5 Acknowledging the Interrupt The following code shows how the el_intr( ) routine acknowledges the interrupt: WRITE_CMD(sc, CMD_ACKINT+(S_IL)); 1 1 Calls the WRITE_CMD macro to write data to the command port register.
13.1.8 Indicating That the Interrupt Was Serviced The following code shows how the el_intr( ) routine indicates that the interrupt was serviced: return INTR_SERVICED; 1 } 1 Returns the INTR_SERVICED constant to the kernel interrupt dispatcher to indicate that el_intr( ) serviced the shared interrupt. 13.2 Implementing the el_rint Routine The if_el driver’s el_rint( ) routine is the receive interrupt completion routine.
13.2.2 Pulling the Packets from the FIFO Buffer The following code shows how the el_rint( ) routine pulls the packets from the first-in/first-out (FIFO) buffer. This task is specific to the hardware device that is associated with the if_el device driver. If you need to perform a similar task with your hardware device, use this example as a model.
2 Looks for errors. 3 Processes the error. 4 Processes the overrun error case. 5 Processes the runt and oversized error cases. 6 Processes the CRC error case. 7 Processes the alignment error case. 8 Discards the packet if none of the previous cases apply. This indicates a size error. 9 Allocates a buffer for the received data. If the length of the received data is less than a small mbuf, allocates a small mbuf. Otherwise, a 2K cluster mbuf is allocated. This code is an optimization.
if (bcmp(mtod(m, unsigned char *), etherbroadcastaddr, 6) != 0) { 8 int ix; LAN_FIND_MULTI(&sc->is_multi, mtod(m, unsigned char *), ix, i); 9 if ( (i != LAN_MULTI_FOUND) || 10 (sc->is_multi.lan_mtable[ix].muse == 0)) { m_freem(m); goto scrap; } } } } 1 If an mbuf was successfully allocated, copies the packet data into the mbuf (receive data are 32-bit aligned). 2 Computes the length of the received data, excluding the size of the MAC header. Records this length in the mbuf header.
eh = *(mtod(m, struct ether_header *)); 2 eh.ether_type = ntohs((unsigned short)eh.ether_type); m->m_data += sizeof(struct ether_header); 4 3 ADD_RECV_PACKET(ifp, sc, m->m_pkthdr.len); 5 if (eh.ether_dhost[0] & 0x1) { ADD_RECV_MPACKET(ifp, sc, m->m_pkthdr.
if ((sc->debug) && (count <= 0)) printf("el%d: Receive in INFINITE loop %04X\n", ifp->if_unit, status); } 1 Calls the WRITE_CMD macro to write data to the command port register. The data to be written is the receive discard top packet command (CMD_RXDTP). 13.3 Implementing the el_tint Routine The if_el device driver’s el_tint( ) routine is the transmit interrupt completion routine. It performs the following tasks: • Counts the transmit interrupt (Section 13.3.
WRITE_CMD(sc, CMD_TXRESET); 4 DELAY(10); WRITE_CMD(sc, CMD_TXENA); 1 Calls the READ_TXS macro to read the transmit status from the transmit status register. 2 Examines the status for a jabber or an underrun error. If either of these errors happened, then the transmitter must be reset. 3 Clears the transmit status register and resets the transmitter. 4 Calls the DELAY macro to wait for 10 microseconds before reenabling the transmitter. 13.3.
2 Updates the softc data structure with the amount of space that is available in the transmit FIFO. 13.3.5 Queuing Other Transmits The following code shows how the el_tint( ) routine clears the output active flag to permit other transmits to be queued to the device: ifp->if_flags &= ~IFF_OACTIVE; } 13.
14 Network Device Driver Configuration Device driver configuration incorporates device drivers into the kernel to make them available to system administration and other utilities. The operating system provides two methods for configuring drivers into the kernel: static and dynamic. We recommend that you implement your driver products as a single binary module so that customers can statically or dynamically configure them into the kernel.
Index Numbers and Special Characters 10Base2 transceiver ensuring that it is off, 8–5 C carrier checking for transmits, 5–23 cfg_subsys_attr_t data structure, 4–2 A allocating the ether_driver data structure, 5–7 attach interface, 6–1 registering adapters, 6–9 setting network attributes, 6–9 autoconfiguration attach interface, 6–1 probe interface, 5–1 autoconfiguration support section, 1–10, 5–1 implementing, 6–1 autosense thread context information, 3–9 autosensethread starting, 8–11 command port regis
of pending transmit frames, 13–4 of receive interrupt, 13–8 debug flag, 3–8 setting, 8–9 debug information printing, 5–24 declarations configure-related, 4–2 network device driver, 1–4 declarations section, 1–4 devdriver.
initializing the enhanced hardware management data structure, 5–8 performing bus-specific tasks, 5–4 registering interrupt handlers, H hardware address determining a change, 5–12 reading current, 12–5 header file devdriver.h, 1–4 errno.h, 1–3 if_elreg.h, 2–1 ioctl.h, 1–4 sysconfig.
interrupt handler enabling, 6–10 ID, 3–6 registering, 5–15 interrupt section, 1–11 implementing, 13–1 ioctl command SIOCADDMULTI, 12–6 SIOCDELMULTI, 12–7 SIOCDISABLBACK, 12–4 SIOCENABLBACK, 12–4 SIOCIFRESET, 12–11 SIOCIFSETCHAR, 12–11 SIOCRDCTRS, 12–8 SIOCRDZCTRS, 12–8 SIOCRPHYSADDR, 12–5 SIOCSIFADDR, 12–9 SIOCSIFFLAGS, 12–10 SIOCSIPMTU, 12–10 SIOCSMACSPEED, 12–11 SIOCSPHYSADDR, 12–5 ioctl interface, 12–1 ioctl section, 1–11 implementing, 12–1 ioctl.
autoconfiguration support section, 1–10 configure section, 1–10 declarations, 1–4 environment, 1–1 include files, 1–3 initialization section, 1–10 interrupt section, 1–11 ioctl section, 1–11 output section, 1–11 register offsets, 2–1 reset section, 1–11 start section, 1–10 watchdog section, 1–11 network layer attaching, 6–8 O operational window setting, 8–10 outgoing bytes accounting for, 9–7 output process marking as active, 9–7 output section, 1–11 P packet copying the first part, 13–7 determining succ
ROM using the default from, 5–21 RX status reading, 13–5 SIOCDISABLBACK ioctl command, 12–4 SIOCENABLBACK ioctl command, 12–4 SIOCIFRESET ioctl command, 12–11 S SIOCIFSETCHAR ioctl command, section autoconfiguration support, 1–10, 12–11 SIOCRDCTRS ioctl command, 5–1, 6–1 configure, 1–10 declarations, 1–4 include files, 1–3 initialization, 1–10, 8–1 interrupt, 1–11, 13–1 ioctl, 1–11, 12–1 output, 1–11 reset, 1–11, 11–1 start, 1–10, 9–1 watchdog, 1–11, 10–1 setting network attributes, 6–9 shutdown rou
loading into the buffer, 5–22 transmitting, 5–22 timeout information in el_softc data structure, 3–9 rearming the next, 13–2 timer clearing, 10–2 transmit counting interrupts, 13–10 counting timeouts, 10–2 discarding all, 9–3 freeing buffer, 9–7 of pending packets, 8–11 processing completed operations, 13–3 queuing, 13–12 reading status, 13–10 saving counters, 5–21 transmitter resetting, 8–4, 8–7 TX and RX enabling, 8–9 U unit resetting, 10–2 V VBA_Option entry sysconfigtab file fragment, 14–1 W w3_eep