1.4 Some details

1.4.1 PDD header

The PDD header defines the characteristics of a driver.

field description

length in bytes

a) far pointer to next device header

4

b) device attribute

2

c) 16 bit offset to strategy routine

2

d) 16 bit offset to inter-device-driver-communication (IDC) routine

2

e) driver name (character DD) / number of units (block DD)

8

f) reserved

8

g) capabilities bit strip

8



a) far pointer to next device header
This pointer should be set to ­1 (ffffffff) in the driver's code. While loading the drivers, OS/2 builds a linked list for all drivers by using this field. If the driver supports multiple devices, there is one header for each device. Only the last header should be set to ­1 the other ones need to be linked together!

b) device attribute
Describes the characteristics of the physical device driver to the system.

c) 16 bit offset to strategy routine
This is the entry point to the code running in kernel mode. The kernel is using this address to call the strategy routine.

d) 16 bit offset to inter-device-driver-communication (IDC) routine
This address could be called by other device drivers to provide IDC.

e) driver name (character DD) / number of units (block DD)
For character DD's, the name needs to be in uppercase, left oriented and filled up with blanks until the length is 8 bytes. The device name takes precedence over file names! To avoid conflicts, sometimes a driver's name uses special symbols, like a $ sign. Block DD's fill in the number of supported units.

f) reserved
reserved area for future use ?????

g) capabilities bit strip
Level 3 device drivers have an additional 8 byte field appended to the device header. Each bit of this new field is a flag indicating whether or not a particular feature is supported.



1.4.2 How PDD's work

Strategy routine:

a) If an application wants to communicate with the PDD, it calls one of the above kernel functions (e.g. DosOpen(), DosWrite(), ...).

b) The kernel does some parameter checking and builds a data structure called request packet.

c) The kernel calls the strategy entry point in the device driver and passes a pointer to the request packet. Pointers in the request packet (only for read/write requests) are already translated into a 32 bit physical address (already locked and verified), which is done automatically by the kernel. The strategy routine may build a request queue for further requests. Addresses received by IOCTL calls, are virtual addresses, not locked and not verified!

d) If the request can be answered in a short time, the strategy routine sets the return status in the request packet and ends. If the request can't be answered quickly (maybe the hardware isn't ready until yet), the driver should call a function to block the application thread. If the interrupt routine recognizes that the device is ready, the thread can be resumed. This mechanism is necessary to guarantee the multitasking mechanism. Code in the DD never preempts by the scheduler! You need to block the applications thread every time, if you can't directly deliver the result to the application. If the request can be answered directly, but it takes a lot of other calculation time in the strategy routine, yield the CPU every 3 milliseconds with a special function call!

e) NO "standard" OS/2 API function call can be made in this mode! Only special device-helper-functions can be used!



Interrupt routine:

a) The interrupt routine can be preempted by higher priority interrupts.

b) If time critical device checking is performed, it's a good idea to disable interrupts (for a very short time), to avoid preemption.

c) If the application thread has been blocked in the strategy routine, it can be resumed from the interrupt routine (if the data is available).

d) NO "standard" OS/2 API function call can be done in this mode! Only special device-helper-functions can be used!



INIT routine:

a) After the device driver is loaded (via a DEVICE= or BASEDEV= statement in CONFIG.SYS), this routine is called via the strategy routine. The request packet is marked as an INIT command!

b) Command line parameters can be read.

c) Because the context of this routine is a kernel thread, running at ring 3 with I/O privilege, some device initialization can be done here.

d) Some "standard" API functions can be used in this mode:



1.4.3 Device Helper Functions

Only these functions can be called for kernel services in the kernel and interrupt mode. Some of them could be called at INIT mode. The interface is called DevHlp interface, which provides these functions.

One very important parameter is received with the first request packet while the driver gets initialized. This is a far pointer to the DevHlp entry point which needs to be saved by the driver to call the DevHlp functions, whenever needed!

You need to look at the PDD reference guide to find out, which function can be called with which context. Not all functions are available at kernel (task time), interrupt and INIT context!

There are about 90 DevHlp functions documented so far. The functions can be grouped together into the following categories:



1.4.4 The Request Packet

The Request Packet which is received by the drivers strategy routine, is divided into two different parts. The "Request Packet Header" and the "Command Specific Data". The following request packet commands have been documented so far:

Code

Function

Block DD

Character DD

0

INIT

x

x

1

MEDIA CHECK

x


2

BUILD BPB

x


4

READ

x

x

5

NONDESTRUCTIVE READ NO WAIT


x

6

INPUT STATUS


x

7

INPUT FLUSH


x

8

WRITE

x

x

9

WRITE WITH VERIFY

x

x

A

OUTPUT STATUS


x

B

OUTPUT FLUSH


x

D

OPEN DEVICE

x

x

E

CLOSE DEVICE

x

x

F

REMOVABLE MEDIA

x


10

GENERIC IOCtl

x

x

11

RESET MEDIA

x


12

GET LOGICAL DRIVE MAP

x


13

SET LOGICAL DRIVE MAP

x


14

DEINSTALL


x

16

PARTITIONABLE HARD DISKS

x


17

GET HARD DISK/LOGICAL UNIT MAP

x


1C

SHUTDOWN

x

x

1D

GET DRIVER CAPABILITIES

x


1F

INITIALIZATION COMPLETE


x



Warpstock Europe 1999

Overview - Contents

back - forward