VxWorks Reference Manual : Libraries
if_eex - Intel EtherExpress 16 network interface driver
eexattach( ) - publish the eex network interface and initialize the driver and device
eexTxStartup( ) - start output on the chip
This module implements the Intel EtherExpress 16 PC network interface card driver. It is specific to that board as used in PC 386/486 hosts. This driver is written using the device's I/O registers exclusively.
This module assumes a little-endian host (80x86); thus, no endian adjustments are needed to manipulate the 82586 data structures (little-endian).
The on-board memory is assumed to be sufficient; thus, no provision is made for additional buffering in system memory.
The "frame descriptor" and "buffer descriptor" structures can be bound into permanent pairs by pointing each FD at a "chain" of one BD of MTU size. The 82586 receive algorithm fills exactly one BD for each FD; it looks to the NEXT FD in line for the next BD.
The transmit and receive descriptor lists are permanently linked into circular queues partitioned into sublists designated by the EEX_LIST headers in the driver control structure. Empty partitions have NULL pointer fields. EL bits are set as needed to tell the 82586 where a partition ends. The lists are managed in strict FIFO fashion; thus the link fields are never modified, just ignored if a descriptor is at the end of a list partition.
This device is soft-configured. No jumpering diagram is required.
This driver provides the standard external interface with the following exceptions. All initialization is performed within the attach routine and there is no separate initialization routine. Therefore, in the global interface structure, the function pointer to the init( ) routine is NULL.
There is one user-callable routine, eexattach( ). For details on usage, see the manual entry for this routine.
None.
- one mutual exclusion semaphore
- one interrupt vector
- one watchdog timer.
- 8 bytes in the initialized data section (data)
- 912 bytes in the uninitialized data section (bss)The data and bss sections are quoted for the MC68020 architecture and may vary for other architectures. The code size (text) will vary widely between architectures, and is thus not quoted here.
The device contains on-board buffer memory; no system memory is required for buffering.
The only adjustable parameter is the number of TFDs to create in adapter buffer memory. The total number of TFDs and RFDs is 21, given full-frame buffering and the sizes of the auxiliary structures. eexattach( ) requires at least MIN_NUM_RFDS RFDs to exist. More than ten TFDs is not sensible in typical circumstances.
eexattach( ) - publish the eex network interface and initialize the driver and device
STATUS eexattach ( int unit, /* unit number */ int port, /* base I/O address */ int ivec, /* interrupt vector number */ int ilevel, /* interrupt level */ int nTfds, /* # of transmit frames (0=default) */ int attachment /* 0=default, 1=AUI, 2=BNC, 3=TPE */ )
The routine publishes the eex interface by filling in a network interface record and adding this record to the system list. This routine also initializes the driver and the device to the operational state.
OK or ERROR.
eexTxStartup( ) - start output on the chip
#ifdef BSD43_DRIVER static void eexTxStartup ( int unit )
Looks for any action on the queue, and begins output if there is anything there. This routine is called from several possible threads. Each will be described below.
The first, and most common thread, is when a user task requests the transmission of data. Under BSD 4.3, this will cause eexOutput( ) to be called, which will cause ether_output( ) to be called, which will cause this routine to be called (usually). This routine will not be called if ether_output( ) finds that our interface output queue is full. In this case, the outgoing data will be thrown out. BSD 4.4 uses a slightly different model in which the generic ether_output( ) routine is called directly, followed by a call to this routine.
The second, and most obscure thread, is when the reception of certain packets causes an immediate (attempted) response. For example, ICMP echo packets (ping), and ICMP "no listener on that port" notifications. All functions in this driver that handle the reception side are executed in the context of netTask( ). Always. So, in the case being discussed, netTask( ) will receive these certain packets, cause IP to be stimulated, and cause the generation of a response to be sent. We then find ourselves following the thread explained in the second example, with the important distinction that the context is that of netTask( ).
The third thread occurs when this routine runs out of TFDs and returns. If this occurs when our output queue is not empty, this routine would typically not get called again until new output was requested. Even worse, if the output queue was also full, this routine would never get called again and we would have a lock state. It DOES happen. To guard against this, the transmit clean-up handler detects the out-of-TFDs state and calls this function. The clean-up handler also runs from netTask.
Note that this function is ALWAYS called between an splnet( ) and an splx( ). This is true because netTask( ), and ether_output( ) take care of this when calling this function. Therefore, no calls to these spl functions are needed anywhere in this output thread.