NDIS Driver Developer's Tool Kit for OS/2 and DOS - Programmer's Guide
- 1 Preface
- 2 Chapter 1. Overview
- 2.1 Types of Device Drivers
- 2.2 Installable Device Drivers
- 2.3 Introduction to NDIS
- 2.4 Media Access Control Drivers
- 3 Chapter 2. OS/2 Device Drivers
- 4 Chapter 3. DOS Device Drivers
- 5 Chapter 4. Writing a Media Access Control Driver
- 5.1 The Strategy and Initialization Routines
- 5.2 The System Request Routine
- 5.3 The Indication Routines
- 5.4 The TransmitChain Routine
- 5.5 The Interrupt Routine
- 5.6 The TransferData Routine
- 5.7 The ReceiveRelease Routine
- 5.8 The General Request Routines
- 6 Notices
How to Use This Manual
How to Use This Manual
The principal audience for this manual is developers of NDIS Media Access Control (MAC) drivers for both DOS and OS/2. It is assumed that the reader is an experienced system programmer, familiar with the operating system, x86 programming, and system internals. Experience with networking and/or device drivers is highly recommended. Familiarity with NDIS, while helpful, is not assumed.
This manual contains guidelines for writing an NDIS MAC driver. It is organized into four chapters. Chapter 1, Overview, contains general background information on device drivers, NDIS, and MAC drivers. Chapter 2, OS/2 Device Drivers, contains OS/2 specific information. Chapter 3, DOS Device Drivers, contains DOS specific information, from the point of view of the differences between DOS and OS/2 drivers. Finally Chapter 4, Writing a Media Access Control Driver, gives guidelines and examples useful for writing your MAC driver.
The intended result of this manual is to aid your driver development.
The following notational conventions are used in this manual
- Hexadecimal (base 16) numbers are given in the form 0xdd, 0xdddd, etc.
For example, 0x28 is hexadecimal for the decimal number 40.
- File names are given in all capital letters. Hence CONFIG.SYS stands for the file named CONFIG.SYS.
- Code examples are given in Courier type face.
NDIS details an internal architecture for network drivers. Drivers are divided into two categories: Media Access Control (MAC) drivers and Protocol drivers. MAC drivers directly control network adapter cards, while protocol drivers interface with the operating system and/or applications. The NDIS details the responsibilities of both types of drivers as well as the interface between them. For more information on NDIS, see the publications: 3Com/Microsoft LAN Manager Network Driver Interface Specification 2.0.1 and NDIS Implementation Information for IBM LAN Systems, NDIS Extensions.
Finding Further Information
Further information can be found in the following document:
If you already have the LAN Technical Reference, you need to order the following document:
Note: Once the Supplement is available, it will ship with orders of the LAN Technical Reference.
Chapter 1. Overview
OS/2 and DOS use specialized software, known as device drivers, to manage input and output. Examples are screen display, keyboard or mouse input, printer output, floppy or hard drive file input/output, and network adapter input/output. Each device driver is responsible for the interface between the device (that is, its controller) and the operating system.
Types of Device Drivers
Each device driver falls into one of two distinct categories, character drivers or block drivers, depending upon its device. Block drivers manage random access devices, such as disc drives, that support logical units and a directory structure. Character drivers manage all other devices, including network adapter cards. We will be concerned with character drivers.
Device drivers are further authorized into base drivers and installable drivers. Base drivers handle the basic system input/output and are usually considered part of the operating system. We will not be concerned with base drivers. Installable drivers handle all other input/output functions.
Installable Device Drivers
Installable device drivers are loaded at system initiation time. The driver initialization thread reads the CONFIG.SYS file and loads and initializes the drivers specified in the "DEVICE=" statements on a first-read-first-loaded basis.
Drivers are loaded into low memory and must consist of a data segment followed by a code segment. Additional data or code segments, if present, will be loaded into high memory.
Parts of a Device Driver
Device drivers consist of from two to five components as follows:
- Device Driver Header (required). The first item in the driver's initial data segment is the device driver header. The header specifies device attributes and driver entry points.
- Strategy Routine (required). System communication with device drivers is accomplished by calling the driver's strategy routine. System requests include initialization and, for most device drivers, input/output requests.
- (Hardware) Interrupt Routine (recommended). OS/2 device drivers usually service hardware requests by means of hardware interrupts.
- Software Interrupt Handler (optional). DOS device drivers usually service hardware requests by means of software interrupts. OS/2 drivers may contain a software interrupt handle for backwards compatibility with DOS.
- Timer Handler (optional). OS/2 device drivers may specify a timer entry point which will be called by the system every 31.25 milliseconds.
Real Versus Protected Mode
OS/2 can emulate DOS, running DOS applications in the "DOS Compatibility Box". While in this mode, the processor emulates the behavior of the 8088 and 8086 chips by running in real mode. Otherwise the processor runs in protected mode.
While in real mode, the processor interprets the CS, DS, ES, and SS registers as segment registers, in protected mode they are selector registers. That is to say, in real mode 20-bit physical addresses are split into an high-order, 16-bit segment and a low-order, 4-bit offset. While in protected mode, address are virtual and consist of a 16-bit selector (whose three low order bits are ignored) and a 16-bit offset. The selector references a position in the appropriate (local or global) descriptor table (LDT or GDT).
While OS/2 is in protected mode, processes (and their threads) have a privilege level or ring number. The privilege level of a process determines its access to descriptor tables. Applications run at Ring 3, and can only access their own local descriptor table. The operating system runs at Ring 0, or kernel mode and can access both local and global descriptor tables.
Device drivers, however, initialize at Ring 3 (as do most applications) and run at Ring 0, to have greater access to the kernel and to hardware.
Introduction to NDIS
Network device drivers were traditionally large, monolithic drivers, containing code for protocols (the language of the network) as well as network hardware. Traditional drivers were difficult to write, had less flexibility, were harder to upgrade, and didn't support multiple protocols. A fully functional monolithic network driver would have to have the ability to interface with every protocol available.
A modular approach to protocol handling (in which only those protocols required are loaded) is a much more efficient use of system memory. The Network Device Interface Specification (NDIS) was developed to eliminate the need for multiple protocols within a single driver. Under NDIS, protocol handling is completely separated from hardware manipulation. NDIS replaces the traditional network driver with two distinct types of installable character drivers: protocol drivers and Media Access Control (MAC) drivers.
NDIS protocol drivers do not manipulate network hardware - they handle the various network data formats. MAC drivers handle the hardware. Working together, these two driver types replace the large monolithic network driver. As a result, protocol and hardware handling drivers are modular and streamlined. Protocol and MAC drivers, as a group, are called NDIS device drivers
The NDIS describes the functionality that both protocol and MAC drivers must provide for each other. The specification also describes a standard network driver interface for the two types (MAC and protocol) of NDIS device drivers
The interface includes a Protocol Manager to help organize configuration data and to bind the various modules together.
NDIS device drivers may choose to run under both OS/2 and DOS. NDIS drivers provide access to many kinds of complex protocols under multiple hardware configurations.
NDIS and the OSI Reference Model
The International Standards Organization, in an effort to standardize networks created the Open Systems Interconnection (OSI) reference model. In the OSI model, network software is thought of as a system of layers with each layer representing a particular task. The OSI model defines seven layers of networking tasks as follows
The lower portion of an NDIS protocol driver functions in the upper portion of the data link layer, above the network device driver interface. The upper portion of an NDIS protocol driver may reside anywhere from the data link to the application layer of the OSI model.
The device driver interface described in the NDIS specification functions within the data link layer of the OSI reference model.
NDIS MAC drivers are implemented at the bottom portion of the data link layer. MAC drivers may work with any physical media: PC Network, Token-Ring, ArcNet, etc. IBM protocol drivers support 802.3 or DIX (EtherNet) and 802.5 (Token-Ring) networks.
The Protocol Manager
The network device driver interface is implemented through a Protocol Manager used to coordinate connections (bindings) between modules. When an NDIS protocol or MAC driver loads and initializes, it passes to the Protocol Manager a pointer to an internal characteristics table that includes the module's name and entry points. Protocol drivers also pass a list of MAC drivers with which they wish to bind. The Protocol Manager reads the protocol driver's bindings list and helps the protocol driver to exchange information with each MAC driver in the list. The information exchanged consists of pointers to each other's characteristics tables. The exchanged entry point information allows protocol and MAC drivers to exchange characteristics tables and communicate directly with one another.
While a protocol driver may bind to multiple MAC drivers, each MAC driver must bind to one, and only one, protocol driver. To allow a MAC driver to bind to multiple protocol drivers or to allow a protocol driver to be dynamically loaded and unloaded, the Protocol Manager provides an additional module known as VECTOR. The VECTOR module shields a MAC driver from these details, allowing the MAC driver to be written as if there were always a single protocol driver bound to it.
Media Access Control Drivers
MAC drivers provide low-level access to network adapters. MAC drivers are loaded at system initialization time and are static - that is, they may not be removed from memory. The primary function of a MAC driver is to transmit and receive packets. Secondarily, the MAC driver also provides some basic adapter management functions.
Parts of a MAC Device Driver
Like other device drivers. an NDIS MAC driver contains the following components:
- Strategy Routine
- Initialization Routine
- Interrupt Routine
Additionally, an NDIS MAC driver must contain entry points for the following seven, NDIS-specific, entry points:
- System Request Routine
- General Request Routine
- TransmitChain Routine
- TransferData Routine
- ReceiveRelease Routine
- IndicationOff Routine
- IndicationOn Routine
Finally, an NDIS MAC driver must contain the following data structures:
- Common Characteristics Table
- Service-Specific Characteristics Table
- Service-Specific Status Table
- Upper Dispatch Table
How a MAC Device Driver Works
The sole purpose of the Strategy Routine in an NDIS MAC driver is to handle load-time initialization of the driver. Later the Protocol Manager directs NDIS drivers to exchange common characteristics table addresses with the drivers they bind to. Chained off of the common characteristics table are the other tables as well as entry points to their NDIS-specific routines.
A MAC driver's Interrupt Routine handles notifications from the hardware to the MAC. These notifications will cover such matters as changes in adapter status, reception of frames, and the completion of previous transmissions.
The System Request Routine handles such matters as binding (during which characteristics tables are exchanged) and unbinding. The General Request Routine handles protocol requests of the MAC. These requests include opening and closing the adapter, setting the station address, updating statistics, and many others. Both system and general requests utilize a request packet and return a completion code in a manner similar to that of an OS/2 driver's Strategy Routine.
The TransmitChain, TransferData, and ReceiveRelease routines are used during the transmission and reception of frames in order to pass data buffers between a protocol and a MAC driver.
The IndicationOff and IndicationOn routines are used to control (turn on and off) status and reception indications. Indications are notifications from a MAC driver to a protocol driver of a change in adapter status or of a reception of a frame. A protocol driver reacts to an indication in a manner similar to a MAC driver reacting to an interrupt.
Chapter 2. OS/2 Device Drivers
As mentioned in the first chapter, OS/2 device drivers contain a device driver header and a strategy routine. As these components are common to all device drivers, they will be discussed here. For more detailed information on OS/2 device drivers, see the following publications from the OS/2 2.0 Technical Library: Control Program Programming Reference (S10G-6263-0), and Physical Device Driver Reference (S10G-6266-0). In this section, we provide a summary of that information.
The Device Driver Header
The first item in the driver's initial data segment is the device driver header. This twenty-six byte data structure is organized as follows:
|0x00||4||Pointer to next header|
|0x04||2||Device Attribute Field|
|0x06||2||Offset to Strategy Routine|
|0x08||2||Offset to IDC Routine|
In order to support multiple devices within a single driver, the device driver header is a linked list. This list is terminated by a pointer of - 1 (0xFFFFFFFF), so if your driver supports only a single device, you should fill this field with -1.
The Device Attribute Field contains descriptive information used by the system. Its structure is as follows:
|0||Keyboard bit: 1 = device is the standard input device, 0 = otherwise|
|1||Screen bit: 1 = device is the standard output device, 0 = otherwise|
|2||NULL attribute bit: 1 = device is the NULL device, 0 = otherwise|
|3||Clock device bit: 1 = device is the system clock device, 0 = otherwise|
|9-7||Function Level: 001 = 0S/2 device driver (hence will be initialized in protect mode), 000 = compatibility box driver (hence will be initialized in real mode)|
|11||Open/close bit: 1 = driver requires an OPEN and CLOSE call from the system, 0 = otherwise|
|12||Shared bit: 1 = system file sharing rules apply, 0 = file ownership contentions will be resolved by the driver|
|13||IBM bit: set to zero for character devices (for block devices: 1 = supports DOS 2.0 and above file formats, 0 = supports DOS 1.0 or 1.10 formats)|
|14||Inter-driver communication (IDC) bit: 1 = driver has an IDC entry, 0 = otherwise|
|15||Device type bit: 1 = character device, 0 = block device|
The other bits are reserved, and should be set to zero.
Following the Device Attribute Field offsets into the main code segment to the entry points of the Strategy Routine and the Inter Device Communication Routine.
Character devices then have an eight byte, ASCII, blank-filled name of the device driver. This name must match the "DriverName=" keyword given in the PROTOCOL.INI file. As a device name takes precedence over a file name in a DosOpen function call, device names should contain some unusual character. A terminating "$" is traditional.
The final eight bytes of the header are reserved and should be zero filled.
The Strategy Routine
The Strategy Routine handles the system's requests of the device driver. For an OS/2 device driver, these requests include installation, normal I/O, character device-specific I/O, block device-specific I/O, and generic I/O control.
The Strategy Routine follows the far call/return mode and can be called in either real or protect mode. At entry, a pointer to a Request Packet is contained in the ES:BX register pair. This pointer is bi-modal and references the same address whether the processor is in real or in protect mode.
The Strategy Routine reads the Request Packet and takes the appropriate action. Upon completion of the request, a status field is set in the Request Packet to indicate the completion status of the request.
The Request Packet
The Request Packet consists of a thirteen byte header followed by a command specific data area. The structure of the request packet header is as follows:
|0x00||1||Total length of Request Packet|
|0x01||1||Unit code (block device)|
|0x09||4||Queue linkage field|
The first byte gives the total length of the packet, including the header and command-specific data area. The next byte is ignored for character devices. The third byte gives the command code, indicating which function (for example, 0 = driver initialization) has been requested of the driver.
The next two bytes contain the status field. This field should be set by the driver to indicate the request completion status. Errors are indicated by setting the high order bit of this field. In this case, an error code should be returned in the low order eight bits.
The next four bytes are reserved, and the final four bytes of the header can be used to maintain a linked list of queued request packets. Either DevHlp services or the driver's own queue management may be used.
The remainder of the request packet contains command-specific data. The type and amount of command-specific data varies with each command.
The Initialization Routine
Every device driver's Strategy Routine must accept the INIT initialization request (request code = 0). The driver's code which processes this request is known as the driver's Initialization Routine. The INIT request is generated by the system during driver loading and initialization. At this time, the driver initialization thread reads the CONFIG.SYS file and interprets the "DEVICE=" command lines.
For each driver referenced, the system loads the first two segments into low memory (and any remaining segments into high memory), resolves intersegment memory references, and interprets the device driver header. Then if the device driver is a DOS-compatible driver (function level = 000) that may only run in the compatibility box, the system switches the processor to real mode, otherwise it remains in protect mode. Finally the driver initialization thread formats an INIT request packet and makes a far call to the driver's Strategy Routine to allow the driver to initialize itself.
The INIT Request Packet
The INIT request packet is twenty-three (0x17) bytes long. It consists of the standard thirteen byte header, followed by ten bytes of INIT-specific data in the following format:
On entry, Data_1 is unused. Pointer_1 contains a bi-modal pointer to the device helper (DevHlp) routine. Pointer_2 contains a far pointer to the device driver parameter string as defined in the "DEVICE=" command in the CONFIG.SYS file. This string consists of the driver file name, followed by blank-separated arguments and is null-terminated. Data_2 is set, for block drivers only, to the drive number of the next logical unit the file manager expects to install. Data_2 is unused for character drivers.
On exit, Data_1 will be set, by block drivers only, to the number of logical units supported by the device. Character drivers should set Data_1 to zero. Pointer_1 should be set to the lengths of the code and data segments after initialization time, with the high-order word giving the code segment length and the low-order word the data segment. This allows the system to free memory used only by the initialization routine. Pointer_2 will be set, by block drivers only, to a far pointer top the BIOS parameter block array. Data_2 is not used on exit.
Finally, on exit the driver should set the status field in the Request Packet header. Successful initialization is indicated by a status value of 0x0100 (only bit 8 set, indicating request done). General Failure is signaled by a status value of 0x810C (bit 15 set, indicating error, bit 8 set, indicating request done, and error code 0x0C, indicating General Failure).
OS/2 Functions Available at Initialization
There are over 200 Application Program Interface (API) function calls available under OS/2. These functions perform I/O, control processes, manage interprocess communication, and perform many other tasks. A subset of these API functions are available to a device driver at initialization time.
An OS/2 device driver's initialization routine is called at Ring 3 in protect mode, and a DOS compatibility box driver's initialization routine is called in real mode. Hence neither process management nor memory management API calls are permitted. However, at a device driver's initialization time, the system base drivers have loaded. Hence the following API calls are available at initialization time:
- Randomly reposition file pointer
- Close a file
- Perform generic I/O control functions
- Open a file
- Read from a file
- Write to a file
- Directory Management
- Delete a file
- Terminate a pattern matching search
- Look for a file, using pattern matching
- Look for next file matching pattern
- File System Information
- Get system configuration information
- Get current working directory
- Get current working disk
- Get file status
- Get file attribute bits
- System Message Handling
- Retrieve message from system message file
- Write message to system message file
- Base-Line I/O
- Produce system audio alert
As device drivers run at Ring 0, kernel mode, API calls are only available during initialization time. Hence an interface to the OS/2 operating services is provided to device drivers through the DevHlp Interface. A pointer to the entry point for DevHlp calls is passed to the driver with the INIT request packet.
There are a total of fifty-seven DevHlp services. The following subsets of these are available at driver initialization time:
- System Clock Management: SchedClockAddr
- Character Que Management: QueueInit
- Memory Management: AllocGDTSelector, AllocPhys, FreePhys, Lock, PhysToGDTSelector, PhysToVirt, Unlock, UnPhysToVirt, VirtToPhys
- Interrupt Management: EOI, SetIRQ, SetROMVector, UnSetIRQ
- Timer Services: ResetTimer, SetTimer, TickCount
- System Services: GetDOSVar
- Advanced BIOS Services: ABIOSCall, ABIOSCommonEntry, FreeLIDEntry, GetLIDEntry
Chapter 3. DOS Device Drivers
There are several areas of difference between DOS and OS/2, mostly in the area of memory access and management. For real mode DOS, the driver's view of memory is straight-forward. A valid address is always valid whether operating in interrupt, system, or user context. Under OS/2 the validity of an address is entirely dependent upon its context. Extra care and planning is required to ensure that the driver's memory management strategy is correctly defined.
The Device Driver Header
The interfaces and entry points defined by NDIS are the same both for DOS and for OS/2. There are however, differences in the basic device driver structure in the two systems. These discrepancies are illustrated by the format of the driver's device header. The DOS driver's header contains two entry points referred to as Strategy and Interrupt and is eight bytes shorter than the OS/2 header. The eighteen byte DOS device header is organized as follows:
|0x00||4||Pointer to next header|
|0x04||2||Device Attribute Field|
|0x06||2||Offset to Strategy Routine|
|0x08||2||Offset to Software Interrupt Routine|
See the section on the OS/2 device header for a detailed description of the Device Attribute Field.
The Strategy Routine
Under DOS when the system processes a request packet, it initially calls the driver's strategy entry point with the register pair ES:BX containing the address of the packet. The only function the DOS strategy routine performs is saving this address in local memory. Immediately after return from the driver strategy routine, DOS calls the driver at the Software Interrupt entry point. The Software Interrupt routine retrieves the pointer stored by the strategy handler and then proceeds to execute the requested task.
The Request Packet
The DOS Request Packet, like the OS/2 Request Packet, consists of a thirteen byte header followed by a command-specific data area. The structure of the request packet header is as follows:
|0x00||1||Total length of Request Packet|
|0x01||1||Unit code (block device)|
See the section on the OS/2 Request Packet for a detailed description of these fields.
The Initialization Routine
Under DOS, the Strategy Routine will save the address of the INIT request packet and return. The initialization Routine will be accessed through the Software Interrupt Entry point.
The INIT Request Packet
The DOS INIT request packet is, like the OS/2 packet, twenty-three (Ox 17) bytes long. It consists of the standard thirteen byte header, followed by ten bytes of INIT-specific data in the following format:
The only difference between the DOS and OS/2 packet is in the usage of Pointer_1. On entry for a DOS device driver, Pointer_1 is unused. On exit for a DOS driver, Pointer_1 should be set to point to the first available byte of memory above the driver.
INT 21 Function Calls at Initialization Time
During system initialization, there are typically several functions which require interface with the underlying operating system. For example, the driver may wish to display a text message identifying itself, or it may wish to query the revision of the system to be sure that some piece of required functionality is present. Particularly, in the case of an NDIS driver, interaction with another driver that has already been loaded is required.
The two operating environments, DOS and OS/2, provide the means to accomplish these tasks. Under DOS, operating system functions are executed by loading parameter values into registers and executing a software interrupt. The system dispatcher fields such requests via vector X'21'. The DOS Technical Reference provides a comprehensive description of the functions available via this method.
The OS/2 driver accesses the system via far calls to API functions linked into the executable file in precisely the same manner as an application program would. This is possible because the OS/2 initialization process executes in Ring 3 just as if it were an ordinary application program.
For both DOS and for OS/2, this functionality is accessible only during system startup. Once the initialization process has returned, neither the INT 21 or the application APIs are available.
Hardware interrupts and the associated interrupt handlers are managed in a slightly different manner between DOS and OS/2. Please note that interrupt handler as used in this context is distinct from the Software Interrupt routine described in the preceding discussions. In the current context, the interrupt handler is the body of code that executes in response to a hardware event and not as part of system request processing.
In an OS/2 environment, the handler is called indirectly by the system's interrupt manager. At the point at which the handler begins execution, all of the system's registers have been saved and a special interrupt stack is in use. In addition, the system provides helper routines to aid in managing Process Interrupt Control (PIC) related tasks such as delivering the SetIRQ command.
Under DOS, the handler is executed directly when a hardware interrupt occurs. Preserving the processor context, switching stacks, and dismissing the interrupt through direct interaction with the PIC are tasks which the driver must perform on its own behalf.
Chapter 4. Writing a Media Access Control Driver
The Media Access Control driver bridges the gap between the physical components of the network and the logical elements contained in the protocol stack. Every network transaction is processed by the MAC driver. Great care must be taken during implementation to ensure that a highly performant and flexible interface is provided. See the NDIS Driver Developer's Tool Kit for OS/2 and DOS Programmer's Performance Guide for guidance on performance Issues.
Typical drivers contain an entry point for requests from the operating system and usually an interrupt handler as well. NDIS MAC drivers contain additional entry points to process the functions that are defined at the boundary with the protocol driver. The calling sequence for the NDIS functions differs from that used by the operating system. Normal system functions such as read, write, open, and close are passed to the driver via a parameter block. NDIS functions are executed across the boundary between the MAC and the protocol using direct calls to entry points defined by the specification. The calling sequence used is far Pascal. The calling routine pushes its parameters on the stack from left to right, and the called routine releases the stack space occupied by the parameters on exit. Return status is passed via register AX. Called routines are responsible for saving and restoring standard register variables DS, DI, SI, and BP.
The following sections of this chapter will provide detailed descriptions and code samples illustrating the process that must be implemented by a MAC driver. These samples are written in assembly language, although C could be used. These samples are examples intended to illustrate possible code structures. Where differences exist between DOS and OS/2 the code fragments contain conditionals to control the assembly time generation of a driver for one system or the other.
The Strategy and Initialization Routines
Standard operating system type functions are signaled to an OS/2 driver via a far call to the Strategy Routine entry point defined in the driver header. The argument to this call is a pointer to a parameter block containing a code that indicates the function to be executed as well as supplementary information to be used in processing the request. The only function that a MAC driver must implement is initialization. Other functions may be implemented at the developer's discretion. For example, read and write might be used to provide access to the MAC's internal structures during debug. But in all cases, whether a function is implemented or not, every request must return a completed status in order to prevent exhaustion of system resources.
The initialization function is signaled to the driver during the processing of the CONFIG.SYS file at system startup time. During initialization, the driver establishes its operating environment, locates its adapter, and allocates the resources necessary for operation.
The PROTOCOL.INI file contains the definition of the communications subsystem that will be built. The PROTOCOL.INI file contains an entry for each driver that is configured in the NDIS environment. As part of its initialization path, the Protocol Manager reads this file and parses its contents into a tree structure. Each node directly below the root of the tree describes a [module] section from this definitions file.
Opening the Protocol Manager
As each NDIS driver initializes, it interacts with the Protocol Manager to obtain its individual parameters and to register itself. Access to the Protocol Manager is via the file system APIs. This is possible because during startup, the driver initialization code executes in Ring 3, just as if it were a normal application. The first step required is to open the Protocol Manager. The format of the function should be similar to that given below.
; ;-- Get handle for Protocol Manager ; if OS2 push ds ; Far pointer to name (input) push offset ProtocolManagerName push ds ; Far pointer to handle (output) push offset ProtocolManagerHandle push ds ; Far pointer (output) push offset ActionTaken push 0 ; Dword file size (output) push 0 push 1 ; Flag (input) push 0C2h ; Mode (input) push 0 ; Dword reserved push 0 call DOSOPEN or ax, ax ; Return status? jnz NoManager ; Display error and abort else ; DOS interface mov dx, offset ProtocolManagerName mov ax, 3d00h ; DOS open function int 21h jc NoManager endif
Protocol Manager Requests
After the Protocol Manager open has succeeded and the file handle is obtained, requests are executed using IOCTL functions, passing a pointer to a parameter block which defines the function to be performed. Under OS/2 the generic IOCTL, function code 16, is used to provide access to all of the functionality provided by the Protocol Manager. The Category code used is 0x81 signifying LAN Manager, with a function code of 0x58, indicating Protocol Manager type command. The parameter buffer contains a far pointer to a common request block structure. The structure given below describes the Protocol Manager request block.
PMBlock struc ; Function code PMCode dw ? ; Status returned by PMStatus dw ? ; ProtMan PMPtrl dd ? ; First parameter PMPtr2 dd ? ; Second parameter PMWord dw ? ; Third parameter PMBlock ends
Getting Configuration Information
Typically, the next step is to gain access to the ConfigMemoryImage parsed from PROTOCOL.INI by the Protocol Manager. The code fragment provided below illustrates the correct procedure for filling in the request block and invoking the Protocol Manager.
; ;-- Fill in request block. Only parameter required ; is function code. ; mov PMReqBlk.PMCode, GetProtManInfo if OS2 push 0 ; Far null pointer push 0 push ds ; Far pointer to ReqBlk push offset PMReqBlk push ProtManCode ; 0x58 push LanManCat ; 0x81 mov ax,[ProtoclManagerHandle] push ax ; Handle returned by open call DOSDEVIOCTL ; System API or ax, ax ; Return okay? jnz NoConfigInfo ; Display error and abort else ; DOS mov bx, [ProtocolManagerHandle] mov dx, offset PMReqBlk mov cx, 14 ; size of block mov ax, 4402h ; IOCTL function int 21h jc NoConfigInfo endif ; ;-- Success. First pointer contains address of ; ConfigMemoryInfo structure. Word parameter ; contains revision of Protocol Manager. Check ; for acceptable values. ; mov ax, PMReqBlk.PMWord cmp ax, ProtManLevel jne InvalidProtMan ;Display error and abort lds si,PMReqBlk.PMPtrl ;Get pointer to config tree
The driver must now traverse the list of ModuleConfig structures, seeking the one that contains its operational parameters. Note that although the nodes are based an the square-bracketed [ModuleName] sections contained in the PROTOCOL.INI file, ModuleName is not the correct key to be used for the search. The value of this field is user definable and may be installation specific. The search should be based on the "DriverName=" keyword. This entry is required within every ModuleName section and must accurately reflect the name used within the driver's device header. Other fields are optional in general, but may be required by specific drivers. Below is an example PROTOCOL.INI entry for the driver for the fictional BITHOSE card. This driver requires two additional parameters, namely the I/O base address of the card and the IRQ to be used.
[bithose_NIF] DriverName = bithose$ Base = 0x300 IntLevel = 3
When the Protocol Manager builds the ConfigMemoryImage, lower case characters are converted to upper case and white space and comment lines are ignored. During initialization, the bithose driver searches for a ModuleName section with the correct DriverName value.
;-- The following structure definitions are used ; by the parsing routine below. ; ModuleConfig struc ModuleNext dd 0 ; Next in chain or ; Null ModulePrev dd 0 ; Previous in chain ModuleName db 16 dup (0) ; Square bracket name KeyWordList dd 0 ; First keyword ModuleConfig ends KeyWord struc KeyWordNext dd 0 ; Next in chain or ; NULL KeyWordPrev dd 0 ; Previous in chain KeyWordName db 16 dup (0) ; Keyword text NumParams dw 0 ; Count of parameters ; ;-- The next section repeats NumParams times ; ParamType dw 0 ; Type of parameter ; =0 then long ; =1 then ASCIIZ string ParamValue dd 0 ; Variable depending ; on type Keyword ends ; ;-- Find our ModuleName section. ; ds:si--> Head of ModuleConfig linked list. ; CheckEndModules: mov ax, ds ; Check for end of or ax, si ; the line jz NoDriverName ; Display error and ; abort ; push ds ; Save our place push si lds si, [si].KeyWordList ; CheckEndKeywords: mov ax, ds or ax, si ; Null pointer? jz EndKeywords ; Yes - try next module ; mov bx, si ; Save structure pointer mov si, [si].KeyWordName mov di, offset DriverKeyword mov cx, 10 ; Length of "DRIVERNAME" cld rep cmpsb jcxz FoundDriverKeyword ; NextKeyword: lds si, [bx].NextKeyword jmp CheckEndKeyWords ; FoundDriverKeyword: cmp [bx].NumParams, 1 jne NextKeyword ; Invalid entry lea si, [bx].Param cmp [si].ParamType, ASCIIZ jne NextKeyword mov cx, OurNameLen cmp cx, [si].ParamLen jne NextKeyWord lea si, [si].ParamValue mov di, offset OurName rep cmpsb jcxz FoundOurName jmp NextKeyword ; EndKeywords: pop si pop ds ; Restore ; ModuleConfig ptr lds si, [si].NextModule jmp CheckEndModules ; FoundOurName: pop si pop ds ; We have our section ; now
Building the Characteristics Tables
After locating the correct ModuleName section, the driver should copy the Name specified by the user into its common characteristics table. The driver should scan the keywords linked to this module for any specific required parameters. In this example, the bithose driver would continue the scan for the two additional required parameters. If they are not present, the driver may choose to display an error message and abort its initialization. For each parameter encountered, the driver should check to ensure that the parameter is of the correct type and that the value given is within range.
After parsing its ModuleConfig section, the driver should have enough information to query its adapter and complete the initialization of its characteristics tables. NDIS defines a set of tables that are maintained by conformant drivers. These tables contain information describing the capabilities of the driver and adapter, as well as several entry points within the driver that are callable by external entities across the NDIS boundary. Most of the fields in the table may be initialized when the driver is coded, with the default values in selected fields overridden by information gained from PROTOCOL.INI parsing.
Several fields within these tables contain far pointers to be used by the protocol driver after binding. The values contained must be Ring 0 GDT selectors. They can not be established at initialization time because the driver is operating in Ring 3. The value for these pointer fields are properly established using the SEG assembler pseudo-op as illustrated in the example below, describing the NDIS System Request dispatch entry point as it might appear within the MAC's Common Characteristics Table.
dw offset System dw SEG System
After the Characteristics Tables have been completely built, the MAC driver can proceed to the final stages of initialization. Depending on the MAC, this may, under OS/2 require reserving GDT selectors and locking extra segments for use during operation. When the implementation-specific initialization functions have completed, the driver is ready to complete its start-up path by registering with the Protocol Manager. This function is executed as a generic IOCTL as described in the preceding section on obtaining the ConfigMemoryInfo. The format of the call is described below.
; ;-- Fill in request block. Required parameters are ; function code and far pointer to the Common ; Characteristics Table. Pointer 2 (bindings ; list) must be null for MAC's. ; mov PMReqBlk.PMCode, RegisterModule mov word ptr PMReqBlk.PMPtrl, offset CCTable mov word ptr PMReqBlk.PMPtrl + 2, SEG CCTable mov word ptr PMReqBlk.PMPtr2, 0 mov word ptr PMReqBlk.PMPtr2 + 2, 0 ; if OS2 push 0 ; Far null pointer push 0 push ds ; Far pointer to ReqBlk push offset PMReqBlk push ProtManCode ; 0x58 push LanManCat ; 0x81 mov ax, [ProtoclManagerHandle] push ax ; Handle returned by open call DOSDEVIOCTL ; System API or ax, ax ; Return okay? jnz RegisterFail ; Display error and abort else ; DOS mov bx, [ProtocolManagerHandle] mov dx, offset PMReqblk mov cx, 14 mov ax, 4402h ; DOS IOCTL int 21h jc RegisterFail endif
Initialization is now completed and no further interaction with the Protocol Manager is required. The file handle used for the interface may now be closed and the driver may exit back to the OS/2 configuration processor.
The System Request Routine
At some point after the system has completed boot up, an application program may request that the network interface be started. This is signaled to the Protocol Manager via a BindAndStart function. A typical source of this request is the NETBIND.EXE program. During the RegisterModule phase, the Protocol Manager built a binding tree describing the protocol driver to MAC linkages to be established in order to create the communications subsystem. Upon receipt of the BindAndStart command the Protocol Manager traverses this tree, requesting that the higher level entities (protocol drivers) bind to the lower (MAC drivers).
For the MAC driver, the end result of this activity will, if the system is correctly configured, generate one and only one bind request from an upper level routine. This request may be issued by a single protocol driver module or it may be issued by a sub-function of the Protocol Manager called VECTOR acting on behalf of multiple protocol driver modules that have specified a binding to the MAC driver. In either case, the interface to the MAC driver is identical. When the MAC is invoked, the stack contains the parameters passed by the protocol driver in the following format
stack --> dword far return --> word MAC's data_seg --> word opcode for Bind (2) --> word pad (0) --> dword pointer where to return CCTable address --> dword callers CCTable address
The Bind System Request
Bind is the only System Request that MAC drivers implement. The MAC should be prepared to bind with no more than one upper lead module. Succeeding Bind requests should return an invalid status. The code fragment provided below demonstrates the Bind procedure.
System proc far push bp ; Save frame pointer mov bp, sp ; And establish ; addressability push ds ; Save push di push si mov ds, [bp].SysDs ; Our data_seg mov ax, INVALID_FUNCTION cmp [bp].SysFunc, BIND jne SysExit ; Nothing else mov ax, [BindStatus] or ax, ax ; We update this when a ; bind has occurred. ; If 1=0 then ; already bound. jnz SysExit ; ;-- Take control of the adapter now. It shouldn't be ; done during bootup in case the adapter is being ; used for remote boot. ; call GetAdapter ; Do adapter specific stuff or ax, ax ; Make sure all went well jnz SysExit ; Some kind of hardware ; problem - fail the bind ; ;-- Mark ourselves as bound and copy in some of the ; Protocol's information for fast access. ; mov [BindStatus], INVALID_FUNCTION or SpecStatusTable.SpecStatus, MACBound mov ax, ds mov es, ax mov di, offset ProtocolTable lds si, [bp].SysProtTable mov ax, [si].CCTableDS ; Save Protocol's DS mov es: [ProtcolDS], ax lds si, [si].CCTableLowerDispatch mov cx, SizeLowerDispatch cld rep movsb xor ax, ax ; Status cleared SysExit: pop si pop di pop ds pop bp ret SizeSysParms ; Clean up stack and exit System endp
If the MAC driver has chosen not to implement Open and Close then, on exit from the System Request function after a successful Bind, the adapter and the MAC should be fully conditioned and ready to support network traffic.
The Indication Routines
An indication, as generated by the MAC to the protocol driver, is a higher level notification of an adapter-generated event. Indications may occur when a frame is received, when an adapter error condition occurs, or, if supported by the underlying hardware. as the result of an InterruptRequest Gall Request issued at some earlier point in time by the protocol driver MAC drivers implement two entry points, IndicationOn and IndicationOff, that provide the protocol driver with a logical mechanism for enabling and disabling these events.
The MAC driver maintains its indication level as a counter. IndicationOff increments the counter and IndicationOn decrements it. At any point if the value of the counter is non-zero, indications may not be signaled to the protocol drive. This correctly handles unwinding from the case where IndicationOff requests have been nested.
On entry to the indication routines, the stack holds the calling context as follows:
Stack --> dword far return --> word MAC's data_seg
The code fragment below provides an example IndicationOff routine. As part of its process path, the routine calls an adapter specific routine to disable its interrupt generation. Depending on the hardware, it may be possible to execute a partial disable, allowing the driver to continue processing non-indication generating functions such as TransmitChain.
IndicationOff proc far push bp ; Standard preamble mov bp, sp push ds push di push si mov ax, [bp].IndDS ; cli ; Per NDIS we return disabled mov al, [IndicationLevel] inc [IndicationLevel] or al, al ; Enabled before? jnz IOffExit ; Yes - HW already disabled ; call AdapterDisable ; Specific to adapter ; IOffExit xor ax, ax ; Return okay pop si pop di pop ds pop bp ret IndParmSize IndicationOff endp
The IndicationOn procedure is the complement of the IndicationOff function. The MACs indication level is decremented and, if the count reaches zero, adapter interrupts are re-enabled.
IndicationOn proc far push bp ; Standard preamble mov bp, sp ; Get stack addressability push ds push di push si mov ds, [bp].IndDS ; Our data_seg ; cli ; Per NDIS we return disabled dec [IndicationLevel] jnz IOnExit ; Still off ; call AdapterEnable ; HW specific to restart ; Must run disabled because ; indications not allowed within ; the context of this call ; IOnExit xor ax, ax ; Status = okay pop si pop di pop ds pop bp ret IndParmSize IndicationOn endp
In addition to these two routines, the indication level is implicitly manipulated by the MAC driver whenever an indication is about to be signaled to the protocol drive. This will be described more fully in the following sections describing the specific indications.
The TransmitChain Routine
The MAC's TransmitChain entry point is called by the protocol driver when there is a frame ready to be dispatched to the network. MAC's may implement TransmitChain synchronously or asynchronously. If the transmission is completed successfully within the context of this call, a successful return status is provided to the calling protocol. If the adapter is currently unable to accept another frame for transmission, the MAC may queue the request and return immediately to the protocol with a status indicating that the request was pended. At some later point when adapter resources become available, probably within the context of the interrupt handler, the frame can be dequeued and transmitted.
If transmission is deferred, the MAC has two additional responsibilities. First, the TransmitChainBuffer Descriptor and any immediate data it describes are valid only during the execution of the original TransmitChain call. Therefore, these volatile portions of the frame description must be copied into the MAC's memory space before returning. Second, when the deferred frame is finally transmitted, it must be confirmed to the protocol driver via the TransmitConfirm function described below.
On entry to TransmitChain, the stack contains the arguments provided by the protocol driver to be used in processing this request.
stack --> dword far return --> word MAC's data_seg --> dword pointer to buffer descriptor --> word request handle --> word Protocol ID
TransmitChain proc far push bp ; Standard preamble mov bp, sp push ds push es push di push si ; ;-- First check if we can start a transmit now. ; call CheckResources ; Adapter specific or ax, ax ; ax=0 then all systems go jz TxOkay ; ;-- Else we have to queue request. ; call CopyChain ; Copy descriptor, immediate ; data, handle, and protocol ID ; ss:bp -->TxChain info mov ax, REQUEST_QUEUED jmp TxChainExit ; Return - xmit deferred ; ;-- We can send now. ; Call DoTransmit ; Adapter specific ; ss:bp-->Txchain info ; Returns status of xmit. ; TxChainExit: pop si pop di pop es pop ds pop bp ret TxChainParmSize TransmitChain endp
The Interrupt Routine
In large part, the design of the interrupt routine is dictated by the functionality of the adapter. There are, however, certain common sense guidelines to which all drivers should adhere.
The Interrupt Routine should be divided into two major sections. The front end is responsible for time-critical functions that execute during initial processing with the adapter disabled. The back end, while still in interrupt context, handles the less critical tasks after the adapter has been reconditioned to process network traffic. It is recommended that nesting within the Interrupt Routine be kept to a minimum. One invocation of the Interrupt Routine can completely clear the adapter's interrupt queue, efficiently using system resources. If multiple invocations of the Interrupt Routine are allowed to occur, then the potential exists to exhaust finite system resources such as stack space.
A simple, workable methodology, that eliminates Interrupt Routine nesting, gates access to the two portions of the Interrupt Routine based on memory resident flags. On entry the front end Interrupt Routine dismisses the interrupt at the PIC and, while interrupts are disabled, the following code sequence guarantees exclusive access to the Interrupt Routine code. A similar mechanism can be used when the front end handler has completed his critical execution path and is ready to continue the back end processing if necessary.
; ;-- Get and set the exclusion flag. ; mov ax, 1 xchg al, [Level1Flag] or al, al jnz IntlExit ; Already running - bail out ;-- Execute front end code ; - - - ; ;-- Front end completed. Clear semaphore and see ; if tail is running. ; cli ; Tests must execute disabled xor al, al xchg [Level1Flag], al ; Get/Clear level 1 xchg [Level2Flag], al ; Get/Set level 2 or al, al jz ExecLevel2 ; Not running - go execute ; IntlExit: if DOS ; Restore registers and swap ; back to original stack popa pop es pop ds mov ss, cs: [savedss] mov sp, cs: [savedsp] iret else ; OS/2 ret endif ; ;-- Execute back end code. ; ExecLevel2: if DOS ; Swap off of interrupt stack popa pop es pop ds mov ss, cs: [savedss] mov sp, cs: [savedsp] end - - - cli ; Clear until we exit mov [Level2Flag], 0 if DOS iret else ; OS/2 ret
With this technique, at most one iteration of the front end handler and one iteration of the back end handler we be active at any one time
On entry to the Interrupt Routine, there are several house-keeping functions that are required for all drivers. When the Interrupt Routine begins execution, interrupts are disabled. Several critical tasks must be performed before re-enabling. The adapter's interrupt should be masked, either at the PIC or at the adapter itself, whichever is more convenient, and an End-of-Interrupt command must be delivered to the PIC to re-enable normal hardware interrupt processing. If running under DOS, the driver must swap to a private interrupt stack. Finally, with the Interrupt Routine secure from recursion, the processor interrupt flag should be set to allow normal system operation.
Before continuing further along its processing path, the driver must ensure that it is executing in protected mode. This is a requirement if any upcalls to the protocol are to be executed during interrupt handling. The procedure for ascertaining whether or not the Interrupt Routine is running in protected mode and, if necessary, executing the mode switch is given below.
if OS2 smsw ax ; Get machine status word mov [ModeSwitch], ax shr ax, 1 ; Shift out Protected Mode bit jc InProtMode ; Okay ; mov dl, RealtoProt ; 0x2F call dword ptr [DevHelp] mov [ModeSwitch], 1 ; InProtMode: endif
Similarly, during the Interrupt Routine's exit procedure, the processor must be resumed to real mode if a switch has been executed at the driver's request.
; ;-- Ready to exit. See if we did mode switch. ; if OS2 xor al, al xchg [ModeSwitch], al or al, al ; =0 then no switch jz NoSwitch ; mov dl, ProttoReal ; 0x30 call dword ptr [DevHelp] ; NoSwitch: endif
There are two basic mechanisms provided for passing received frames up to the protocol. The choice is based primarily on the type of interface supported by the adapter. For adapters that support shared memory such that the MAC drive has complete visibility to the entire received frame, the ReceiveChain primitive provides the more efficient mechanism for conveying frames to the protocol driver. If, on the other hand, the adapter interfaces via programmed I/O, ReceiveLookahead offers a facility whereby the driver can input a relatively small leading portion of the received frame and advertise it to the protocol driver. Drivers that generally use ReceiveChain may occasionally revert to ReceiveLookahead in situations where adapter memory resources are running low. Both methods are described in more detail below.
ReceiveLookahead and ReceiveChain are both defined as indications, and may be suppressed based on the value of the indication level variable. The level of indication may be manipulated explicitly by the protocol driver via the IndicationOn and IndicationOff MAC entries. Additionally, the MAC explicitly disables indications before calling the protocol driver at an indication entry point. This ensures that the protocol driver will not be interrupted during indication processing by the arrival of another indication. Beside the other arguments passed to the protocol driver during an indication call, the MAC passes the address of a byte location called the IndicateFlag. Before the upcall, the MAC initializes this location with the value 0xFF. During indication processing the protocol driver may clear this location. On return, the MAC examines the value contained in the flag. If it has been cleared, then indications remain disabled. Otherwise, the MAC decrements the value of indication level potentially re-enabling indications.
The code fragment given below illustrates the sequence required to signal a ReceiveLookahead indication to the protocol driver. If the Protocol accepts the frame, it will call the MAC driver's TransferData entry within the context of the ReceiveLookahead call in order to receive a copy of the frame data.
; ;-- Execute a ReceiveLookahead upcall. The assumption is ; that if we have reached this point indications are ; currently enabled. ; mov byte ptr [IndicateFlag], -1 inc byte ptr [IndicationLevel1] push [MacId] ; Assigned by ProtMan push [FrameSize] ; Total size of frame push [LookAheadLen] ; Range of LookAhead ; This could be entire frame push ds ; Far ptr to LookAhead buffer push offset LookAheadBuff push ds ; Far ptr to action flag push offset IndicateFlag push [ProtocolDS] ; Obtained during bind push dword ptr [ReceiveLookahead] ; Address copied during bind ; ;-- If the Protocol wants the frame it will call our ; TransferData entry from within the context of this call ; mov dl [IndicateFlag] ; On return either 0 or -1 add [IndicationLevel, dl inc [NeedIndComplete] ; Remember we need a complete
The process path for ReceiveChain is conceptually similar to that used by ReceiveLookahead. ReceiveChain is more appropriately used when the entire frame is available in memory visible to the MAC driver. The indication level is managed similarly for both calls. With ReceiveChain the protocol driver may elect to copy the frame immediately into its space or it may defer the copy and queue the frame for copy and process during back end interrupt processing. If the protocol driver chooses to defer, the MAC driver must maintain the data buffers until they are explicitly released.
; ;-- ReceiveChain upcall processing. On entry the ; frame buffers have already been linked to the ; BufDescr. ; mov byte ptr [IndicateFlag], -1 inc byte ptr [IndicationLevel] inc word ptr [RequestHandle] ; Generate a new handle push push [MacId] ; Assigned by ProtMan push [FrameSize] ; Total size of frame push [RequestHandle] ; Identify this request push ds ; Far ptr to BufDescr push offset RxBufDescr ; These are volatile so we ; we only need one push ds ; Far ptr to action flag push offset IndicateFlag push [ProtocolDS] ; Obtained during bind call dword ptr [ReceiveChain] ; Address copied ; during bind mov dl, [IndicateFlag] ; On return either 0 or -1 add [IndicationLevel], dl inc [NeedIndComplete] ; Remember that we need a ; complete cmp ax, REQUEST_QUEUED ; If no -- jne ReleaseBuf ; then we can release call QueuedRecv ; Put buffers on a waiting ; queue. The unique handle ; generated before the ; call will be used for ID ; during release
Note that a MAC that normally uses ReceiveChain may switch temporarily to ReceiveLookahead if the protocol driver has deferred processing on several frames and the MAC is running low on resources. ReceiveLookahead forces the protocol driver to process or reject the frame synchronously within the context of the call.
In addition to receive processing, there are several other tasks that the interrupt Interrupt Routine may be called upon to manage. Adapter errors should be monitored and if necessary AdapterCheck status indications may be generated to the protocol driver in response to serious failures. If a transmit completion occurs, the MAC must generate a confirmation to the protocol driver, using the request handle passed with the original TransmitChain. If another frame is queued, a new transmit request can be passed to the adapter.
Only those functions that are time critical should be processed during front end interrupt handling. Whenever possible, work should be deferred until post processing when the adapter is re-enabled. Before exiting its back end interrupt processing, the MAC driver should generate an IndicationComplete upcall to allow the protocol driver to complete any of the processing it has deferred during indication time.
The TransferData Routine
TransferData is used only in conjunction with ReceiveLookahead. It describes a service entry point within the MAC driver that the protocol driver may invoke in order to transfer a received frame into its space. This call is valid only within the context of a ReceiveLookahead upcall from the MAC.
The MAC driver processes the data from the network card into the buffers linked to the TransferData buffer descriptor. The actual method of interface, DMA, programmed I/O, etc., is specific to the adapter. The process completes until either the entire frame has been transferred or until the protocol driver's buffers have been completely filled. In either case, the actual number of bytes copied is returned to the protocol driver in the location pointed to by the BytesCopied argument.
Depending on the hardware, the MAC may be able to support multiple calls to TransferData within the context of a single ReceiveLookahead upcall. If at all possible, the MAC should support this feature to allow for the case where multiple protocols are bound, via Vector, to a single MAC.
The ReceiveRelease Routine
ReceiveRelease is a MAC entry point called by the protocol driver when a ReceiveChain indication has been deferred. The protocol driver must remember the handle passed with the original ReceiveChain upcall and pass it back to the MAC. The handle is used to uniquely identify the buffers that are to be released.
The General Request Routines
The General Requests provide the protocol driver with the ability to perform adapter administration operations. All of the requests are handled via a single entry point. Specific operations are demultiplexed by the MAC via a function code parameter.
The MAC may choose to either handle the requests synchronously or to queue the request for later processing. If the request is deferred, the MAC must remember the handle and protocol ID passed with the call to be used later when the request is confirmed.
Personal Software Products
11400 Burnet Road
Austin, Texas 78758
Second Edition (January 1996)
First Edition (May 1993)
The following paragraph does not apply to the United Kingdom or any country where such provisions are inconsistent with local law: INTERNATIONAL BUSINESS MACHINES CORPORATION PROVIDES THIS PUBLICATION "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Some states do not allow disclaimer of express or implied warranties in certain transactions, therefore, this statement may not apply to you.
This publication could include technical inaccuracies or typographical errors. Changes are periodically made to the information herein; these changes will be incorporated in new editions of the publication. IBM may make improvements and/or changes in the product(s) and/or program(s) described in this publication at any time.
It is possible that this publication may contain reference to, or information about, IBM products (machines and programs), programming, or services that are not announced in your country. Such references or information must not be construed to mean that IBM intends to announce such IBM products, programming, or services in your country.
© Copyright International Business Machines Corporation 1993. All rights reserved.
Note to U.S. Government Users - Documentation related to restricted rights - Use, duplication or disclosure is subject to restrictions set forth in GSA ADP Schedule Contract with IBM Corp.
References in this products to IBM products, programs or services do not imply that IBM intends to make these available in all countries in which IBM operates. Any reference to an IBM product, program or service is not intended to state or imply that only IBM's product, program, or service may be used. Any functionally equivalent product, program, or service that does not infringe any of the intellectual property rights of IBM may be used instead of the IBM product, program, or service. The evaluation and verification of operation in conjunction with other products except those expressly designated by IBM, are the responsibility of the user.
IBM may have patents or pending patent applications covering subject matter this document. The furnishing of this document does not give you any license to these patents. You can send license inquiries in writing to the IBM Director of Commercial relations IBM Corporation Purchase NY 10577 - USA.
The following terms are trademarks of the International Business Machine Company:
- IBM OS/2
The following terms are trademarks of the indicated companies:
- Microsoft - Microsoft Corporation
- LAN Manager - Microsoft Corporation
- 3Com - 3Com Corporation
Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation