PDDREF:Physical Device Driver Architecture and Structure

The architecture and structure of a physical device driver is more dependent on how the application performs I/O to its device and the environment in which it operates (such as programming model, execution environment, and available system services), than it is on any other factors.

Physical Device Driver Load Module Layout
The data segment must be the first segment after the EXE file header. Because the device header must be located at the beginning of the file, this allows the data segment to be located immediately after the EXE file header.

Notes The file image of a physical device driver is shown in the following figure:  ┌───────────────┐     │ Device Driver │     Data Segment (64KB max) │   Header     │     Data accessed by interrupt, LOW ├─ ─ ─ ─ ─ ─ ─ ─┤    timer handlers, and device ▲ │               │     monitors, must reside in this │ │     Data      │     segment. │ │               │   │  │               │   │  │─ ─ ─ ─ ─ ─ ─ ─┤     Code Segment (64KB max) │ │               │     Interrupt and timer handlers, │ │     Code      │     and device monitor must reside │ │               │     in this segment. │ ├─ ─ ─ ─ ─ ─ ─ ─┤   │  │ Swappable or  │ │ │  Temporary    │ │ │     Data      │ │ │               │     Multiple │ ├─ ─ ─ ─ ─ ─ ─ ─┤     Data or   ▼  │ Swappable or  │     Code Segments HIGH │ Temporary    │ │    Code      │ │              │      ├─ ─ ─ ─ ─ ─ ─ ─┤      │               │ 
 * Multisegmented device drivers that support character device monitors must be organized so that the monitor notification routine resides in the first code segment or in fixed memory.
 * Physical device drivers that support interrupt or timer handlers must ensure that those functions reside in the first code segment.
 * Physical device drivers that provide IDC services must ensure that the entry point routines reside in the first code segment.

OS/2 Device Driver Execution Contexts
There are three contexts (modes) in which OS/2 device drivers operate:


 * Kernel Mode : The OS/2 kernel calls the physical device driver strategy routine for task-time operations; that is, it will execute as a thread within a process. The strategy routine will not be preempted by a task switch but can be interrupted by incoming hardware interrupts or page faults. Kernel mode is also referred to as task context.


 * Interrupt Mode : The OS/2 kernel calls the physical device driver interrupt-time components, the hardware interrupt handler, and the timer handler. Interrupt time is a generic term that refers to the execution of code as a result of an interrupt; the thread of execution does not belong to a process. The hardware interrupt handler and the timer handler do not execute code as a thread belonging to a thread-specific process. The thread of execution results from a hardware interrupt.


 * INIT Mode : The physical device driver INIT strategy routine is called only once at system startup time, with a request packet containing the INIT command. The initialization code runs at Ring 3 with I/O privilege. A limited set of system API calls are available for use, as well as a portion of the device helper (DevHlp) function calls. For more information, refer to Physical Device Driver Initialization.

Physical Device Driver Programming Model
The physical device driver programming model is a 16:16 based protect-mode model. The physical device driver can have multiple code and data segments. The first segment in the device driver must be a data segment and the second segment must be a code segment. These two segments are fixed in memory and (by default) will be the only two segments kept in the system after device driver initialization. OS/2 assumes that every other segment is needed for initialization only, unless it is marked as permanent in the header of the device driver EXE file.

A permanent segment remains after initialization and is assumed to be movable and swappable, but not discardable. A physical device driver can lock a permanent segment using the appropriate device helper service, if it is necessary to prevent it from being swapped out or moved. I/O Protect Level (IOPL) is available at privilege level 3 during device driver installation. The physical device driver programmer uses the SEGMENTS directive and its IOPL option in the linker DEF file to mark those segments that are to be kept after initialization. Because the first two segments are always kept, they do not have to be marked in this fashion.

Note: Unlike the OS/2 Version 1.x operating systems, the OS/2 2.1 (or later) device drivers always execute in protect mode.

The physical device driver executable image does not contain a stack segment. An 8KB stack is provided by the system. However, at initialization, a device driver may indicate to the system its actual stack usage by calling the RegisterStackUsage device helper routine for each IRQ it services. See Limiting the Number of Nested Interrupts for more information.

Physical Device Driver Header
The first data segment of a physical device driver must contain a device header as the first item. The structure of a physical device driver header is shown in the following table.

Pointer to Next Device Header
This pointer is set by OS/2 2.1 (or later) at the time the physical device driver is loaded. This field should be set to -1.

Note: For a character device driver that supports multiple devices, the data segment must contain a device header for each device. These headers must be linked together and the link pointer in the last header must be set to -1. The first WORD is an offset; the second WORD is the segment.

Device Attribute
Describes the characteristics of the physical device driver to the system. The format of the OS/2 device attribute field is: ┌───┬───┬───┬───┬───┬───┬───────────┬───┬───┬───┬───┬───┬───┬───┐      │ C │ I │ I │ S │ O │///│           │///│///│///│ C │ N │ S │ K │ │ H │ D │ B │ H │ P │///│  LEVEL   │///│///│///│ L │ U │ C │ B │ │ R │ C │ M │ R │ N │///│          │///│///│///│ K │ L │ R │ D │ └───┴───┴───┴───┴───┴───┴───────────┴───┴───┴───┴───┴───┴───┴───┘   Bit 15  14  13  12  11  10  09  08  07   06  05  04  03  02  01  00 The attributes are:
 * CHR (Bit 15) : Set, if the physical device driver operates in character mode. Bit 15 is the device type bit. Use bit 15 to tell the system if the device driver is a block or character device. For block device drivers, bit 15 is 0. For character device drivers, bit 15 is 1.
 * IDC (Bit 14): Set, if the physical device driver participates in inter-device-driver communication (IDC). Bit 14 is the IDC bit and indicates that the offset to the IDC entry point in the physical device driver header is set.
 * IBM (Bit 13) : Set, if non-IBM block format (block device drivers only).
 * For block device drivers, bit 13 indicates the method the physical device driver uses to determine the media type. If a block device driver uses information in the BIOS Parameter Block (BPB) to determine the media type, bit 13 should be set to 1. If the physical device driver uses the media descriptor byte to determine the media type, bit 13 must be 0.


 * SHR (Bit 12) : Set, if the device driver supports shared-device access-checking (character devices). Bit 12 is the shared bit. It is set if the device name is not to be protected by the sharer. Bit 12 has no meaning for block device drivers and must be 0.
 * If clear (default), file system sharing rules do not apply to the device, and the physical device driver provides contention control.
 * If set, file system sharing rules apply to the device, just as they apply to any other file system name. In addition, any given physical device can have only one logical name. (Devices cannot have aliases.)


 * OPN (Bit 11) : Set, if the device driver supports removable media (block devices) or device open/close (character devices). For block device drivers, bit 11 is the removable media bit. If set, this bit indicates that the physical device driver handles removable media.
 * For character device drivers, bit 11 is the open/close bit. If set, this bit indicates that the physical device driver must receive OPEN and CLOSE request packets.

│Bit 9│Bit 8│Bit 7│Description
 * Bit 10 : Reserved=0.
 * Bits 9-7 : Bits 9-7 indicate the physical device driver function level, where:

│ 0  │  0  │  1  │OS/2 device driver │ 0  │  1  │  0  │Supports DosDevIOCtl2 and SHUTDOWN request packets │ 0  │  1  │  1  │Uses a Capabilities Bit Strip in the header
 * Bit 6 : Reserved=0.
 * Bit 5 : Reserved=0.
 * Bit 4 : Reserved=0.
 * CLK (Bit 3) : Set, if CLOCK device. Bit 3 is the clock device bit. It is used by a character device driver to indicate the system clock device.
 * NUL (Bit 2) : Set, if NULL device. Bit 2 is the NULL attribute bit. It is used by character devices only. Bit 2 is used to tell the OS/2 operating system if the character device driver is a NULL device. Although there is a NULL device attribute bit, the NULL device cannot be reassigned. (This attribute exists so that the operating system can tell if the NULL device is being used.)
 * SCR (Bit 1) : Set, if standard output device (STDOUT). For character devices, bits 1 and 0 are the standard input or standard output bits. These bits are used to tell the OS/2 operating system if the character device driver is the new standard input or standard output device.
 * KBD (Bit 0) : Set, if standard input device (STDIN). See above.

Offset to Strategy Routine
Contains the 16-bit offset from the start of the first code segment to the device driver's strategy entry point. The OS/2 operating system uses this offset to call the strategy routine.

Offset to IDC Entry Point
The 16-bit offset from the start of the first code segment of the physical device driver to the entry point, which is callable by other device drivers.

Name or Units
Contains the 8-character name of a character device supported by the character device driver or the number of units supported by the block device driver.

For a character device driver, the name of the device must be uppercase ASCII characters and left-justified with the remaining spaces set to blanks. The device name is used by applications to identify the device for I/O. A character device driver should consider the following rule when selecting a physical device driver name. To avoid conflicts with file names, a character device driver should choose a character string with some unusual character (such as a $ sign) as the last character.

''A device name takes precedence over a file name in a DosOpen function. This means that files cannot have the same name as a character device. The DosOpen function always opens the device, rather than the file.''

Capabilities Bit Strip
Level 3 device drivers have an additional DWORD field appended to the device header. Each bit of this new field is a flag indicating whether or not a particular feature is supported. The flags in this field are:
 * Bit 0 : Set to 1, if DosDevIOCtl2 request packets are supported, and if shutdown support is provided.
 * Bit 1 : For block device drivers, this bit is reserved and must be set to 0. Block device drivers indicate their ability to support greater than 16MB by way of the Query Device Parameters IOCtl (Category 08h, Function 63h) Device attributes field, bit 2.
 * For character device drivers, this bit is set to 1 (if memory addressing above 16MB is supported, that is, support for full 32-bit memory addressability verses 24-bit memory addressability).


 * Bit 2 : Set to 1, if the physical device driver supports parallel ports.
 * Bit 3 : Indicates that the physical device driver is participating in the adapter device driver strategy, which, in turn, selects an alternate INIT request packet format from the kernel.
 * Bit 4 : If set to 1, the Initialization Complete Command (1Fh) is supported.
 * Bits 5-31 : Reserved. Must be set to 0.

Physical Device Driver Components
The components of a physical device driver are illustrated in the following figure.  ┌────────────────────────────┐   ┌───────────────────────────┐ │          Task Time         │    │      Other PDD            │ │                           │    │           ▲               │ │    ┌────────┼──────────┼───┘    └───────────┼──────────┐    │ │    │        │          │                    │          │    │ │    │  ┌─────┼──────────┼────────────────────┼───────┐  │    │ │ K  │  │     │          │                    │       │  │    │ │ E │  │ ┌───▼───┐  ┌───▼───┐            ┌───▼───┐   │  │    │ │ R │  │ │ Strat │  │Context│            │  IDC  │   │  └────┘ │ N │  │ └───────┘  └───────┘   OS/2     └───────┘   │ │ E │  │                        PDD                  │ Any Context │ L │  │                                             │ │   │  │ ┌───────┐  ┌───────┐            ┌───────┐   │  ┌────┐ │    │  │ │ Timer │  │  Int  │            │  VDD  │   │  │    │ │   │  │ └───▲───┘  └───▲───┘            └───▲───┘   │  │    │ │    │  │     │          │                    │       │  │    │ │    │  └─────┼──────────┼────────────────────┼───────┘  │    │ │    │        │          │                    │          │    │ │    └────────┼──────────┼───┐    ┌───────────┼──────────┘    │ │                            │    │           ▼               │ │       Interrupt Time       │    │      Matched VDD          │ └────────────────────────────┘   └───────────────────────────┘

(1) Strategy Entry Point  (required) (2) Task-time Context  (optional) (3) Timer Services Entry Point  (optional) (4) Hardware Interrupt Entry Point  (mandatory) (5) PDD-PDD IDC Entry Point  (optional) (6) PDD-VDD IDC Entry Point  (optional)  Deciding what components to include in a physical device driver depends on two things, the complexity of the task and how the application performs I/O to its device. A physical device driver must have a strategy routine and can have a hardware interrupt routine, a timer handler, a context hook handler, an IDC handler or a VDD communications handler: The strategy routine is called at task-time to handle I/O requests through a request packet interface with the OS/2 kernel as a result of an application I/O request. Application I/O requests can come from OS/2 applications active in protect mode or from DOS applications active in a DOS session.
 * Strategy Routine (Required)

The strategy routine follows the 16-bit far call/return model. When it completes processing, it issues a far return to the kernel. By convention, OS/2 preserves any registers used by the strategy routine.

The request packet interface to device drivers is described in Physical Device Driver Strategy Commands.

This routine is called by the OS/2 kernel at task time as a result of issuing the DevHelp_ArmContextHook call by the physical device driver. The handler runs in the first available task context after being armed.
 * Context Hook Handler (Optional)

Note: A thread running in the OS/2 kernel or a physical device driver cannot be pre-empted so the context hook, though called at kernel level, will wait until an application level thread would be dispatched before running.

The context hook handler follows the 16-bit far call/return model. When it has completed processing it issues a far return to the kernel. The handler must save and restore any registers it uses.


 * Timer Handler (Optional)

The timer handler is called as a result of a periodic clock tick and executes at interrupt time. This handler can be used to manage timeouts or polling of a non-interrupt driven device.

The timer handler follows the far call/return model. When it has completed processing, it issues a 16-bit far return to OS/2. The handler must save and restore any registers it uses.


 * Hardware Interrupt Handler (Optional)

The hardware interrupt handler is called as a result of a hardware interrupt and executes at interrupt time. The interrupt handler follows the 16-bit far call/return model. When it completes processing, it issues a far return to the OS/2 operating system. The handler must clear or set the Carry Flag (CF) to indicate whether it owns the hardware interrupt. If the device owns the interrupt, the carry flag is cleared (CLC). If the device does not own the interrupt, the interrupt handler must set the carry flag (STC) before returning. By convention, OS/2 2.1 (or later) preserves any registers used by the hardware interrupt handler.


 * Inter-Device-Driver Communications Handler (optional)

A physical device driver can call and pass data to another physical device driver by using the inter-device-driver communication (IDC) mechanism that is provided by the OS/2 operating system. To communicate with each other, device drivers must maintain addressability, while being sensitive to interrupt-time performance.

A physical device driver uses its device driver header to indicate that another device driver can communicate with it. See the section Physical Device Driver Header for a detailed description of the physical device driver header.


 * The physical device driver must set bit 14 in the attribute field to indicate that it can participate in inter-device-driver communication.


 * The physical device driver must set up the offset to its entry point for other device drivers, which is identified as the IDC Entry Point.

Another device driver can communicate with this driver by calling its IDC Entry Point. The other device driver obtains the address of this entry point (and other information it needs to be able to call this driver) by calling the AttachDD device helper routine. This DevHlp service returns the address of the IDC Entry Point of the specified named device driver. See Device Helper (DevHlp) Services for more information.

The type and form of communication are defined by the physical device driver that provides the IDC Entry Point. Registers can be used to indicate the type of communication (for example, initialize a buffer, write data to a buffer) as well as the form of communication (for example, data structures). To communicate with a physical device driver, therefore, another device driver must use the published interface to the IDC Entry Point.

By default, all IDC services provided by a device driver are assumed to be valid at kernel-context mode. Services that are valid at other calling contexts must be explicitly defined by the driver providing the IDC service.


 * Virtual Device Driver Communications Handler (optional)

A physical device and a virtual device driver can call and pass data to each other using a virtual-to-physical device driver communication mechanism. The physical device driver must register the communications handler entry point using the DevHelp_RegisterPDD call at initialization time. The virtual device driver will then gain the handler's address by using the VDHOpenPDD call.

To communicate with each other, the virtual and physical device drivers must maintain addressability while being sensitive to interrupt time performance.

The type and form of communication are defined by the physical/virtual device driver pair. A register-based or stack-based calling convention is acceptable but the initial call into the physical device driver is stack based and requires a 32-bit far return. See the DevHelp_RegisterPDD definition for more information.

Building a Physical Device Driver
When a physical device driver is installed, new or optional devices can be installed without modifying the operating system. You can build a physical device driver by either using the samples in the IBM Developer Connection Device Driver Kit for OS/2, or by following these instructions. To create a physical device driver that the OS/2 operating system can install:


 * Create the Data and Code segments. A physical device driver can have multiple code and data segments. The first segment after the .EXE file header must be the first data segment (default). Because a physical device driver can have multiple code and data segments, it can make far calls to other code segments.

Note: OS/2 can install the physical device driver anywhere in memory; therefore, care must be taken in making any memory references. Do not expect the physical device driver to be loaded at the same place every time. Do not hard code addresses.


 * 1) By default, only the first data and code segments remain in memory after initialization of the physical device driver. All other segments are assumed to be initialization code, unless otherwise designated. Memory used by these segments is returned to the system.
 * 2) Define the physical device driver header. The physical device driver header must be the first data in the first data segment and must be located immediately after the .EXE file header. The physical device driver header defines the characteristics of a physical device driver for the OS/2 operating system. See Physical Device Driver Header for a detailed description of each device driver header field.
 * 3) Define a strategy routine and optional interrupt handler routine in the code segments.
 * 4) Define the code and data segments and their attributes in the linker DEF file (module definition file). The SEGMENTS directive and its IOPL option in the DEF file indicate which segments are to be permanent (that is, remain in memory after initialization).
 * 5) Link the code and data segments as a library.
 * 6) Include a DEVICE= statement for the physical device driver in the CONFIG.SYS file so the physical device driver is installed when the system is initialized.
 * 7) Prepare a Device Driver Profile (see Device Driver Profile) to include on a device support diskette so that users can install the physical device driver by using the DDINSTAL utility.