diff options
| author | 1983-08-12 17:53:34 -0700 | |
|---|---|---|
| committer | 2018-09-21 17:53:34 -0700 | |
| commit | 80ab2fddfdf30f09f0a0a637654cbb3cd5c7baa6 (patch) | |
| tree | ee4357f7f3dd0f2ded59b9c6e7384432d85e7ec9 /v2.0/bin/DEVDRIV.DOC | |
| parent | MS-DOS v1.25 Release (diff) | |
| download | ms-dos-80ab2fddfdf30f09f0a0a637654cbb3cd5c7baa6.tar.gz ms-dos-80ab2fddfdf30f09f0a0a637654cbb3cd5c7baa6.tar.xz ms-dos-80ab2fddfdf30f09f0a0a637654cbb3cd5c7baa6.zip | |
MS-DOS v2.0 Release
Diffstat (limited to 'v2.0/bin/DEVDRIV.DOC')
| -rw-r--r-- | v2.0/bin/DEVDRIV.DOC | 802 |
1 files changed, 802 insertions, 0 deletions
diff --git a/v2.0/bin/DEVDRIV.DOC b/v2.0/bin/DEVDRIV.DOC new file mode 100644 index 0000000..3c82793 --- /dev/null +++ b/v2.0/bin/DEVDRIV.DOC | |||
| @@ -0,0 +1,802 @@ | |||
| 1 | MS-DOS 2.0 Device Drivers | ||
| 2 | |||
| 3 | INTRODUCTION | ||
| 4 | |||
| 5 | In the past, DOS-device driver (BIOS for those who are | ||
| 6 | familiar with CP/M) communication has been mediated with | ||
| 7 | registers and a fixed-address jump-table. This approach | ||
| 8 | has suffered heavily from the following two observations: | ||
| 9 | |||
| 10 | o The old jump-table ideas of the past are fixed in | ||
| 11 | scope and allow no extensibility. | ||
| 12 | |||
| 13 | o The past device driver interfaces have been written | ||
| 14 | without regard for the true power of the hardware. | ||
| 15 | When a multitasking system or interrupt driven | ||
| 16 | hardware is installed a new BIOS must be written | ||
| 17 | largely from scratch. | ||
| 18 | |||
| 19 | In MSDOS 2.0, the DOS-device driver interface has changed | ||
| 20 | from the old jump-table style to one in which the device | ||
| 21 | drivers are linked together in a list. This allows new | ||
| 22 | drivers for optional hardware to be installed (and even | ||
| 23 | written) in the field by other vendors or the user himself. | ||
| 24 | This flexibility is one of the major new features of MS-DOS | ||
| 25 | 2.0. | ||
| 26 | |||
| 27 | Each driver in the chain defines two entry points; the | ||
| 28 | strategy routine and the interrupt routine. The 2.0 DOS | ||
| 29 | does not really make use of two entry points (it simply calls | ||
| 30 | strategy, then immediately calls interrupt). This dual entry | ||
| 31 | point scheme is designed to facilitate future multi-tasking | ||
| 32 | versions of MS-DOS. In multi-tasking environments I/O must | ||
| 33 | be asynchronous, to accomplish this the strategy routine | ||
| 34 | will be called to queue (internally) a request and return | ||
| 35 | quickly. It is then the responsibility of the interrupt | ||
| 36 | routine to perform the actual I/O at interrupt time by picking | ||
| 37 | requests off the internal queue (set up by the strategy | ||
| 38 | routine), and process them. When a request is complete, | ||
| 39 | it is flagged as "done" by the interrupt routine. The DOS | ||
| 40 | periodically scans the list of requests looking for ones | ||
| 41 | flagged as done, and "wakes up" the process waiting for the | ||
| 42 | completion of the request. | ||
| 43 | |||
| 44 | In order for requests to be queued as above it is no | ||
| 45 | longer sufficient to pass I/O information in registers, since | ||
| 46 | many requests may be pending at any one time. Therefore | ||
| 47 | the new device interface uses data "packets" to pass request | ||
| 48 | information. A device is called with a pointer to a packet, | ||
| 49 | this packet is linked into a global chain of all pending | ||
| 50 | I/O requests maintained by the DOS. The device then links | ||
| 51 | the packet into its own local chain of requests for this | ||
| 52 | particular device. The device interrupt routine picks | ||
| 53 | requests of the local chain for processing. The DOS scans | ||
| 54 | the global chain looking for completed requests. These | ||
| 55 | packets are composed of two pieces, a static piece which | ||
| 56 | has the same format for all requests (called the static | ||
| 57 | request header), which is followed by information specific | ||
| 58 | to the request. Thus packets have a variable size and format. | ||
| 59 | |||
| 60 | At this points it should be emphasized that MS-DOS 2.0 | ||
| 61 | does not implement most of these features, as future versions | ||
| 62 | will. There is no global or local queue. Only one request | ||
| 63 | is pending at any one time, and the DOS waits for this current | ||
| 64 | request to be completed. For 2.0 it is sufficient for the | ||
| 65 | strategy routine to simply store the address of the packet | ||
| 66 | at a fixed location, and for the interrupt routine to then | ||
| 67 | process this packet by doing the request and returning. | ||
| 68 | Remember: the DOS just calls the strategy routine and then | ||
| 69 | immediately calls the interrupt routine, it is assumed that | ||
| 70 | the request is completed when the interrupt routine returns. | ||
| 71 | This additional functionality is defined at this time so | ||
| 72 | that people will be aware and thinking about the future. | ||
| 73 | |||
| 74 | |||
| 75 | FORMAT OF A DEVICE DRIVER | ||
| 76 | |||
| 77 | A device driver is simply a relocatable memory image | ||
| 78 | with all of the code in it to implement the device (like | ||
| 79 | a .COM file, but not ORGed at 100 Hex). In addition it has | ||
| 80 | a special header at the front of it which identifies it as | ||
| 81 | a device, defines the strategy and interrupt entry points, | ||
| 82 | and defines various attributes. It should also be noted | ||
| 83 | that there are two basic types of devices. | ||
| 84 | |||
| 85 | The first is character devices. These are devices which | ||
| 86 | are designed to do character I/O in a serial manner like | ||
| 87 | CON, AUX, and PRN. These devices are named (ie. CON, AUX, | ||
| 88 | CLOCK, etc.), and users may open channels (FCBs) to do I/O | ||
| 89 | to them. | ||
| 90 | |||
| 91 | The second class of devices is block devices. These | ||
| 92 | devices are the "disk drives" on the system, they can do | ||
| 93 | random I/O in pieces called blocks (usually the physical | ||
| 94 | sector size) and hence the name. These devices are not | ||
| 95 | "named" as the character devices are, and therefore cannot | ||
| 96 | be "opened" directly. Instead they are "mapped" via the | ||
| 97 | drive letters (A,B,C, etc.). | ||
| 98 | |||
| 99 | Block devices also have units. In other words a single | ||
| 100 | driver may be responsible for one or more disk drives. For | ||
| 101 | instance block device driver ALPHA (please note that we cannot | ||
| 102 | actually refer to block devices by a name!) may be | ||
| 103 | responsible for drives A,B,C and D, this simply means that | ||
| 104 | it has four units (0-3) defined and therefore takes up four | ||
| 105 | drive letters. Which units correspond to which drive letters | ||
| 106 | is determined by the position of the driver in the chain | ||
| 107 | of all drivers: if driver ALPHA is the first block driver | ||
| 108 | in the device chain, and it defines 4 units (0-3), then they | ||
| 109 | will be A,B,C and D. If BETA is the second block driver | ||
| 110 | and defines three units (0-2), then they will be E,F and | ||
| 111 | G and so on. MS-DOS 2.0 is not limited to 16 block device | ||
| 112 | units, as previous versions were. The theoretical limit | ||
| 113 | is 63 (2^6 - 1), but it should be noted that after 26 the | ||
| 114 | drive letters get a little strange (like ] \ and ^). NOTE: | ||
| 115 | Character devices cannot define multiple units (this because | ||
| 116 | they have only one name). | ||
| 117 | |||
| 118 | |||
| 119 | Here is what that special device header looks like: | ||
| 120 | |||
| 121 | +--------------------------------------+ | ||
| 122 | | DWORD Pointer to next device | | ||
| 123 | | (Must be set to -1) | | ||
| 124 | +--------------------------------------+ | ||
| 125 | | WORD Attributes | | ||
| 126 | | Bit 15 = 1 if char device 0 if blk | | ||
| 127 | | if bit 15 is 1 | | ||
| 128 | | Bit 0 = 1 if Current sti device | | ||
| 129 | | Bit 1 = 1 if Current sto output | | ||
| 130 | | Bit 2 = 1 if Current NUL device | | ||
| 131 | | Bit 3 = 1 if Current CLOCK dev | | ||
| 132 | | Bit 4 = 1 if SPECIAL | | ||
| 133 | | Bit 14 is the IOCTL bit (see below) | | ||
| 134 | | Bit 13 is the NON IBM FORMAT bit | | ||
| 135 | +--------------------------------------+ | ||
| 136 | | WORD Pointer to Device strategy | | ||
| 137 | | entry point | | ||
| 138 | +--------------------------------------+ | ||
| 139 | | WORD Pointer to Device interrupt | | ||
| 140 | | entry point | | ||
| 141 | +--------------------------------------+ | ||
| 142 | | 8-BYTE character device name field | | ||
| 143 | | Character devices set a device name | | ||
| 144 | | For block devices the first byte is | | ||
| 145 | | The number of units | | ||
| 146 | +--------------------------------------+ | ||
| 147 | |||
| 148 | Note that the device entry points are words. They must | ||
| 149 | be offsets from the same segment number used to point to | ||
| 150 | this table. Ie. if XXX.YYY points to the start of this | ||
| 151 | table, then XXX.strategy and XXX.interrupt are the entry | ||
| 152 | points. | ||
| 153 | |||
| 154 | A word about the Attribute field. This field is used | ||
| 155 | most importantly to tell the system whether this device is | ||
| 156 | a block or character device (bit 15). Most of other bits | ||
| 157 | are used to give selected character devices certain special | ||
| 158 | treatment (NOTE: these bits mean nothing on a block device). | ||
| 159 | Let's say a user has a new device driver which he wants to | ||
| 160 | be the standard input and output. Besides just installing | ||
| 161 | the driver he needs to tell SYSINIT (and the DOS) that he | ||
| 162 | wishes his new driver to override the current sti and sto | ||
| 163 | (the "CON" device). This is accomplished by setting the | ||
| 164 | attributes to the desired characteristics, so he would set | ||
| 165 | Bits 0 and 1 to 1 (note that they are separate!!). Similarly | ||
| 166 | a new CLOCK device could be installed by setting that | ||
| 167 | attribute, see the section at the end on the CLOCK device. | ||
| 168 | NOTE: that although there is a NUL device attribute, the | ||
| 169 | NUL device cannot be re-assigned. This attribute exists | ||
| 170 | for the DOS so that it can tell if the NUL device is being | ||
| 171 | used. | ||
| 172 | |||
| 173 | The NON IBM FORMAT bit applies only to block devices | ||
| 174 | and effects the operation of the get BPB device call (see | ||
| 175 | below). | ||
| 176 | |||
| 177 | The other bit of interest is the IOCTL bit which has | ||
| 178 | meaning on character or block devices. This bit tells the | ||
| 179 | DOS whether this device can handle control strings (via the | ||
| 180 | IOCTL system call). | ||
| 181 | |||
| 182 | If a driver cannot process control strings, it should | ||
| 183 | initially set this bit to 0. This tells the DOS to return | ||
| 184 | an error if an attempt is made (via IOCTL system call) to | ||
| 185 | send or receive control strings to this device. A device | ||
| 186 | which can process control strings should initialize it to | ||
| 187 | 1. For drivers of this type, the DOS will make calls to | ||
| 188 | the IOCTL INPUT and OUTPUT device functions to send and | ||
| 189 | receive IOCTL strings (see IOCTL in the SYSTEM-CALLS | ||
| 190 | document). | ||
| 191 | |||
| 192 | The IOCTL functions allow data to be sent and received | ||
| 193 | by the device itself for its own use (to set baud rate, stop | ||
| 194 | bits, form length etc., etc.), instead of passing data over | ||
| 195 | the device channel as a normal read or write does. The | ||
| 196 | interpretation of the passed information is up to the device, | ||
| 197 | but it MUST NOT simply be treated as a normal I/O. | ||
| 198 | |||
| 199 | The SPECIAL bit applies only to character drivers and | ||
| 200 | more particularly to CON drivers. The new 2.0 interface | ||
| 201 | is a much more general and consistent interface than the | ||
| 202 | old 1.25 DOS interface. It allows for a number of additional | ||
| 203 | features of 2.0. It is also slower than 1.25 if old style | ||
| 204 | "single byte" system calls are made. To make most efficient | ||
| 205 | use of the interface all applications should block their | ||
| 206 | I/O as much as possible. This means make one XENIX style | ||
| 207 | system call to output X bytes rather than X system calls | ||
| 208 | to output one byte each. Also putting a device channel in | ||
| 209 | RAW mode (see IOCTL) provides a means of putting out | ||
| 210 | characters even FASTER than 1.25. To help alleviate the | ||
| 211 | CON output speed problem for older programs which use the | ||
| 212 | 1 - 12 system calls to output large amounts of data the | ||
| 213 | SPECIAL bit has been implemented. If this bit is 1 it means | ||
| 214 | the device is the CON output device, and has implemented | ||
| 215 | an interrupt 29 Hex handler, where the 29 Hex handler is | ||
| 216 | defined as follows: | ||
| 217 | |||
| 218 | Interrupt 29h handlers | ||
| 219 | |||
| 220 | Input: | ||
| 221 | Character in AL | ||
| 222 | |||
| 223 | Function: | ||
| 224 | output the character in al to the user | ||
| 225 | screen. | ||
| 226 | Output: | ||
| 227 | None | ||
| 228 | Registers: | ||
| 229 | all registers except bx must be preserved. | ||
| 230 | No registers except for al have a known or | ||
| 231 | consistent value. | ||
| 232 | |||
| 233 | If a character device implements the SPECIAL bit, it | ||
| 234 | is the responsibility of the driver to install an address | ||
| 235 | at the correct location in the interrupt table for interrupt | ||
| 236 | 29 Hex as part of its INIT code. IMPLICATION: There can | ||
| 237 | be only one device driver with the SPECIAL bit set in the | ||
| 238 | system. There is no check to insure this state. | ||
| 239 | |||
| 240 | WARNING: THIS FEATURE WILL NOT BE SUPPORTED IN FUTURE VERSIONS | ||
| 241 | OF THE OPERATING SYSTEM. IMPLICATION: Any application | ||
| 242 | (not device driver) which uses INT 29H directly will | ||
| 243 | not work on future versions, YOU HAVE BEEN WARNED. | ||
| 244 | |||
| 245 | In order to "make" a device driver that SYSINIT can | ||
| 246 | install, a memory image or .EXE (non-IBM only) format file | ||
| 247 | must be created with the above header at the start. The | ||
| 248 | link field should be initialized to -1 (SYSINIT fills it | ||
| 249 | in). The attribute field and entry points must be set | ||
| 250 | correctly, and if the device is a character device, the name | ||
| 251 | field must be filled in with the name (if a block device | ||
| 252 | SYSINIT will fill in the correct unit count). This name | ||
| 253 | can be any 8 character "legal" file name. In fact SYSINIT | ||
| 254 | always installs character devices at the start of the device | ||
| 255 | list, so if you want to install a new CON device all you | ||
| 256 | have to do is name it "CON". The new one is ahead of the | ||
| 257 | old one in the list and thus preempts the old one as the | ||
| 258 | search for devices stops on the first match. Be sure to | ||
| 259 | set the sti and sto bits on a new CON device! | ||
| 260 | |||
| 261 | NOTE: Since SYSINIT may install the driver anywhere, you | ||
| 262 | must be very careful about FAR memory references. You | ||
| 263 | should NOT expect that your driver will go in the same | ||
| 264 | place every time (The default BIOS drivers are exempted | ||
| 265 | from this of course). | ||
| 266 | |||
| 267 | |||
| 268 | INSTALLATION OF DEVICE DRIVERS | ||
| 269 | |||
| 270 | Unlike past versions MS-DOS 2.0 allows new device drivers | ||
| 271 | to be installed dynamically at boot time. This is | ||
| 272 | accomplished by the new SYSINIT module supplied by Microsoft, | ||
| 273 | which reads and processes the CONFIG.SYS file. This module | ||
| 274 | is linked together with the OEM default BIOS in a similar | ||
| 275 | manner to the way FORMAT is built. | ||
| 276 | |||
| 277 | One of the functions defined for each device is INIT. | ||
| 278 | This routine is called once when the device is installed, | ||
| 279 | and never again. The only thing returned by the init routine | ||
| 280 | is a location (DS:DX) which is a pointer to the first free | ||
| 281 | byte of memory after the device driver, (like a terminate | ||
| 282 | and stay resident). This pointer method can be used to "throw | ||
| 283 | away" initialization code that is only needed once, saving | ||
| 284 | on space. | ||
| 285 | |||
| 286 | Block devices are installed the same way and also return | ||
| 287 | a first free byte pointer as above, additional information | ||
| 288 | is also returned: | ||
| 289 | |||
| 290 | o The number of units is returned, this determines | ||
| 291 | logical device names. If the current maximum logical | ||
| 292 | device letter is F at the time of the install call, | ||
| 293 | and the init routine returns 4 as the number of units, | ||
| 294 | then they will have logical names G, H, I and J. | ||
| 295 | This mapping is determined by by the position of | ||
| 296 | the driver in the device list and the number of units | ||
| 297 | on the device (stored in the first byte of the device | ||
| 298 | name field). | ||
| 299 | |||
| 300 | o A pointer to a BPB (Bios Parameter Block) pointer | ||
| 301 | array is also returned. This will be similar to | ||
| 302 | the INIT table used in previous versions, but will | ||
| 303 | have more information in it. There is one table | ||
| 304 | for each unit defined. These blocks will be used | ||
| 305 | to build a DPB (Drive Parameter Block) for each of | ||
| 306 | the units. The pointer passed to the DOS from the | ||
| 307 | driver points to an array of n word pointers to BPBs | ||
| 308 | where n is the number of units defined. In this | ||
| 309 | way if all units are the same, all of the pointers | ||
| 310 | can point to the same BPB, saving space. NOTE: this | ||
| 311 | array must be protected (below the free pointer set | ||
| 312 | by the return) since the DPB will be built starting | ||
| 313 | at the byte pointed to by the free pointer. The | ||
| 314 | sector size defined must be less than or equal to | ||
| 315 | the maximum sector size defined at default BIOS init | ||
| 316 | time. If it isn't the install will fail. One new | ||
| 317 | piece of DPB info set from this table will be a "media | ||
| 318 | descriptor byte". This byte means nothing to the | ||
| 319 | DOS, but is passed to devices so that they know what | ||
| 320 | form of a DPB the DOS is currently using for a | ||
| 321 | particular Drive-Unit. | ||
| 322 | |||
| 323 | Block devices may take several approaches; they may be | ||
| 324 | dumb or smart. A dumb device would define a unit (and | ||
| 325 | therefore a DPB) for each possible media drive combination. | ||
| 326 | Unit 0 = drive 0 single side, unit 1 = drive 0 double side, | ||
| 327 | etc. For this approach media descriptor bytes would mean | ||
| 328 | nothing. A smart device would allow multiple media per unit, | ||
| 329 | in this case the BPB table returned at init must define space | ||
| 330 | large enough to accommodate the largest possible media | ||
| 331 | supported. Smart drivers will use the "media byte" to pass | ||
| 332 | around info about what media is currently in a unit. NOTE: | ||
| 333 | If the DPB is a "hybrid" made to get the right sizes, it | ||
| 334 | should give an invalid "media byte" back to the DOS. | ||
| 335 | |||
| 336 | The BOOT (default BIOS) drivers are installed pretty | ||
| 337 | much as above. The preset device list is scanned. If block | ||
| 338 | drivers are encountered they are installed as above (with | ||
| 339 | the exception that the break is not moved since the drivers | ||
| 340 | are already resident in the BIOS). Note that the logical | ||
| 341 | drive letters are assigned in list order, thus the driver | ||
| 342 | which is to have logical A must be the first unit of the | ||
| 343 | first block device in the list. The order of character | ||
| 344 | devices is also important. There must be at least 4 character | ||
| 345 | devices defined at boot which must be the first four devices | ||
| 346 | (of either type), the first will become standard input, | ||
| 347 | standard output, and standard error output. The second will | ||
| 348 | become standard auxiliary input and output, the third will | ||
| 349 | become standard list output, and the forth will become the | ||
| 350 | date/time (CLOCK) device. Thus the BIOS device list must | ||
| 351 | look like this: | ||
| 352 | |||
| 353 | ->CON->AUX->PRN->CLOCK->any other block or character devices | ||
| 354 | |||
| 355 | THE DRIVER | ||
| 356 | |||
| 357 | A device driver will define the following functions: | ||
| 358 | |||
| 359 | Command Function | ||
| 360 | Code | ||
| 361 | |||
| 362 | 0 INIT | ||
| 363 | 1 MEDIA CHECK (Block only, NOP for character) | ||
| 364 | 2 BUILD BPB " " " " " | ||
| 365 | 3 IOCTL INPUT (Only called if device has IOCTL) | ||
| 366 | 4 INPUT (read) | ||
| 367 | 5 NON-DESTRUCTIVE INPUT NO WAIT (Char devs only) | ||
| 368 | 6 INPUT STATUS " " " | ||
| 369 | 7 INPUT FLUSH " " " | ||
| 370 | 8 OUTPUT (write) | ||
| 371 | 9 OUTPUT (Write) with verify | ||
| 372 | 10 OUTPUT STATUS " " " | ||
| 373 | 11 OUTPUT FLUSH " " " | ||
| 374 | 12 IOCTL OUTPUT (Only called if device has IOCTL) | ||
| 375 | |||
| 376 | As mentioned before, the first entry point is the strategy | ||
| 377 | routine which is called with a pointer to a data block. This | ||
| 378 | call does not perform the request, all it does is queue it | ||
| 379 | (save the data block pointer). The second interrupt entry | ||
| 380 | point is called immediately after the strategy call. The | ||
| 381 | "interrupt" routine is called with no parameters, its primary | ||
| 382 | function is to perform the operation based on the queued | ||
| 383 | data block and set up any returns. | ||
| 384 | |||
| 385 | The "BUILD BPB" and "MEDIA CHECK" are the interesting | ||
| 386 | new ones, these are explained by examining the sequence of | ||
| 387 | events in the DOS which occurs when a drive access call (other | ||
| 388 | than read or write) is made: | ||
| 389 | |||
| 390 | I. Turn drive letter into DPB pointer by looking | ||
| 391 | for DPB with correct driver-unit number. | ||
| 392 | |||
| 393 | II. Call device driver and request media check for | ||
| 394 | Drive-Unit. DOS passes its current Media | ||
| 395 | descriptor byte (from DPB). Call returns: | ||
| 396 | |||
| 397 | Media Not Changed | ||
| 398 | Media Changed | ||
| 399 | Not Sure | ||
| 400 | Error | ||
| 401 | |||
| 402 | Error - If an error occurs the error code should | ||
| 403 | be set accordingly. | ||
| 404 | |||
| 405 | Media Not changed - Current DPB and media byte | ||
| 406 | are OK, done. | ||
| 407 | |||
| 408 | Media Changed - Current DPB and media are wrong, | ||
| 409 | invalidate any buffers for this unit, and | ||
| 410 | goto III. | ||
| 411 | |||
| 412 | Not Sure - If there are dirty buffers for this | ||
| 413 | unit, assume DPB and media byte are OK and | ||
| 414 | done. If nothing dirty, assume media changed, | ||
| 415 | invalidate any buffers for unit, and goto | ||
| 416 | III. | ||
| 417 | |||
| 418 | NOTE: If a hybrid DPB was built at init and | ||
| 419 | an invalid Media byte was set, the driver | ||
| 420 | should return media changed when this invalid | ||
| 421 | media byte is encountered. | ||
| 422 | |||
| 423 | III. Call device driver to build BPB with media byte | ||
| 424 | and buffer. | ||
| 425 | |||
| 426 | What the driver must do at step III is determine the | ||
| 427 | correct media that is currently in the unit, and return a | ||
| 428 | pointer to a BPB table (same as for the install call). This | ||
| 429 | table will be used as at init to build a correct DPB for | ||
| 430 | the unit If the determined media descriptor byte in the table | ||
| 431 | turns out to be the same as the one passed in, then the DOS | ||
| 432 | will not build a new table, but rather just use the old one. | ||
| 433 | Therefore in this case the driver doesn't have to correctly | ||
| 434 | fill in the other entries if desired. | ||
| 435 | |||
| 436 | The build BPB call also gets a pointer to a one sector | ||
| 437 | buffer. What this buffer contains is determined by the NON | ||
| 438 | IBM FORMAT bit in the attribute field. If the bit is zero | ||
| 439 | (device is IBM format compatible) then the buffer contains | ||
| 440 | the first sector of the first FAT, in particular the FAT | ||
| 441 | ID byte is the first byte of this buffer. NOTE: It must | ||
| 442 | be true that the BPB is the same, as far as location of the | ||
| 443 | FAT is concerned, for all possible media. This is because | ||
| 444 | this first FAT sector must be read BEFORE the actual BPB | ||
| 445 | is returned. If the NON IBM FORMAT bit is set then the | ||
| 446 | pointer points to one sector of scratch space which may be | ||
| 447 | used for anything. | ||
| 448 | |||
| 449 | CALL FORMAT | ||
| 450 | |||
| 451 | When the DOS calls a device driver to perform a finction, | ||
| 452 | it passes a structure (Drive Request Structure) in ES:BX | ||
| 453 | to perform operations and does a long call to the driver's | ||
| 454 | strategy entry point. This structure is a fixed length header | ||
| 455 | (Static Request Header) followed by data pertinent to the | ||
| 456 | operation being performed. NOTE: It is the drivers | ||
| 457 | responsibility to preserve machine state. | ||
| 458 | |||
| 459 | STATIC REQUEST HEADER -> | ||
| 460 | +-----------------------------+ | ||
| 461 | | BYTE length of record | | ||
| 462 | | Length in bytes of this | | ||
| 463 | | Drive Request Structure | | ||
| 464 | +-----------------------------+ | ||
| 465 | | BYTE unit code | | ||
| 466 | | The subunit the operation | | ||
| 467 | | is for (minor device) | | ||
| 468 | | (no meaning on character | | ||
| 469 | | devices) | | ||
| 470 | +-----------------------------+ | ||
| 471 | | BYTE command code | | ||
| 472 | +-----------------------------+ | ||
| 473 | | WORD Status | | ||
| 474 | +-----------------------------+ | ||
| 475 | | 8 bytes reserved here for | | ||
| 476 | | two DWORD links. One will | | ||
| 477 | | be a link for the DOS queue | | ||
| 478 | | The other for the device | | ||
| 479 | | queue | | ||
| 480 | +-----------------------------+ | ||
| 481 | |||
| 482 | STATUS WORD | ||
| 483 | |||
| 484 | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | ||
| 485 | +---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+ | ||
| 486 | | E | | B | D | | | ||
| 487 | | R | RESERVED | U | O | ERROR CODE (bit 15 on)| | ||
| 488 | | R | | I | N | | | ||
| 489 | +---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+ | ||
| 490 | |||
| 491 | The status word is zero on entry and is set by the driver | ||
| 492 | interrupt routine on return. | ||
| 493 | |||
| 494 | Bit 8 is the done bit, it means the operation is complete. | ||
| 495 | For the moment the Driver just sets it to one when it exits, | ||
| 496 | in the future this will be set by the interrupt routine to | ||
| 497 | tell the DOS the operation is complete. | ||
| 498 | |||
| 499 | Bit 15 is the error bit, if it is set then the low 8 | ||
| 500 | bits indicate the error: | ||
| 501 | |||
| 502 | 0 Write Protect violation | ||
| 503 | (NEW) 1 Unknown Unit | ||
| 504 | 2 Drive not ready | ||
| 505 | (NEW) 3 Unknown command | ||
| 506 | 4 CRC error | ||
| 507 | (NEW) 5 Bad Drive Request Structure length | ||
| 508 | 6 Seek error | ||
| 509 | (NEW) 7 Unknown media | ||
| 510 | 8 Sector not found | ||
| 511 | (NEW) 9 Printer out of paper | ||
| 512 | A Write Fault | ||
| 513 | (NEW) B Read Fault | ||
| 514 | C General Failure | ||
| 515 | |||
| 516 | Bit 9 is the busy bit which is set only by status calls (see | ||
| 517 | STATUS CALL below). | ||
| 518 | |||
| 519 | |||
| 520 | Here is the data block format for each function: | ||
| 521 | |||
| 522 | READ or WRITE - ES:BX (Including IOCTL) -> | ||
| 523 | +------------------------------------+ | ||
| 524 | | 13-BYTE Static Request Header | | ||
| 525 | +------------------------------------+ | ||
| 526 | | BYTE Media descriptor from DPB | | ||
| 527 | +------------------------------------+ | ||
| 528 | | DWORD transfer address | | ||
| 529 | +------------------------------------+ | ||
| 530 | | WORD byte/sector Count | | ||
| 531 | ---+------------------------------------+--- | ||
| 532 | | WORD starting sector number | | ||
| 533 | | (ignored on Char Devs) | | ||
| 534 | +------------------------------------+ | ||
| 535 | |||
| 536 | In addition to setting the status word, the driver must | ||
| 537 | set the Sector count to the actual number of sectors (or | ||
| 538 | bytes) transferred. NOTE: No error check is performed on | ||
| 539 | an IOCTL I/O call, driver MUST correctly set the return sector | ||
| 540 | (byte) count to the actual number of bytes transferred, | ||
| 541 | however. | ||
| 542 | |||
| 543 | NOTE: THE FOLLOWING APPLIES TO BLOCK DEVICE DRIVERS. | ||
| 544 | |||
| 545 | Under certain circumstances the BIOS may be asked to | ||
| 546 | do a write operation of 64K bytes which seems to be a "wrap | ||
| 547 | around" of the transfer address in the BIOS I/O packet. This | ||
| 548 | arises due to an optimization added to the write code in | ||
| 549 | MS-DOS. It will only manifest on user WRITEs which are within | ||
| 550 | a sector size of 64K bytes on files which are "growing" past | ||
| 551 | the current EOF. IT IS ALLOWABLE FOR THE BIOS TO IGNORE | ||
| 552 | THE BALANCE OF THE WRITE WHICH "WRAPS AROUND" IF IT SO | ||
| 553 | CHOOSES. For instance a WRITE of 10000H bytes worth of | ||
| 554 | sectors with a transfer address of XXX:1 could ignore the | ||
| 555 | last two bytes (remember that a user program can never request | ||
| 556 | an I/O of more than FFFFH bytes and cannot wrap around (even | ||
| 557 | to 0) in his transfer segment, so in this case the last two | ||
| 558 | bytes can be ignored). | ||
| 559 | |||
| 560 | |||
| 561 | NON DESRUCTIVE READ NO WAIT - ES:BX -> | ||
| 562 | +------------------------------------+ | ||
| 563 | | 13-BYTE Static Request Header | | ||
| 564 | +------------------------------------+ | ||
| 565 | | BYTE read from device | | ||
| 566 | +------------------------------------+ | ||
| 567 | |||
| 568 | This call is analogous to the console input status call | ||
| 569 | on MS-DOS 1.25. If the character device returns Busy bit | ||
| 570 | = 0 (characters in buffer), then the next character that | ||
| 571 | would be read is returned. This character is NOT removed | ||
| 572 | from the input buffer (hence the term Non Destructive Read). | ||
| 573 | In essence this call allows the DOS to look ahead one input | ||
| 574 | character. | ||
| 575 | |||
| 576 | |||
| 577 | MEDIA CHECK - ES:BX -> | ||
| 578 | +------------------------------------+ | ||
| 579 | | 13-BYTE Static Request Header | | ||
| 580 | +------------------------------------+ | ||
| 581 | | BYTE Media Descriptor from DPB | | ||
| 582 | +------------------------------------+ | ||
| 583 | | BYTE returned | | ||
| 584 | +------------------------------------+ | ||
| 585 | |||
| 586 | In addition to setting status word, driver must set the | ||
| 587 | return byte. | ||
| 588 | |||
| 589 | Return Byte : | ||
| 590 | -1 Media has been changed | ||
| 591 | 0 Don't know if media has been changed | ||
| 592 | 1 Media has not been changed | ||
| 593 | |||
| 594 | If the driver can return -1 or 1 (by having a door-lock | ||
| 595 | or other interlock mechanism) the performance of MSDOS 2.0 | ||
| 596 | is enhanced as the DOS need not reread the FAT for each | ||
| 597 | directory access. | ||
| 598 | |||
| 599 | |||
| 600 | BUILD BPB - ES:BX -> | ||
| 601 | +------------------------------------+ | ||
| 602 | | 13-BYTE Static Request Header | | ||
| 603 | +------------------------------------+ | ||
| 604 | | BYTE Media Descriptor from DPB | | ||
| 605 | +------------------------------------+ | ||
| 606 | | DWORD Transfer Address | | ||
| 607 | | (points to one sectors worth of | | ||
| 608 | | scratch space or first sector | | ||
| 609 | | of FAT depending on the value | | ||
| 610 | | of the NON IBM FORMAT bit) | | ||
| 611 | +------------------------------------+ | ||
| 612 | | DWORD Pointer to BPB | | ||
| 613 | +------------------------------------+ | ||
| 614 | |||
| 615 | If the NON IBM FORMAT bit of the device is set, then | ||
| 616 | the DWORD Transfer Address points to a one sector buffer | ||
| 617 | which can be used for any purpose. If the NON IBM FORMAT | ||
| 618 | bit is 0, then this buffer contains the first sector of the | ||
| 619 | FAT; in this case the driver must not alter this buffer (this | ||
| 620 | mode is useful if all that is desired is to read the FAT | ||
| 621 | ID byte). | ||
| 622 | |||
| 623 | If IBM compatible format is used (NON IBM FORMAT BIT | ||
| 624 | = 0), then it must be true that the first sector of the first | ||
| 625 | FAT is located at the same sector on all possible media. | ||
| 626 | This is because the FAT sector will be read BEFORE the media | ||
| 627 | is actually determined. | ||
| 628 | |||
| 629 | In addition to setting status word, driver must set the | ||
| 630 | Pointer to the BPB on return. | ||
| 631 | |||
| 632 | |||
| 633 | In order to allow for many different OEMs to read each | ||
| 634 | other's disks, the following standard is suggested: The | ||
| 635 | information relating to the BPB for a particular piece of | ||
| 636 | media is kept in the boot sector for the media. In | ||
| 637 | particular, the format of the boot sector is: | ||
| 638 | |||
| 639 | +------------------------------------+ | ||
| 640 | | 3 BYTE near JUMP to boot code | | ||
| 641 | +------------------------------------+ | ||
| 642 | | 8 BYTES OEM name and version | | ||
| 643 | ---+------------------------------------+--- | ||
| 644 | B | WORD bytes per sector | | ||
| 645 | P +------------------------------------+ | ||
| 646 | B | BYTE sectors per allocation unit | | ||
| 647 | +------------------------------------+ | ||
| 648 | | | WORD reserved sectors | | ||
| 649 | V +------------------------------------+ | ||
| 650 | | BYTE number of FATs | | ||
| 651 | +------------------------------------+ | ||
| 652 | | WORD number of root dir entries | | ||
| 653 | +------------------------------------+ | ||
| 654 | | WORD number of sectors in logical | | ||
| 655 | ^ | image | | ||
| 656 | | +------------------------------------+ | ||
| 657 | B | BYTE media descriptor | | ||
| 658 | P +------------------------------------+ | ||
| 659 | B | WORD number of FAT sectors | | ||
| 660 | ---+------------------------------------+--- | ||
| 661 | | WORD sectors per track | | ||
| 662 | +------------------------------------+ | ||
| 663 | | WORD number of heads | | ||
| 664 | +------------------------------------+ | ||
| 665 | | WORD number of hidden sectors | | ||
| 666 | +------------------------------------+ | ||
| 667 | |||
| 668 | The three words at the end are optional, the DOS doesn't | ||
| 669 | care about them (since they are not part of the BPB). They | ||
| 670 | are intended to help the BIOS understand the media. Sectors | ||
| 671 | per track may be redundant (could be figured out from total | ||
| 672 | size of the disk). Number of heads is useful for supporting | ||
| 673 | different multi-head drives which have the same storage | ||
| 674 | capacity, but a different number of surfaces. Number of | ||
| 675 | hidden sectors is useful for supporting drive partitioning | ||
| 676 | schemes. | ||
| 677 | |||
| 678 | |||
| 679 | Currently, the media descriptor byte has been defined | ||
| 680 | for a small range of media: | ||
| 681 | |||
| 682 | 5 1/4" diskettes: | ||
| 683 | |||
| 684 | Flag bits: | ||
| 685 | 01h - on -> 2 double sided | ||
| 686 | |||
| 687 | All other bits must be on. | ||
| 688 | |||
| 689 | 8" disks: | ||
| 690 | FEh - IBM 3740 format, singled-sided, single-density, | ||
| 691 | 128 bytes per sector, soft sectored, 4 sectors | ||
| 692 | per allocation unit, 1 reserved sector, 2 FATs, | ||
| 693 | 68 directory entries, 77*26 sectors | ||
| 694 | |||
| 695 | FDh - 8" IBM 3740 format, singled-sided, | ||
| 696 | single-density, 128 bytes per sector, soft | ||
| 697 | sectored, 4 sectors per allocation unit, 4 | ||
| 698 | reserved sectors, 2 FATs, 68 directory entries, | ||
| 699 | 77*26 sectors | ||
| 700 | |||
| 701 | FEh - 8" Double-sided, double-density, 1024 bytes | ||
| 702 | per sector, soft sectored, 1 sector per allocation | ||
| 703 | unit, 1 reserved sector, 2 FATs, 192 directory | ||
| 704 | entries, 77*8*2 sectors | ||
| 705 | |||
| 706 | |||
| 707 | STATUS Calls - ES:BX -> | ||
| 708 | +------------------------------------+ | ||
| 709 | | 13-BYTE Static Request Header | | ||
| 710 | +------------------------------------+ | ||
| 711 | |||
| 712 | All driver must do is set status word accordingly and | ||
| 713 | set the busy bit as follows: | ||
| 714 | |||
| 715 | o For output on character devices: If it is 1 on | ||
| 716 | return, a write request (if made) would wait for | ||
| 717 | completion of a current request. If it is 0, there | ||
| 718 | is no current request and a write request (if made) | ||
| 719 | would start immediately. | ||
| 720 | |||
| 721 | o For input on character devices with a buffer a return | ||
| 722 | of 1 means, a read request (if made) would go to | ||
| 723 | the physical device. If it is 0 on return, then | ||
| 724 | there are characters in the devices buffer and a | ||
| 725 | read would return quickly, it also indicates that | ||
| 726 | the user has typed something. The DOS assumes all | ||
| 727 | character devices have an input type ahead buffer. | ||
| 728 | Devices which don't have them should always return | ||
| 729 | busy = 0 so that the DOS won't hang waiting for | ||
| 730 | something to get into a buffer which doesn't exist. | ||
| 731 | |||
| 732 | |||
| 733 | FLUSH Calls - ES:BX -> | ||
| 734 | +------------------------------------+ | ||
| 735 | | 13-BYTE Static Request Header | | ||
| 736 | +------------------------------------+ | ||
| 737 | |||
| 738 | This call tells the driver to flush (terminate) all | ||
| 739 | pending requests that it has knowledge of. Its primary use | ||
| 740 | is to flush the input queue on character devices. | ||
| 741 | |||
| 742 | |||
| 743 | INIT - ES:BX -> | ||
| 744 | +------------------------------------+ | ||
| 745 | | 13-BYTE Static Request Header | | ||
| 746 | +------------------------------------+ | ||
| 747 | | BYTE # of units | | ||
| 748 | +------------------------------------+ | ||
| 749 | | DWORD Break Address | | ||
| 750 | ---+------------------------------------+--- | ||
| 751 | | DWORD Pointer to BPB array | | ||
| 752 | | (not set by Character devices) | | ||
| 753 | +------------------------------------+ | ||
| 754 | |||
| 755 | The number of units, break address, and BPB pointer are | ||
| 756 | set by the driver. | ||
| 757 | |||
| 758 | |||
| 759 | FORMAT OF BPB (Bios Parameter Block) - | ||
| 760 | |||
| 761 | +------------------------------------+ | ||
| 762 | | WORD Sector size in Bytes | | ||
| 763 | | Must be at least 32 | | ||
| 764 | +------------------------------------+ | ||
| 765 | | BYTE Sectors/Allocation unit | | ||
| 766 | | Must be a power of 2 | | ||
| 767 | +------------------------------------+ | ||
| 768 | | WORD Number of reserved sectors | | ||
| 769 | | May be zero | | ||
| 770 | +------------------------------------+ | ||
| 771 | | BYTE Number of FATS | | ||
| 772 | +------------------------------------+ | ||
| 773 | | WORD Number of directory entries | | ||
| 774 | +------------------------------------+ | ||
| 775 | | WORD Total number of sectors | | ||
| 776 | +------------------------------------+ | ||
| 777 | | BYTE Media descriptor | | ||
| 778 | +------------------------------------+ | ||
| 779 | | WORD Number of sectors occupied by | | ||
| 780 | | FAT | | ||
| 781 | +------------------------------------+ | ||
| 782 | |||
| 783 | |||
| 784 | THE CLOCK DEVICE | ||
| 785 | |||
| 786 | One of the most popular add on boards seems to be "Real | ||
| 787 | Time CLOCK Boards". To allow these boards to be integrated | ||
| 788 | into the system for TIME and DATE, there is a special device | ||
| 789 | (determined by the attribute word) which is the CLOCK device. | ||
| 790 | In all respects this device defines and performs functions | ||
| 791 | like any other character device (most functions will be "set | ||
| 792 | done bit, reset error bit, return). When a read or write | ||
| 793 | to this device occurs, exactly 6 bytes are transferred. This | ||
| 794 | I/O can be thought of as transferring 3 words which correspond | ||
| 795 | exactly to the values of AX, CX and DX which were used in | ||
| 796 | the old 1.25 DOS date and time routines. Thus the first | ||
| 797 | two bytes are a word which is the count of days since 1-1-80. | ||
| 798 | The third byte is minutes, the fourth hours, the fifth | ||
| 799 | hundredths of seconds, and the sixth seconds. Reading the | ||
| 800 | CLOCK device gets the date and time, writing to it sets the | ||
| 801 | date and time. | ||
| 802 | |||