|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1991 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: floppy.c ! 8: ! 9: Abstract: ! 10: ! 11: This is the NEC PD756 (aka AT, aka ISA, aka ix86) and Intel 82077 ! 12: (aka MIPS) floppy diskette driver for NT. ! 13: ! 14: Author: ! 15: ! 16: Chad Schwitters (chads) 14-Jul-1991. ! 17: ! 18: Environment: ! 19: ! 20: Kernel mode only. ! 21: ! 22: Revision History: ! 23: ! 24: 02-Aug-1991 (chads) Made driver work on MIPS as well as ix86. ! 25: ! 26: Notes: ! 27: ! 28: The NEC PD765 is the controller standard used on almost all ISA PCs ! 29: (Industry Standard Architecture, which use Intel x86 processors). ! 30: More advanced controllers like the Intel 82077 (which is used on ! 31: many MIPS machines) are supersets of the PD765 standard. ! 32: ! 33: ! 34: Overview of this driver: ! 35: ! 36: This driver must deal with floppy drives, and the media that may ! 37: or may not be in them. "Drive" and "controller" refer to the ! 38: hardware connected to the machine, and "media" or "diskette" ! 39: refers to the floppy that gets inserted into the drive. ! 40: ! 41: Communicating with the controller can involve a lot of delays, ! 42: so this driver creates a thread to talk to the controller (since ! 43: we can't wait in another thread's context). The initialization ! 44: and dispatch routines are executed in the context of the caller, ! 45: and the ISR and DPC routines could be anywhere, but everything ! 46: else is executed in the context of the thread. The dispatch ! 47: routines put requests into an interlocked queue and signal the ! 48: thread; the thread wakes up and processes the requests serially. ! 49: ! 50: A big advantage of the thread approach is that synchronization ! 51: problems are almost non-existent. Interrupts always come when ! 52: the floppy is blocked and waiting for them (well, there could be ! 53: a spurious interrupt, but the ISR won't do anything critical in ! 54: that event), so the only opening for contention is with the DPC ! 55: that turns off the drive motor. A spin lock is used to keep the ! 56: thread and the DPC from trying to access variables or registers ! 57: at the same time. ! 58: ! 59: Data structures include a controller extension that holds all ! 60: variables common to the controller, a device extension that ! 61: holds all variables common to the drive, and a read-only table ! 62: that holds parameters used for communicating with the controller ! 63: given a drive/media combination. The data structures will be ! 64: described in more detail later. ! 65: ! 66: Since this driver deals with removable media, it must do its ! 67: share of volume tracking. Before processing any packet, it must ! 68: check some flags - if the volume needs to be verified, the ! 69: packet must be returned with STATUS_VERIFY_REQUIRED. Then, the ! 70: disk's changeline must be checked. If it is set, it should be ! 71: reset, and the packet should be returned with ! 72: STATUS_VERIFY_REQUIRED. (If it can't be reset, then the packet ! 73: should be failed with STATUS_NO_MEDIA_IN_DEVICE). ! 74: ! 75: Before any operation, the motor timer must be cancelled, the ! 76: drive must be selected, its motor must be turned on and given a ! 77: chance to spin up, the changeline must be checked (and possibly ! 78: dealt with as mentioned above), write access (if requested) must ! 79: be checked, and the media type must be determined. ! 80: ! 81: Determining the media type is an unusual process. The drive ! 82: type is obtained from the configuration manager at ! 83: initialization time. Any time that the changeline is set (which ! 84: includes startup) the media type is unknown, and must be ! 85: determined. The DriveMediaLimits table is used to determine ! 86: which drive/media combinations are allowable, and the driver ! 87: assumes that the media with the largest capacity is in the ! 88: drive. It sets up the controller to read that media, and tries ! 89: to read an ID mark from the disk. As long as that fails, it ! 90: tries a lower media type. If no media type works, an error is ! 91: returned. If one works, it is assumed to properly indicate the ! 92: media in the drive, but it could be wrong because some ! 93: drive/media combinations use the same controller parameters. So ! 94: whenever we find that the first sector on the disk is being read ! 95: (which should be the first thing the file system does for a new ! 96: disk; this will work even if the media type assumption is wrong) ! 97: we sneak a peek at the media descriptor byte and change our ! 98: assumption about the media type if necessary. ! 99: ! 100: An operation passed in by the system is called a "request". ! 101: This driver often breaks the request into smaller pieces called ! 102: "transfers" because of limitations in the amount of data that ! 103: can be read or written at one time. ! 104: ! 105: At the end of any operation, the motor timer (MotorTimer in the ! 106: controller object) should be started. If the timer runs for a ! 107: couple of seconds without getting cancelled, it should turn the ! 108: motor off. ! 109: ! 110: Background on hardware operation: ! 111: ! 112: The following info was gathered from a number of technical ! 113: reference documents and existing device drivers. These sources ! 114: often did not agree; where there was a problem, I tried to ! 115: determine the answer by consensus or experimentation. ! 116: ! 117: At initialization, the following steps should be performed: ! 118: ! 119: reset the controller ! 120: wait for an interrupt ! 121: for each diskette ! 122: issue SENSE INTERRUPT STATUS command ! 123: optionally issue the CONFIGURE command ! 124: issue SPECIFY command ! 125: program the data rate ! 126: ! 127: The data rate, CONFIGURE and SPECIFY information should be ! 128: reprogrammed after every reset. ! 129: ! 130: To do a SEEK or RECALIBRATE, the motor should be turned on and ! 131: the command should be issued. After the interrupt comes, a ! 132: SENSE INTERRUPT STATUS command should be issued. ! 133: ! 134: To do a READ or WRITE, the motor should be turned on, and left ! 135: to spin up for at least 500ms. The recorded data rate of the ! 136: inserted media can then be determined by performing a READ ID at ! 137: each data rate until a successful status is returned. Then ! 138: there should be a seek, followed by at least a 15ms head ! 139: settling time. DMA is set up, and the command is issued. When ! 140: the data has been transferred, the controller will interrupt. ! 141: ! 142: If an error is encountered, two more retries should be performed ! 143: by reinitializing the DMA and re-issuing the command. If that ! 144: fails, the disk should be recalibrated and the seek repeated for ! 145: two more tries. ! 146: ! 147: The following registers can be used to program the floppy ! 148: controller. Each is discussed in detail below: ! 149: ! 150: AT JAZZ Read/ Register Name ! 151: Address Address Write (for this driver) ! 152: ! 153: 3f2 write DriveControl ! 154: 3f4 read Status ! 155: 3f5 both Fifo ! 156: 3f7 write DataRate ! 157: 3f7 read DiskChange ! 158: ! 159: Notes on other register usages: ! 160: ! 161: 3f0 is used by the Intel chip, but only for PS/2s. ! 162: ! 163: 3f1 is readable on Compaqs, and called "media id". The ! 164: Intel chip only uses 3f1 on PS/2s. ! 165: ! 166: 3f2 is readable on the Intel chip. ! 167: ! 168: 3f3 doesn't appear to be used by anybody. ! 169: ! 170: 3f4 is writable and called "data rate select" on the Intel ! 171: chip. ! 172: ! 173: 3f6 is used for fixed disk operations. ! 174: ! 175: 3f7 does not seem to be mentioned by one [old] reference, ! 176: but all the others do - and it seems to be essential, so I'm ! 177: going to use it. ! 178: ! 179: DriveControl (aka "digital output", aka "floppy operations"): ! 180: ! 181: bits 0-1: drive select (values 10 and 11 not always used) ! 182: bit 2: 0 = reset controller, 1 = enable controller ! 183: bit 3: 0 = interrupts and DMA disabled, 1 = enabled ! 184: bit 4: 0 = drive 1 motor off, 1 = on ! 185: bit 5: 0 = drive 2 motor off, 1 = on ! 186: bit 6: 0 = drive 3 motor off, 1 = on (not always used) ! 187: bit 7: 0 = drive 4 motor off, 1 = on (not always used) ! 188: ! 189: Note that a drive cannot be selected unless its motor is on ! 190: (setting the bits at the same time is acceptable). ! 191: ! 192: Status: ! 193: ! 194: bit 0: drive 0 busy (seeking or recalibrating) ! 195: bit 1: drive 1 busy ! 196: bit 2: drive 2 busy (not always used) ! 197: bit 3: drive 3 busy (not always used) ! 198: bit 4: controller busy (from command byte until result phase) ! 199: bit 5: DMA is not being used ! 200: bit 6: 0 = data from processor to controller, 1 = reverse ! 201: bit 7: 1 = data ready to be transferred ! 202: ! 203: Note that command bytes can't be written to the DATA ! 204: register unless bit 7 is 1 and bit 6 is 0. Similarly, ! 205: result bytes can't be read from the DATA register unless bit ! 206: 7 is 1 and bit 6 is 1. The delay for this to become true ! 207: could be 175us on the Intel chip; older chips may take ! 208: longer. ! 209: ! 210: Fifo (aka "data"): ! 211: ! 212: All commands are written here one byte at a time, and all ! 213: results are similarly read from here. Commands and results ! 214: are discussed below. ! 215: ! 216: Some controllers have a buffer and programmable threshold, ! 217: which allows the data to be sent in chunks rather than one ! 218: byte at a time. This reduces the chance of an overrun. ! 219: ! 220: After some commands, the values of status registers (and ! 221: other things) are returned through the Fifo register. ! 222: Here's the layout of the status registers: ! 223: ! 224: Status Register 0: ! 225: ! 226: bits 0-1: drive number ! 227: bit 2: head ! 228: bit 3: set if drive is not ready ! 229: bit 4: set if drive faults, or recalibrate didn't find ! 230: track 0 ! 231: bit 5: set when seek is completed ! 232: bits 6-7: 00 = normal termination ! 233: 01 = abnormal termination, error ! 234: 10 = invalid command ! 235: 11 = abnormal termination, drive became not ready ! 236: ! 237: Status Register 1: ! 238: ! 239: bit 0: set if the ID address mark wasn't found ! 240: bit 1: set if write-protection detected during a write ! 241: bit 2: set if sector not found ! 242: bit 3: always 0 ! 243: bit 4: set for data overrun ! 244: bit 5: set if CRC error detected in ID or data ! 245: bit 6: always 0 ! 246: bit 7: set on attempt to access a sector beyond the end of a ! 247: cylinder ! 248: ! 249: Status Register 2: ! 250: ! 251: bit 0: set if data address or deleted data mark not found ! 252: bit 1: set if bad cylinder found ! 253: bit 2: set if SCAN fails to find sector meeting condition ! 254: bit 3: set if SCAN command meets "equal" condition ! 255: bit 4: set if wrong cylinder found ! 256: bit 5: set if CRC error detected in data ! 257: bit 6: set if deleted address data mark encountered during ! 258: READ or SCAN ! 259: bit 7: always 0 ! 260: ! 261: Status Register 3: ! 262: ! 263: bits 0-1: drive number ! 264: bit 2: head ! 265: bit 3: set if drive is two-sided ! 266: bit 4: set if drive is on track 0 ! 267: bit 5: set if the drive is ready ! 268: bit 6: set if the drive is write-protected ! 269: bit 7: set if the drive has faulted ! 270: ! 271: DataRate (aka "configuration control"): ! 272: ! 273: bits 0-1: 00 = 500 kb/s, 01 = 300, 10 = 250, 11 = 1 Mb/s for ! 274: 3.5" and 125 kb/s for 5.25" ! 275: bits 2-7: reserved, 0 ! 276: ! 277: DiskChange (aka "digital input", aka "diskette status"): ! 278: ! 279: bits 0-6: reserved (often used for fixed disks) ! 280: bit 7: 1 = previous diskette has been removed ! 281: ! 282: Common Commands: ! 283: ! 284: Each command and its parameters are given to the controller ! 285: through the Data register. The controller then executes the ! 286: command. When finished, the results can be read from the ! 287: controller through the Data register. ! 288: ! 289: A drive's motor must be on before the drive can be ! 290: selected. Units 0 and 1 cannot have their motor on ! 291: simultaneously; neither can units 2 and 3. ! 292: ! 293: A drive cannot be accessed until <head load time> has passed ! 294: since selecting the drive. ! 295: ! 296: A drive cannot be accessed until <head settle time> has ! 297: passed since an earlier access. ! 298: ! 299: Fields used in commands: ! 300: ! 301: Multi-Track: if this bit is set, both tracks of the ! 302: cylinder will be operated on. ! 303: ! 304: MFM/FM Mode: if this bit is set, MFM mode (double ! 305: density) is selected if it's implemented; if not, FM ! 306: mode (single density) is selected. ! 307: ! 308: Skip: when this bit is set, sectors with a deleted data ! 309: address mark will be skipped for READ DATA or accessed ! 310: for READ DELETED DATA. ! 311: ! 312: Head: one bit, 0 or 1. ! 313: ! 314: Drive Select: two bits to select drive 0 through 3. ! 315: ! 316: Cylinder: 7 bits selecting the cylinder. ! 317: ! 318: Sector: 4 bits giving the number of the first sector to ! 319: be accessed. ! 320: ! 321: Sector Size Code: the sector size is 2^(this value) * ! 322: 128. Sometimes forced to be 2, for 512-byte sectors. ! 323: ! 324: Final Sector of Track: 4 bits giving the final sector ! 325: number of current track. ! 326: ! 327: Gap Length: 8 bits giving the size of the gap between ! 328: sectors excluding the VC0 synchronization field. ! 329: ! 330: Data Length: if Sector Size Code is 0, the sector size ! 331: is 128 but this value says how many bytes are actually ! 332: transferred (extra bytes dropped on READs, extra bytes ! 333: zeroed on WRITEs). If Sector Size code is not 0 ! 334: (sometimes it's forced nonzero), this value should be ! 335: 0xff. ! 336: ! 337: Sectors per Track: 4 bits giving the number of sectors ! 338: per cylinder to be initialized by a FORMAT. ! 339: ! 340: Data Pattern: 8 bits giving the pattern to be written in ! 341: each sector data field during a FORMAT. ! 342: ! 343: Step Rate Interval: 4 bits. The time between step ! 344: pulses. From .5 to 8ms in .5ms increments at 1Mb data ! 345: rate. See the SPECIFY command. ! 346: ! 347: Head Unload Time: 4 bits. The time from the end of a ! 348: read or write until the head is unloaded. 0 to 480ms in ! 349: 32ms increments. See the SPECIFY command. ! 350: ! 351: Head Load Time: 7 bits. The time from loading the head ! 352: until starting the read or write operation. 4 to 512ms ! 353: in 4ms increments. See the SPECIFY command. ! 354: ! 355: Non-DMA Mode Flag: 0 = DMA mode, 1 = host is interrupted ! 356: for each data transfer. ! 357: ! 358: New Cylinder Number: 7 bits giving the desired cylinder ! 359: number. ! 360: ! 361: The commands are given below. For each commands, the bytes ! 362: that must be written to the controller are listed. When the ! 363: command is finished (after an interrupt for most commands) ! 364: the further listed bytes MUST be read from the controller. ! 365: ! 366: READ DATA - move sector from diskette to memory via DMA. ! 367: Heads are automatically loaded and unloaded. ! 368: ! 369: WRITE Multi-Track, MFM/FM Mode, Skip, 00110 ! 370: WRITE 00000, Head, Drive Select ! 371: WRITE Cylinder ! 372: WRITE Head ! 373: WRITE Sector ! 374: WRITE Sector Size Code ! 375: WRITE Final Sector of Track ! 376: WRITE Gap Length ! 377: WRITE Data Length ! 378: ! 379: <interrupt> ! 380: ! 381: READ Status Register 0 ! 382: READ Status Register 1 ! 383: READ Status Register 2 ! 384: READ Cylinder ! 385: READ Head ! 386: READ Sector ! 387: READ Sector Size Code ! 388: ! 389: READ DELETED DATA - same as READ DATA, but only sectors with ! 390: the deleted data address mark are read. ! 391: ! 392: WRITE Multi-Track, MFM/FM Mode, Skip, 01100 ! 393: WRITE 00000, Head, Drive Select ! 394: WRITE Cylinder ! 395: WRITE Head ! 396: WRITE Sector ! 397: WRITE Sector Size Code ! 398: WRITE Final Sector of Track ! 399: WRITE Gap Length ! 400: WRITE Data Length ! 401: ! 402: <interrupt> ! 403: ! 404: READ Status Register 0 ! 405: READ Status Register 1 ! 406: READ Status Register 2 ! 407: READ Cylinder ! 408: READ Head ! 409: READ Sector ! 410: READ Sector Size Code ! 411: ! 412: READ TRACK - same as READ DATA, but all sectors from the index ! 413: mark to the "end of track" sector are read. ! 414: ! 415: WRITE 0, MFM/FM Mode, 000010 ! 416: WRITE 00000, Head, Drive Select ! 417: WRITE Cylinder ! 418: WRITE Head ! 419: WRITE Sector ! 420: WRITE Sector Size Code ! 421: WRITE Final Sector of Track ! 422: WRITE Gap Length ! 423: WRITE Data Length ! 424: ! 425: <interrupt> ! 426: ! 427: READ Status Register 0 ! 428: READ Status Register 1 ! 429: READ Status Register 2 ! 430: READ Cylinder ! 431: READ Head ! 432: READ Sector ! 433: READ Sector Size Code ! 434: ! 435: WRITE DATA - move sector from memory to diskette via DMA. ! 436: Heads are automatically loaded and unloaded. ! 437: ! 438: WRITE Multi-Track, MFM/FM Mode, 000101 ! 439: WRITE 00000, Head, Drive Select ! 440: WRITE Cylinder ! 441: WRITE Head ! 442: WRITE Sector ! 443: WRITE Sector Size Code ! 444: WRITE Final Sector of Track ! 445: WRITE Gap Length ! 446: WRITE Data Length ! 447: ! 448: <interrupt> ! 449: ! 450: READ Status Register 0 ! 451: READ Status Register 1 ! 452: READ Status Register 2 ! 453: READ Cylinder ! 454: READ Head ! 455: READ Sector ! 456: READ Sector Size Code ! 457: ! 458: ! 459: WRITE DELETED DATA - same as WRITE DATA, except a deleted ! 460: data address mark is written at the beginning of the data ! 461: field instead of the normal data address mark. ! 462: ! 463: WRITE Multi-Track, MFM/FM Mode, 001001 ! 464: WRITE 00000, Head, Drive Select ! 465: WRITE Cylinder ! 466: WRITE Head ! 467: WRITE Sector ! 468: WRITE Sector Size Code ! 469: WRITE Final Sector of Track ! 470: WRITE Gap Length ! 471: WRITE Data Length ! 472: ! 473: <interrupt> ! 474: ! 475: READ Status Register 0 ! 476: READ Status Register 1 ! 477: READ Status Register 2 ! 478: READ Cylinder ! 479: READ Head ! 480: READ Sector ! 481: READ Sector Size Code ! 482: ! 483: READ ID - the first ID field is read, and the status registers ! 484: are updated. ! 485: ! 486: WRITE 0, MFM/FM Mode, 001010 ! 487: WRITE 00000, Head, Drive Select ! 488: ! 489: <interrupt> ! 490: ! 491: READ Status Register 0 ! 492: READ Status Register 1 ! 493: READ Status Register 2 ! 494: READ Cylinder ! 495: READ Head ! 496: READ Sector ! 497: READ Sector Size Code ! 498: ! 499: FORMAT TRACK - the selected track is formatted from index to ! 500: "end of track" sector with address marks, ID fields, data ! 501: fields and field gaps. The data field is filled with the ! 502: specified pattern. The ID field data is specified by the host ! 503: *for each sector*. ! 504: ! 505: The DMA must be set up to send four bytes for each sector to ! 506: be formatted. The bytes are Cylinder, Head, Sector, and Sector ! 507: Size Code. ! 508: ! 509: WRITE 0, MFM/FM Mode, 001101 ! 510: WRITE 00000, Head, Drive Select ! 511: WRITE Sector Size Code ! 512: WRITE Sectors per Track ! 513: WRITE Gap Length ! 514: WRITE Data Pattern ! 515: ! 516: <interrupt> ! 517: ! 518: READ Status Register 0 ! 519: READ Status Register 1 ! 520: READ Status Register 2 ! 521: READ Undefined ! 522: READ Undefined ! 523: READ Undefined ! 524: READ Undefined ! 525: ! 526: RECALIBRATE - the heads are stepped to track 0. But note ! 527: that some controllers give up before reaching track 0, so it ! 528: might be necessary to RECALIBRATE more than once. All ! 529: drives must be RECALIBRATEd at initialization time. There ! 530: are no result registers, so the ISR should issue a SENSE ! 531: INTERRUPT STATUS command - which will result in two result ! 532: registers. ! 533: ! 534: WRITE 00000111 ! 535: WRITE 000000, Drive Select ! 536: ! 537: <interrupt> ! 538: ! 539: SENSE INTERRUPT STATUS - the interrupt level is cleared, and ! 540: the controller status is returned. ! 541: ! 542: WRITE 00001000 ! 543: ! 544: READ Status Register 0 ! 545: READ Cylinder ! 546: ! 547: SPECIFY - the head load and unload rates, the drive step rate, ! 548: and the DMA data transfer mode are set. ! 549: ! 550: WRITE 00000011 ! 551: WRITE Step Rate Interval, Head Unload Time ! 552: WRITE Head Load Time, Non-DMA Mode Flag ! 553: ! 554: SENSE DRIVE STATUS - the status of the selected drive is ! 555: returned. ! 556: ! 557: WRITE 00000100 ! 558: WRITE 00000, Head, Drive Select ! 559: ! 560: READ Status Register 3 ! 561: ! 562: SEEK - the selected drive is stepped to the new cylinder. ! 563: Seeks generally must be explicit, but on some controllers ! 564: can be made implicit via the CONFIGURE command. When not ! 565: implicit, READs and WRITEs should be preceded by SEEK, SENSE ! 566: INTERRUPT STATUS, and READ ID. There are no result ! 567: registers, so the ISR should issue a SENSE INTERRUPT STATUS ! 568: command - which does have two result registers. ! 569: ! 570: WRITE 00001111 ! 571: WRITE 00000, Head, Drive Select ! 572: WRITE New Cylinder Number ! 573: ! 574: <interrupt> ! 575: ! 576: Commands not always implemented: ! 577: ! 578: Any command not implemented by a controller will result in ! 579: Status Register 0 returning x80 - "invalid command". ! 580: ! 581: The following commands are implemented by some controllers, ! 582: but not by all of the ones studied: ! 583: ! 584: Scan Equal ! 585: Scan Low or Equal ! 586: Scan High or Equal ! 587: Verify ! 588: Version ! 589: Configure ! 590: Relative Seek ! 591: Dump Registers ! 592: Perpendicular Mode ! 593: ! 594: ! 595: Data structures: ! 596: ! 597: For each floppy controller in the system (there's seldom more ! 598: than one) a controller data area is allocated. This area holds ! 599: all information about the controller, and all information common ! 600: to all of the drives attached to it. It has the following ! 601: fields: ! 602: ! 603: FifoBuffer[10] - data is sent to and received from the ! 604: controller via a FIFO port. A single routine, ! 605: FlIssueCommand(), is used to send the command and ! 606: parameters, and receive the result bytes. Before calling ! 607: FlIssueCommand(), the parameters should be placed into the ! 608: FifoBuffer; and after the command, the result bytes can be ! 609: read from the buffer. Note that for commands with a result ! 610: phase, the first result byte is read into the buffer by the ! 611: ISR. For commands without a result phase, the ISR writes a ! 612: SENSE INTERRUPT STATUS command, which means that *that* ! 613: command's result bytes will have to be read by ! 614: FlIssueCommand(). ! 615: ! 616: InterruptDelay - set to a few seconds. When we're waiting ! 617: for an interrupt, we use this as a time-out value. ! 618: ! 619: Minimum10msDelay - set to 10 milliseconds, which is the ! 620: smallest unit of time that the floppy thread can block. Used ! 621: when blocking to wait for the controller to become ready to ! 622: transfer bytes through the FIFO. ! 623: ! 624: ListEntry - the list of requests for the floppy driver to ! 625: process. The dispatch routines add requests to the tail of ! 626: the list, and the floppy thread takes them off at the head. ! 627: In some cases of hardware failure, the floppy thread will ! 628: reinsert a request at the head of the list to try the packet ! 629: again. ! 630: ! 631: InterruptEvent - the event that is waited on when we're ! 632: expecting the controller to interrupt. It should be reset ! 633: before programming the controller, and set in the DPC that ! 634: is queued by the ISR. ! 635: ! 636: AllocateAdapterChannelEvent - the event that is waited on ! 637: when we're allocating a DMA adapter channel. It should be ! 638: reset before requesting the adapter, and set by the DPC that ! 639: is queued by the IO system when the adapter channel is ! 640: available. ! 641: ! 642: RequestSemaphore - the semaphore that the floppy thread waits ! 643: on. It should be released by the dispatch routines whenever ! 644: they add a request to the list. Note that it can also be ! 645: released when the thread is supposed to terminate; see ! 646: "UnloadingDriver". ! 647: ! 648: TimerSpinLock - a spinlock that is used to protect access to ! 649: "MotorTimer" and the DriveControl register, since they are ! 650: accessed by FloppyMotorOffDpc() as well as by routines in ! 651: the floppy thread. ! 652: ! 653: ListSpinLock - a spinlock that is allocated and used when ! 654: manipulating the list of requests for the floppy thread in ! 655: an atomic fashion (via the ExInterlocked* routines). ! 656: ! 657: InterruptObject - a pointer to an interrupt object; it must ! 658: be passed to IoConnectInterrupt. ! 659: ! 660: MapRegisterBase - the base address of the map registers. ! 661: Whenever an adapter channel is allocated, this value is passed ! 662: to our DPC. It's stored in the controller object so it can ! 663: be used when we call IoMapTransfer() and ! 664: IoFlushAdapterBuffers(). ! 665: ! 666: IoBuffer - this driver always needs to allocate at least a ! 667: page to format floppies. On systems where there might not ! 668: be enough map registers to map the largest possible transfer ! 669: (the size of the largest supported track on the system), a ! 670: contiguous buffer of that size is allocated. Transfers for ! 671: which there aren't enough map registers are copied to or from ! 672: this buffer, since it is contiguous. ! 673: ! 674: IoBufferMdl - an MDL (memory descriptor list) to describe ! 675: "IoBuffer". Used to lock the pages, flush the buffer, etc. ! 676: ! 677: AdapterObject - an object obtained from HalGetAdapter() that ! 678: must be used when allocating a DMA adapter channel. ! 679: ! 680: CurrentDeviceObject - set to the device object in question ! 681: whenever an interrupt is expected. This aids debugging and ! 682: lets the ISR know whether an interrupt was expected or not. ! 683: ! 684: DriverObject - We keep a pointer around to the driver object ! 685: so that we can log an error if the controller object. The reason ! 686: we don't use the CurrentDeviceObject is that we may not have one ! 687: when we get around to logging the error. ! 688: ! 689: ControllerAddress - the virtual or I/O space address of the ! 690: base of the floppy controller, which is obtained from ! 691: configuration management. ! 692: ! 693: LastDisketteExtension - this value is used with ! 694: CreatedArtificialDrive, below, to decide when to return an ! 695: error. If the system only has one drive, it uses this field ! 696: to determine whether the device object describing the drive ! 697: has changed, so it knows when to return an error so the user ! 698: will be prompted to insert the other diskette. ! 699: ! 700: IoBufferSize - the size of "IoBuffer"; it is either a single ! 701: page (if there's plenty of map registers) or the size of the ! 702: largest track supported by the drives in the system. ! 703: ! 704: IsrReentered - This is counter that is used to determine ! 705: if we are in a hang condition from the controller on a ! 706: level sensitive machine. ! 707: ! 708: MotorTimer - used to count how long the drive motor has been ! 709: on, to determine when to turn it off. At the end of every ! 710: operation, it's set to 3; MotorOffDpc() is called every ! 711: second to decrement it. When it reaches 0, the motor is ! 712: turned off. Whenever the motor doesn't need to be turned ! 713: off (ie the drive is in use, or already off) the value is ! 714: -1. Note that "3" is an upper boundary; the motor will be ! 715: turned off between 2 and 3 seconds after the last operation. ! 716: ! 717: SpanOfControllerAddress - Indicates the number of bytes ! 718: used by the controllers register set. This is only useful ! 719: when the device is being unloaded and the controller address ! 720: is being unmapped. ! 721: ! 722: LastDriveMediaType - every time FlDatarateSpecifyConfigure() ! 723: is called, this value is set to the DriveMediaType that it ! 724: configured the controller to handle. When FlStartDrive() is ! 725: preparing an operation, it checks to see if the current ! 726: drive/media combination is the same - if not, ! 727: FlDatarateSpecifyConfigure() must be called again. ! 728: ! 729: NumberOfMapRegisters - the number of map registers available ! 730: to this driver, obtained from HalGetAdapter(), and possibly ! 731: lowered to the maximum number needed. Each register allows ! 732: the driver to map a single page (or more if the pages are ! 733: contiguous, but that's only counted on when the driver ! 734: allocated the contiguous buffer itself). This value is used ! 735: to determine whether or not the driver needs to allocate a ! 736: contiguous buffer to accomodate a transfer the size of the ! 737: largest track, and it is passed to IoAllocateAdapterChannel(). ! 738: ! 739: NumberOfDrives - the number of drives attached to this ! 740: controller, obtained from the configuration manager. This ! 741: is used when allocating device objects and resetting the ! 742: hardware. ! 743: ! 744: DriveControlImage - the image of the drive control register. ! 745: We must keep track of it since the register is read-only on ! 746: some systems. It should always be updated before writing to ! 747: the drive control register. ! 748: ! 749: ControllerConfigurable - indicates whether or not the ! 750: CONFIGURE command is available. Assumed to be TRUE, it's ! 751: set to FALSE if an attempt to issue the CONFIGURE command ! 752: fails. Controllers with the CONFIGURE command are configured ! 753: to SEEK implicitly. ! 754: ! 755: HardwareFailCount - this is only used in FlFinishOperation. ! 756: If an operation fails due to a hardware problem, we'll retry ! 757: a certain number of times, and this keeps track of how many ! 758: times we've retried. ! 759: ! 760: HardwareFailed - this Boolean is set to FALSE at ! 761: initialization time and when each packet starts (even if ! 762: it's a retry). Whenever a hardware problem is encountered, ! 763: it is set to TRUE. At initialization time, failure to ! 764: initialize the hardware on the first drive means we must try ! 765: again on subsequent drives - if we never succeed, the driver ! 766: is unloaded. For each packet, hardware errors mean we'll ! 767: reset the hardware and retry the packet until it succeeds or ! 768: we overrun HardwareFailCount. ! 769: ! 770: CommandHasResultPhase - whenever a command is issued, ! 771: FlIssueCommand() sets this to TRUE if the command will ! 772: return result bytes. FloppyInterruptService() uses this to ! 773: decide how to dismiss the interrupt. Note that the BUSY bit ! 774: in the STATUS register should give us this information, but ! 775: it's sometimes set when it shouldn't be. ! 776: ! 777: CreatedArtificialDrive - if there's only one drive in the ! 778: system, the initialization code will create a *two* device ! 779: objects to describe it, and set this to TRUE. Whenever a ! 780: drive is accessed, if this is TRUE and the device object ! 781: being used is different, an error is returned so the user ! 782: will be prompted to insert the other diskette. ! 783: ! 784: UnloadingDriver - set to TRUE when the driver is supposed to ! 785: unload itself; setting this and then signalling the request ! 786: semaphore tells the thread to terminate itself. ! 787: ! 788: MappedControllerAddress - Set to TRUE indicates that when ! 789: unloading the driver, the pointer to the device controller ! 790: base register should be unmapped. ! 791: ! 792: For each physical floppy drive, a device object is allocated so ! 793: that the I/O system can access the drive. Attached to each device ! 794: object is a diskette extension structure, which contains ! 795: information specific to the drive and the media in it. Each ! 796: diskette extension contains a pointer to the controller data area ! 797: for the controller that it's attached to. Fields in the structure: ! 798: ! 799: DeviceObject - a pointer to the device object to which this ! 800: diskette extension is appended. ! 801: ! 802: ControllerData - a pointer to the controller data area that ! 803: describes the controller this drive is attached to. ! 804: ! 805: DriveType - the type of the physical drive, as defined in ! 806: flo_data.h. ! 807: ! 808: BytesPerSector - the bytes per sector of the media that was ! 809: last identified in the drive. Used to validate access ! 810: requests in the dispatch routines. ! 811: ! 812: ByteCapacity - the total number of bytes on the media that ! 813: was last identified in the drive. Used to validate access ! 814: requests in the dispatch routines. ! 815: ! 816: MediaType - the last type of media identified in the drive ! 817: (or "Unknown") as defined in ntdddisk.h. This value is used ! 818: to determine whether other media values in the diskette ! 819: extension are valid, and whether or not ! 820: FlDetermineMediaType() needs to be called. ! 821: ! 822: DriveMediaType - the last drive/media combination value, ! 823: determined when the media in the drive was last identified. ! 824: This is used to index into the DriveMediaConstants table. ! 825: ! 826: DeviceUnit - the controller-relative diskette number, which ! 827: is needed for some controller commands. ! 828: ! 829: DriveOnValue - the value that must be written to the ! 830: Drive Control register to start up the drive in question. ! 831: It's the "DeviceUnit" plus a few bits. ! 832: ! 833: ArtificialVerifyRequired - if there's only one drive in the ! 834: system, the user is prompted to switch drives by returning ! 835: STATUS_NO_MEDIA_IN_DEVICE. At that time, this value is set ! 836: to TRUE, so that the next time STATUS_VERIFY_REQUIRED can be ! 837: returned, to tell the file system to clean out it's caches. ! 838: ! 839: The DriveMediaLimits table, which is read-only, tells the driver ! 840: which drive/media combinations are valid for a drive type. The ! 841: table is indexed by the drive type, and has LowestDriveMediaType ! 842: and HighestDriveMediaType fields. The drive/media types are ! 843: enumerated in ascending order, so the driver can start at the ! 844: highest possible combination and decrement the value until the ! 845: correct one is found (or it goes below the lowest valid ! 846: drive/media combination). ! 847: ! 848: The DriveMediaConstants table, which is read-only, tells the driver ! 849: values that it needs to use when communicating with the controller ! 850: given the drive and media type. The table is indexed by the ! 851: DriveMedia number (unique for each drive/media combination) and ! 852: has the following fields: ! 853: ! 854: MediaType - the type of media specified by this drive/media ! 855: combination. The drive type is stored in the diskette ! 856: extension, since it never changes. ! 857: ! 858: StepRateHeadUnloadTime - a combination value that is written ! 859: to the controller as part of the SPECIFY command. The step ! 860: rate is how fast the heads can be moved track-to-track, and ! 861: the head unload time is how long it takes for the heads to ! 862: be unloaded after a READ or WRITE. ! 863: ! 864: HeadLoadTime - a value that is written to the controller as ! 865: part of the SPECIFY command. The head load time is how long ! 866: it takes the heads to stabilize after a SEEK before a READ ! 867: or WRITE can be initiated. ! 868: ! 869: MotorOffTime - not used by this driver, but included to keep ! 870: the table complete. ! 871: ! 872: SectorLengthCode - a code number that specifies the sector ! 873: size. The sector size is 2 to the "code" power, times 128. ! 874: So 0 means 128 bytes, 1 means 256, 2 means 512, etc. This ! 875: number is needed to pass to the controller for several ! 876: commands. ! 877: ! 878: BytesPerSector - the bytes per sector, which can be ! 879: determined from SectorLengthCode. Included as a separate ! 880: field for simplicity and speed. ! 881: ! 882: SectorsPerTrack - the number of sectors on a track (one head ! 883: of a cylinder). ! 884: ! 885: ReadWriteGapLength - the space between sectors, not ! 886: including the synchronization field. Used for READ and ! 887: WRITE commands. ! 888: ! 889: FormatGapLength - gap length passed to the FORMAT command. ! 890: ! 891: FormatFillCharacter - passed to the FORMAT command; this ! 892: byte will be used to fill the data fields on the disk. ! 893: ! 894: HeadSettleTime - the amount of time, in milliseconds, that ! 895: the driver must wait after performing a seek. ! 896: ! 897: MotorSettleTimeRead - the amount of time, in milliseconds, ! 898: that the driver must wait for the drive to spin up before ! 899: performing a READ. ! 900: ! 901: MotorSettleTimeWrite - the amount of time, in milliseconds, ! 902: that the driver must wait for the drive to spin up before ! 903: performing a WRITE. Note that WRITEs are more picky about ! 904: stable rotation speeds, so the drive must always spin up for ! 905: a longer than it would for a READ. ! 906: ! 907: MaximumTrack - the number of the highest track, or cylinder ! 908: on disk (zero-based). ! 909: ! 910: CylinderShift - normally 0, so it does nothing. This field ! 911: is used as a shift for the cylinder number before a SEEK ! 912: command. This is because of a hardware bug; 1.2Mb drives ! 913: don't seek the proper distance for low-density media, so for ! 914: those drive/media combinations this value is 1. ! 915: ! 916: DataTransferRate - the number written to the Datarate ! 917: register before accessing the media. ! 918: ! 919: NumberOfHeads - number of heads on the media, always 1 or 2 ! 920: for floppies. ! 921: ! 922: DataLength - always 0xff, this value must be given to the ! 923: controller for a READ or WRITE command. ! 924: ! 925: The CommandTable, which is read-only, tells the driver how many ! 926: bytes it has to send and receive when issuing a command to the ! 927: controller. It is indexed by the command itself (minus any extra ! 928: bits, like COMMND_MFM) and has the following fields: ! 929: ! 930: NumberOfParameters - the number of parameter bytes that must ! 931: be sent along with this command. ! 932: ! 933: FirstResultByte - if the command has a result phase, then the ! 934: ISR reads the first byte so this value is 1 (meaning that the ! 935: 0th byte has already been read). If there is no result phase, ! 936: then the ISR must give a SENSE INTERRUPT STATUS command, and ! 937: this value is 0. ! 938: ! 939: NumberOfResultBytes - the number of bytes that must be read ! 940: from the controller after this command. For commands with ! 941: a result phase, this is the number of bytes returned minus ! 942: one (which was read by the ISR); for commands without a result ! 943: phase, this is "2" since that many bytes are returned by the ! 944: SENSE INTERRUPT STATUS command that is issued by the ISR. ! 945: ! 946: InterruptExpected - a Boolean that indicates whether or not ! 947: this command will give an interrupt. ! 948: ! 949: AlwaysImplemented - a Boolean that indicates whether or not ! 950: this command will always work. The CONFIGURE command, for ! 951: example, is useful but not always available. This helps to ! 952: determine the correct course of action when the controller ! 953: returns an error. ! 954: ! 955: Hardware quirks: ! 956: ! 957: Many controllers will only step 77 tracks on a recalibrate ! 958: command. But many drives have more tracks than that, so two ! 959: recalibrates are sometimes needed. ! 960: ! 961: When a 40-track diskette is in a 1.2Mb drive, the cylinder ! 962: number must be *doubled* before seeking. The number returned by ! 963: the seek will be the fake number, but the number returned by a ! 964: READ ID will be the correct cylinder. This makes implied SEEKs ! 965: impossible on low-density 5.25" media. ! 966: ! 967: Some machines will give an unexpected interrupt during a ! 968: controller reset unless bit 2 of the drive control register is ! 969: set in BOTH of the bytes that are written to the register. ! 970: ! 971: On fast machines, the BUSY bit is sometimes set in the main ! 972: status register even though the command doesn't have a result ! 973: phase and the command is obviously finished (as evidenced by the ! 974: fact that it interrupted; the ISR is where this problem shows ! 975: up). ! 976: ! 977: On at least the NCR 8 processor machine, we have seen the driver's ! 978: system thread run before the floppy controller can start the ! 979: SENSE_INTERRUPT command. We have placed code in the ISR to spin ! 980: until the SENSE command starts. (Actually it will time ! 981: out after ISR_SENSE_RETRY_COUNT 1 microsecond stalls.) ! 982: ! 983: --*/ ! 984: ! 985: // ! 986: // Include files. ! 987: // ! 988: ! 989: #include "ntddk.h" // various NT definitions ! 990: #include "ntdddisk.h" // disk device driver I/O control codes ! 991: #include <flo_data.h> // this driver's data declarations ! 992: ! 993: ! 994: // ! 995: // This is the actual definition of FloppyDebugLevel. ! 996: // Note that it is only defined if this is a "debug" ! 997: // build. ! 998: // ! 999: #if DBG ! 1000: extern ULONG FloppyDebugLevel = 0; ! 1001: #endif ! 1002: ! 1003: #ifdef ALLOC_PRAGMA ! 1004: #pragma alloc_text(init,DriverEntry) ! 1005: #pragma alloc_text(init,FlConfigCallBack) ! 1006: #pragma alloc_text(init,FlGetConfigurationInformation) ! 1007: #pragma alloc_text(init,FlReportResources) ! 1008: #pragma alloc_text(init,FlInitializeController) ! 1009: #pragma alloc_text(init,FlInitializeDrive) ! 1010: #pragma alloc_text(init,FlGetControllerBase) ! 1011: #endif ! 1012: ! 1013: // #define KEEP_COUNTERS 1 ! 1014: ! 1015: #ifdef KEEP_COUNTERS ! 1016: ULONG FloppyUsedSeek = 0; ! 1017: ULONG FloppyNoSeek = 0; ! 1018: ULONG FloppyUsedBuffer = 0; ! 1019: ULONG FloppyInterrupts = 0; ! 1020: ULONG FloppySpurious = 0; ! 1021: ULONG FloppyIntrBitSet = 0; ! 1022: ULONG FloppyDPCs = 0; ! 1023: ULONG FloppyThreadWake = 0; ! 1024: LARGE_INTEGER FloppyIntrDelay = { 0, 0 }; ! 1025: LARGE_INTEGER FloppyDPCDelay = { 0, 0 }; ! 1026: LARGE_INTEGER FloppyThreadDelay = { 0, 0 }; ! 1027: LARGE_INTEGER FloppyFromIntrDelay = { 0, 0 }; ! 1028: LARGE_INTEGER FloppyThreadTime = { 0, 0 }; ! 1029: LARGE_INTEGER FloppyIntrTime = { 0, 0 }; ! 1030: LARGE_INTEGER FloppyEndIntrTime = { 0, 0 }; ! 1031: LARGE_INTEGER FloppyDPCTime = { 0, 0 }; ! 1032: #endif ! 1033: ! 1034: ! 1035: NTSTATUS ! 1036: DriverEntry( ! 1037: IN PDRIVER_OBJECT DriverObject, ! 1038: IN PUNICODE_STRING RegistryPath ! 1039: ) ! 1040: ! 1041: /*++ ! 1042: ! 1043: Routine Description: ! 1044: ! 1045: This routine is the driver's entry point, called by the I/O system ! 1046: to load the driver. This routine can be called any number of times, ! 1047: as long as the IO system and the configuration manager conspire to ! 1048: give it an unmanaged controller to support at each call. It could ! 1049: also be called a single time and given all of the controllers at ! 1050: once. ! 1051: ! 1052: It initializes the passed-in driver object, calls the configuration ! 1053: manager to learn about the devices that it is to support, and for ! 1054: each controller to be supported it calls a routine to initialize the ! 1055: controller (and all drives attached to it). ! 1056: ! 1057: Arguments: ! 1058: ! 1059: DriverObject - a pointer to the object that represents this device ! 1060: driver. ! 1061: ! 1062: Return Value: ! 1063: ! 1064: If we successfully initialize at least one drive, STATUS_SUCCESS is ! 1065: returned. ! 1066: ! 1067: If we don't (because the configuration manager returns an error, or ! 1068: the configuration manager says that there are no controllers or ! 1069: drives to support, or no controllers or drives can be successfully ! 1070: initialized), then the last error encountered is propogated. ! 1071: ! 1072: --*/ ! 1073: ! 1074: { ! 1075: PCONFIG_DATA configData; // pointer to config mgr's returned data ! 1076: NTSTATUS ntStatus; ! 1077: UCHAR controllerNumber; ! 1078: BOOLEAN partlySuccessful = FALSE; // TRUE if any controller init'd properly ! 1079: ! 1080: // ! 1081: // We use this to query into the registry as to whether we ! 1082: // should break at driver entry. ! 1083: // ! 1084: RTL_QUERY_REGISTRY_TABLE paramTable[3]; ! 1085: ULONG zero = 0; ! 1086: ULONG debugLevel = 0; ! 1087: ULONG shouldBreak = 0; ! 1088: PWCHAR path; ! 1089: ! 1090: UNREFERENCED_PARAMETER(RegistryPath); ! 1091: ! 1092: // ! 1093: // Since the registry path parameter is a "counted" UNICODE string, it ! 1094: // might not be zero terminated. For a very short time allocate memory ! 1095: // to hold the registry path zero terminated so that we can use it to ! 1096: // delve into the registry. ! 1097: // ! 1098: // NOTE NOTE!!!! This is not an architected way of breaking into ! 1099: // a driver. It happens to work for this driver because the author ! 1100: // likes to do things this way. ! 1101: // ! 1102: ! 1103: if (path = ExAllocatePool( ! 1104: PagedPool, ! 1105: RegistryPath->Length+sizeof(WCHAR) ! 1106: )) { ! 1107: ! 1108: RtlZeroMemory( ! 1109: ¶mTable[0], ! 1110: sizeof(paramTable) ! 1111: ); ! 1112: RtlZeroMemory( ! 1113: path, ! 1114: RegistryPath->Length+sizeof(WCHAR) ! 1115: ); ! 1116: RtlMoveMemory( ! 1117: path, ! 1118: RegistryPath->Buffer, ! 1119: RegistryPath->Length ! 1120: ); ! 1121: paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; ! 1122: paramTable[0].Name = L"BreakOnEntry"; ! 1123: paramTable[0].EntryContext = &shouldBreak; ! 1124: paramTable[0].DefaultType = REG_DWORD; ! 1125: paramTable[0].DefaultData = &zero; ! 1126: paramTable[0].DefaultLength = sizeof(ULONG); ! 1127: paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT; ! 1128: paramTable[1].Name = L"DebugLevel"; ! 1129: paramTable[1].EntryContext = &debugLevel; ! 1130: paramTable[1].DefaultType = REG_DWORD; ! 1131: paramTable[1].DefaultData = &zero; ! 1132: paramTable[1].DefaultLength = sizeof(ULONG); ! 1133: ! 1134: if (!NT_SUCCESS(RtlQueryRegistryValues( ! 1135: RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, ! 1136: path, ! 1137: ¶mTable[0], ! 1138: NULL, ! 1139: NULL ! 1140: ))) { ! 1141: ! 1142: shouldBreak = 0; ! 1143: debugLevel = 0; ! 1144: ! 1145: } ! 1146: ! 1147: } ! 1148: ! 1149: // ! 1150: // We don't need that path anymore. ! 1151: // ! 1152: ! 1153: if (path) { ! 1154: ! 1155: ExFreePool(path); ! 1156: ! 1157: } ! 1158: ! 1159: #if DBG ! 1160: FloppyDebugLevel = debugLevel; ! 1161: #endif ! 1162: ! 1163: if (shouldBreak) { ! 1164: ! 1165: DbgBreakPoint(); ! 1166: ! 1167: } ! 1168: ! 1169: FloppyDump( ! 1170: FLOPSHOW, ! 1171: ("Floppy: DriverEntry...\n") ! 1172: ); ! 1173: ! 1174: // ! 1175: // Ask configuration manager for information on the hardware that ! 1176: // we're supposed to support. ! 1177: // ! 1178: ! 1179: ntStatus = FlGetConfigurationInformation( &configData ); ! 1180: ! 1181: // ! 1182: // If FlGetConfigurationInformation() failed, just exit and propogate ! 1183: // the error. If it said that there are no controllers to support, ! 1184: // return an error. ! 1185: // Otherwise, try to init the controllers. If at least one succeeds, ! 1186: // return STATUS_SUCCESS, otherwise return the last error. ! 1187: // ! 1188: ! 1189: if ( NT_SUCCESS( ntStatus ) ) { ! 1190: ! 1191: // ! 1192: // Call FlInitializeController() for each controller (and its ! 1193: // attached drives) that we're supposed to support. ! 1194: // ! 1195: // Return success if we successfully initialize at least one ! 1196: // device; propogate error otherwise. Set an error first in ! 1197: // case there aren't any controllers. ! 1198: // ! 1199: ! 1200: ntStatus = STATUS_NO_SUCH_DEVICE; ! 1201: ! 1202: for ( controllerNumber = 0; ! 1203: controllerNumber < configData->NumberOfControllers; ! 1204: controllerNumber++ ) { ! 1205: ! 1206: ntStatus = FlInitializeController( ! 1207: configData, ! 1208: controllerNumber, ! 1209: DriverObject ); ! 1210: ! 1211: if ( NT_SUCCESS( ntStatus ) ) { ! 1212: ! 1213: partlySuccessful = TRUE; ! 1214: } ! 1215: } ! 1216: ! 1217: if ( partlySuccessful ) { ! 1218: ! 1219: ntStatus = STATUS_SUCCESS; ! 1220: ! 1221: // ! 1222: // Initialize the driver object with this driver's entry points. ! 1223: // ! 1224: ! 1225: DriverObject->MajorFunction[IRP_MJ_CREATE] = ! 1226: FloppyDispatchCreateClose; ! 1227: DriverObject->MajorFunction[IRP_MJ_CLOSE] = ! 1228: FloppyDispatchCreateClose; ! 1229: DriverObject->MajorFunction[IRP_MJ_READ] = FloppyDispatchReadWrite; ! 1230: DriverObject->MajorFunction[IRP_MJ_WRITE] = FloppyDispatchReadWrite; ! 1231: DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ! 1232: FloppyDispatchDeviceControl; ! 1233: } ! 1234: } ! 1235: ! 1236: if ( !NT_SUCCESS( ntStatus ) ) { ! 1237: ! 1238: FloppyDump( ! 1239: FLOPDBGP, ! 1240: ("Floppy: exiting with error %lx\n", ntStatus) ! 1241: ); ! 1242: } ! 1243: ! 1244: if (configData) { ! 1245: ! 1246: ExFreePool(configData); ! 1247: ! 1248: } ! 1249: ! 1250: return ntStatus; ! 1251: } ! 1252: ! 1253: NTSTATUS ! 1254: FlConfigCallBack( ! 1255: IN PVOID Context, ! 1256: IN PUNICODE_STRING PathName, ! 1257: IN INTERFACE_TYPE BusType, ! 1258: IN ULONG BusNumber, ! 1259: IN PKEY_VALUE_FULL_INFORMATION *BusInformation, ! 1260: IN CONFIGURATION_TYPE ControllerType, ! 1261: IN ULONG ControllerNumber, ! 1262: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation, ! 1263: IN CONFIGURATION_TYPE PeripheralType, ! 1264: IN ULONG PeripheralNumber, ! 1265: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation ! 1266: ) ! 1267: ! 1268: /*++ ! 1269: ! 1270: Routine Description: ! 1271: ! 1272: This routine is used to acquire all of the configuration ! 1273: information for each floppy disk controller and the ! 1274: peripheral driver attached to that controller. ! 1275: ! 1276: Arguments: ! 1277: ! 1278: Context - Pointer to the confuration information we are building ! 1279: up. ! 1280: ! 1281: PathName - unicode registry path. Not Used. ! 1282: ! 1283: BusType - Internal, Isa, ... ! 1284: ! 1285: BusNumber - Which bus if we are on a multibus system. ! 1286: ! 1287: BusInformation - Configuration information about the bus. Not Used. ! 1288: ! 1289: ControllerType - Should always be DiskController. ! 1290: ! 1291: ControllerNumber - Which controller if there is more than one ! 1292: controller in the system. ! 1293: ! 1294: ControllerInformation - Array of pointers to the three pieces of ! 1295: registry information. ! 1296: ! 1297: PeripheralType - Should always be FloppyDiskPeripheral. ! 1298: ! 1299: PeripheralNumber - Which floppy if this controller is maintaining ! 1300: more than one. ! 1301: ! 1302: PeripheralInformation - Arrya of pointers to the three pieces of ! 1303: registry information. ! 1304: ! 1305: Return Value: ! 1306: ! 1307: STATUS_SUCCESS if everything went ok, or STATUS_INSUFFICIENT_RESOURCES ! 1308: if it couldn't map the base csr or acquire the adapter object, or ! 1309: all of the resource information couldn't be acquired. ! 1310: ! 1311: --*/ ! 1312: ! 1313: { ! 1314: ! 1315: // ! 1316: // So we don't have to typecast the context. ! 1317: // ! 1318: PCONFIG_DATA config = Context; ! 1319: ! 1320: // ! 1321: // Simple iteration variable. ! 1322: // ! 1323: ULONG i; ! 1324: ! 1325: // ! 1326: // This boolean will be used to denote whether we've seen this ! 1327: // controller before. ! 1328: // ! 1329: BOOLEAN newController; ! 1330: ! 1331: // ! 1332: // This will be used to denote whether we even have room ! 1333: // for a new controller. ! 1334: // ! 1335: BOOLEAN outOfRoom; ! 1336: ! 1337: // ! 1338: // Iteration variable that will end up indexing to where ! 1339: // the controller information should be placed. ! 1340: // ! 1341: ULONG ControllerSlot; ! 1342: ! 1343: // ! 1344: // Short hand for referencing the particular controller config ! 1345: // information that we are building up. ! 1346: // ! 1347: PCONFIG_CONTROLLER_DATA controller; ! 1348: ! 1349: PCM_FULL_RESOURCE_DESCRIPTOR peripheralData; ! 1350: ! 1351: // ! 1352: // These three boolean will tell us whether we got all the ! 1353: // information that we needed. ! 1354: // ! 1355: BOOLEAN foundPort = FALSE; ! 1356: BOOLEAN foundInterrupt = FALSE; ! 1357: BOOLEAN foundDma = FALSE; ! 1358: ! 1359: ASSERT(ControllerType == DiskController); ! 1360: ASSERT(PeripheralType == FloppyDiskPeripheral); ! 1361: ! 1362: // ! 1363: // Check if the infprmation from the registry for this device ! 1364: // is valid. ! 1365: // ! 1366: ! 1367: if (!(((PUCHAR)PeripheralInformation[IoQueryDeviceConfigurationData]) + ! 1368: PeripheralInformation[IoQueryDeviceConfigurationData]->DataLength) || ! 1369: ! 1370: !(((PUCHAR)ControllerInformation[IoQueryDeviceConfigurationData]) + ! 1371: ControllerInformation[IoQueryDeviceConfigurationData]->DataOffset)) { ! 1372: ! 1373: ASSERT(FALSE); ! 1374: return STATUS_INVALID_PARAMETER; ! 1375: ! 1376: } ! 1377: ! 1378: peripheralData = (PCM_FULL_RESOURCE_DESCRIPTOR) ! 1379: (((PUCHAR)PeripheralInformation[IoQueryDeviceConfigurationData]) + ! 1380: PeripheralInformation[IoQueryDeviceConfigurationData]->DataOffset); ! 1381: ! 1382: // ! 1383: // Loop through the "slots" that we have for a new controller. ! 1384: // Determine if this is a controller that we've already seen, ! 1385: // or a new controller. ! 1386: // ! 1387: ! 1388: outOfRoom = TRUE; ! 1389: for ( ! 1390: ControllerSlot = 0; ! 1391: ControllerSlot < MAXIMUM_CONTROLLERS_PER_MACHINE; ! 1392: ControllerSlot++ ! 1393: ) { ! 1394: ! 1395: if (config->Controller[ControllerSlot].ActualControllerNumber == -1) { ! 1396: ! 1397: newController = TRUE; ! 1398: outOfRoom = FALSE; ! 1399: config->Controller[ControllerSlot].ActualControllerNumber = ! 1400: ControllerNumber; ! 1401: config->NumberOfControllers++; ! 1402: break; ! 1403: ! 1404: } else if (config->Controller[ControllerSlot].ActualControllerNumber ! 1405: == (LONG)ControllerNumber) { ! 1406: ! 1407: newController = FALSE; ! 1408: outOfRoom = FALSE; ! 1409: break; ! 1410: ! 1411: } ! 1412: ! 1413: } ! 1414: ! 1415: if (outOfRoom) { ! 1416: ! 1417: // ! 1418: // Just return and ignore the controller. ! 1419: // ! 1420: ! 1421: return STATUS_SUCCESS; ! 1422: ! 1423: } ! 1424: ! 1425: // ! 1426: // Make sure we have room for this floppy disk peripheral. ! 1427: // ! 1428: ! 1429: if (config->Controller[ControllerSlot].NumberOfDrives >= ! 1430: MAXIMUM_DISKETTES_PER_CONTROLLER) { ! 1431: ! 1432: return STATUS_SUCCESS; ! 1433: ! 1434: } ! 1435: ! 1436: controller = &config->Controller[ControllerSlot]; ! 1437: ! 1438: if (newController) { ! 1439: ! 1440: PCM_FULL_RESOURCE_DESCRIPTOR controllerData = ! 1441: (PCM_FULL_RESOURCE_DESCRIPTOR) ! 1442: (((PUCHAR)ControllerInformation[IoQueryDeviceConfigurationData]) + ! 1443: ControllerInformation[IoQueryDeviceConfigurationData]->DataOffset); ! 1444: ! 1445: // ! 1446: // We have the pointer. Save off the interface type and ! 1447: // the busnumber for use when we call the Hal and the ! 1448: // Io System. ! 1449: // ! 1450: ! 1451: controller->InterfaceType = BusType; ! 1452: controller->BusNumber = BusNumber; ! 1453: controller->SharableVector = TRUE; ! 1454: controller->SaveFloatState = FALSE; ! 1455: ! 1456: // ! 1457: // We need to get the following information out of the partial ! 1458: // resource descriptors. ! 1459: // ! 1460: // The irql and vector. ! 1461: // ! 1462: // The dma channel. ! 1463: // ! 1464: // The base address and span covered by the floppy controllers ! 1465: // registers. ! 1466: // ! 1467: // It is not defined how these appear in the partial resource ! 1468: // lists, so we will just loop over all of them. If we find ! 1469: // something we don't recognize, we drop that information on ! 1470: // the floor. When we have finished going through all the ! 1471: // partial information, we validate that we got the above ! 1472: // three. ! 1473: // ! 1474: ! 1475: for ( ! 1476: i = 0; ! 1477: i < controllerData->PartialResourceList.Count; ! 1478: i++ ! 1479: ) { ! 1480: ! 1481: PCM_PARTIAL_RESOURCE_DESCRIPTOR partial = ! 1482: &controllerData->PartialResourceList.PartialDescriptors[i]; ! 1483: ! 1484: switch (partial->Type) { ! 1485: ! 1486: case CmResourceTypePort: { ! 1487: ! 1488: foundPort = TRUE; ! 1489: ! 1490: // ! 1491: // Save of the pointer to the partial so ! 1492: // that we can later use it to report resources ! 1493: // and we can also use this later in the routine ! 1494: // to make sure that we got all of our resources. ! 1495: // ! 1496: ! 1497: controller->SpanOfControllerAddress = ! 1498: partial->u.Port.Length; ! 1499: controller->OriginalBaseAddress = ! 1500: partial->u.Port.Start; ! 1501: controller->ResourcePortType = ! 1502: !!partial->Flags; ! 1503: controller->ControllerBaseAddress = ! 1504: FlGetControllerBase( ! 1505: BusType, ! 1506: BusNumber, ! 1507: partial->u.Port.Start, ! 1508: controller->SpanOfControllerAddress, ! 1509: (BOOLEAN)!!partial->Flags, ! 1510: &controller->MappedAddress ! 1511: ); ! 1512: ! 1513: if (!controller->ControllerBaseAddress) { ! 1514: ! 1515: return STATUS_INSUFFICIENT_RESOURCES; ! 1516: ! 1517: } ! 1518: ! 1519: break; ! 1520: } ! 1521: case CmResourceTypeInterrupt: { ! 1522: ! 1523: foundInterrupt = TRUE; ! 1524: if (partial->Flags & CM_RESOURCE_INTERRUPT_LATCHED) { ! 1525: ! 1526: controller->InterruptMode = Latched; ! 1527: ! 1528: } else { ! 1529: ! 1530: controller->InterruptMode = LevelSensitive; ! 1531: ! 1532: } ! 1533: ! 1534: controller->OriginalIrql = partial->u.Interrupt.Level; ! 1535: controller->OriginalVector = partial->u.Interrupt.Vector; ! 1536: controller->ControllerVector = ! 1537: HalGetInterruptVector( ! 1538: BusType, ! 1539: BusNumber, ! 1540: partial->u.Interrupt.Level, ! 1541: partial->u.Interrupt.Vector, ! 1542: &controller->ControllerIrql, ! 1543: &controller->ProcessorMask ! 1544: ); ! 1545: ! 1546: break; ! 1547: } ! 1548: case CmResourceTypeDma: { ! 1549: ! 1550: DEVICE_DESCRIPTION deviceDesc = {0}; ! 1551: ! 1552: foundDma = TRUE; ! 1553: controller->OriginalDmaChannel = partial->u.Dma.Channel; ! 1554: deviceDesc.Version = DEVICE_DESCRIPTION_VERSION; ! 1555: deviceDesc.DmaWidth = Width8Bits; ! 1556: deviceDesc.DemandMode = TRUE; ! 1557: deviceDesc.MaximumLength = ! 1558: DriveMediaConstants[NUMBER_OF_DRIVE_MEDIA_COMBINATIONS-1]. ! 1559: BytesPerSector * ! 1560: DriveMediaConstants[NUMBER_OF_DRIVE_MEDIA_COMBINATIONS-1]. ! 1561: SectorsPerTrack; ! 1562: ! 1563: // ! 1564: // Always ask for one more page than maximum transfer size. ! 1565: // ! 1566: ! 1567: deviceDesc.MaximumLength += PAGE_SIZE; ! 1568: ! 1569: deviceDesc.DmaChannel = partial->u.Dma.Channel; ! 1570: deviceDesc.InterfaceType = BusType; ! 1571: deviceDesc.DmaSpeed = TypeA; ! 1572: controller->AdapterObject = ! 1573: HalGetAdapter( ! 1574: &deviceDesc, ! 1575: &controller->NumberOfMapRegisters ! 1576: ); ! 1577: ! 1578: if (!controller->AdapterObject) { ! 1579: ! 1580: return STATUS_INSUFFICIENT_RESOURCES; ! 1581: ! 1582: } ! 1583: ! 1584: break; ! 1585: ! 1586: } ! 1587: default: { ! 1588: ! 1589: break; ! 1590: ! 1591: } ! 1592: ! 1593: } ! 1594: ! 1595: } ! 1596: ! 1597: // ! 1598: // If we didn't get all the information then we return ! 1599: // insufficient resources. ! 1600: // ! 1601: ! 1602: if ((!foundPort) || ! 1603: (!foundInterrupt) || ! 1604: (!foundDma)) { ! 1605: ! 1606: return STATUS_INSUFFICIENT_RESOURCES; ! 1607: ! 1608: } ! 1609: ! 1610: } ! 1611: ! 1612: // ! 1613: // With Version 2.0 or greater for this resource list, we will get ! 1614: // the full int13 information for the drive. So get that if available. ! 1615: // ! 1616: // Otherwise, the only thing that we want out of the peripheral information ! 1617: // is the maximum drive capacity. ! 1618: // ! 1619: ! 1620: // ! 1621: // Drop any other information on the floor other then the ! 1622: // device specfic floppy information. ! 1623: // ! 1624: ! 1625: for ( ! 1626: i = 0; ! 1627: i < peripheralData->PartialResourceList.Count; ! 1628: i++ ! 1629: ) { ! 1630: ! 1631: PCM_PARTIAL_RESOURCE_DESCRIPTOR partial = ! 1632: &peripheralData->PartialResourceList.PartialDescriptors[i]; ! 1633: ! 1634: if (partial->Type == CmResourceTypeDeviceSpecific) { ! 1635: ! 1636: // ! 1637: // Point to right after this partial. This will take ! 1638: // us to the beginning of the "real" device specific. ! 1639: // ! 1640: ! 1641: PCM_FLOPPY_DEVICE_DATA fDeviceData; ! 1642: UCHAR driveType; ! 1643: PDRIVE_MEDIA_CONSTANTS biosDriveMediaConstants = ! 1644: &(controller->BiosDriveMediaConstants[controller->NumberOfDrives]); ! 1645: ! 1646: ! 1647: fDeviceData = (PCM_FLOPPY_DEVICE_DATA)(partial + 1); ! 1648: ! 1649: // ! 1650: // Get the driver density ! 1651: // ! 1652: ! 1653: switch ( fDeviceData->MaxDensity ) { ! 1654: ! 1655: case 360: ! 1656: ! 1657: driveType = DRIVE_TYPE_0360; ! 1658: ! 1659: break; ! 1660: ! 1661: ! 1662: case 1200: ! 1663: ! 1664: driveType = DRIVE_TYPE_1200; ! 1665: ! 1666: break; ! 1667: ! 1668: ! 1669: case 1185: ! 1670: ! 1671: driveType = DRIVE_TYPE_1200; ! 1672: ! 1673: break; ! 1674: ! 1675: case 1423: ! 1676: ! 1677: driveType = DRIVE_TYPE_1440; ! 1678: ! 1679: break; ! 1680: ! 1681: case 1440: ! 1682: ! 1683: driveType = DRIVE_TYPE_1440; ! 1684: ! 1685: break; ! 1686: ! 1687: case 2880: ! 1688: ! 1689: driveType = DRIVE_TYPE_2880; ! 1690: ! 1691: break; ! 1692: ! 1693: default: ! 1694: ! 1695: FloppyDump( ! 1696: FLOPDBGP, ! 1697: ("Floppy: Bad DriveCapacity!\n" ! 1698: "------ density is %d\n", ! 1699: fDeviceData->MaxDensity) ! 1700: ); ! 1701: ! 1702: driveType = DRIVE_TYPE_1200; ! 1703: ! 1704: FloppyDump( ! 1705: FLOPDBGP, ! 1706: ("Floppy: run a setup program to set the floppy\n" ! 1707: "------ drive type; assuming 1.2mb\n" ! 1708: "------ (type is %x)\n",fDeviceData->MaxDensity) ! 1709: ); ! 1710: ! 1711: break; ! 1712: ! 1713: } ! 1714: ! 1715: controller->DriveType[controller->NumberOfDrives] = driveType; ! 1716: ! 1717: // ! 1718: // Pick up all the default from our own table and override ! 1719: // with the BIOS information ! 1720: // ! 1721: ! 1722: *biosDriveMediaConstants = DriveMediaConstants[ ! 1723: DriveMediaLimits[driveType].HighestDriveMediaType]; ! 1724: ! 1725: // ! 1726: // If the version is high enough, get the rest of the information. ! 1727: // DeviceSpecific information with a version >= 2 should have ! 1728: // this information ! 1729: // ! 1730: ! 1731: if (fDeviceData->Version >= 2) { ! 1732: ! 1733: // biosDriveMediaConstants->MediaType = ! 1734: ! 1735: biosDriveMediaConstants->StepRateHeadUnloadTime = ! 1736: fDeviceData->StepRateHeadUnloadTime; ! 1737: ! 1738: biosDriveMediaConstants->HeadLoadTime = ! 1739: fDeviceData->HeadLoadTime; ! 1740: ! 1741: biosDriveMediaConstants->MotorOffTime = ! 1742: fDeviceData->MotorOffTime; ! 1743: ! 1744: biosDriveMediaConstants->SectorLengthCode = ! 1745: fDeviceData->SectorLengthCode; ! 1746: ! 1747: // biosDriveMediaConstants->BytesPerSector = ! 1748: ! 1749: biosDriveMediaConstants->SectorsPerTrack = ! 1750: fDeviceData->SectorPerTrack; ! 1751: ! 1752: biosDriveMediaConstants->ReadWriteGapLength = ! 1753: fDeviceData->ReadWriteGapLength; ! 1754: ! 1755: biosDriveMediaConstants->FormatGapLength = ! 1756: fDeviceData->FormatGapLength; ! 1757: ! 1758: biosDriveMediaConstants->FormatFillCharacter = ! 1759: fDeviceData->FormatFillCharacter; ! 1760: ! 1761: biosDriveMediaConstants->HeadSettleTime = ! 1762: fDeviceData->HeadSettleTime; ! 1763: ! 1764: biosDriveMediaConstants->MotorSettleTimeRead = ! 1765: fDeviceData->MotorSettleTime * 1000 / 8; ! 1766: ! 1767: biosDriveMediaConstants->MotorSettleTimeWrite = ! 1768: fDeviceData->MotorSettleTime * 1000 / 8; ! 1769: ! 1770: biosDriveMediaConstants->MaximumTrack = ! 1771: fDeviceData->MaximumTrackValue; ! 1772: ! 1773: // biosDriveMediaConstants->CylinderShift = ! 1774: ! 1775: // NOTE CHICAGO does not use this value ! 1776: // ! 1777: //biosDriveMediaConstants->DataTransferRate = ! 1778: // fDeviceData->DataTransferRate; ! 1779: ! 1780: // biosDriveMediaConstants->NumberOfHeads = ! 1781: ! 1782: biosDriveMediaConstants->DataLength = ! 1783: fDeviceData->DataTransferLength; ! 1784: ! 1785: } ! 1786: ! 1787: } ! 1788: ! 1789: } ! 1790: ! 1791: controller->NumberOfDrives++; ! 1792: controller->OkToUseThisController = TRUE; ! 1793: ! 1794: return STATUS_SUCCESS; ! 1795: } ! 1796: ! 1797: NTSTATUS ! 1798: FlGetConfigurationInformation( ! 1799: OUT PCONFIG_DATA *ConfigData ! 1800: ) ! 1801: ! 1802: /*++ ! 1803: ! 1804: Routine Description: ! 1805: ! 1806: This routine is called by DriverEntry() to get information about the ! 1807: devices to be supported from configuration mangement and/or the ! 1808: hardware architecture layer (HAL). ! 1809: ! 1810: Arguments: ! 1811: ! 1812: ConfigData - a pointer to the pointer to a data structure that ! 1813: describes the controllers and the drives attached to them ! 1814: ! 1815: Return Value: ! 1816: ! 1817: Returns STATUS_SUCCESS unless there is no drive 0 or we didn't get ! 1818: any configuration information. ! 1819: ! 1820: --*/ ! 1821: ! 1822: { ! 1823: ! 1824: INTERFACE_TYPE InterfaceType; ! 1825: NTSTATUS Status; ! 1826: ULONG i; ! 1827: ! 1828: *ConfigData = ExAllocatePool( ! 1829: PagedPool, ! 1830: sizeof(CONFIG_DATA) ! 1831: ); ! 1832: ! 1833: if (!*ConfigData) { ! 1834: ! 1835: return STATUS_INSUFFICIENT_RESOURCES; ! 1836: ! 1837: } ! 1838: ! 1839: // ! 1840: // Zero out the config structure and fill in the actual ! 1841: // controller numbers with -1's so that the callback routine ! 1842: // can recognize a new controller. ! 1843: // ! 1844: ! 1845: RtlZeroMemory( ! 1846: *ConfigData, ! 1847: sizeof(CONFIG_DATA) ! 1848: ); ! 1849: ! 1850: for ( ! 1851: i = 0; ! 1852: i < MAXIMUM_CONTROLLERS_PER_MACHINE; ! 1853: i++ ! 1854: ) { ! 1855: ! 1856: (*ConfigData)->Controller[i].ActualControllerNumber = -1; ! 1857: ! 1858: } ! 1859: ! 1860: // ! 1861: // Go through all of the various bus types looking for ! 1862: // disk controllers. The disk controller sections of the ! 1863: // hardware registry only deal with the floppy drives. ! 1864: // The callout routine that can get called will then ! 1865: // look for information pertaining to a particular ! 1866: // device on the controller. ! 1867: // ! 1868: ! 1869: for ( ! 1870: InterfaceType = 0; ! 1871: InterfaceType < MaximumInterfaceType; ! 1872: InterfaceType++ ! 1873: ) { ! 1874: ! 1875: CONFIGURATION_TYPE Dc = DiskController; ! 1876: CONFIGURATION_TYPE Fp = FloppyDiskPeripheral; ! 1877: ! 1878: Status = IoQueryDeviceDescription( ! 1879: &InterfaceType, ! 1880: NULL, ! 1881: &Dc, ! 1882: NULL, ! 1883: &Fp, ! 1884: NULL, ! 1885: FlConfigCallBack, ! 1886: *ConfigData ! 1887: ); ! 1888: ! 1889: if (!NT_SUCCESS(Status) && (Status != STATUS_OBJECT_NAME_NOT_FOUND)) { ! 1890: ! 1891: ExFreePool(*ConfigData); ! 1892: *ConfigData = NULL; ! 1893: return Status; ! 1894: ! 1895: } ! 1896: ! 1897: } ! 1898: ! 1899: // ! 1900: // Get a pointer to the Io system location that is keeping ! 1901: // a count of all the floppy devices on the system. ! 1902: // ! 1903: ! 1904: if ( IoGetConfigurationInformation() == NULL ) { ! 1905: ! 1906: FloppyDump( ! 1907: FLOPDBGP, ! 1908: ("Floppy: configuration information is NULL\n") ! 1909: ); ! 1910: ExFreePool(*ConfigData); ! 1911: *ConfigData = NULL; ! 1912: return STATUS_INSUFFICIENT_RESOURCES; ! 1913: } ! 1914: ! 1915: (*ConfigData)->FloppyCount = &IoGetConfigurationInformation()->FloppyCount; ! 1916: ! 1917: return STATUS_SUCCESS; ! 1918: } ! 1919: ! 1920: BOOLEAN ! 1921: FlReportResources( ! 1922: IN PDRIVER_OBJECT DriverObject, ! 1923: IN PCONFIG_DATA ConfigData, ! 1924: IN UCHAR ControllerNumber ! 1925: ) ! 1926: ! 1927: /*++ ! 1928: ! 1929: Routine Description: ! 1930: ! 1931: This routine will build up a resource list using the ! 1932: data for this particular controller as well as all ! 1933: previous *successfully* configured controllers. ! 1934: ! 1935: N.B. This routine assumes that it called in controller ! 1936: number order. ! 1937: ! 1938: Arguments: ! 1939: ! 1940: DriverObject - a pointer to the object that represents this device ! 1941: driver. ! 1942: ! 1943: ConfigData - a pointer to the structure that describes the ! 1944: controller and the disks attached to it, as given to us by the ! 1945: configuration manager. ! 1946: ! 1947: ControllerNumber - which controller in ConfigData we are ! 1948: about to try to report. ! 1949: ! 1950: Return Value: ! 1951: ! 1952: TRUE if no conflict was detected, FALSE otherwise. ! 1953: ! 1954: --*/ ! 1955: ! 1956: { ! 1957: ! 1958: ! 1959: ULONG sizeOfResourceList; ! 1960: ULONG numberOfFrds; ! 1961: ULONG i; ! 1962: PCM_RESOURCE_LIST resourceList; ! 1963: PCM_FULL_RESOURCE_DESCRIPTOR nextFrd; ! 1964: ! 1965: // ! 1966: // Loop through all of the controllers previous to this ! 1967: // controller. If the controllers previous to this one ! 1968: // didn't have a conflict, then accumulate the size of the ! 1969: // CM_FULL_RESOURCE_DESCRIPTOR associated with it. ! 1970: // ! 1971: ! 1972: for ( ! 1973: i = 0,numberOfFrds = 0,sizeOfResourceList = 0; ! 1974: i <= ControllerNumber; ! 1975: i++ ! 1976: ) { ! 1977: ! 1978: if (ConfigData->Controller[i].OkToUseThisController) { ! 1979: ! 1980: sizeOfResourceList += sizeof(CM_FULL_RESOURCE_DESCRIPTOR); ! 1981: ! 1982: // ! 1983: // The full resource descriptor already contains one ! 1984: // partial. Make room for three more. ! 1985: // ! 1986: // It will hold the irq "prd", the controller "csr" "prd" which ! 1987: // is actually in two pieces since we don't use one of the ! 1988: // registers, and the controller dma "prd". ! 1989: // ! 1990: ! 1991: sizeOfResourceList += 3*sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR); ! 1992: numberOfFrds++; ! 1993: ! 1994: } ! 1995: ! 1996: } ! 1997: ! 1998: // ! 1999: // Now we increment the length of the resource list by field offset ! 2000: // of the first frd. This will give us the length of what preceeds ! 2001: // the first frd in the resource list. ! 2002: // ! 2003: ! 2004: sizeOfResourceList += FIELD_OFFSET( ! 2005: CM_RESOURCE_LIST, ! 2006: List[0] ! 2007: ); ! 2008: ! 2009: resourceList = ExAllocatePool( ! 2010: PagedPool, ! 2011: sizeOfResourceList ! 2012: ); ! 2013: ! 2014: if (!resourceList) { ! 2015: ! 2016: return FALSE; ! 2017: ! 2018: } ! 2019: ! 2020: // ! 2021: // Zero out the field ! 2022: // ! 2023: ! 2024: RtlZeroMemory( ! 2025: resourceList, ! 2026: sizeOfResourceList ! 2027: ); ! 2028: ! 2029: resourceList->Count = numberOfFrds; ! 2030: nextFrd = &resourceList->List[0]; ! 2031: ! 2032: for ( ! 2033: i = 0; ! 2034: numberOfFrds; ! 2035: i++ ! 2036: ) { ! 2037: ! 2038: if (ConfigData->Controller[i].OkToUseThisController) { ! 2039: ! 2040: PCM_PARTIAL_RESOURCE_DESCRIPTOR partial; ! 2041: ! 2042: nextFrd->InterfaceType = ConfigData->Controller[i].InterfaceType; ! 2043: nextFrd->BusNumber = ConfigData->Controller[i].BusNumber; ! 2044: ! 2045: // ! 2046: // We are only going to report 4 items no matter what ! 2047: // was in the original. ! 2048: // ! 2049: ! 2050: nextFrd->PartialResourceList.Count = 4; ! 2051: ! 2052: // ! 2053: // Now fill in the port data. We don't wish to share ! 2054: // this port range with anyone ! 2055: // ! 2056: ! 2057: partial = &nextFrd->PartialResourceList.PartialDescriptors[0]; ! 2058: ! 2059: partial->Type = CmResourceTypePort; ! 2060: partial->ShareDisposition = CmResourceShareShared; ! 2061: partial->Flags = (USHORT)ConfigData->Controller[i].ResourcePortType; ! 2062: partial->u.Port.Start = ! 2063: ConfigData->Controller[i].OriginalBaseAddress; ! 2064: partial->u.Port.Length = 6; ! 2065: ! 2066: partial++; ! 2067: ! 2068: partial->Type = CmResourceTypePort; ! 2069: partial->ShareDisposition = CmResourceShareShared; ! 2070: partial->Flags = (USHORT)ConfigData->Controller[i].ResourcePortType; ! 2071: partial->u.Port.Start = RtlLargeIntegerAdd( ! 2072: ConfigData->Controller[i].OriginalBaseAddress, ! 2073: RtlConvertUlongToLargeInteger((ULONG)7) ! 2074: ); ! 2075: partial->u.Port.Length = 1; ! 2076: ! 2077: partial++; ! 2078: ! 2079: partial->Type = CmResourceTypeDma; ! 2080: partial->ShareDisposition = CmResourceShareShared; ! 2081: partial->Flags = 0; ! 2082: partial->u.Dma.Channel = ! 2083: ConfigData->Controller[i].OriginalDmaChannel; ! 2084: ! 2085: partial++; ! 2086: ! 2087: // ! 2088: // Now fill in the irq stuff. ! 2089: // ! 2090: ! 2091: partial->Type = CmResourceTypeInterrupt; ! 2092: partial->u.Interrupt.Level = ! 2093: ConfigData->Controller[i].OriginalIrql; ! 2094: partial->u.Interrupt.Vector = ! 2095: ConfigData->Controller[i].OriginalVector; ! 2096: ! 2097: // if (nextFrd->InterfaceType == MicroChannel) { ! 2098: // ! 2099: // partial->ShareDisposition = CmResourceShareShared; ! 2100: // ! 2101: // } else { ! 2102: // ! 2103: // partial->ShareDisposition = CmResourceShareDriverExclusive; ! 2104: // ! 2105: // } ! 2106: ! 2107: partial->ShareDisposition = CmResourceShareShared; ! 2108: ! 2109: if (ConfigData->Controller[i].InterruptMode == Latched) { ! 2110: ! 2111: partial->Flags = CM_RESOURCE_INTERRUPT_LATCHED; ! 2112: ! 2113: } else { ! 2114: ! 2115: partial->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; ! 2116: ! 2117: } ! 2118: ! 2119: partial++; ! 2120: ! 2121: nextFrd = (PVOID)partial; ! 2122: ! 2123: numberOfFrds--; ! 2124: ! 2125: } ! 2126: ! 2127: } ! 2128: ! 2129: IoReportResourceUsage( ! 2130: NULL, ! 2131: DriverObject, ! 2132: resourceList, ! 2133: sizeOfResourceList, ! 2134: NULL, ! 2135: NULL, ! 2136: 0, ! 2137: FALSE, ! 2138: &ConfigData->Controller[ControllerNumber].OkToUseThisController ! 2139: ); ! 2140: ! 2141: // ! 2142: // The above routine sets the boolean the parameter ! 2143: // to TRUE if a conflict was detected. ! 2144: // ! 2145: ! 2146: ConfigData->Controller[ControllerNumber].OkToUseThisController = ! 2147: !ConfigData->Controller[ControllerNumber].OkToUseThisController; ! 2148: ! 2149: ExFreePool(resourceList); ! 2150: ! 2151: return ConfigData->Controller[ControllerNumber].OkToUseThisController; ! 2152: ! 2153: } ! 2154: ! 2155: NTSTATUS ! 2156: FlInitializeController( ! 2157: IN PCONFIG_DATA ConfigData, ! 2158: IN UCHAR ControllerNumber, ! 2159: IN PDRIVER_OBJECT DriverObject ! 2160: ) ! 2161: ! 2162: /*++ ! 2163: ! 2164: Routine Description: ! 2165: ! 2166: This routine is called at initialization time by DriverEntry() - ! 2167: once for each controller that the configuration manager tells it we ! 2168: have to support. ! 2169: ! 2170: When this routine is called, the configuration data has already been ! 2171: filled in. ! 2172: ! 2173: Arguments: ! 2174: ! 2175: ConfigData - a pointer to the structure that describes the ! 2176: controller and the disks attached to it, as given to us by the ! 2177: configuration manager. ! 2178: ! 2179: ControllerNumber - which controller in ConfigData we are ! 2180: initializing. ! 2181: ! 2182: DriverObject - a pointer to the object that represents this device ! 2183: driver. ! 2184: ! 2185: Return Value: ! 2186: ! 2187: STATUS_SUCCESS if this controller and at least one of its disks were ! 2188: initialized; an error otherwise. ! 2189: ! 2190: --*/ ! 2191: ! 2192: { ! 2193: PCONTROLLER_DATA controllerData; ! 2194: PVOID threadObject; ! 2195: CONFIG_CONTROLLER_DATA *tempData; ! 2196: NTSTATUS ntStatus; ! 2197: NTSTATUS ntStatus2; ! 2198: ULONG ioBufferSize; ! 2199: ULONG maximumDriveTrackSize; ! 2200: HANDLE threadHandle = 0; ! 2201: UCHAR driveNumber; ! 2202: BOOLEAN partlySuccessful; ! 2203: UCHAR ntNameBuffer[256]; ! 2204: STRING ntNameString; ! 2205: UNICODE_STRING ntUnicodeString; ! 2206: OBJECT_ATTRIBUTES objectAttributes; ! 2207: ! 2208: FloppyDump( ! 2209: FLOPSHOW, ! 2210: ("Floppy: FlInitializeController...\n") ! 2211: ); ! 2212: ! 2213: // ! 2214: // This routine will take attempt to "append" the resources ! 2215: // used by this controller into the resource map of the ! 2216: // registry. If there was a conflict with previously "declared" ! 2217: // data, then this routine will return false, in which case we ! 2218: // will NOT try to initialize this particular controller. ! 2219: // ! 2220: ! 2221: if (!FlReportResources( ! 2222: DriverObject, ! 2223: ConfigData, ! 2224: ControllerNumber ! 2225: )) { ! 2226: ! 2227: return STATUS_INSUFFICIENT_RESOURCES; ! 2228: ! 2229: } ! 2230: ! 2231: // ! 2232: // Allocate and zero-initialize data to describe this controller ! 2233: // ! 2234: ! 2235: controllerData = (PCONTROLLER_DATA) ExAllocatePool( ! 2236: NonPagedPool, ! 2237: sizeof( CONTROLLER_DATA ) ); ! 2238: ! 2239: if ( controllerData == NULL ) { ! 2240: ! 2241: return STATUS_INSUFFICIENT_RESOURCES; ! 2242: } ! 2243: ! 2244: RtlZeroMemory( controllerData, sizeof( CONTROLLER_DATA ) ); ! 2245: ! 2246: (VOID) sprintf( ! 2247: ntNameBuffer, ! 2248: "\\Device\\FloppyControllerEvent%d", ! 2249: ControllerNumber ); ! 2250: ! 2251: RtlInitString( &ntNameString, ntNameBuffer ); ! 2252: ! 2253: ntStatus = RtlAnsiStringToUnicodeString( ! 2254: &ntUnicodeString, ! 2255: &ntNameString, ! 2256: TRUE ); ! 2257: ! 2258: InitializeObjectAttributes( ! 2259: &objectAttributes, ! 2260: &ntUnicodeString, ! 2261: OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_OPENIF, ! 2262: NULL, ! 2263: NULL ); ! 2264: ! 2265: ! 2266: controllerData->ControllerEvent = IoCreateSynchronizationEvent( ! 2267: &ntUnicodeString, ! 2268: &controllerData->ControllerEventHandle); ! 2269: ! 2270: RtlFreeUnicodeString( &ntUnicodeString ); ! 2271: ! 2272: if ( !NT_SUCCESS( ntStatus ) ) { ! 2273: return STATUS_INSUFFICIENT_RESOURCES; ! 2274: } ! 2275: ! 2276: // ! 2277: // Stick the driver object into it so that we can use it to log ! 2278: // an error if the controller hangs up. ! 2279: // ! 2280: ! 2281: controllerData->DriverObject = DriverObject; ! 2282: ! 2283: // ! 2284: // Fill in some items that we got from configuration management and ! 2285: // the HAL. ! 2286: // ! 2287: ! 2288: controllerData->ControllerAddress = ! 2289: ConfigData->Controller[ControllerNumber].ControllerBaseAddress; ! 2290: controllerData->AdapterObject = ! 2291: ConfigData->Controller[ControllerNumber].AdapterObject; ! 2292: controllerData->NumberOfMapRegisters = ! 2293: ConfigData->Controller[ControllerNumber].NumberOfMapRegisters; ! 2294: controllerData->NumberOfDrives = ! 2295: ConfigData->Controller[ControllerNumber].NumberOfDrives; ! 2296: ! 2297: // ! 2298: // Set the time to wait for an interrupt before timing out to a ! 2299: // few seconds. ! 2300: // ! 2301: ! 2302: controllerData->InterruptDelay = RtlLargeIntegerNegate( ! 2303: RtlConvertLongToLargeInteger( ! 2304: (LONG)(10 * 1000 * 4000) ! 2305: ) ! 2306: ); ! 2307: ! 2308: // ! 2309: // Set the minimum time that we can delay (10ms according to system ! 2310: // rules). This will be used when we have to delay to, say, wait ! 2311: // for the FIFO - the FIFO should become ready is well under 10ms. ! 2312: // ! 2313: ! 2314: controllerData->Minimum10msDelay = RtlLargeIntegerNegate( ! 2315: RtlConvertLongToLargeInteger( ! 2316: (LONG)(10 * 1000 * 10) ! 2317: ) ! 2318: ); ! 2319: ! 2320: // ! 2321: // Occasionally during stress we've seen the device lock up. ! 2322: // We create a dpc so that we can log that the device lock up ! 2323: // occured and that we reset the device. ! 2324: // ! 2325: ! 2326: KeInitializeDpc( ! 2327: &controllerData->LogErrorDpc, ! 2328: FlLogErrorDpc, ! 2329: controllerData ! 2330: ); ! 2331: ! 2332: // ! 2333: // Assume there is a CONFIGURE command until found otherwise. ! 2334: // Other Booleans were zero-initialized to FALSE. ! 2335: // ! 2336: ! 2337: controllerData->ControllerConfigurable = TRUE; ! 2338: ! 2339: // ! 2340: // Initialize and connect to the interrupt object in the controller ! 2341: // extension. ! 2342: // ! 2343: ! 2344: controllerData->CurrentInterrupt = TRUE; ! 2345: ! 2346: ntStatus = IoConnectInterrupt( ! 2347: &controllerData->InterruptObject, ! 2348: FloppyInterruptService, ! 2349: controllerData, ! 2350: NULL, ! 2351: ConfigData->Controller[ControllerNumber].ControllerVector, ! 2352: ConfigData->Controller[ControllerNumber].ControllerIrql, ! 2353: ConfigData->Controller[ControllerNumber].ControllerIrql, ! 2354: ConfigData->Controller[ControllerNumber].InterruptMode, ! 2355: ConfigData->Controller[ControllerNumber].SharableVector, ! 2356: ConfigData->Controller[ControllerNumber].ProcessorMask, ! 2357: ConfigData->Controller[ControllerNumber].SaveFloatState); ! 2358: ! 2359: controllerData->CurrentInterrupt = TRUE; ! 2360: ! 2361: if ( NT_SUCCESS( ntStatus ) ) { ! 2362: ! 2363: // ! 2364: // Allocate spinlock to protect controller and data ! 2365: // ! 2366: ! 2367: KeInitializeSpinLock( &controllerData->TimerSpinLock ); ! 2368: ! 2369: // ! 2370: // Calculate the size of the largest track that we could possibly ! 2371: // deal with on this controller. ! 2372: // ! 2373: ! 2374: ioBufferSize = 0; ! 2375: tempData = &ConfigData->Controller[ControllerNumber]; ! 2376: ! 2377: for ( driveNumber = 0; ! 2378: driveNumber < tempData->NumberOfDrives; ! 2379: driveNumber++ ) { ! 2380: ! 2381: // ! 2382: // Get the size out of the BIOS information store in the ! 2383: // diskette configuration information ! 2384: // ! 2385: ! 2386: maximumDriveTrackSize = ! 2387: tempData->BiosDriveMediaConstants[driveNumber].BytesPerSector * ! 2388: tempData->BiosDriveMediaConstants[driveNumber].SectorsPerTrack; ! 2389: ! 2390: if ( maximumDriveTrackSize > ioBufferSize ) { ! 2391: ! 2392: ioBufferSize = maximumDriveTrackSize; ! 2393: } ! 2394: } ! 2395: ! 2396: // ! 2397: // If we don't have enough map registers to handle the largest ! 2398: // possible track size, allocate a contiguous buffer to hold it. ! 2399: // ! 2400: ! 2401: if ( ( tempData->NumberOfMapRegisters * PAGE_SIZE ) < ioBufferSize ) { ! 2402: ! 2403: controllerData->IoBuffer = MmAllocateContiguousMemory( ! 2404: ioBufferSize, ! 2405: RtlConvertUlongToLargeInteger (MAXIMUM_DMA_ADDRESS) ); ! 2406: ! 2407: } ! 2408: ! 2409: // ! 2410: // We need a single page to do FORMATs. If we already allocated a ! 2411: // buffer, we'll use that. If not, let's allocate a single page. ! 2412: // Note that we'd have to do this anyway if there's not enough map ! 2413: // registers. ! 2414: // ! 2415: ! 2416: if ( controllerData->IoBuffer == NULL ) { ! 2417: ! 2418: ioBufferSize = PAGE_SIZE; ! 2419: ! 2420: controllerData->IoBuffer = ExAllocatePool( ! 2421: NonPagedPool, ! 2422: ioBufferSize ); ! 2423: } ! 2424: ! 2425: // ! 2426: // If we can't even get a page to use as a buffer, exit. ! 2427: // ! 2428: ! 2429: if ( controllerData->IoBuffer == NULL ) { ! 2430: ! 2431: ntStatus = STATUS_INSUFFICIENT_RESOURCES; ! 2432: ! 2433: } else { ! 2434: ! 2435: // ! 2436: // We have a buffer. Get and lock down an MDL for it now. ! 2437: // ! 2438: ! 2439: controllerData->IoBufferMdl = IoAllocateMdl( ! 2440: controllerData->IoBuffer, ! 2441: ioBufferSize, ! 2442: FALSE, ! 2443: FALSE, ! 2444: NULL ); ! 2445: ! 2446: if ( controllerData->IoBufferMdl == NULL ) { ! 2447: ! 2448: ntStatus = STATUS_INSUFFICIENT_RESOURCES; ! 2449: ! 2450: } else { ! 2451: ! 2452: MmProbeAndLockPages( ! 2453: controllerData->IoBufferMdl, ! 2454: KernelMode, ! 2455: IoModifyAccess ); ! 2456: ! 2457: FloppyDump( ! 2458: FLOPSHOW, ! 2459: ("Floppy: Buffer size = %x\n", ioBufferSize) ! 2460: ); ! 2461: ! 2462: controllerData->IoBufferSize = ioBufferSize; ! 2463: ! 2464: // ! 2465: // Initialize the interlocked request queue, including a ! 2466: // counting semaphore to indicate items in the queue ! 2467: // ! 2468: ! 2469: KeInitializeSemaphore( ! 2470: &controllerData->RequestSemaphore, ! 2471: 0L, ! 2472: MAXLONG ); ! 2473: ! 2474: KeInitializeSpinLock( &controllerData->ListSpinLock ); ! 2475: ! 2476: InitializeListHead( &controllerData->ListEntry ); ! 2477: ! 2478: // ! 2479: // Initialize events to signal interrupts and adapter object ! 2480: // allocation ! 2481: // ! 2482: ! 2483: KeInitializeEvent( ! 2484: &controllerData->InterruptEvent, ! 2485: SynchronizationEvent, ! 2486: FALSE); ! 2487: ! 2488: KeInitializeEvent( ! 2489: &controllerData->AllocateAdapterChannelEvent, ! 2490: NotificationEvent, ! 2491: FALSE ); ! 2492: ! 2493: // ! 2494: // Create a thread with entry point FloppyThread() ! 2495: // ! 2496: ! 2497: ntStatus = PsCreateSystemThread( ! 2498: &threadHandle, ! 2499: (ACCESS_MASK) 0L, ! 2500: NULL, ! 2501: (HANDLE) 0L, ! 2502: NULL, ! 2503: FloppyThread, ! 2504: controllerData ); ! 2505: ! 2506: if ( !NT_SUCCESS( ntStatus ) ) { ! 2507: ! 2508: FloppyDump( ! 2509: FLOPDBGP, ! 2510: ("Floppy: error %x creating thread\n",ntStatus) ! 2511: ); ! 2512: ! 2513: } ! 2514: ! 2515: if ( NT_SUCCESS( ntStatus ) ) { ! 2516: ! 2517: // ! 2518: // Call FlInitializeDrive() for each drive on the ! 2519: // controller ! 2520: // ! 2521: ! 2522: ntStatus = STATUS_NO_SUCH_DEVICE; ! 2523: partlySuccessful = FALSE; ! 2524: ! 2525: for ( driveNumber = 0; ! 2526: driveNumber < controllerData->NumberOfDrives; ! 2527: driveNumber++ ) { ! 2528: ! 2529: ntStatus = FlInitializeDrive( ! 2530: ConfigData, ! 2531: controllerData, ! 2532: ControllerNumber, ! 2533: driveNumber, ! 2534: driveNumber, ! 2535: DriverObject ); ! 2536: ! 2537: if ( NT_SUCCESS( ntStatus ) ) { ! 2538: ! 2539: ( *( ConfigData->FloppyCount ) )++; ! 2540: partlySuccessful = TRUE; ! 2541: } ! 2542: } ! 2543: ! 2544: if ( partlySuccessful ) { ! 2545: ! 2546: ntStatus = STATUS_SUCCESS; ! 2547: } ! 2548: } ! 2549: } ! 2550: } ! 2551: } ! 2552: ! 2553: // ! 2554: // If we're exiting with an error, clean up first. ! 2555: // ! 2556: ! 2557: if ( !NT_SUCCESS( ntStatus ) ) { ! 2558: ! 2559: FloppyDump( ! 2560: FLOPDBGP, ! 2561: ("Floppy: InitializeController failing\n") ! 2562: ); ! 2563: ! 2564: // ! 2565: // If we created the thread, wake it up and tell it to kill itself. ! 2566: // Wait until it's dead. (Note that since it's a system thread, ! 2567: // it has to kill itself - we can't do it). ! 2568: // ! 2569: ! 2570: if ( threadHandle != 0 ) { ! 2571: ! 2572: controllerData->UnloadingDriver = TRUE; ! 2573: ! 2574: ntStatus2 = ObReferenceObjectByHandle( ! 2575: threadHandle, ! 2576: THREAD_ALL_ACCESS, ! 2577: NULL, ! 2578: KernelMode, ! 2579: (PVOID *) &threadObject, ! 2580: NULL ); ! 2581: ! 2582: KeReleaseSemaphore( ! 2583: &controllerData->RequestSemaphore, ! 2584: (KPRIORITY) 0, ! 2585: 1, ! 2586: FALSE ); ! 2587: ! 2588: if ( NT_SUCCESS( ntStatus2 ) ) { ! 2589: ! 2590: // ! 2591: // The thread object will be signalled when it dies. ! 2592: // ! 2593: ! 2594: ntStatus2 = KeWaitForSingleObject( ! 2595: threadObject, ! 2596: Suspended, ! 2597: KernelMode, ! 2598: FALSE, ! 2599: NULL ); ! 2600: ! 2601: ASSERT( ntStatus2 == STATUS_SUCCESS ); ! 2602: ! 2603: ObDereferenceObject( threadObject ); ! 2604: ! 2605: } else { ! 2606: ! 2607: // ! 2608: // We can't get the thread object for some reason; just ! 2609: // block for a while to give the thread a chance to run ! 2610: // and die. ! 2611: // ! 2612: ! 2613: FloppyDump( ! 2614: FLOPDBGP, ! 2615: ("Floppy: couldn't get thread object\n") ! 2616: ); ! 2617: ! 2618: KeDelayExecutionThread( ! 2619: KernelMode, ! 2620: FALSE, ! 2621: &controllerData->InterruptDelay ); ! 2622: } ! 2623: } ! 2624: ! 2625: if ( controllerData->IoBufferMdl != NULL ) { ! 2626: ! 2627: MmUnlockPages( controllerData->IoBufferMdl ); ! 2628: IoFreeMdl( controllerData->IoBufferMdl ); ! 2629: } ! 2630: ! 2631: if ( controllerData->IoBuffer != NULL ) { ! 2632: ! 2633: if ( controllerData->IoBufferSize > PAGE_SIZE ) { ! 2634: ! 2635: MmFreeContiguousMemory( controllerData->IoBuffer ); ! 2636: ! 2637: } else { ! 2638: ! 2639: ExFreePool( controllerData->IoBuffer ); ! 2640: } ! 2641: } ! 2642: ! 2643: if ( controllerData->InterruptObject != NULL ) { ! 2644: ! 2645: IoDisconnectInterrupt( controllerData->InterruptObject ); ! 2646: } ! 2647: ! 2648: ExFreePool( controllerData ); ! 2649: ! 2650: // ! 2651: // Support for the ghost drive is being removed. If it ! 2652: // is needed later, then we can just "un" ifdef this ! 2653: // code. ! 2654: // ! 2655: ! 2656: #ifdef FLOPPY_ARTIFICIAL ! 2657: ! 2658: } else { ! 2659: ! 2660: // ! 2661: // Controller and drive initialization were successful. If ! 2662: // there's only 1 drive, set up an artificial second drive to ! 2663: // point to the same thing. ! 2664: // ! 2665: ! 2666: if ( ( ConfigData->NumberOfControllers == 1 ) && ! 2667: ( controllerData->NumberOfDrives == 1 ) ) { ! 2668: ! 2669: // ! 2670: // Discard status, since we want to return success even ! 2671: // if this artificial creation fails. ! 2672: // ! 2673: ! 2674: ntStatus2 = FlInitializeDrive( ! 2675: ConfigData, ! 2676: controllerData, ! 2677: ControllerNumber, ! 2678: 1, ! 2679: 0, ! 2680: DriverObject ); ! 2681: ! 2682: if ( NT_SUCCESS( ntStatus2 ) ) { ! 2683: ! 2684: controllerData->CreatedArtificialDrive = TRUE; ! 2685: } ! 2686: } ! 2687: #endif ! 2688: } ! 2689: ! 2690: return ntStatus; ! 2691: } ! 2692: ! 2693: NTSTATUS ! 2694: FlInitializeControllerHardware( ! 2695: IN PCONTROLLER_DATA ControllerData, ! 2696: IN PDEVICE_OBJECT DeviceObject ! 2697: ) ! 2698: ! 2699: /*++ ! 2700: ! 2701: Routine Description: ! 2702: ! 2703: This routine is called at initialization time by FlInitializeDrive() ! 2704: - once for each controller that we have to support. It is also ! 2705: called by FlFinishOperation() when an operation appears to have ! 2706: failed due to a hardware problem. ! 2707: ! 2708: When this routine is called, the controller data structures have all ! 2709: been allocated. ! 2710: ! 2711: Arguments: ! 2712: ! 2713: ControllerData - the completed data structure associated with the ! 2714: controller hardware being initialized. ! 2715: ! 2716: DeviceObject - a pointer to a device object; this routine will cause ! 2717: an interrupt, and the ISR requires CurrentDeviceObject to be filled ! 2718: in. ! 2719: ! 2720: Return Value: ! 2721: ! 2722: STATUS_SUCCESS if this controller appears to have been reset properly, ! 2723: error otherwise. ! 2724: ! 2725: --*/ ! 2726: ! 2727: { ! 2728: NTSTATUS ntStatus; ! 2729: UCHAR statusRegister0; ! 2730: UCHAR cylinder; ! 2731: UCHAR driveNumber; ! 2732: ! 2733: FloppyDump( ! 2734: FLOPSHOW, ! 2735: ("Floppy: FlInitializeControllerHardware...\n") ! 2736: ); ! 2737: ! 2738: // ! 2739: // Reset the controller. This will cause an interrupt. Reset ! 2740: // CurrentDeviceObject until after the 10ms wait, in case any ! 2741: // stray interrupts come in. ! 2742: // ! 2743: ! 2744: ControllerData->DriveControlImage |= DRVCTL_ENABLE_DMA_AND_INTERRUPTS; ! 2745: ControllerData->DriveControlImage &= ~( DRVCTL_ENABLE_CONTROLLER ); ! 2746: ! 2747: WRITE_CONTROLLER( ! 2748: &ControllerData->ControllerAddress->DriveControl, ! 2749: ControllerData->DriveControlImage ); ! 2750: ! 2751: KeStallExecutionProcessor( 10 ); ! 2752: ! 2753: ControllerData->CurrentDeviceObject = DeviceObject; ! 2754: ControllerData->CommandHasResultPhase = FALSE; ! 2755: KeResetEvent( &ControllerData->InterruptEvent ); ! 2756: ! 2757: ControllerData->DriveControlImage |= DRVCTL_ENABLE_CONTROLLER; ! 2758: ! 2759: WRITE_CONTROLLER( ! 2760: &ControllerData->ControllerAddress->DriveControl, ! 2761: ControllerData->DriveControlImage ); ! 2762: ! 2763: // ! 2764: // Wait for an interrupt. Note that STATUS_TIMEOUT and STATUS_SUCCESS ! 2765: // are the only possible return codes, since we aren't alertable and ! 2766: // won't get APCs. ! 2767: // ! 2768: ! 2769: ntStatus = KeWaitForSingleObject( ! 2770: &ControllerData->InterruptEvent, ! 2771: Executive, ! 2772: KernelMode, ! 2773: FALSE, ! 2774: &ControllerData->InterruptDelay ); ! 2775: ! 2776: if ( ntStatus == STATUS_TIMEOUT ) { ! 2777: ! 2778: // ! 2779: // Change info to an error. ! 2780: // ! 2781: ! 2782: ntStatus = STATUS_IO_TIMEOUT; ! 2783: ! 2784: ControllerData->HardwareFailed = TRUE; ! 2785: } ! 2786: ! 2787: #ifdef KEEP_COUNTERS ! 2788: FloppyThreadTime = KeQueryPerformanceCounter((PVOID)NULL); ! 2789: FloppyThreadDelay = RtlLargeIntegerAdd(FloppyThreadDelay, ! 2790: RtlLargeIntegerSubtract(FloppyDPCTime, ! 2791: FloppyThreadTime)); ! 2792: FloppyFromIntrDelay = RtlLargeIntegerAdd(FloppyFromIntrDelay, ! 2793: RtlLargeIntegerSubtract(FloppyIntrTime, ! 2794: FloppyThreadTime)); ! 2795: FloppyThreadWake++; ! 2796: #endif ! 2797: ! 2798: if ( !NT_SUCCESS( ntStatus ) ) { ! 2799: ! 2800: FloppyDump( ! 2801: FLOPDBGP, ! 2802: ("Floppy: controller didn't interrupt after reset\n") ! 2803: ); ! 2804: ! 2805: return ntStatus; ! 2806: } ! 2807: ! 2808: // ! 2809: // Sense interrupt status for all drives. ! 2810: // ! 2811: ! 2812: for ( driveNumber = 0; ! 2813: ( driveNumber < ControllerData->NumberOfDrives ) && ! 2814: ( NT_SUCCESS( ntStatus ) ); ! 2815: driveNumber++ ) { ! 2816: ! 2817: if ( driveNumber != 0 ) { ! 2818: ! 2819: // ! 2820: // Note that the ISR issued first SENSE INTERRUPT for us. ! 2821: // ! 2822: ! 2823: ntStatus = FlSendByte( COMMND_SENSE_INTERRUPT, ControllerData ); ! 2824: } ! 2825: ! 2826: if ( NT_SUCCESS( ntStatus ) ) { ! 2827: ! 2828: ntStatus = FlGetByte( &statusRegister0, ControllerData ); ! 2829: ! 2830: if ( NT_SUCCESS( ntStatus ) ) { ! 2831: ! 2832: ntStatus = FlGetByte( &cylinder, ControllerData ); ! 2833: } ! 2834: } ! 2835: } ! 2836: ! 2837: // ! 2838: // Set PERPENDICULAR MODE for all drives that are perpendicular. ! 2839: // ! 2840: ! 2841: if ( ControllerData->PerpendicularDrives != 0 ) { ! 2842: ntStatus = FlSendByte( COMMND_PERPENDICULAR_MODE, ControllerData ); ! 2843: ! 2844: if ( NT_SUCCESS( ntStatus ) ) { ! 2845: ntStatus = FlSendByte( COMMND_PERPENDICULAR_MODE_OW | ! 2846: (ControllerData->PerpendicularDrives << 2), ! 2847: ControllerData ); ! 2848: } ! 2849: } ! 2850: ! 2851: return ntStatus; ! 2852: } ! 2853: ! 2854: NTSTATUS ! 2855: FlInitializeDrive( ! 2856: IN PCONFIG_DATA ConfigData, ! 2857: IN PCONTROLLER_DATA ControllerData, ! 2858: IN UCHAR ControllerNum, ! 2859: IN UCHAR DisketteNum, ! 2860: IN UCHAR DisketteUnit, ! 2861: IN PDRIVER_OBJECT DriverObject ! 2862: ) ! 2863: ! 2864: /*++ ! 2865: ! 2866: Routine Description: ! 2867: ! 2868: This routine is called at initialization time by ! 2869: FlInitializeController(), once for each disk that we are supporting ! 2870: on the controller. ! 2871: ! 2872: Arguments: ! 2873: ! 2874: ConfigData - a pointer to the structure that describes the ! 2875: controller and the disks attached to it, as given to us by the ! 2876: configuration manager. ! 2877: ! 2878: ControllerData - a pointer to our data area for this controller. ! 2879: ! 2880: ControllerNum - which controller in ConfigData we're working on. ! 2881: ! 2882: DisketteNum - which logical disk on the current controller we're ! 2883: working on. ! 2884: ! 2885: DisketteUnit - which physical disk on the current controller we're ! 2886: working on. Only different from DisketteNum when we're creating a ! 2887: secondary device object for a previously initialized drive. ! 2888: ! 2889: DriverObject - a pointer to the object that represents this device ! 2890: driver. ! 2891: ! 2892: Return Value: ! 2893: ! 2894: STATUS_SUCCESS if this disk is initialized; an error otherwise. ! 2895: ! 2896: --*/ ! 2897: ! 2898: { ! 2899: UCHAR ntNameBuffer[256]; ! 2900: UCHAR arcNameBuffer[256]; ! 2901: STRING ntNameString; ! 2902: STRING arcNameString; ! 2903: UNICODE_STRING ntUnicodeString; ! 2904: UNICODE_STRING arcUnicodeString; ! 2905: NTSTATUS ntStatus; ! 2906: PDEVICE_OBJECT deviceObject = NULL; ! 2907: PDISKETTE_EXTENSION disketteExtension; ! 2908: ! 2909: FloppyDump( ! 2910: FLOPSHOW, ! 2911: ("Floppy: FlInitializeDrive...\n") ! 2912: ); ! 2913: ! 2914: sprintf( ! 2915: ntNameBuffer, ! 2916: "\\Device\\Floppy%d", ! 2917: *( ConfigData->FloppyCount ) ); ! 2918: ! 2919: RtlInitString( &ntNameString, ntNameBuffer ); ! 2920: ! 2921: ntStatus = RtlAnsiStringToUnicodeString( ! 2922: &ntUnicodeString, ! 2923: &ntNameString, ! 2924: TRUE ); ! 2925: ! 2926: if ( NT_SUCCESS( ntStatus ) ) { ! 2927: ! 2928: // ! 2929: // Create a device object for this floppy drive. ! 2930: // ! 2931: ! 2932: ntStatus = IoCreateDevice( ! 2933: DriverObject, ! 2934: sizeof( DISKETTE_EXTENSION ), ! 2935: &ntUnicodeString, ! 2936: FILE_DEVICE_DISK, ! 2937: FILE_REMOVABLE_MEDIA | FILE_FLOPPY_DISKETTE, ! 2938: FALSE, ! 2939: &deviceObject ); ! 2940: ! 2941: if ( NT_SUCCESS( ntStatus ) ) { ! 2942: ! 2943: // ! 2944: // Create a symbolic link from the disk name to the corresponding ! 2945: // ARC name, to be used if we're booting off the disk. This will ! 2946: // if it's not system initialization time; that's fine. The ARC ! 2947: // name looks something like \ArcName\multi(0)disk(0)rdisk(0). ! 2948: // ! 2949: ! 2950: sprintf( ! 2951: arcNameBuffer, ! 2952: "%s(%d)disk(%d)fdisk(%d)", ! 2953: "\\ArcName\\multi", ! 2954: ConfigData->Controller[ControllerNum].BusNumber, ! 2955: ConfigData->Controller[ControllerNum].ActualControllerNumber, ! 2956: DisketteNum ); ! 2957: ! 2958: RtlInitString( &arcNameString, arcNameBuffer ); ! 2959: ! 2960: ntStatus = RtlAnsiStringToUnicodeString( ! 2961: &arcUnicodeString, ! 2962: &arcNameString, ! 2963: TRUE ); ! 2964: ! 2965: if ( !NT_SUCCESS( ntStatus ) ) { ! 2966: ! 2967: RtlFreeUnicodeString( &ntUnicodeString ); ! 2968: ! 2969: } else { ! 2970: ! 2971: IoAssignArcName( &arcUnicodeString, &ntUnicodeString ); ! 2972: RtlFreeUnicodeString( &ntUnicodeString ); ! 2973: RtlFreeUnicodeString( &arcUnicodeString ); ! 2974: ! 2975: // ! 2976: // Initialize the DPC structure in the device object, so that ! 2977: // the ISR can queue DPCs. ! 2978: // ! 2979: ! 2980: IoInitializeDpcRequest( deviceObject, FloppyDeferredProcedure ); ! 2981: ! 2982: deviceObject->Flags |= DO_DIRECT_IO; ! 2983: ! 2984: if ( deviceObject->AlignmentRequirement < FILE_WORD_ALIGNMENT ) { ! 2985: ! 2986: deviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; ! 2987: } ! 2988: ! 2989: // ! 2990: // Copy the drive type from the configuration info; note that ! 2991: // the media type has not been determined. ! 2992: // ! 2993: ! 2994: disketteExtension = deviceObject->DeviceExtension; ! 2995: ! 2996: // ! 2997: // In the event that the system only has one drive, we ! 2998: // want this variable to initially point to the extension ! 2999: // of the *first* device object that describes it, so the ! 3000: // user's initial access of the drive doesn't result in ! 3001: // a prompt to insert media. ! 3002: // ! 3003: ! 3004: if ( ( DisketteNum == 0 ) && ( DisketteUnit == 0 ) ) { ! 3005: ! 3006: ControllerData->LastDisketteExtension = disketteExtension; ! 3007: } ! 3008: ! 3009: disketteExtension->ControllerData = ControllerData; ! 3010: disketteExtension->DeviceObject = deviceObject; ! 3011: disketteExtension->DeviceUnit = DisketteUnit; ! 3012: ! 3013: disketteExtension->DriveOnValue = (UCHAR)( DisketteUnit | ! 3014: ( DRVCTL_ENABLE_CONTROLLER + ! 3015: DRVCTL_ENABLE_DMA_AND_INTERRUPTS ) | ! 3016: ( DRVCTL_DRIVE_0 << DisketteUnit ) ); ! 3017: ! 3018: disketteExtension->DriveType = ConfigData-> ! 3019: Controller[ControllerNum].DriveType[DisketteUnit]; ! 3020: ! 3021: disketteExtension->MediaType = Undetermined; ! 3022: ! 3023: disketteExtension->BiosDriveMediaConstants = ConfigData-> ! 3024: Controller[ControllerNum].BiosDriveMediaConstants[DisketteUnit]; ! 3025: ! 3026: if ( disketteExtension->DriveType == DRIVE_TYPE_2880 ) { ! 3027: ControllerData->PerpendicularDrives |= 1 << DisketteUnit; ! 3028: } ! 3029: ! 3030: // ! 3031: // If this is the first drive, start the motor timer (this ! 3032: // would best be done in FlInitializeController(), but we ! 3033: // must have a device object to attach to it.) ! 3034: // ! 3035: ! 3036: if ( DisketteNum == 0 ) { ! 3037: ! 3038: ControllerData->MotorTimer = TIMER_CANCEL; ! 3039: ! 3040: IoInitializeTimer( ! 3041: deviceObject, ! 3042: FloppyMotorOffDpc, ! 3043: ControllerData ); ! 3044: ! 3045: IoStartTimer( deviceObject ); ! 3046: } ! 3047: ! 3048: // ! 3049: // FlInitializeControllerHardware() should logically be called ! 3050: // from FlInitializeController(). But the hardware can't be ! 3051: // initialized until a device object exists, since the ISR has ! 3052: // to queue a DPC. So we do it here, where we get a chance to ! 3053: // clean up easily if FlInitializeControllerHardware() fails. ! 3054: // ! 3055: // The controller is normally only reset once, when the first ! 3056: // diskette is initialized. But we'll try again on subsequent ! 3057: // diskettes if it failed on the first one. ! 3058: // ! 3059: ! 3060: if ( ( DisketteNum == 0 ) || ! 3061: ( disketteExtension->DriveType == DRIVE_TYPE_2880 ) || ! 3062: ( ControllerData->HardwareFailed ) ) { ! 3063: ! 3064: ControllerData->CurrentInterrupt = TRUE; ! 3065: ! 3066: ntStatus = FlInitializeControllerHardware( ! 3067: ControllerData, ! 3068: deviceObject ); ! 3069: ! 3070: ControllerData->CurrentInterrupt = FALSE; ! 3071: ! 3072: if ( NT_SUCCESS( ntStatus ) ) { ! 3073: ! 3074: FloppyDump( ! 3075: FLOPSHOW, ! 3076: ("Floppy: DriveType = %x\n", ! 3077: disketteExtension->DriveType) ! 3078: ); ! 3079: ! 3080: ControllerData->HardwareFailed = FALSE; ! 3081: ! 3082: } else { ! 3083: ! 3084: ControllerData->HardwareFailed = TRUE; ! 3085: } ! 3086: } ! 3087: } ! 3088: } ! 3089: } ! 3090: ! 3091: // ! 3092: // If we're failing, clean up - stop the timer (it doesn't hurt to ! 3093: // stop it even if it wasn't started) and delete the device object. ! 3094: // ! 3095: ! 3096: if ( !NT_SUCCESS( ntStatus ) ) { ! 3097: ! 3098: FloppyDump( ! 3099: FLOPDBGP, ! 3100: ("Floppy: InitiaiizeDrive failing\n") ! 3101: ); ! 3102: ! 3103: if ( deviceObject != NULL ) { ! 3104: ! 3105: if ( DisketteNum == 0 ) { ! 3106: ! 3107: IoStopTimer( deviceObject ); ! 3108: } ! 3109: ! 3110: IoDeleteDevice( deviceObject ); ! 3111: } ! 3112: } ! 3113: ! 3114: return ntStatus; ! 3115: } ! 3116: ! 3117: NTSTATUS ! 3118: FloppyDispatchCreateClose( ! 3119: IN PDEVICE_OBJECT DeviceObject, ! 3120: IN PIRP Irp ! 3121: ) ! 3122: ! 3123: /*++ ! 3124: ! 3125: Routine Description: ! 3126: ! 3127: This routine is called only rarely by the I/O system; it's mainly ! 3128: for layered drivers to call. All it does is complete the IRP ! 3129: successfully. ! 3130: ! 3131: Arguments: ! 3132: ! 3133: DeviceObject - a pointer to the object that represents the device ! 3134: that I/O is to be done on. ! 3135: ! 3136: Irp - a pointer to the I/O Request Packet for this request. ! 3137: ! 3138: Return Value: ! 3139: ! 3140: Always returns STATUS_SUCCESS, since this is a null operation. ! 3141: ! 3142: --*/ ! 3143: ! 3144: { ! 3145: UNREFERENCED_PARAMETER( DeviceObject ); ! 3146: ! 3147: FloppyDump( ! 3148: FLOPSHOW, ! 3149: ("Floppy: DispatchCreateClose...\n") ! 3150: ); ! 3151: ! 3152: // ! 3153: // Null operation. Do not give an I/O boost since ! 3154: // no I/O was actually done. IoStatus.Information should be ! 3155: // FILE_OPENED for an open; it's undefined for a close. ! 3156: // ! 3157: ! 3158: Irp->IoStatus.Status = STATUS_SUCCESS; ! 3159: Irp->IoStatus.Information = FILE_OPENED; ! 3160: ! 3161: IoCompleteRequest( Irp, IO_NO_INCREMENT ); ! 3162: ! 3163: return STATUS_SUCCESS; ! 3164: } ! 3165: ! 3166: NTSTATUS ! 3167: FloppyDispatchDeviceControl( ! 3168: IN PDEVICE_OBJECT DeviceObject, ! 3169: IN PIRP Irp ! 3170: ) ! 3171: ! 3172: /*++ ! 3173: ! 3174: Routine Description: ! 3175: ! 3176: This routine is called by the I/O system to perform a device I/O ! 3177: control function. ! 3178: ! 3179: Arguments: ! 3180: ! 3181: DeviceObject - a pointer to the object that represents the device ! 3182: that I/O is to be done on. ! 3183: ! 3184: Irp - a pointer to the I/O Request Packet for this request. ! 3185: ! 3186: Return Value: ! 3187: ! 3188: STATUS_SUCCESS or STATUS_PENDING if recognized I/O control code, ! 3189: STATUS_INVALID_DEVICE_REQUEST otherwise. ! 3190: ! 3191: --*/ ! 3192: ! 3193: { ! 3194: PIO_STACK_LOCATION irpSp; ! 3195: PDISKETTE_EXTENSION disketteExtension; ! 3196: PDISK_GEOMETRY outputBuffer; ! 3197: NTSTATUS ntStatus; ! 3198: ULONG outputBufferLength; ! 3199: UCHAR i; ! 3200: DRIVE_MEDIA_TYPE lowestDriveMediaType; ! 3201: DRIVE_MEDIA_TYPE highestDriveMediaType; ! 3202: ! 3203: FloppyDump( ! 3204: FLOPSHOW, ! 3205: ("Floppy: DispatchDeviceControl...\n") ! 3206: ); ! 3207: ! 3208: disketteExtension = DeviceObject->DeviceExtension; ! 3209: irpSp = IoGetCurrentIrpStackLocation( Irp ); ! 3210: ! 3211: switch( irpSp->Parameters.DeviceIoControl.IoControlCode ) { ! 3212: ! 3213: case IOCTL_DISK_FORMAT_TRACKS: ! 3214: ! 3215: // ! 3216: // Make sure that we got all the necessary format parameters. ! 3217: // ! 3218: ! 3219: if ( irpSp->Parameters.DeviceIoControl.InputBufferLength < ! 3220: sizeof( FORMAT_PARAMETERS ) ) { ! 3221: ! 3222: FloppyDump( ! 3223: FLOPDBGP, ! 3224: ("Floppy: invalid FORMAT buffer length\n") ! 3225: ); ! 3226: ! 3227: ntStatus = STATUS_INVALID_PARAMETER; ! 3228: break; ! 3229: } ! 3230: ! 3231: // ! 3232: // Make sure the parameters we got are reasonable. ! 3233: // ! 3234: ! 3235: if ( !FlCheckFormatParameters( ! 3236: disketteExtension, ! 3237: (PFORMAT_PARAMETERS) Irp->AssociatedIrp.SystemBuffer ) ) { ! 3238: ! 3239: FloppyDump( ! 3240: FLOPDBGP, ! 3241: ("Floppy: invalid FORMAT parameters\n") ! 3242: ); ! 3243: ! 3244: ntStatus = STATUS_INVALID_PARAMETER; ! 3245: break; ! 3246: } ! 3247: ! 3248: // ! 3249: // Fall through to queue the request. ! 3250: // ! 3251: ! 3252: case IOCTL_DISK_CHECK_VERIFY: ! 3253: case IOCTL_DISK_GET_DRIVE_GEOMETRY: ! 3254: ! 3255: // ! 3256: // The thread must know which diskette to operate on, but the ! 3257: // request list only passes the IRP. So we'll stick a pointer ! 3258: // to the diskette extension in Type3InputBuffer, which is ! 3259: // a field that isn't used for floppy ioctls. ! 3260: // ! 3261: ! 3262: // ! 3263: // Add the request to the queue, and wake up the thread to ! 3264: // process it. ! 3265: // ! 3266: ! 3267: IoMarkIrpPending( Irp ); ! 3268: ! 3269: irpSp->Parameters.DeviceIoControl.Type3InputBuffer = (PVOID) ! 3270: disketteExtension; ! 3271: ! 3272: FloppyDump( ! 3273: FLOPIRPPATH, ! 3274: ("Floppy: Enqueing up IRP: %x\n",Irp) ! 3275: ); ! 3276: ExInterlockedInsertTailList( ! 3277: &disketteExtension->ControllerData->ListEntry, ! 3278: &Irp->Tail.Overlay.ListEntry, ! 3279: &disketteExtension->ControllerData->ListSpinLock ); ! 3280: ! 3281: KeReleaseSemaphore( ! 3282: &disketteExtension->ControllerData->RequestSemaphore, ! 3283: (KPRIORITY) 0, ! 3284: 1, ! 3285: FALSE ); ! 3286: ! 3287: ntStatus = STATUS_PENDING; ! 3288: break; ! 3289: ! 3290: ! 3291: case IOCTL_DISK_GET_MEDIA_TYPES: { ! 3292: ! 3293: FloppyDump( ! 3294: FLOPSHOW, ! 3295: ("Floppy: IOCTL_DISK_GET_MEDIA_TYPES called\n") ! 3296: ); ! 3297: ! 3298: lowestDriveMediaType = DriveMediaLimits[ ! 3299: disketteExtension->DriveType].LowestDriveMediaType; ! 3300: highestDriveMediaType = DriveMediaLimits[ ! 3301: disketteExtension->DriveType].HighestDriveMediaType; ! 3302: ! 3303: outputBufferLength = ! 3304: irpSp->Parameters.DeviceIoControl.OutputBufferLength; ! 3305: ! 3306: // ! 3307: // Make sure that the input buffer has enough room to return ! 3308: // at least one descriptions of a supported media type. ! 3309: // ! 3310: ! 3311: if ( outputBufferLength < ( sizeof( DISK_GEOMETRY ) ) ) { ! 3312: ! 3313: FloppyDump( ! 3314: FLOPDBGP, ! 3315: ("Floppy: invalid GET_MEDIA_TYPES buffer size\n") ! 3316: ); ! 3317: ! 3318: ntStatus = STATUS_BUFFER_TOO_SMALL; ! 3319: break; ! 3320: } ! 3321: ! 3322: // ! 3323: // Assume success, although we might modify it to a buffer ! 3324: // overflow warning below (if the buffer isn't big enough ! 3325: // to hold ALL of the media descriptions). ! 3326: // ! 3327: ! 3328: ntStatus = STATUS_SUCCESS; ! 3329: ! 3330: if ( outputBufferLength < ( sizeof( DISK_GEOMETRY ) * ! 3331: ( highestDriveMediaType - lowestDriveMediaType + 1 ) ) ) { ! 3332: ! 3333: // ! 3334: // The buffer is too small for all of the descriptions; ! 3335: // calculate what CAN fit in the buffer. ! 3336: // ! 3337: ! 3338: FloppyDump( ! 3339: FLOPDBGP, ! 3340: ("Floppy: GET_MEDIA_TYPES buffer size too small\n") ! 3341: ); ! 3342: ! 3343: ntStatus = STATUS_BUFFER_OVERFLOW; ! 3344: ! 3345: highestDriveMediaType = (DRIVE_MEDIA_TYPE)( ( lowestDriveMediaType - 1 ) + ! 3346: ( outputBufferLength / ! 3347: sizeof( DISK_GEOMETRY ) ) ); ! 3348: } ! 3349: ! 3350: outputBuffer = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer; ! 3351: ! 3352: for ( ! 3353: i = (UCHAR)lowestDriveMediaType; ! 3354: i <= (UCHAR)highestDriveMediaType; ! 3355: i++ ) { ! 3356: ! 3357: outputBuffer->MediaType = DriveMediaConstants[i].MediaType; ! 3358: outputBuffer->Cylinders.LowPart = ! 3359: DriveMediaConstants[i].MaximumTrack + 1; ! 3360: outputBuffer->Cylinders.HighPart = 0; ! 3361: outputBuffer->TracksPerCylinder = ! 3362: DriveMediaConstants[i].NumberOfHeads; ! 3363: outputBuffer->SectorsPerTrack = ! 3364: DriveMediaConstants[i].SectorsPerTrack; ! 3365: outputBuffer->BytesPerSector = ! 3366: DriveMediaConstants[i].BytesPerSector; ! 3367: FloppyDump( ! 3368: FLOPSHOW, ! 3369: ("Floppy: media types supported [%d]\n" ! 3370: "------- Cylinders low: 0x%x\n" ! 3371: "------- Cylinders high: 0x%x\n" ! 3372: "------- Track/Cyl: 0x%x\n" ! 3373: "------- Sectors/Track: 0x%x\n" ! 3374: "------- Bytes/Sector: 0x%x\n" ! 3375: "------- Media Type: %d\n", ! 3376: i, ! 3377: outputBuffer->Cylinders.LowPart, ! 3378: outputBuffer->Cylinders.HighPart, ! 3379: outputBuffer->TracksPerCylinder, ! 3380: outputBuffer->SectorsPerTrack, ! 3381: outputBuffer->BytesPerSector, ! 3382: outputBuffer->MediaType) ! 3383: ); ! 3384: outputBuffer++; ! 3385: ! 3386: Irp->IoStatus.Information += sizeof( DISK_GEOMETRY ); ! 3387: } ! 3388: ! 3389: break; ! 3390: } ! 3391: ! 3392: default: { ! 3393: ! 3394: FloppyDump( ! 3395: FLOPDBGP, ! 3396: ("Floppy: invalid device request %x\n", ! 3397: irpSp->Parameters.DeviceIoControl.IoControlCode) ! 3398: ); ! 3399: ! 3400: ntStatus = STATUS_INVALID_DEVICE_REQUEST; ! 3401: break; ! 3402: } ! 3403: } ! 3404: ! 3405: if ( ntStatus != STATUS_PENDING ) { ! 3406: ! 3407: Irp->IoStatus.Status = ntStatus; ! 3408: if (!NT_SUCCESS( ntStatus ) && ! 3409: IoIsErrorUserInduced( ntStatus )) { ! 3410: ! 3411: IoSetHardErrorOrVerifyDevice( Irp, DeviceObject ); ! 3412: ! 3413: } ! 3414: IoCompleteRequest( Irp, IO_NO_INCREMENT ); ! 3415: } ! 3416: ! 3417: return ntStatus; ! 3418: } ! 3419: ! 3420: NTSTATUS ! 3421: FloppyDispatchReadWrite( ! 3422: IN PDEVICE_OBJECT DeviceObject, ! 3423: IN PIRP Irp ! 3424: ) ! 3425: ! 3426: /*++ ! 3427: ! 3428: Routine Description: ! 3429: ! 3430: This routine is called by the I/O system to read or write to a ! 3431: device that we control. ! 3432: ! 3433: Arguments: ! 3434: ! 3435: DeviceObject - a pointer to the object that represents the device ! 3436: that I/O is to be done on. ! 3437: ! 3438: Irp - a pointer to the I/O Request Packet for this request. ! 3439: ! 3440: Return Value: ! 3441: ! 3442: STATUS_INVALID_PARAMETER if parameters are invalid, ! 3443: STATUS_PENDING otherwise. ! 3444: ! 3445: --*/ ! 3446: ! 3447: { ! 3448: PIO_STACK_LOCATION irpSp; ! 3449: NTSTATUS ntStatus; ! 3450: PDISKETTE_EXTENSION disketteExtension; ! 3451: ! 3452: FloppyDump( ! 3453: FLOPSHOW, ! 3454: ("Floppy: FloppyDispatchReadWrite...\n") ! 3455: ); ! 3456: ! 3457: disketteExtension = DeviceObject->DeviceExtension; ! 3458: ! 3459: irpSp = IoGetCurrentIrpStackLocation( Irp ); ! 3460: ! 3461: if ( ( disketteExtension->MediaType > Unknown ) && ! 3462: ( ( ( irpSp->Parameters.Read.ByteOffset ).LowPart + ! 3463: irpSp->Parameters.Read.Length > disketteExtension->ByteCapacity ) || ! 3464: ( ( irpSp->Parameters.Read.Length & ! 3465: ( disketteExtension->BytesPerSector - 1 ) ) != 0 ) ) ) { ! 3466: ! 3467: FloppyDump( ! 3468: FLOPDBGP, ! 3469: ("Floppy: Invalid Parameter, rejecting request\n") ! 3470: ); ! 3471: ! 3472: FloppyDump( ! 3473: FLOPWARN, ! 3474: ("Floppy: Starting offset = %lx\n" ! 3475: "------ I/O Length = %lx\n" ! 3476: "------ ByteCapacity = %lx\n" ! 3477: "------ BytesPerSector = %lx\n", ! 3478: irpSp->Parameters.Read.ByteOffset.LowPart, ! 3479: irpSp->Parameters.Read.Length, ! 3480: disketteExtension->ByteCapacity, ! 3481: disketteExtension->BytesPerSector) ! 3482: ); ! 3483: ! 3484: ntStatus = STATUS_INVALID_PARAMETER; ! 3485: Irp->IoStatus.Status = ntStatus; ! 3486: IoCompleteRequest( ! 3487: Irp, ! 3488: 0 ! 3489: ); ! 3490: ! 3491: } else { ! 3492: ! 3493: IoMarkIrpPending( Irp ); ! 3494: ! 3495: // ! 3496: // We need to pass the disketteExtension somewhere in the irp. ! 3497: // The "Key" field in our stack location should be unused. ! 3498: // ! 3499: ! 3500: irpSp->Parameters.Read.Key = (ULONG) disketteExtension; ! 3501: ! 3502: FloppyDump( ! 3503: FLOPIRPPATH, ! 3504: ("Floppy: Enqueing up IRP: %x\n",Irp) ! 3505: ); ! 3506: ExInterlockedInsertTailList( ! 3507: &disketteExtension->ControllerData->ListEntry, ! 3508: &Irp->Tail.Overlay.ListEntry, ! 3509: &disketteExtension->ControllerData->ListSpinLock ); ! 3510: ! 3511: KeReleaseSemaphore( ! 3512: &disketteExtension->ControllerData->RequestSemaphore, ! 3513: (KPRIORITY) 0, ! 3514: 1, ! 3515: FALSE ); ! 3516: ! 3517: ntStatus = STATUS_PENDING; ! 3518: } ! 3519: ! 3520: return ntStatus; ! 3521: } ! 3522: ! 3523: BOOLEAN ! 3524: FloppyInterruptService( ! 3525: IN PKINTERRUPT Interrupt, ! 3526: IN PVOID Context ! 3527: ) ! 3528: ! 3529: /*++ ! 3530: ! 3531: Routine Description: ! 3532: ! 3533: This routine is called at DIRQL by the system when the controller ! 3534: interrupts. ! 3535: ! 3536: Arguments: ! 3537: ! 3538: Interrupt - a pointer to the interrupt object. ! 3539: ! 3540: Context - a pointer to our controller data area for the controller ! 3541: that interrupted. (This was set up by the call to ! 3542: IoConnectInterrupt). ! 3543: ! 3544: Return Value: ! 3545: ! 3546: Normally returns TRUE, but will return FALSE if this interrupt was ! 3547: not expected. ! 3548: ! 3549: --*/ ! 3550: ! 3551: { ! 3552: PCONTROLLER_DATA controllerData; ! 3553: PDEVICE_OBJECT currentDeviceObject; ! 3554: ULONG i; ! 3555: UCHAR statusByte; ! 3556: BOOLEAN controllerStateError = FALSE; ! 3557: ! 3558: UNREFERENCED_PARAMETER( Interrupt ); ! 3559: ! 3560: #ifdef KEEP_COUNTERS ! 3561: FloppyIntrTime = KeQueryPerformanceCounter((PVOID)NULL); ! 3562: FloppyInterrupts++; ! 3563: #endif ! 3564: ! 3565: FloppyDump( ! 3566: FLOPSHOW, ! 3567: ("Floppy: FloppyInterruptService...\n") ! 3568: ); ! 3569: ! 3570: KeStallExecutionProcessor(10); ! 3571: ! 3572: controllerData = (PCONTROLLER_DATA) Context; ! 3573: ! 3574: // ! 3575: // CurrentDeviceObject is set to the device object that is ! 3576: // expecting an interrupt. ! 3577: // ! 3578: ! 3579: currentDeviceObject = controllerData->CurrentDeviceObject; ! 3580: controllerData->CurrentDeviceObject = NULL; ! 3581: ! 3582: if (currentDeviceObject == NULL && ! 3583: !controllerData->CurrentInterrupt) { ! 3584: ! 3585: return FALSE; ! 3586: ! 3587: } else { ! 3588: ! 3589: if ( controllerData->CommandHasResultPhase ) { ! 3590: ! 3591: // ! 3592: // Result phase of previous command. (Note that we can't trust ! 3593: // the CMD_BUSY bit in the status register to tell us whether ! 3594: // there's result bytes or not; it's sometimes wrong). ! 3595: // By reading the first result byte, we reset the interrupt. ! 3596: // The other result bytes will be read by a thread. ! 3597: // Note that we want to do this even if the interrupt is ! 3598: // unexpected, to make sure the interrupt is dismissed. ! 3599: // ! 3600: ! 3601: if ( ( READ_CONTROLLER( &controllerData->ControllerAddress->Status ) ! 3602: & STATUS_IO_READY_MASK ) == STATUS_READ_READY ) { ! 3603: ! 3604: controllerData->FifoBuffer[0] = ! 3605: READ_CONTROLLER( &controllerData->ControllerAddress->Fifo ); ! 3606: ! 3607: } else { ! 3608: ! 3609: // ! 3610: // Should never get here. If we do, DON'T wake up the thread; ! 3611: // let it time out and reset the controller, or let another ! 3612: // interrupt handle this. ! 3613: // ! 3614: ! 3615: FloppyDump( ! 3616: FLOPDBGP, ! 3617: ("Floppy: controller not ready to be read in ISR\n") ! 3618: ); ! 3619: ! 3620: controllerStateError = TRUE; ! 3621: } ! 3622: ! 3623: } else { ! 3624: ! 3625: // ! 3626: // Previous command doesn't have a result phase. To read how it ! 3627: // completed, issue a sense interrupt command. Don't read ! 3628: // the result bytes from the sense interrupt; that is the ! 3629: // responsibility of the calling thread. ! 3630: // Note that we want to do this even if the interrupt is ! 3631: // unexpected, to make sure the interrupt is dismissed. ! 3632: // ! 3633: ! 3634: i = 0; ! 3635: ! 3636: do { ! 3637: ! 3638: KeStallExecutionProcessor( 1 ); ! 3639: statusByte = READ_CONTROLLER( ! 3640: &controllerData->ControllerAddress->Status ); ! 3641: i++; ! 3642: ! 3643: } while ( ( i < FIFO_ISR_TIGHTLOOP_RETRY_COUNT ) && ! 3644: ( ( statusByte & STATUS_CONTROLLER_BUSY ) || ! 3645: ( ( statusByte & STATUS_IO_READY_MASK ) != STATUS_WRITE_READY ) ) ); ! 3646: ! 3647: if ( !( statusByte & STATUS_CONTROLLER_BUSY ) && ! 3648: ( ( statusByte & STATUS_IO_READY_MASK ) == STATUS_WRITE_READY ) ) { ! 3649: ! 3650: WRITE_CONTROLLER( ! 3651: &controllerData->ControllerAddress->Fifo, ! 3652: COMMND_SENSE_INTERRUPT ); ! 3653: ! 3654: // ! 3655: // Wait for the controller to ACK the SenseInterrupt command, by ! 3656: // showing busy. On very fast machines we can end up running ! 3657: // driver's system-thread before the controller has had time to ! 3658: // set the busy bit. ! 3659: // ! 3660: ! 3661: for (i = ISR_SENSE_RETRY_COUNT; i; i--) { ! 3662: statusByte = READ_CONTROLLER( ! 3663: &controllerData->ControllerAddress->Status ); ! 3664: ! 3665: if (statusByte & STATUS_CONTROLLER_BUSY) ! 3666: break; ! 3667: ! 3668: KeStallExecutionProcessor( 1 ); ! 3669: } ! 3670: ! 3671: if ( currentDeviceObject == NULL ) { ! 3672: ! 3673: // ! 3674: // This is an unexpected interrupt, so nobody's going to ! 3675: // read the result bytes. Read them now. ! 3676: // ! 3677: ! 3678: READ_CONTROLLER( &controllerData->ControllerAddress->Fifo ); ! 3679: READ_CONTROLLER( &controllerData->ControllerAddress->Fifo ); ! 3680: } ! 3681: ! 3682: } else { ! 3683: ! 3684: // ! 3685: // Shouldn't get here. If we do, DON'T wake up the thread; ! 3686: // let it time out and reset the controller, or let another ! 3687: // interrupt take care of it. ! 3688: // ! 3689: ! 3690: FloppyDump( ! 3691: FLOPDBGP, ! 3692: ("Floppy: no result, but can't write SenseIntr\n") ! 3693: ); ! 3694: ! 3695: controllerStateError = TRUE; ! 3696: } ! 3697: } ! 3698: ! 3699: // ! 3700: // We've written to the controller, and we're about to leave. On ! 3701: // machines with levelsensitive interrupts, we'll get another interrupt ! 3702: // if we RETURN before the port is flushed. To make sure that doesn't ! 3703: // happen, we'll do a read here. ! 3704: // ! 3705: ! 3706: statusByte = READ_CONTROLLER( &controllerData->ControllerAddress->Status ); ! 3707: ! 3708: // ! 3709: // Let the interrupt settle. ! 3710: // ! 3711: ! 3712: KeStallExecutionProcessor(10); ! 3713: ! 3714: #ifdef KEEP_COUNTERS ! 3715: FloppyEndIntrTime = KeQueryPerformanceCounter((PVOID)NULL); ! 3716: FloppyIntrDelay = RtlLargeIntegerAdd(FloppyIntrDelay, ! 3717: RtlLargeIntegerSubtract(FloppyEndIntrTime, ! 3718: FloppyIntrTime)); ! 3719: #endif ! 3720: if ( currentDeviceObject == NULL ) { ! 3721: ! 3722: // ! 3723: // We didn't expect this interrupt. We've dismissed it just ! 3724: // in case, but now return FALSE withOUT waking up the thread. ! 3725: // ! 3726: ! 3727: FloppyDump( ! 3728: FLOPDBGP, ! 3729: ("Floppy: unexpected interrupt\n") ! 3730: ); ! 3731: ! 3732: return FALSE; ! 3733: } ! 3734: ! 3735: if ( !controllerStateError ) { ! 3736: ! 3737: // ! 3738: // Request a DPC for execution later to get the remainder of the ! 3739: // floppy state. ! 3740: // ! 3741: ! 3742: IoRequestDpc( ! 3743: currentDeviceObject, ! 3744: currentDeviceObject->CurrentIrp, ! 3745: (PVOID) NULL ); ! 3746: } ! 3747: ! 3748: } ! 3749: ! 3750: // ! 3751: // We've written to the controller, and we're about to leave. On ! 3752: // machines with levelsensitive interrupts, we'll get another interrupt ! 3753: // if we RETURN before the port is flushed. To make sure that doesn't ! 3754: // happen, we'll do a read here. ! 3755: // ! 3756: ! 3757: statusByte = READ_CONTROLLER( &controllerData->ControllerAddress->Status ); ! 3758: ! 3759: // ! 3760: // Let the interrupt settle. ! 3761: // ! 3762: ! 3763: KeStallExecutionProcessor(10); ! 3764: ! 3765: #ifdef KEEP_COUNTERS ! 3766: FloppyEndIntrTime = KeQueryPerformanceCounter((PVOID)NULL); ! 3767: FloppyIntrDelay = RtlLargeIntegerAdd(FloppyIntrDelay, ! 3768: RtlLargeIntegerSubtract(FloppyEndIntrTime, ! 3769: FloppyIntrTime)); ! 3770: #endif ! 3771: if ( currentDeviceObject == NULL ) { ! 3772: ! 3773: // ! 3774: // We didn't expect this interrupt. We've dismissed it just ! 3775: // in case, but now return FALSE withOUT waking up the thread. ! 3776: // ! 3777: ! 3778: FloppyDump( ! 3779: FLOPDBGP, ! 3780: ("Floppy: unexpected interrupt\n") ! 3781: ); ! 3782: ! 3783: return FALSE; ! 3784: } ! 3785: ! 3786: if ( !controllerStateError ) { ! 3787: ! 3788: // ! 3789: // Request a DPC for execution later to get the remainder of the ! 3790: // floppy state. ! 3791: // ! 3792: ! 3793: controllerData->IsrReentered = 0; ! 3794: IoRequestDpc( ! 3795: currentDeviceObject, ! 3796: currentDeviceObject->CurrentIrp, ! 3797: (PVOID) NULL ); ! 3798: ! 3799: } else { ! 3800: ! 3801: // ! 3802: // Running the floppy (at least on R4000 boxes) we've seen ! 3803: // examples where the device interrupts, yet it never says ! 3804: // it *ISN'T* busy. If this ever happens on non-MCA x86 boxes ! 3805: // it would be ok since we use latched interrupts. Even if ! 3806: // the device isn't touched so that the line would be pulled ! 3807: // down, on the latched machine, this ISR wouldn't be called ! 3808: // again. The normal timeout code for a request would eventually ! 3809: // reset the controller and retry the request. ! 3810: // ! 3811: // On the R4000 boxes and on MCA machines, the floppy is using ! 3812: // level sensitive interrupts. Therefore if we don't do something ! 3813: // to lower the interrupt line, we will be called over and over, ! 3814: // *forever*. This makes it look as though the machine is hung. ! 3815: // Unless we were lucky enough to be on a multiprocessor, the ! 3816: // normal timeout code would NEVER get a chance to run because ! 3817: // the timeout code runs at dispatch level, and we will never ! 3818: // leave device level. ! 3819: // ! 3820: // What we will do is keep a counter that is incremented every ! 3821: // time we reach this section of code. When the counter goes ! 3822: // over the threshold we will do a hard reset of the device ! 3823: // and reset the counter down to zero. The counter will be ! 3824: // initialized when the device is first initialized. It will ! 3825: // be set to zero in the other arm of this if, and it will be ! 3826: // reset to zero by the normal timeout logic. ! 3827: // ! 3828: ! 3829: controllerData->CurrentDeviceObject = currentDeviceObject; ! 3830: if (controllerData->IsrReentered > FLOPPY_RESET_ISR_THRESHOLD) { ! 3831: ! 3832: // ! 3833: // Reset the controller. This could cause an interrupt ! 3834: // ! 3835: ! 3836: controllerData->IsrReentered = 0; ! 3837: ! 3838: controllerData->DriveControlImage |= DRVCTL_ENABLE_DMA_AND_INTERRUPTS; ! 3839: controllerData->DriveControlImage &= ~( DRVCTL_ENABLE_CONTROLLER ); ! 3840: ! 3841: WRITE_CONTROLLER( ! 3842: &controllerData->ControllerAddress->DriveControl, ! 3843: controllerData->DriveControlImage ); ! 3844: ! 3845: KeStallExecutionProcessor( 10 ); ! 3846: ! 3847: controllerData->DriveControlImage |= DRVCTL_ENABLE_CONTROLLER; ! 3848: ! 3849: WRITE_CONTROLLER( ! 3850: &controllerData->ControllerAddress->DriveControl, ! 3851: controllerData->DriveControlImage ); ! 3852: ! 3853: // ! 3854: // Give the device plenty of time to be reset and ! 3855: // interrupt again. Then just do the sense interrupt. ! 3856: // this should quiet the device. We will then let ! 3857: // the normal timeout code do its work. ! 3858: // ! 3859: ! 3860: KeStallExecutionProcessor(500); ! 3861: WRITE_CONTROLLER( ! 3862: &controllerData->ControllerAddress->Fifo, ! 3863: COMMND_SENSE_INTERRUPT ); ! 3864: KeStallExecutionProcessor(500); ! 3865: ! 3866: KeInsertQueueDpc( ! 3867: &controllerData->LogErrorDpc, ! 3868: NULL, ! 3869: NULL ! 3870: ); ! 3871: ! 3872: } else { ! 3873: ! 3874: controllerData->IsrReentered++; ! 3875: ! 3876: } ! 3877: ! 3878: } ! 3879: return TRUE; ! 3880: } ! 3881: ! 3882: VOID ! 3883: FloppyDeferredProcedure( ! 3884: IN PKDPC Dpc, ! 3885: IN PVOID DeferredContext, ! 3886: IN PVOID SystemArgument1, ! 3887: IN PVOID SystemArgument2 ! 3888: ) ! 3889: ! 3890: /*++ ! 3891: ! 3892: Routine Description: ! 3893: ! 3894: This routine is called at DISPATCH_LEVEL by the system at the ! 3895: request of FloppyInterruptService(). It simply sets the interrupt ! 3896: event, which wakes up the floppy thread. ! 3897: ! 3898: Arguments: ! 3899: ! 3900: Dpc - a pointer to the DPC object used to invoke this routine. ! 3901: ! 3902: DeferredContext - a pointer to the device object associated with this ! 3903: DPC. ! 3904: ! 3905: SystemArgument1 - unused. ! 3906: ! 3907: SystemArgument2 - unused. ! 3908: ! 3909: Return Value: ! 3910: ! 3911: None. ! 3912: ! 3913: --*/ ! 3914: ! 3915: { ! 3916: PDEVICE_OBJECT deviceObject; ! 3917: PDISKETTE_EXTENSION disketteExtension; ! 3918: ! 3919: UNREFERENCED_PARAMETER( Dpc ); ! 3920: UNREFERENCED_PARAMETER( SystemArgument1 ); ! 3921: UNREFERENCED_PARAMETER( SystemArgument2 ); ! 3922: ! 3923: #ifdef KEEP_COUNTERS ! 3924: FloppyDPCs++; ! 3925: FloppyDPCTime = KeQueryPerformanceCounter((PVOID)NULL); ! 3926: ! 3927: FloppyDPCDelay = RtlLargeIntegerAdd(FloppyDPCDelay, ! 3928: RtlLargeIntegerSubtract(FloppyDPCTime, ! 3929: FloppyIntrTime)); ! 3930: #endif ! 3931: ! 3932: deviceObject = (PDEVICE_OBJECT) DeferredContext; ! 3933: disketteExtension = deviceObject->DeviceExtension; ! 3934: ! 3935: KeSetEvent( ! 3936: &disketteExtension->ControllerData->InterruptEvent, ! 3937: (KPRIORITY) 0, ! 3938: FALSE ); ! 3939: } ! 3940: ! 3941: NTSTATUS ! 3942: FlSendByte( ! 3943: IN UCHAR ByteToSend, ! 3944: IN PCONTROLLER_DATA ControllerData ! 3945: ) ! 3946: ! 3947: /*++ ! 3948: ! 3949: Routine Description: ! 3950: ! 3951: This routine is called to send a byte to the controller. It won't ! 3952: send the byte unless the controller is ready to receive a byte; if ! 3953: it's not ready after checking FIFO_TIGHTLOOP_RETRY_COUNT times, we ! 3954: delay for the minimum possible time (10ms) and then try again. It ! 3955: should always be ready after waiting 10ms. ! 3956: ! 3957: Arguments: ! 3958: ! 3959: ByteToSend - the byte to send to the controller. ! 3960: ! 3961: ControllerData - a pointer to our data area for this controller. ! 3962: ! 3963: Return Value: ! 3964: ! 3965: STATUS_SUCCESS if the byte was sent to the controller; ! 3966: STATUS_DEVICE_NOT_READY otherwise. ! 3967: ! 3968: --*/ ! 3969: ! 3970: { ! 3971: ULONG i = 0; ! 3972: BOOLEAN byteWritten = FALSE; ! 3973: ! 3974: // ! 3975: // Sit in a tight loop for a while. If the controller becomes ready, ! 3976: // send the byte. ! 3977: // ! 3978: ! 3979: do { ! 3980: ! 3981: if ( ( READ_CONTROLLER( &ControllerData->ControllerAddress->Status ) ! 3982: & STATUS_IO_READY_MASK ) == STATUS_WRITE_READY ) { ! 3983: ! 3984: WRITE_CONTROLLER( ! 3985: &ControllerData->ControllerAddress->Fifo, ! 3986: ByteToSend ); ! 3987: ! 3988: byteWritten = TRUE; ! 3989: ! 3990: } ! 3991: ! 3992: i++; ! 3993: ! 3994: } while ( (!byteWritten) && ( i < FIFO_TIGHTLOOP_RETRY_COUNT ) ); ! 3995: ! 3996: // ! 3997: // We hope that in most cases the FIFO will become ready very quickly ! 3998: // and the above loop will have written the byte. But if the FIFO ! 3999: // is not yet ready, we'll loop a few times delaying for 10ms and then ! 4000: // try it again. ! 4001: // ! 4002: ! 4003: i = 0; ! 4004: ! 4005: while ( ( !byteWritten ) && ( i < FIFO_DELAY_RETRY_COUNT ) ) { ! 4006: ! 4007: FloppyDump( ! 4008: FLOPINFO, ! 4009: ("Floppy: waiting for 10ms for controller write\n") ! 4010: ); ! 4011: ! 4012: KeDelayExecutionThread( ! 4013: KernelMode, ! 4014: FALSE, ! 4015: &ControllerData->Minimum10msDelay ); ! 4016: ! 4017: i++; ! 4018: ! 4019: if ( (READ_CONTROLLER( &ControllerData->ControllerAddress->Status ) ! 4020: & STATUS_IO_READY_MASK) == STATUS_WRITE_READY ) { ! 4021: ! 4022: WRITE_CONTROLLER( ! 4023: &ControllerData->ControllerAddress->Fifo, ! 4024: ByteToSend ); ! 4025: ! 4026: byteWritten = TRUE; ! 4027: } ! 4028: } ! 4029: ! 4030: if ( byteWritten ) { ! 4031: ! 4032: return STATUS_SUCCESS; ! 4033: ! 4034: } else { ! 4035: ! 4036: // ! 4037: // We've waited over 30ms, and the FIFO *still* isn't ready. ! 4038: // Return an error. ! 4039: // ! 4040: ! 4041: FloppyDump( ! 4042: FLOPWARN, ! 4043: ("Floppy: FIFO not ready to write after 30ms\n") ! 4044: ); ! 4045: ! 4046: ControllerData->HardwareFailed = TRUE; ! 4047: ! 4048: return STATUS_DEVICE_NOT_READY; ! 4049: } ! 4050: } ! 4051: ! 4052: NTSTATUS ! 4053: FlGetByte( ! 4054: OUT PUCHAR ByteToGet, ! 4055: IN PCONTROLLER_DATA ControllerData ! 4056: ) ! 4057: ! 4058: /*++ ! 4059: ! 4060: Routine Description: ! 4061: ! 4062: This routine is called to get a byte from the controller. It won't ! 4063: read the byte unless the controller is ready to send a byte; if ! 4064: it's not ready after checking FIFO_RETRY_COUNT times, we delay for ! 4065: the minimum possible time (10ms) and then try again. It should ! 4066: always be ready after waiting 10ms. ! 4067: ! 4068: Arguments: ! 4069: ! 4070: ByteToGet - the address in which the byte read from the controller ! 4071: is stored. ! 4072: ! 4073: ControllerData - a pointer to our data area for this controller. ! 4074: ! 4075: Return Value: ! 4076: ! 4077: STATUS_SUCCESS if a byte was read from the controller; ! 4078: STATUS_DEVICE_NOT_READY otherwise. ! 4079: ! 4080: --*/ ! 4081: ! 4082: { ! 4083: ULONG i = 0; ! 4084: BOOLEAN byteRead = FALSE; ! 4085: ! 4086: // ! 4087: // Sit in a tight loop for a while. If the controller becomes ready, ! 4088: // read the byte. ! 4089: // ! 4090: ! 4091: do { ! 4092: ! 4093: if ( ( READ_CONTROLLER( &ControllerData->ControllerAddress->Status ) ! 4094: & STATUS_IO_READY_MASK ) == STATUS_READ_READY ) { ! 4095: ! 4096: *ByteToGet = READ_CONTROLLER( ! 4097: &ControllerData->ControllerAddress->Fifo ); ! 4098: ! 4099: byteRead = TRUE; ! 4100: ! 4101: } ! 4102: ! 4103: i++; ! 4104: ! 4105: } while ( ( !byteRead ) && ( i < FIFO_TIGHTLOOP_RETRY_COUNT ) ); ! 4106: ! 4107: // ! 4108: // We hope that in most cases the FIFO will become ready very quickly ! 4109: // and the above loop will have read the byte. But if the FIFO ! 4110: // is not yet ready, we'll loop a few times delaying for 10ms and then ! 4111: // trying it again. ! 4112: // ! 4113: ! 4114: i = 0; ! 4115: ! 4116: while ( ( !byteRead ) && ( i < FIFO_DELAY_RETRY_COUNT ) ) { ! 4117: ! 4118: FloppyDump( ! 4119: FLOPINFO, ! 4120: ("Floppy: waiting for 10ms for controller read\n") ! 4121: ); ! 4122: ! 4123: KeDelayExecutionThread( ! 4124: KernelMode, ! 4125: FALSE, ! 4126: &ControllerData->Minimum10msDelay ); ! 4127: ! 4128: i++; ! 4129: ! 4130: if ( (READ_CONTROLLER( &ControllerData->ControllerAddress->Status ) ! 4131: & STATUS_IO_READY_MASK) == STATUS_READ_READY ) { ! 4132: ! 4133: *ByteToGet = READ_CONTROLLER( ! 4134: &ControllerData->ControllerAddress->Fifo ); ! 4135: ! 4136: byteRead = TRUE; ! 4137: ! 4138: } ! 4139: } ! 4140: ! 4141: if ( byteRead ) { ! 4142: ! 4143: return STATUS_SUCCESS; ! 4144: ! 4145: } else { ! 4146: ! 4147: // ! 4148: // We've waited over 30ms, and the FIFO *still* isn't ready. ! 4149: // Return an error. ! 4150: // ! 4151: ! 4152: FloppyDump( ! 4153: FLOPWARN, ! 4154: ("Floppy: FIFO not ready to read after 30ms\n") ! 4155: ); ! 4156: ! 4157: ControllerData->HardwareFailed = TRUE; ! 4158: ! 4159: return STATUS_DEVICE_NOT_READY; ! 4160: } ! 4161: ! 4162: } ! 4163: ! 4164: NTSTATUS ! 4165: FlInterpretError( ! 4166: IN UCHAR StatusRegister1, ! 4167: IN UCHAR StatusRegister2 ! 4168: ) ! 4169: ! 4170: /*++ ! 4171: ! 4172: Routine Description: ! 4173: ! 4174: This routine is called when the floppy controller returns an error. ! 4175: Status registers 1 and 2 are passed in, and this returns an appropriate ! 4176: error status. ! 4177: ! 4178: Arguments: ! 4179: ! 4180: StatusRegister1 - the controller's status register #1. ! 4181: ! 4182: StatusRegister2 - the controller's status register #2. ! 4183: ! 4184: Return Value: ! 4185: ! 4186: An NTSTATUS error determined from the status registers. ! 4187: ! 4188: --*/ ! 4189: ! 4190: { ! 4191: if ( ( StatusRegister1 & STREG1_CRC_ERROR ) || ! 4192: ( StatusRegister2 & STREG2_CRC_ERROR ) ) { ! 4193: ! 4194: return STATUS_CRC_ERROR; ! 4195: } ! 4196: ! 4197: if ( StatusRegister1 & STREG1_DATA_OVERRUN ) { ! 4198: ! 4199: return STATUS_DATA_OVERRUN; ! 4200: } ! 4201: ! 4202: if ( ( StatusRegister1 & STREG1_SECTOR_NOT_FOUND ) || ! 4203: ( StatusRegister1 & STREG1_END_OF_DISKETTE ) ) { ! 4204: ! 4205: return STATUS_NONEXISTENT_SECTOR; ! 4206: } ! 4207: ! 4208: if ( ( StatusRegister2 & STREG2_DATA_NOT_FOUND ) || ! 4209: ( StatusRegister2 & STREG2_BAD_CYLINDER ) || ! 4210: ( StatusRegister2 & STREG2_DELETED_DATA ) ) { ! 4211: ! 4212: return STATUS_DEVICE_DATA_ERROR; ! 4213: } ! 4214: ! 4215: if ( StatusRegister1 & STREG1_WRITE_PROTECTED ) { ! 4216: ! 4217: return STATUS_MEDIA_WRITE_PROTECTED; ! 4218: } ! 4219: ! 4220: if ( StatusRegister1 & STREG1_ID_NOT_FOUND ) { ! 4221: ! 4222: return STATUS_FLOPPY_ID_MARK_NOT_FOUND; ! 4223: ! 4224: } ! 4225: ! 4226: if ( StatusRegister2 & STREG2_WRONG_CYLINDER ) { ! 4227: ! 4228: return STATUS_FLOPPY_WRONG_CYLINDER; ! 4229: ! 4230: } ! 4231: ! 4232: // ! 4233: // There's other error bits, but no good status values to map them ! 4234: // to. Just return a generic one. ! 4235: // ! 4236: ! 4237: return STATUS_FLOPPY_UNKNOWN_ERROR; ! 4238: } ! 4239: ! 4240: BOOLEAN ! 4241: FlClearIsrReentered( ! 4242: IN PVOID Context ! 4243: ) ! 4244: ! 4245: /*++ ! 4246: ! 4247: Routine Description: ! 4248: ! 4249: This routine is simply used to clear the reentered count of the isr. ! 4250: ! 4251: Arguments: ! 4252: ! 4253: Context - Simply a pointer to the re-entered count of the isr. ! 4254: ! 4255: Return Value: ! 4256: ! 4257: Always False. ! 4258: ! 4259: --*/ ! 4260: ! 4261: { ! 4262: ! 4263: *((ULONG *)Context) = 0; ! 4264: return FALSE; ! 4265: ! 4266: } ! 4267: ! 4268: VOID ! 4269: FlFinishOperation( ! 4270: IN OUT PIRP Irp, ! 4271: IN PDISKETTE_EXTENSION DisketteExtension ! 4272: ) ! 4273: ! 4274: /*++ ! 4275: ! 4276: Routine Description: ! 4277: ! 4278: This routine is called by FloppyThread at the end of any operation ! 4279: whether it succeeded or not. ! 4280: ! 4281: If the packet is failing due to a hardware error, this routine will ! 4282: reinitialize the hardware and retry once. ! 4283: ! 4284: When the packet is done, this routine will start the timer to turn ! 4285: off the motor, and complete the IRP. ! 4286: ! 4287: Arguments: ! 4288: ! 4289: Irp - a pointer to the IO Request Packet being processed. ! 4290: ! 4291: DisketteExtension - a pointer to the diskette extension for the ! 4292: diskette on which the operation occurred. ! 4293: ! 4294: Return Value: ! 4295: ! 4296: None. ! 4297: ! 4298: --*/ ! 4299: ! 4300: { ! 4301: KIRQL oldIrql; ! 4302: PCONTROLLER_DATA controllerData; ! 4303: NTSTATUS ntStatus; ! 4304: UCHAR driveStatus; ! 4305: ! 4306: FloppyDump( ! 4307: FLOPSHOW, ! 4308: ("Floppy: FloppyFinishOperation...\n") ! 4309: ); ! 4310: ! 4311: controllerData = DisketteExtension->ControllerData; ! 4312: ! 4313: // ! 4314: // See if this packet is being failed due to a hardware error. ! 4315: // ! 4316: ! 4317: if ( ( Irp->IoStatus.Status != STATUS_SUCCESS ) && ! 4318: ( controllerData->HardwareFailed ) ) { ! 4319: ! 4320: controllerData->HardwareFailCount++; ! 4321: ! 4322: if ( controllerData->HardwareFailCount < HARDWARE_RESET_RETRY_COUNT ) { ! 4323: ! 4324: KeSynchronizeExecution( ! 4325: controllerData->InterruptObject, ! 4326: FlClearIsrReentered, ! 4327: &controllerData->IsrReentered ! 4328: ); ! 4329: // ! 4330: // This is our first time through (that is, we're not retrying ! 4331: // the packet after a hardware failure). If it failed this first ! 4332: // time because of a hardware problem, set the HardwareFailed flag ! 4333: // and put the IRP at the beginning of the request queue. ! 4334: // ! 4335: ! 4336: ntStatus = FlInitializeControllerHardware( ! 4337: controllerData, ! 4338: DisketteExtension->DeviceObject ); ! 4339: ! 4340: if ( NT_SUCCESS( ntStatus ) ) { ! 4341: ! 4342: FloppyDump( ! 4343: FLOPINFO, ! 4344: ("Floppy: packet failed; hardware reset. Retry.\n") ! 4345: ); ! 4346: ! 4347: // ! 4348: // Force media to be redetermined, in case we messed up ! 4349: // and to make sure FlDatarateSpecifyConfigure() gets ! 4350: // called. ! 4351: // ! 4352: ! 4353: DisketteExtension->MediaType = Undetermined; ! 4354: ! 4355: FloppyDump( ! 4356: FLOPIRPPATH, ! 4357: ("Floppy: irp %x failed - back on the queue with it\n", ! 4358: Irp) ! 4359: ); ! 4360: ExInterlockedInsertHeadList( ! 4361: &controllerData->ListEntry, ! 4362: &Irp->Tail.Overlay.ListEntry, ! 4363: &controllerData->ListSpinLock ); ! 4364: ! 4365: return; ! 4366: } ! 4367: ! 4368: FloppyDump( ! 4369: FLOPDBGP, ! 4370: ("Floppy: packet AND hardware reset failed.\n") ! 4371: ); ! 4372: } ! 4373: ! 4374: } ! 4375: ! 4376: // ! 4377: // If we didn't already RETURN, we're done with this packet so ! 4378: // reset the HardwareFailCount for the next packet. ! 4379: // ! 4380: ! 4381: controllerData->HardwareFailCount = 0; ! 4382: ! 4383: // ! 4384: // If there's a motor on, set the timer so that it will be turned off ! 4385: // in a couple of seconds if nobody uses it. ! 4386: // ! 4387: ! 4388: driveStatus = controllerData->DriveControlImage; ! 4389: ! 4390: if ( ( driveStatus & DRVCTL_MOTOR_MASK ) != 0 ) { ! 4391: ! 4392: KeAcquireSpinLock( &controllerData->TimerSpinLock, &oldIrql ); ! 4393: ! 4394: driveStatus = controllerData->DriveControlImage; ! 4395: ! 4396: if ( ( driveStatus & DRVCTL_MOTOR_MASK ) != 0 ) { ! 4397: ! 4398: controllerData->MotorTimer = TIMER_START; ! 4399: } ! 4400: ! 4401: KeReleaseSpinLock( &controllerData->TimerSpinLock, oldIrql ); ! 4402: } ! 4403: ! 4404: // ! 4405: // If this request was unsuccessful and the error is one that can be ! 4406: // remedied by the user, save the Device Object so that the file system, ! 4407: // after reaching its original entry point, can know the real device. ! 4408: // ! 4409: ! 4410: if ( !NT_SUCCESS( Irp->IoStatus.Status ) && ! 4411: IoIsErrorUserInduced( Irp->IoStatus.Status ) ) { ! 4412: ! 4413: IoSetHardErrorOrVerifyDevice( Irp, DisketteExtension->DeviceObject ); ! 4414: } ! 4415: ! 4416: // ! 4417: // Even if the operation failed, it probably had to wait for the drive ! 4418: // to spin up or somesuch so we'll always complete the request with the ! 4419: // standard priority boost. ! 4420: // ! 4421: ! 4422: if ( ( Irp->IoStatus.Status != STATUS_SUCCESS ) && ! 4423: ( Irp->IoStatus.Status != STATUS_VERIFY_REQUIRED ) && ! 4424: ( Irp->IoStatus.Status != STATUS_NO_MEDIA_IN_DEVICE ) ) { ! 4425: ! 4426: FloppyDump( ! 4427: FLOPDBGP, ! 4428: ("Floppy: IRP failed with error %lx\n", Irp->IoStatus.Status) ! 4429: ); ! 4430: ! 4431: } else { ! 4432: ! 4433: FloppyDump( ! 4434: FLOPINFO, ! 4435: ("Floppy: IoStatus.Status = %x\n", Irp->IoStatus.Status) ! 4436: ); ! 4437: } ! 4438: ! 4439: FloppyDump( ! 4440: FLOPINFO, ! 4441: ("Floppy: IoStatus.Information = %x\n", Irp->IoStatus.Information) ! 4442: ); ! 4443: ! 4444: FloppyDump( ! 4445: FLOPIRPPATH, ! 4446: ("Floppy: Finishing up IRP: %x\n",Irp) ! 4447: ); ! 4448: IoCompleteRequest( Irp, IO_DISK_INCREMENT ); ! 4449: } ! 4450: ! 4451: VOID ! 4452: FloppyMotorOffDpc( ! 4453: IN PDEVICE_OBJECT DeviceObject, ! 4454: IN PVOID Context ! 4455: ) ! 4456: ! 4457: /*++ ! 4458: ! 4459: Routine Description: ! 4460: ! 4461: This routine is called at DISPATCH_LEVEL once every second by the ! 4462: I/O system. ! 4463: ! 4464: If the timer is "set" (greater than 0) this routine will decrement ! 4465: it. If it ever reaches 0, the running motor is turned off. ! 4466: ! 4467: Arguments: ! 4468: ! 4469: DeviceObject - a pointer to the device object associated with this ! 4470: timer (always the first disk on the controller). ! 4471: ! 4472: Context - unused. ! 4473: ! 4474: Return Value: ! 4475: ! 4476: None. ! 4477: ! 4478: --*/ ! 4479: ! 4480: { ! 4481: KIRQL oldIrql; ! 4482: PDISKETTE_EXTENSION disketteExtension; ! 4483: PCONTROLLER_DATA controllerData; ! 4484: ! 4485: UNREFERENCED_PARAMETER( Context ); ! 4486: ! 4487: disketteExtension = (PDISKETTE_EXTENSION) DeviceObject->DeviceExtension; ! 4488: controllerData = disketteExtension->ControllerData; ! 4489: ! 4490: if ( controllerData->MotorTimer != TIMER_CANCEL ) { ! 4491: ! 4492: // ! 4493: // One of the motors is running - grab the timer spinlock and ! 4494: // decrement the timer counter. If it expires, turn off the ! 4495: // motor. ! 4496: // ! 4497: ! 4498: KeAcquireSpinLock( &controllerData->TimerSpinLock, &oldIrql ); ! 4499: ! 4500: if ( controllerData->MotorTimer != TIMER_CANCEL ) { ! 4501: ! 4502: controllerData->MotorTimer--; ! 4503: ! 4504: if ( controllerData->MotorTimer == TIMER_EXPIRED ) { ! 4505: ! 4506: controllerData->MotorTimer = TIMER_CANCEL; ! 4507: ! 4508: controllerData->DriveControlImage = ! 4509: DRVCTL_ENABLE_DMA_AND_INTERRUPTS + ! 4510: DRVCTL_ENABLE_CONTROLLER; ! 4511: ! 4512: WRITE_CONTROLLER( ! 4513: &controllerData->ControllerAddress->DriveControl, ! 4514: controllerData->DriveControlImage ); ! 4515: } ! 4516: } ! 4517: ! 4518: KeReleaseSpinLock( &controllerData->TimerSpinLock, oldIrql ); ! 4519: } ! 4520: } ! 4521: ! 4522: NTSTATUS ! 4523: FlIssueCommand( ! 4524: IN UCHAR Command, ! 4525: IN OUT PDISKETTE_EXTENSION DisketteExtension ! 4526: ) ! 4527: ! 4528: /*++ ! 4529: ! 4530: Routine Description: ! 4531: ! 4532: This routine sends the command and all parameters to the controller, ! 4533: waits for the command to interrupt if necessary, and reads the result ! 4534: bytes from the controller, if any. ! 4535: ! 4536: Before calling this routine, the caller should put the parameters for ! 4537: the command in ControllerData->FifoBuffer[]. The result bytes will ! 4538: be returned in the same place. ! 4539: ! 4540: This routine runs off the CommandTable. For each command, this says ! 4541: how many parameters there are, whether or not there is an interrupt ! 4542: to wait for, and how many result bytes there are. Note that commands ! 4543: without result bytes actually have two, since the ISR will issue a ! 4544: SENSE INTERRUPT STATUS command on their behalf. ! 4545: ! 4546: Arguments: ! 4547: ! 4548: Command - a byte specifying the command to be sent to the controller. ! 4549: ! 4550: DisketteExtension - a pointer to our data area for the drive being ! 4551: accessed (any drive if a controller command is being given). ! 4552: ! 4553: Return Value: ! 4554: ! 4555: STATUS_SUCCESS if the command was sent and bytes received properly; ! 4556: appropriate error propogated otherwise. ! 4557: ! 4558: --*/ ! 4559: ! 4560: { ! 4561: PCONTROLLER_DATA controllerData; ! 4562: NTSTATUS ntStatus; ! 4563: NTSTATUS ntStatus2; ! 4564: UCHAR i; ! 4565: ! 4566: FloppyDump( ! 4567: FLOPSHOW, ! 4568: ("Floppy: FloppyIssueCommand...\n") ! 4569: ); ! 4570: ! 4571: controllerData = DisketteExtension->ControllerData; ! 4572: ! 4573: // ! 4574: // If this command causes an interrupt, set CurrentDeviceObject and ! 4575: // reset the interrupt event. ! 4576: // ! 4577: ! 4578: if ( CommandTable[Command & COMMAND_MASK].InterruptExpected ) { ! 4579: ! 4580: controllerData->CurrentDeviceObject = DisketteExtension->DeviceObject; ! 4581: ! 4582: controllerData->CommandHasResultPhase = ! 4583: !!CommandTable[Command & COMMAND_MASK].FirstResultByte; ! 4584: ! 4585: KeResetEvent( &controllerData->InterruptEvent ); ! 4586: } ! 4587: ! 4588: // ! 4589: // Send the command to the controller. ! 4590: // ! 4591: ! 4592: ntStatus = FlSendByte( Command, controllerData ); ! 4593: ! 4594: // ! 4595: // If the command was successfully sent, we can proceed. ! 4596: // ! 4597: ! 4598: if ( NT_SUCCESS( ntStatus ) ) { ! 4599: ! 4600: // ! 4601: // Send the parameters as long as we succeed. ! 4602: // ! 4603: ! 4604: for ( i = 0; ! 4605: ( i < CommandTable[Command & COMMAND_MASK].NumberOfParameters ) && ! 4606: ( NT_SUCCESS( ntStatus ) ); ! 4607: i++ ) { ! 4608: ! 4609: ntStatus = FlSendByte( ! 4610: controllerData->FifoBuffer[i], ! 4611: controllerData ); ! 4612: } ! 4613: ! 4614: if ( NT_SUCCESS( ntStatus ) ) { ! 4615: ! 4616: // ! 4617: // If there is an interrupt, wait for it. ! 4618: // ! 4619: ! 4620: if ( CommandTable[Command & COMMAND_MASK].InterruptExpected ) { ! 4621: ! 4622: ntStatus = KeWaitForSingleObject( ! 4623: &controllerData->InterruptEvent, ! 4624: Executive, ! 4625: KernelMode, ! 4626: FALSE, ! 4627: &controllerData->InterruptDelay ); ! 4628: ! 4629: if ( ntStatus == STATUS_TIMEOUT ) { ! 4630: ! 4631: // ! 4632: // Change info to an error. We'll just say ! 4633: // that the device isn't ready. ! 4634: // ! 4635: ! 4636: ntStatus = STATUS_DEVICE_NOT_READY; ! 4637: ! 4638: controllerData->HardwareFailed = TRUE; ! 4639: } ! 4640: #ifdef KEEP_COUNTERS ! 4641: FloppyThreadTime = KeQueryPerformanceCounter((PVOID)NULL); ! 4642: FloppyThreadDelay = RtlLargeIntegerAdd(FloppyThreadDelay, ! 4643: RtlLargeIntegerSubtract(FloppyThreadTime, ! 4644: FloppyDPCTime)); ! 4645: FloppyFromIntrDelay = RtlLargeIntegerAdd(FloppyFromIntrDelay, ! 4646: RtlLargeIntegerSubtract(FloppyThreadTime, ! 4647: FloppyIntrTime)); ! 4648: FloppyThreadWake++; ! 4649: #endif ! 4650: } ! 4651: ! 4652: // ! 4653: // If successful so far, get the result bytes. ! 4654: // ! 4655: ! 4656: if ( NT_SUCCESS( ntStatus ) ) { ! 4657: ! 4658: for ( i = CommandTable[Command & COMMAND_MASK].FirstResultByte; ! 4659: ( i < CommandTable[Command & COMMAND_MASK]. ! 4660: NumberOfResultBytes ) && ( NT_SUCCESS( ntStatus ) ); ! 4661: i++ ) { ! 4662: ! 4663: ntStatus = FlGetByte( ! 4664: &controllerData->FifoBuffer[i], ! 4665: controllerData ); ! 4666: } ! 4667: } ! 4668: } ! 4669: } ! 4670: ! 4671: // ! 4672: // If there was a problem, check to see if it was caused by an ! 4673: // unimplemented command. ! 4674: // ! 4675: ! 4676: if ( !NT_SUCCESS( ntStatus ) ) { ! 4677: ! 4678: if ( ( i == 1 ) && ! 4679: ( !CommandTable[Command & COMMAND_MASK].AlwaysImplemented ) ) { ! 4680: ! 4681: // ! 4682: // This error is probably caused by a command that's not ! 4683: // implemented on this controller. Read the error from the ! 4684: // controller, and we should be in a stable state. ! 4685: // ! 4686: ! 4687: ntStatus2 = FlGetByte( ! 4688: &controllerData->FifoBuffer[0], ! 4689: controllerData ); ! 4690: ! 4691: // ! 4692: // If GetByte went as planned, we'll return the original error. ! 4693: // ! 4694: ! 4695: if ( NT_SUCCESS( ntStatus2 ) ) { ! 4696: ! 4697: if ( controllerData->FifoBuffer[0] != ! 4698: STREG0_END_INVALID_COMMAND ) { ! 4699: ! 4700: // ! 4701: // Status isn't as we expect, so return generic error. ! 4702: // ! 4703: ! 4704: ntStatus = STATUS_FLOPPY_BAD_REGISTERS; ! 4705: ! 4706: controllerData->HardwareFailed = TRUE; ! 4707: } ! 4708: ! 4709: } else { ! 4710: ! 4711: // ! 4712: // GetByte returned an error, so propogate THAT. ! 4713: // ! 4714: ! 4715: ntStatus = ntStatus2; ! 4716: } ! 4717: } ! 4718: } ! 4719: ! 4720: if ( !NT_SUCCESS( ntStatus ) ) { ! 4721: ! 4722: // ! 4723: // Print an error message unless the command isn't always ! 4724: // implemented, ie CONFIGURE. ! 4725: // ! 4726: ! 4727: if ( !( ( ntStatus == STATUS_DEVICE_NOT_READY ) && ! 4728: ( !CommandTable[Command & COMMAND_MASK].AlwaysImplemented ) ) ) { ! 4729: ! 4730: FloppyDump( ! 4731: FLOPDBGP, ! 4732: ("Floppy: err %x " ! 4733: "------ while giving command %x\n", ! 4734: ntStatus, ! 4735: Command) ! 4736: ); ! 4737: } ! 4738: } ! 4739: ! 4740: return ntStatus; ! 4741: } ! 4742: ! 4743: NTSTATUS ! 4744: FlStartDrive( ! 4745: IN OUT PDISKETTE_EXTENSION DisketteExtension, ! 4746: IN BOOLEAN WriteOperation, ! 4747: IN BOOLEAN SetUpMedia, ! 4748: IN BOOLEAN IgnoreChange ! 4749: ) ! 4750: ! 4751: /*++ ! 4752: ! 4753: Routine Description: ! 4754: ! 4755: This routine is called at the beginning of every operation. It cancels ! 4756: the motor timer if it's on, turns the motor on and waits for it to ! 4757: spin up if it was off, resets the disk change line and returns ! 4758: VERIFY_REQUIRED if the disk has been changed, determines the diskette ! 4759: media type if it's not known and SetUpMedia=TRUE, and makes sure that ! 4760: the disk isn't write protected if WriteOperation = TRUE. ! 4761: ! 4762: Arguments: ! 4763: ! 4764: DisketteExtension - a pointer to our data area for the drive being ! 4765: started. ! 4766: ! 4767: WriteOperation - TRUE if the diskette will be written to, FALSE ! 4768: otherwise. ! 4769: ! 4770: SetUpMedia - TRUE if the media type of the diskette in the drive ! 4771: should be determined. ! 4772: ! 4773: IgnoreChange - Do not return VERIFY_REQUIRED eventhough we are mounting ! 4774: for the first time. ! 4775: ! 4776: Return Value: ! 4777: ! 4778: STATUS_SUCCESS if the drive is started properly; appropriate error ! 4779: propogated otherwise. ! 4780: ! 4781: --*/ ! 4782: ! 4783: { ! 4784: LARGE_INTEGER motorOnDelay; ! 4785: KIRQL oldIrql; ! 4786: PCONTROLLER_DATA controllerData; ! 4787: NTSTATUS ntStatus = STATUS_SUCCESS; ! 4788: USHORT timeToWait; ! 4789: UCHAR driveStatus; ! 4790: BOOLEAN motorStarted = FALSE; ! 4791: ! 4792: FloppyDump( ! 4793: FLOPSHOW, ! 4794: ("Floppy: FloppyStartDrive...\n") ! 4795: ); ! 4796: ! 4797: // ! 4798: // IMPORTANT ! 4799: // NOTE ! 4800: // COMMENT ! 4801: // ! 4802: // Here we will copy the BIOS floppy configuration on top of the ! 4803: // highest media value in our global array so that any type of processing ! 4804: // that will recalibrate the drive can have it done here. ! 4805: // An optimization would be to only do it when we will try to recalibrate ! 4806: // the driver or media in it. ! 4807: // At this point, we ensure that on any processing of a command we ! 4808: // are going to have the real values inthe first entry of the array for ! 4809: // driver constants. ! 4810: // ! 4811: ! 4812: DriveMediaConstants[DriveMediaLimits[DisketteExtension->DriveType]. ! 4813: HighestDriveMediaType] = DisketteExtension->BiosDriveMediaConstants; ! 4814: ! 4815: ! 4816: ! 4817: controllerData = DisketteExtension->ControllerData; ! 4818: ! 4819: if ( ( controllerData->CreatedArtificialDrive ) && ! 4820: ( controllerData->LastDisketteExtension != DisketteExtension ) ) { ! 4821: ! 4822: // ! 4823: // There's an artificial drive, and the user has switched, so ! 4824: // pretend there's no media so the user will be prompted to ! 4825: // insert the other diskette. ! 4826: // ! 4827: ! 4828: controllerData->LastDisketteExtension = DisketteExtension; ! 4829: DisketteExtension->ArtificialVerifyRequired = TRUE; ! 4830: ! 4831: FloppyDump( ! 4832: FLOPSHOW, ! 4833: ("Floppy: start drive - artificial drive needs verification\n") ! 4834: ); ! 4835: return STATUS_NO_MEDIA_IN_DEVICE; ! 4836: } ! 4837: ! 4838: // ! 4839: // There is no override of the artifically induced verify. ! 4840: // ! 4841: ! 4842: if ( DisketteExtension->ArtificialVerifyRequired == TRUE ) { ! 4843: ! 4844: if ( DisketteExtension->DeviceObject->Vpb->Flags & VPB_MOUNTED ) { ! 4845: ! 4846: DisketteExtension->DeviceObject->Flags |= DO_VERIFY_VOLUME; ! 4847: } ! 4848: ! 4849: DisketteExtension->ArtificialVerifyRequired = FALSE; ! 4850: FloppyDump( ! 4851: FLOPSHOW, ! 4852: ("Floppy: start drive - artificial verify required\n") ! 4853: ); ! 4854: return STATUS_VERIFY_REQUIRED; ! 4855: } ! 4856: ! 4857: // ! 4858: // Grab the timer spin lock and cancel the timer, since we want the ! 4859: // motor to run for the whole operation. If the proper drive is ! 4860: // already running, great; if not, start the motor and wait for it ! 4861: // to spin up. ! 4862: // ! 4863: ! 4864: KeAcquireSpinLock( &controllerData->TimerSpinLock, &oldIrql ); ! 4865: ! 4866: controllerData->MotorTimer = TIMER_CANCEL; ! 4867: ! 4868: driveStatus = controllerData->DriveControlImage; ! 4869: ! 4870: if ( driveStatus != DisketteExtension->DriveOnValue ) { ! 4871: ! 4872: controllerData->DriveControlImage = DisketteExtension->DriveOnValue; ! 4873: ! 4874: WRITE_CONTROLLER( ! 4875: &controllerData->ControllerAddress->DriveControl, ! 4876: controllerData->DriveControlImage ); ! 4877: ! 4878: // ! 4879: // If this the drive media is unknown, initialize the diskette ! 4880: // extension. This is done to get the time to wait value so use ! 4881: // the slowest and oldest drive type. ! 4882: // ! 4883: ! 4884: if ((DisketteExtension->MediaType == Undetermined) || ! 4885: (DisketteExtension->MediaType == Unknown)) { ! 4886: ! 4887: DisketteExtension->DriveMediaConstants = DriveMediaConstants[0]; ! 4888: } ! 4889: ! 4890: KeReleaseSpinLock( &controllerData->TimerSpinLock, oldIrql ); ! 4891: ! 4892: // ! 4893: // Wait the appropriate length of time for the drive to spin up. ! 4894: // ! 4895: ! 4896: if ( WriteOperation ) { ! 4897: ! 4898: timeToWait = DisketteExtension->DriveMediaConstants.MotorSettleTimeWrite; ! 4899: ! 4900: } else { ! 4901: ! 4902: timeToWait = DisketteExtension->DriveMediaConstants.MotorSettleTimeRead; ! 4903: } ! 4904: ! 4905: FloppyDump( ! 4906: FLOPSHOW, ! 4907: ("Floppy: Waiting for motor to spin up (0x%x)...\n", timeToWait) ! 4908: ); ! 4909: ! 4910: motorOnDelay.LowPart = - ( 10 * 1000 * timeToWait ); ! 4911: motorOnDelay.HighPart = -1; ! 4912: ! 4913: KeDelayExecutionThread( KernelMode, FALSE, &motorOnDelay ); ! 4914: ! 4915: motorStarted = TRUE; ! 4916: ! 4917: } else { ! 4918: ! 4919: KeReleaseSpinLock( &controllerData->TimerSpinLock, oldIrql ); ! 4920: ! 4921: } ! 4922: ! 4923: driveStatus = READ_CONTROLLER( ! 4924: &controllerData->ControllerAddress->DRDC.DiskChange ); ! 4925: ! 4926: // ! 4927: // Support for 360K drives: ! 4928: // They have no change line, so we will assume a power up of the motor ! 4929: // to be equivalent to a change of floppy (we assume noone will ! 4930: // change the floppy while it is turning. ! 4931: // So force a VERIFY here (unless the file system explicitly turned ! 4932: // it off). ! 4933: // ! 4934: ! 4935: if ( ((DisketteExtension->DriveType == DRIVE_TYPE_0360) && ! 4936: motorStarted) || ! 4937: ((DisketteExtension->DriveType != DRIVE_TYPE_0360) && ! 4938: (driveStatus & DSKCHG_DISKETTE_REMOVED)) ) { ! 4939: ! 4940: FloppyDump( ! 4941: FLOPSHOW, ! 4942: ("Floppy: disk changed...\n") ! 4943: ); ! 4944: ! 4945: DisketteExtension->MediaType = Undetermined; ! 4946: ! 4947: // ! 4948: // If the volume is mounted, we must tell the filesystem to ! 4949: // verify that the media in the drive is the same volume. ! 4950: // ! 4951: ! 4952: if ( DisketteExtension->DeviceObject->Vpb->Flags & VPB_MOUNTED ) { ! 4953: ! 4954: DisketteExtension->DeviceObject->Flags |= DO_VERIFY_VOLUME; ! 4955: ! 4956: } ! 4957: ! 4958: // ! 4959: // Only go through the device reset if we did get the flag set ! 4960: // We really only want to go throught here if the diskette changed, ! 4961: // but on 360 it will always say the diskette has changed. ! 4962: // So based on our previous test, only proceed if it is NOT ! 4963: // a 360K driver ! 4964: ! 4965: // if ( driveStatus & DSKCHG_DISKETTE_REMOVED ) { ! 4966: ! 4967: if (DisketteExtension->DriveType != DRIVE_TYPE_0360) { ! 4968: ! 4969: // ! 4970: // Now seek twice to reset the "disk changed" line. First ! 4971: // seek to 1. ! 4972: // ! 4973: // Normally we'd do a READ ID after a seek. However, we don't ! 4974: // even know if this disk is formatted. We're not really ! 4975: // trying to get anywhere; we're just doing this to reset the ! 4976: // "disk changed" line so we'll skip the READ ID. ! 4977: // ! 4978: ! 4979: controllerData->FifoBuffer[0] = DisketteExtension->DeviceUnit; ! 4980: controllerData->FifoBuffer[1] = 1; ! 4981: ! 4982: ntStatus = FlIssueCommand( COMMND_SEEK, DisketteExtension ); ! 4983: ! 4984: if ( !NT_SUCCESS( ntStatus ) ) { ! 4985: ! 4986: FloppyDump( ! 4987: FLOPWARN, ! 4988: ("Floppy: seek to 1 returned %x\n", ntStatus) ! 4989: ); ! 4990: ! 4991: return ntStatus; ! 4992: ! 4993: } else { ! 4994: ! 4995: if ( !( controllerData->FifoBuffer[0] & STREG0_SEEK_COMPLETE ) ! 4996: || ( controllerData->FifoBuffer[1] != 1 ) ) { ! 4997: ! 4998: FloppyDump( ! 4999: FLOPWARN, ! 5000: ("Floppy: Seek to 1 had bad return registers\n") ! 5001: ); ! 5002: ! 5003: controllerData->HardwareFailed = TRUE; ! 5004: ! 5005: return STATUS_FLOPPY_BAD_REGISTERS; ! 5006: } ! 5007: } ! 5008: ! 5009: // ! 5010: // Seek back to 0. We can once again skip the READ ID. ! 5011: // ! 5012: ! 5013: controllerData->FifoBuffer[0] = DisketteExtension->DeviceUnit; ! 5014: controllerData->FifoBuffer[1] = 0; ! 5015: ! 5016: ntStatus = FlIssueCommand( COMMND_SEEK, DisketteExtension ); ! 5017: ! 5018: if ( !NT_SUCCESS( ntStatus ) ) { ! 5019: ! 5020: FloppyDump( ! 5021: FLOPWARN, ! 5022: ("Floppy: seek to 0 returned %x\n", ntStatus) ! 5023: ); ! 5024: ! 5025: return ntStatus; ! 5026: ! 5027: } else { ! 5028: ! 5029: if ( !( controllerData->FifoBuffer[0] & STREG0_SEEK_COMPLETE ) ! 5030: || ( controllerData->FifoBuffer[1] != 0 ) ) { ! 5031: ! 5032: FloppyDump( ! 5033: FLOPWARN, ! 5034: ("Floppy: Seek to 0 had bad return registers\n") ! 5035: ); ! 5036: ! 5037: controllerData->HardwareFailed = TRUE; ! 5038: ! 5039: return STATUS_FLOPPY_BAD_REGISTERS; ! 5040: } ! 5041: } ! 5042: ! 5043: driveStatus = READ_CONTROLLER( ! 5044: &controllerData->ControllerAddress->DRDC.DiskChange ); ! 5045: ! 5046: if ( driveStatus & DSKCHG_DISKETTE_REMOVED ) { ! 5047: ! 5048: // ! 5049: // If "disk changed" is still set after the double seek, the ! 5050: // drive door must be opened. ! 5051: // ! 5052: ! 5053: FloppyDump( ! 5054: FLOPINFO, ! 5055: ("Floppy: close the door!\n") ! 5056: ); ! 5057: ! 5058: // ! 5059: // Turn off the flag for now so that we will not get so many ! 5060: // gratuitous verifys. It will be set again the next time. ! 5061: // ! 5062: ! 5063: if ( DisketteExtension->DeviceObject->Vpb->Flags & VPB_MOUNTED ) { ! 5064: ! 5065: DisketteExtension->DeviceObject->Flags &= ~DO_VERIFY_VOLUME; ! 5066: ! 5067: } ! 5068: ! 5069: return STATUS_NO_MEDIA_IN_DEVICE; ! 5070: } ! 5071: } ! 5072: ! 5073: // ! 5074: // IgnoreChange indicates the file system is in the process ! 5075: // of performing a verify so do not return verify required. ! 5076: // ! 5077: ! 5078: if (( IgnoreChange == FALSE ) && ! 5079: ( DisketteExtension->DeviceObject->Vpb->Flags & VPB_MOUNTED )) { ! 5080: ! 5081: // ! 5082: // Drive WAS mounted, but door was opened since the last time ! 5083: // we checked so tell the file system to verify the diskette. ! 5084: // ! 5085: ! 5086: FloppyDump( ! 5087: FLOPSHOW, ! 5088: ("Floppy: start drive - verify required because door opened\n") ! 5089: ); ! 5090: ! 5091: return STATUS_VERIFY_REQUIRED; ! 5092: } ! 5093: } ! 5094: ! 5095: if ( SetUpMedia ) { ! 5096: ! 5097: if ( DisketteExtension->MediaType == Undetermined ) { ! 5098: ! 5099: ntStatus = FlDetermineMediaType( DisketteExtension ); ! 5100: ! 5101: } else { ! 5102: ! 5103: if ( DisketteExtension->MediaType == Unknown ) { ! 5104: ! 5105: // ! 5106: // We've already tried to determine the media type and ! 5107: // failed. It's probably not formatted. ! 5108: // ! 5109: ! 5110: FloppyDump( ! 5111: FLOPSHOW, ! 5112: ("Floppy - start drive - media type was unknown\n") ! 5113: ); ! 5114: return STATUS_UNRECOGNIZED_MEDIA; ! 5115: ! 5116: } else { ! 5117: ! 5118: if ( DisketteExtension->DriveMediaType != ! 5119: controllerData->LastDriveMediaType ) { ! 5120: ! 5121: // ! 5122: // Last drive/media combination accessed by the ! 5123: // controller was different, so set up the controller. ! 5124: // ! 5125: ! 5126: ntStatus = FlDatarateSpecifyConfigure( DisketteExtension ); ! 5127: if (!NT_SUCCESS(ntStatus)) { ! 5128: ! 5129: FloppyDump( ! 5130: FLOPWARN, ! 5131: ("Floppy: start drive - bad status from datarate" ! 5132: "------ specify %x\n", ! 5133: ntStatus) ! 5134: ); ! 5135: ! 5136: } ! 5137: } ! 5138: } ! 5139: } ! 5140: } ! 5141: ! 5142: // ! 5143: // If this is a WRITE, check the drive to make sure it's not write ! 5144: // protected. If so, return an error. ! 5145: // ! 5146: ! 5147: if ( ( WriteOperation ) && ( NT_SUCCESS( ntStatus ) ) ) { ! 5148: ! 5149: controllerData->FifoBuffer[0] = DisketteExtension->DeviceUnit; ! 5150: ! 5151: ntStatus = FlIssueCommand( COMMND_SENSE_DRIVE, DisketteExtension ); ! 5152: ! 5153: if ( !NT_SUCCESS( ntStatus ) ) { ! 5154: ! 5155: FloppyDump( ! 5156: FLOPWARN, ! 5157: ("Floppy: SENSE_DRIVE returned %x\n", ntStatus) ! 5158: ); ! 5159: ! 5160: return ntStatus; ! 5161: } ! 5162: ! 5163: if ( controllerData->FifoBuffer[0] & STREG3_WRITE_PROTECTED ) { ! 5164: ! 5165: FloppyDump( ! 5166: FLOPSHOW, ! 5167: ("Floppy: start drive - media is write protected\n") ! 5168: ); ! 5169: return STATUS_MEDIA_WRITE_PROTECTED; ! 5170: } ! 5171: } ! 5172: ! 5173: return ntStatus; ! 5174: } ! 5175: ! 5176: NTSTATUS ! 5177: FlDatarateSpecifyConfigure( ! 5178: IN PDISKETTE_EXTENSION DisketteExtension ! 5179: ) ! 5180: ! 5181: /*++ ! 5182: ! 5183: Routine Description: ! 5184: ! 5185: This routine is called to set up the controller every time a new type ! 5186: of diskette is to be accessed. It issues the CONFIGURE command if ! 5187: it's available, does a SPECIFY, sets the data rate, and RECALIBRATEs ! 5188: the drive. ! 5189: ! 5190: The caller must set DisketteExtension->DriveMediaType before calling ! 5191: this routine. ! 5192: ! 5193: Arguments: ! 5194: ! 5195: DisketteExtension - pointer to our data area for the drive to be ! 5196: prepared. ! 5197: ! 5198: Return Value: ! 5199: ! 5200: STATUS_SUCCESS if the controller is properly prepared; appropriate ! 5201: error propogated otherwise. ! 5202: ! 5203: --*/ ! 5204: ! 5205: { ! 5206: PCONTROLLER_DATA controllerData; ! 5207: NTSTATUS ntStatus = STATUS_SUCCESS; ! 5208: ! 5209: FloppyDump( ! 5210: FLOPSHOW, ! 5211: ("Floppy: FloppyDatarateSpecifyConfigure...\n") ! 5212: ); ! 5213: ! 5214: controllerData = DisketteExtension->ControllerData; ! 5215: ! 5216: // ! 5217: // If the controller has a CONFIGURE command, use it to enable implied ! 5218: // seeks. If it doesn't, we'll find out here the first time through. ! 5219: // ! 5220: ! 5221: if ( controllerData->ControllerConfigurable ) { ! 5222: ! 5223: controllerData->FifoBuffer[0] = 0; ! 5224: controllerData->FifoBuffer[1] = COMMND_CONFIGURE_FIFO_THRESHOLD + ! 5225: COMMND_CONFIGURE_DISABLE_POLLING; ! 5226: ! 5227: if (!DisketteExtension->DriveMediaConstants.CylinderShift) { ! 5228: ! 5229: controllerData->FifoBuffer[1] += COMMND_CONFIGURE_IMPLIED_SEEKS; ! 5230: ! 5231: } ! 5232: ! 5233: controllerData->FifoBuffer[2] = 0; ! 5234: ! 5235: ntStatus = FlIssueCommand( COMMND_CONFIGURE, DisketteExtension ); ! 5236: ! 5237: if ( ntStatus == STATUS_DEVICE_NOT_READY ) { ! 5238: ! 5239: // ! 5240: // Note the CONFIGURE command doesn't exist. Set status to ! 5241: // success, so we can issue the SPECIFY command below. ! 5242: // ! 5243: ! 5244: FloppyDump( ! 5245: FLOPINFO, ! 5246: ("Floppy: Ignore above error - no CONFIGURE command\n") ! 5247: ); ! 5248: ! 5249: controllerData->ControllerConfigurable = FALSE; ! 5250: ! 5251: ntStatus = STATUS_SUCCESS; ! 5252: } ! 5253: } ! 5254: ! 5255: // ! 5256: // Issue SPECIFY command to program the head load and unload ! 5257: // rates, the drive step rate, and the DMA data transfer mode. ! 5258: // ! 5259: ! 5260: if ( NT_SUCCESS( ntStatus ) ) { ! 5261: ! 5262: controllerData->FifoBuffer[0] = ! 5263: DisketteExtension->DriveMediaConstants.StepRateHeadUnloadTime; ! 5264: ! 5265: controllerData->FifoBuffer[1] = ! 5266: DisketteExtension->DriveMediaConstants.HeadLoadTime; ! 5267: ! 5268: ntStatus = FlIssueCommand( COMMND_SPECIFY, DisketteExtension ); ! 5269: ! 5270: if ( NT_SUCCESS( ntStatus ) ) { ! 5271: ! 5272: // ! 5273: // Program the data rate ! 5274: // ! 5275: ! 5276: WRITE_CONTROLLER( ! 5277: &controllerData->ControllerAddress->DRDC.DataRate, ! 5278: DisketteExtension->DriveMediaConstants.DataTransferRate ); ! 5279: ! 5280: // ! 5281: // Recalibrate the drive, now that we've changed all its ! 5282: // parameters. ! 5283: // ! 5284: ! 5285: ntStatus = FlRecalibrateDrive( DisketteExtension ); ! 5286: } ! 5287: } ! 5288: ! 5289: if ( NT_SUCCESS( ntStatus ) ) { ! 5290: ! 5291: controllerData->LastDriveMediaType = DisketteExtension->DriveMediaType; ! 5292: ! 5293: } else { ! 5294: ! 5295: controllerData->LastDriveMediaType = Unknown; ! 5296: } ! 5297: ! 5298: return ntStatus; ! 5299: } ! 5300: ! 5301: NTSTATUS ! 5302: FlRecalibrateDrive( ! 5303: IN PDISKETTE_EXTENSION DisketteExtension ! 5304: ) ! 5305: ! 5306: /*++ ! 5307: ! 5308: Routine Description: ! 5309: ! 5310: This routine recalibrates a drive. It is called whenever we're ! 5311: setting up to access a new diskette, and after certain errors. It ! 5312: will actually recalibrate twice, since many controllers stop after ! 5313: 77 steps and many disks have 80 tracks. ! 5314: ! 5315: Arguments: ! 5316: ! 5317: DisketteExtension - pointer to our data area for the drive to be ! 5318: recalibrated. ! 5319: ! 5320: Return Value: ! 5321: ! 5322: STATUS_SUCCESS if the drive is successfully recalibrated; appropriate ! 5323: error is propogated otherwise. ! 5324: ! 5325: --*/ ! 5326: ! 5327: { ! 5328: PCONTROLLER_DATA controllerData; ! 5329: NTSTATUS ntStatus; ! 5330: UCHAR recalibrateCount; ! 5331: ! 5332: FloppyDump( ! 5333: FLOPSHOW, ! 5334: ("Floppy: FloppyRecalibrateDrive...\n") ! 5335: ); ! 5336: ! 5337: controllerData = DisketteExtension->ControllerData; ! 5338: ! 5339: recalibrateCount = 0; ! 5340: ! 5341: do { ! 5342: ! 5343: // ! 5344: // Issue the recalibrate command ! 5345: // ! 5346: ! 5347: controllerData->FifoBuffer[0] = DisketteExtension->DeviceUnit; ! 5348: ! 5349: ntStatus = FlIssueCommand( COMMND_RECALIBRATE, DisketteExtension ); ! 5350: ! 5351: if ( !NT_SUCCESS( ntStatus ) ) { ! 5352: ! 5353: FloppyDump( ! 5354: FLOPWARN, ! 5355: ("Floppy: recalibrate returned %x\n", ntStatus) ! 5356: ); ! 5357: ! 5358: } ! 5359: ! 5360: if ( NT_SUCCESS( ntStatus ) ) { ! 5361: ! 5362: if ( !( controllerData->FifoBuffer[0] & STREG0_SEEK_COMPLETE ) || ! 5363: ( controllerData->FifoBuffer[1] != 0 ) ) { ! 5364: ! 5365: FloppyDump( ! 5366: FLOPWARN, ! 5367: ("Floppy: recalibrate had bad registers\n") ! 5368: ); ! 5369: ! 5370: controllerData->HardwareFailed = TRUE; ! 5371: ! 5372: ntStatus = STATUS_FLOPPY_BAD_REGISTERS; ! 5373: } ! 5374: } ! 5375: ! 5376: recalibrateCount++; ! 5377: ! 5378: } while ( ( !NT_SUCCESS( ntStatus ) ) && ( recalibrateCount < 2 ) ); ! 5379: ! 5380: return ntStatus; ! 5381: } ! 5382: ! 5383: NTSTATUS ! 5384: FlDetermineMediaType( ! 5385: IN OUT PDISKETTE_EXTENSION DisketteExtension ! 5386: ) ! 5387: ! 5388: /*++ ! 5389: ! 5390: Routine Description: ! 5391: ! 5392: This routine is called by FlStartDrive() when the media type is ! 5393: unknown. It assumes the largest media supported by the drive is ! 5394: available, and keeps trying lower values until it finds one that ! 5395: works. ! 5396: ! 5397: Arguments: ! 5398: ! 5399: DisketteExtension - pointer to our data area for the drive whose ! 5400: media is to checked. ! 5401: ! 5402: Return Value: ! 5403: ! 5404: STATUS_SUCCESS if the type of the media is determined; appropriate ! 5405: error propogated otherwise. ! 5406: ! 5407: --*/ ! 5408: ! 5409: { ! 5410: NTSTATUS ntStatus; ! 5411: PCONTROLLER_DATA controllerData; ! 5412: PDRIVE_MEDIA_CONSTANTS driveMediaConstants; ! 5413: BOOLEAN mediaTypesExhausted = FALSE; ! 5414: ULONG retries = 0; ! 5415: ! 5416: FloppyDump( ! 5417: FLOPSHOW, ! 5418: ("Floppy: FloppyDetermineMediaType...\n") ! 5419: ); ! 5420: ! 5421: controllerData = DisketteExtension->ControllerData; ! 5422: ! 5423: // ! 5424: // Try up to three times for read the media id. ! 5425: // ! 5426: ! 5427: for ( ! 5428: retries = 0; ! 5429: retries < 3; ! 5430: retries++ ! 5431: ) { ! 5432: ! 5433: if (retries) { ! 5434: ! 5435: // ! 5436: // We're retrying the media determination because ! 5437: // some silly controllers don't always want to work ! 5438: // at setup. First we'll reset the device to give ! 5439: // it a better chance of working. ! 5440: // ! 5441: ! 5442: FlInitializeControllerHardware( ! 5443: controllerData, ! 5444: DisketteExtension->DeviceObject ! 5445: ); ! 5446: ! 5447: } ! 5448: ! 5449: // ! 5450: // Assume that the largest supported media is in the drive. If that ! 5451: // turns out to be untrue, we'll try successively smaller media types ! 5452: // until we find what's really in there (or we run out and decide ! 5453: // that the media isn't formatted). ! 5454: // ! 5455: ! 5456: DisketteExtension->DriveMediaType = ! 5457: DriveMediaLimits[DisketteExtension->DriveType].HighestDriveMediaType; ! 5458: DisketteExtension->DriveMediaConstants = ! 5459: DriveMediaConstants[DisketteExtension->DriveMediaType]; ! 5460: ! 5461: do { ! 5462: ! 5463: ntStatus = FlDatarateSpecifyConfigure( DisketteExtension ); ! 5464: ! 5465: if ( !NT_SUCCESS( ntStatus ) ) { ! 5466: ! 5467: // ! 5468: // The SPECIFY or CONFIGURE commands resulted in an error. ! 5469: // Force ourselves out of this loop and return error. ! 5470: // ! 5471: ! 5472: mediaTypesExhausted = TRUE; ! 5473: ! 5474: } else { ! 5475: ! 5476: // ! 5477: // Use the media constants table when trying to determine ! 5478: // media type. ! 5479: // ! 5480: ! 5481: driveMediaConstants = ! 5482: &DriveMediaConstants[DisketteExtension->DriveMediaType]; ! 5483: ! 5484: // ! 5485: // Now try to read the ID from wherever we're at. ! 5486: // ! 5487: ! 5488: controllerData->FifoBuffer[0] = (UCHAR) ! 5489: ( DisketteExtension->DeviceUnit | ! 5490: ( ( driveMediaConstants->NumberOfHeads - 1 ) << 2 ) ); ! 5491: ! 5492: ntStatus = FlIssueCommand( ! 5493: COMMND_READ_ID + COMMND_MFM, ! 5494: DisketteExtension ); ! 5495: ! 5496: if ( ( !NT_SUCCESS( ntStatus ) ) || ! 5497: ( controllerData->FifoBuffer[0] != ! 5498: (UCHAR)( ( DisketteExtension->DeviceUnit ) | ! 5499: ( ( driveMediaConstants->NumberOfHeads - 1 ) << 2 ) ) ) || ! 5500: ( controllerData->FifoBuffer[1] != 0 ) || ! 5501: ( controllerData->FifoBuffer[2] != 0 ) ) { ! 5502: ! 5503: FloppyDump( ! 5504: FLOPINFO, ! 5505: ("Floppy: READID failed trying lower media\n" ! 5506: "------ status = %x\n" ! 5507: "------ SR0 = %x\n" ! 5508: "------ SR1 = %x\n" ! 5509: "------ SR2 = %x\n", ! 5510: ntStatus, ! 5511: controllerData->FifoBuffer[0], ! 5512: controllerData->FifoBuffer[1], ! 5513: controllerData->FifoBuffer[2]) ! 5514: ); ! 5515: ! 5516: DisketteExtension->DriveMediaType--; ! 5517: DisketteExtension->DriveMediaConstants = ! 5518: DriveMediaConstants[DisketteExtension->DriveMediaType]; ! 5519: ! 5520: if (ntStatus != STATUS_DEVICE_NOT_READY) { ! 5521: ! 5522: ntStatus = STATUS_UNRECOGNIZED_MEDIA; ! 5523: ! 5524: } ! 5525: ! 5526: // ! 5527: // Next comparison must be signed, for when ! 5528: // LowestDriveMediaType = 0. ! 5529: // ! 5530: ! 5531: if ( (CHAR)( DisketteExtension->DriveMediaType ) < ! 5532: (CHAR)( DriveMediaLimits[DisketteExtension->DriveType]. ! 5533: LowestDriveMediaType ) ) { ! 5534: ! 5535: DisketteExtension->MediaType = Unknown; ! 5536: mediaTypesExhausted = TRUE; ! 5537: ! 5538: FloppyDump( ! 5539: FLOPINFO, ! 5540: ("Floppy: Unrecognized media.\n") ! 5541: ); ! 5542: ! 5543: } ! 5544: ! 5545: } ! 5546: ! 5547: } ! 5548: ! 5549: } while ( ( !NT_SUCCESS( ntStatus ) ) && !( mediaTypesExhausted ) ); ! 5550: ! 5551: if (NT_SUCCESS(ntStatus)) { ! 5552: ! 5553: // ! 5554: // We determined the media type. Time to move on. ! 5555: // ! 5556: ! 5557: break; ! 5558: ! 5559: } ! 5560: ! 5561: } ! 5562: ! 5563: if ( (!NT_SUCCESS( ntStatus )) || mediaTypesExhausted) { ! 5564: ! 5565: return ntStatus; ! 5566: ! 5567: } ! 5568: ! 5569: DisketteExtension->MediaType = driveMediaConstants->MediaType; ! 5570: ! 5571: DisketteExtension->BytesPerSector = ! 5572: driveMediaConstants->BytesPerSector; ! 5573: ! 5574: FloppyDump( ! 5575: FLOPINFO, ! 5576: ("Floppy: MediaType is %x\n", DisketteExtension->MediaType) ! 5577: ); ! 5578: ! 5579: DisketteExtension->ByteCapacity = ! 5580: ( driveMediaConstants->BytesPerSector ) * ! 5581: driveMediaConstants->SectorsPerTrack * ! 5582: ( 1 + driveMediaConstants->MaximumTrack ) * ! 5583: driveMediaConstants->NumberOfHeads; ! 5584: ! 5585: // ! 5586: // Structure copy the media constants into the diskette extension. ! 5587: // ! 5588: ! 5589: DisketteExtension->DriveMediaConstants = ! 5590: DriveMediaConstants[DisketteExtension->DriveMediaType]; ! 5591: ! 5592: return ntStatus; ! 5593: } ! 5594: ! 5595: VOID ! 5596: FloppyThread( ! 5597: PVOID Context ! 5598: ) ! 5599: ! 5600: /*++ ! 5601: ! 5602: Routine Description: ! 5603: ! 5604: This is the code executed by the system thread created when the ! 5605: floppy driver initializes. This thread loops forever (or until a ! 5606: flag is set telling the thread to kill itself) processing packets ! 5607: put into the queue by the dispatch routines. ! 5608: ! 5609: For each packet, this thread calls appropriate routines to process ! 5610: the request, and then calls FlFinishOperation() to complete the ! 5611: packet. ! 5612: ! 5613: Arguments: ! 5614: ! 5615: Context - a pointer to our data area for the controller being ! 5616: supported (there is one thread per controller). ! 5617: ! 5618: Return Value: ! 5619: ! 5620: None. ! 5621: ! 5622: --*/ ! 5623: ! 5624: { ! 5625: PCONTROLLER_DATA controllerData = Context; ! 5626: PIRP irp; ! 5627: PIO_STACK_LOCATION irpSp; ! 5628: PLIST_ENTRY request; ! 5629: PDISKETTE_EXTENSION disketteExtension; ! 5630: KIRQL oldIrql; ! 5631: NTSTATUS ntStatus; ! 5632: NTSTATUS waitStatus; ! 5633: LARGE_INTEGER controllerWait; ! 5634: ! 5635: // ! 5636: // Set thread priority to lowest realtime level. ! 5637: // ! 5638: ! 5639: KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY); ! 5640: ! 5641: controllerWait = RtlLargeIntegerNegate( ! 5642: RtlConvertLongToLargeInteger( ! 5643: (LONG)(10 * 1000 * 3000) ! 5644: ) ! 5645: ); ! 5646: ! 5647: do { ! 5648: ! 5649: // ! 5650: // Wait for a request from the dispatch routines. ! 5651: // KeWaitForSingleObject won't return error here - this thread ! 5652: // isn't alertable and won't take APCs, and we're not passing in ! 5653: // a timeout. ! 5654: // ! 5655: ! 5656: KeWaitForSingleObject( ! 5657: (PVOID) &controllerData->RequestSemaphore, ! 5658: UserRequest, ! 5659: KernelMode, ! 5660: FALSE, ! 5661: (PLARGE_INTEGER) NULL ); ! 5662: ! 5663: if ( controllerData->UnloadingDriver ) { ! 5664: ! 5665: FloppyDump( ! 5666: FLOPDBGP, ! 5667: ("Floppy: Thread asked to kill itself\n") ! 5668: ); ! 5669: ! 5670: PsTerminateSystemThread( STATUS_SUCCESS ); ! 5671: } ! 5672: ! 5673: waitStatus = STATUS_SUCCESS; ! 5674: ! 5675: waitStatus = KeWaitForSingleObject( ! 5676: controllerData->ControllerEvent, ! 5677: Executive, ! 5678: KernelMode, ! 5679: FALSE, ! 5680: &controllerWait); ! 5681: ! 5682: ! 5683: if (waitStatus == STATUS_TIMEOUT) { ! 5684: ! 5685: while ( !IsListEmpty( &( controllerData->ListEntry ) ) ) { ! 5686: ! 5687: // ! 5688: // Get the request from the queue. We know there is one, ! 5689: // because of the check above. ! 5690: // ! 5691: ! 5692: request = ExInterlockedRemoveHeadList( ! 5693: &controllerData->ListEntry, ! 5694: &controllerData->ListSpinLock ); ! 5695: ! 5696: controllerData->HardwareFailed = FALSE; ! 5697: ! 5698: irp = CONTAINING_RECORD( request, IRP, Tail.Overlay.ListEntry ); ! 5699: ! 5700: irp->IoStatus.Status = STATUS_DEVICE_BUSY; ! 5701: ! 5702: IoCompleteRequest( irp, IO_DISK_INCREMENT ); ! 5703: ! 5704: } //while there's packets to process ! 5705: ! 5706: } else { ! 5707: ! 5708: controllerData->CurrentInterrupt = TRUE; ! 5709: ! 5710: while ( !IsListEmpty( &( controllerData->ListEntry ) ) ) { ! 5711: ! 5712: // ! 5713: // Get the request from the queue. We know there is one, ! 5714: // because of the check above. ! 5715: // ! 5716: ! 5717: request = ExInterlockedRemoveHeadList( ! 5718: &controllerData->ListEntry, ! 5719: &controllerData->ListSpinLock ); ! 5720: ! 5721: controllerData->HardwareFailed = FALSE; ! 5722: ! 5723: irp = CONTAINING_RECORD( request, IRP, Tail.Overlay.ListEntry ); ! 5724: ! 5725: ! 5726: irpSp = IoGetCurrentIrpStackLocation( irp ); ! 5727: ! 5728: FloppyDump( ! 5729: FLOPIRPPATH, ! 5730: ("Floppy: Starting up IRP: %x for extension %x\n", ! 5731: irp,irpSp->Parameters.Read.Key) ! 5732: ); ! 5733: switch ( irpSp->MajorFunction ) { ! 5734: ! 5735: case IRP_MJ_READ: ! 5736: case IRP_MJ_WRITE: { ! 5737: ! 5738: // ! 5739: // Get the diskette extension from where it was hidden ! 5740: // in the IRP. ! 5741: // ! 5742: ! 5743: disketteExtension = (PDISKETTE_EXTENSION) ! 5744: irpSp->Parameters.Read.Key; ! 5745: ! 5746: // ! 5747: // Until the file system clears the DO_VERIFY_VOLUME ! 5748: // flag, we should return all requests with error. ! 5749: // ! 5750: ! 5751: if (( disketteExtension->DeviceObject->Flags & ! 5752: DO_VERIFY_VOLUME ) && ! 5753: !(irpSp->Flags & SL_OVERRIDE_VERIFY_VOLUME)) ! 5754: { ! 5755: ! 5756: FloppyDump( ! 5757: FLOPINFO, ! 5758: ("Floppy: clearing queue; verify required\n") ! 5759: ); ! 5760: ! 5761: // ! 5762: // The disk changed, and we set this bit. Fail ! 5763: // all current IRPs for this device; when all are ! 5764: // returned, the file system will clear ! 5765: // DO_VERIFY_VOLUME. ! 5766: // ! 5767: ! 5768: ntStatus = STATUS_VERIFY_REQUIRED; ! 5769: ! 5770: } else { ! 5771: ! 5772: // ! 5773: // Allocate an adapter channel for the I/O. ! 5774: // ! 5775: ! 5776: FloppyDump( ! 5777: FLOPIRPPATH, ! 5778: ("Floppy: About to allocate adapter channel %x\n", ! 5779: controllerData->AdapterObject) ! 5780: ); ! 5781: KeResetEvent( ! 5782: &controllerData->AllocateAdapterChannelEvent ); ! 5783: ! 5784: KeRaiseIrql( DISPATCH_LEVEL, &oldIrql ); ! 5785: ! 5786: IoAllocateAdapterChannel( ! 5787: controllerData->AdapterObject, ! 5788: disketteExtension->DeviceObject, ! 5789: controllerData->NumberOfMapRegisters, ! 5790: FloppyAllocateAdapterChannel, ! 5791: controllerData ); ! 5792: ! 5793: KeLowerIrql( oldIrql ); ! 5794: ! 5795: // ! 5796: // Wait for the adapter to be allocated. No ! 5797: // timeout; we trust the system to do it ! 5798: // properly - so KeWaitForSingleObject can't ! 5799: // return an error. ! 5800: // ! 5801: ! 5802: KeWaitForSingleObject( ! 5803: &controllerData->AllocateAdapterChannelEvent, ! 5804: Executive, ! 5805: KernelMode, ! 5806: FALSE, ! 5807: (PLARGE_INTEGER) NULL ); ! 5808: ! 5809: FloppyDump( ! 5810: FLOPIRPPATH, ! 5811: ("Floppy: Allocated adapter channel %x\n", ! 5812: controllerData->AdapterObject) ! 5813: ); ! 5814: ntStatus = FlReadWrite( disketteExtension, irp ); ! 5815: ! 5816: // ! 5817: // Free the adapter channel that we just used. ! 5818: // ! 5819: ! 5820: KeRaiseIrql( DISPATCH_LEVEL, &oldIrql ); ! 5821: ! 5822: IoFreeAdapterChannel( controllerData->AdapterObject ); ! 5823: ! 5824: KeLowerIrql( oldIrql ); ! 5825: } ! 5826: ! 5827: break; ! 5828: } ! 5829: ! 5830: case IRP_MJ_DEVICE_CONTROL: { ! 5831: ! 5832: disketteExtension = (PDISKETTE_EXTENSION) ! 5833: irpSp->Parameters.DeviceIoControl.Type3InputBuffer; ! 5834: ! 5835: // ! 5836: // Until the file system clears the DO_VERIFY_VOLUME ! 5837: // flag, we should return all requests with error. ! 5838: // ! 5839: ! 5840: if (( disketteExtension->DeviceObject->Flags & ! 5841: DO_VERIFY_VOLUME ) && ! 5842: !(irpSp->Flags & SL_OVERRIDE_VERIFY_VOLUME)) ! 5843: { ! 5844: ! 5845: FloppyDump( ! 5846: FLOPINFO, ! 5847: ("Floppy: clearing queue; verify required\n") ! 5848: ); ! 5849: ! 5850: // ! 5851: // The disk changed, and we set this bit. Fail ! 5852: // all current IRPs; when all are returned, the ! 5853: // file system will clear DO_VERIFY_VOLUME. ! 5854: // ! 5855: ! 5856: ntStatus = STATUS_VERIFY_REQUIRED; ! 5857: ! 5858: } else { ! 5859: ! 5860: switch ( ! 5861: irpSp->Parameters.DeviceIoControl.IoControlCode ) { ! 5862: ! 5863: case IOCTL_DISK_CHECK_VERIFY: { ! 5864: ! 5865: // ! 5866: // Just start the drive; it will ! 5867: // automatically check whether or not the ! 5868: // disk has been changed. ! 5869: // ! 5870: ! 5871: FloppyDump( ! 5872: FLOPSHOW, ! 5873: ("Floppy: IOCTL_DISK_CHECK_VERIFY called\n") ! 5874: ); ! 5875: ! 5876: ntStatus = FlStartDrive( ! 5877: disketteExtension, ! 5878: FALSE, ! 5879: FALSE, ! 5880: FALSE); ! 5881: ! 5882: break; ! 5883: } ! 5884: ! 5885: case IOCTL_DISK_GET_DRIVE_GEOMETRY: { ! 5886: ! 5887: FloppyDump( ! 5888: FLOPSHOW, ! 5889: ("Floppy: IOCTL_DISK_GET_DRIVE_GEOMETRY\n") ! 5890: ); ! 5891: ! 5892: // ! 5893: // If there's enough room to write the ! 5894: // data, start the drive to make sure we ! 5895: // know what type of media is in the drive. ! 5896: // ! 5897: ! 5898: if ( irpSp->Parameters.DeviceIoControl. ! 5899: OutputBufferLength < ! 5900: sizeof( DISK_GEOMETRY ) ) { ! 5901: ! 5902: ntStatus = STATUS_INVALID_PARAMETER; ! 5903: ! 5904: } else { ! 5905: ! 5906: ntStatus = FlStartDrive( ! 5907: disketteExtension, ! 5908: FALSE, ! 5909: TRUE, ! 5910: (BOOLEAN)!!(irpSp->Flags & ! 5911: SL_OVERRIDE_VERIFY_VOLUME)); ! 5912: } ! 5913: ! 5914: // ! 5915: // If the media wasn't formatted, FlStartDrive ! 5916: // returned STATUS_UNRECOGNIZED_MEDIA. ! 5917: // ! 5918: ! 5919: if ( NT_SUCCESS( ntStatus ) || ! 5920: ( ntStatus == STATUS_UNRECOGNIZED_MEDIA ) ) { ! 5921: ! 5922: PDISK_GEOMETRY outputBuffer = ! 5923: (PDISK_GEOMETRY) ! 5924: irp->AssociatedIrp.SystemBuffer; ! 5925: ! 5926: // ! 5927: // Always return the media type, even if ! 5928: // it's unknown. ! 5929: // ! 5930: ! 5931: ntStatus = STATUS_SUCCESS; ! 5932: ! 5933: outputBuffer->MediaType = ! 5934: disketteExtension->MediaType; ! 5935: ! 5936: // ! 5937: // The rest of the fields only have meaning ! 5938: // if the media type is known. ! 5939: // ! 5940: ! 5941: if ( disketteExtension->MediaType == ! 5942: Unknown ) { ! 5943: ! 5944: FloppyDump( ! 5945: FLOPSHOW, ! 5946: ("Floppy: geometry unknown\n") ! 5947: ); ! 5948: ! 5949: // ! 5950: // Just zero out everything. The ! 5951: // caller shouldn't look at it. ! 5952: // ! 5953: ! 5954: outputBuffer->Cylinders.LowPart = 0; ! 5955: outputBuffer->Cylinders.HighPart = 0; ! 5956: outputBuffer->TracksPerCylinder = 0; ! 5957: outputBuffer->SectorsPerTrack = 0; ! 5958: outputBuffer->BytesPerSector = 0; ! 5959: ! 5960: } else { ! 5961: ! 5962: // ! 5963: // Return the geometry of the current ! 5964: // media. ! 5965: // ! 5966: ! 5967: FloppyDump( ! 5968: FLOPSHOW, ! 5969: ("Floppy: geomentry is known\n") ! 5970: ); ! 5971: outputBuffer->Cylinders.LowPart = ! 5972: disketteExtension->DriveMediaConstants.MaximumTrack + 1; ! 5973: ! 5974: outputBuffer->Cylinders.HighPart = 0; ! 5975: ! 5976: outputBuffer->TracksPerCylinder = ! 5977: disketteExtension->DriveMediaConstants.NumberOfHeads; ! 5978: ! 5979: outputBuffer->SectorsPerTrack = ! 5980: disketteExtension->DriveMediaConstants.SectorsPerTrack; ! 5981: ! 5982: outputBuffer->BytesPerSector = ! 5983: disketteExtension->DriveMediaConstants.BytesPerSector; ! 5984: } ! 5985: ! 5986: FloppyDump( ! 5987: FLOPSHOW, ! 5988: ("Floppy: Geometry\n" ! 5989: "------- Cylinders low: 0x%x\n" ! 5990: "------- Cylinders high: 0x%x\n" ! 5991: "------- Track/Cyl: 0x%x\n" ! 5992: "------- Sectors/Track: 0x%x\n" ! 5993: "------- Bytes/Sector: 0x%x\n" ! 5994: "------- Media Type: %d\n", ! 5995: outputBuffer->Cylinders.LowPart, ! 5996: outputBuffer->Cylinders.HighPart, ! 5997: outputBuffer->TracksPerCylinder, ! 5998: outputBuffer->SectorsPerTrack, ! 5999: outputBuffer->BytesPerSector, ! 6000: outputBuffer->MediaType) ! 6001: ); ! 6002: ! 6003: } ! 6004: ! 6005: irp->IoStatus.Information = ! 6006: sizeof( DISK_GEOMETRY ); ! 6007: ! 6008: break; ! 6009: } ! 6010: ! 6011: case IOCTL_DISK_FORMAT_TRACKS: { ! 6012: ! 6013: FloppyDump( ! 6014: FLOPSHOW, ! 6015: ("Floppy: IOCTL_DISK_FORMAT_TRACKS\n") ! 6016: ); ! 6017: ! 6018: // ! 6019: // Start the drive, and make sure it's not ! 6020: // write protected. ! 6021: // ! 6022: ! 6023: ntStatus = FlStartDrive( ! 6024: disketteExtension, ! 6025: TRUE, ! 6026: FALSE, ! 6027: FALSE ); ! 6028: ! 6029: // ! 6030: // Note that FlStartDrive could have returned ! 6031: // STATUS_UNRECOGNIZED_MEDIA if the drive ! 6032: // wasn't formatted. ! 6033: // ! 6034: ! 6035: if ( NT_SUCCESS( ntStatus ) || ! 6036: ( ntStatus == STATUS_UNRECOGNIZED_MEDIA ) ) { ! 6037: ! 6038: // ! 6039: // Allocate an adapter channel to do ! 6040: // the format. ! 6041: // ! 6042: ! 6043: KeResetEvent( &controllerData-> ! 6044: AllocateAdapterChannelEvent ); ! 6045: ! 6046: KeRaiseIrql( DISPATCH_LEVEL, &oldIrql ); ! 6047: ! 6048: IoAllocateAdapterChannel( ! 6049: controllerData->AdapterObject, ! 6050: disketteExtension->DeviceObject, ! 6051: controllerData->NumberOfMapRegisters, ! 6052: FloppyAllocateAdapterChannel, ! 6053: controllerData ); ! 6054: ! 6055: KeLowerIrql( oldIrql ); ! 6056: ! 6057: // ! 6058: // Wait for the adapter to be allocated. ! 6059: // No timeout; we trust the system to do ! 6060: // it properly - so KeWaitForSingleObject ! 6061: // can't return an error. ! 6062: // ! 6063: ! 6064: KeWaitForSingleObject( ! 6065: &controllerData-> ! 6066: AllocateAdapterChannelEvent, ! 6067: Executive, ! 6068: KernelMode, ! 6069: FALSE, ! 6070: (PLARGE_INTEGER) NULL ); ! 6071: ! 6072: ntStatus = FlFormat( ! 6073: disketteExtension, ! 6074: irp ); ! 6075: ! 6076: // ! 6077: // Free the adapter channel. ! 6078: // ! 6079: ! 6080: KeRaiseIrql( DISPATCH_LEVEL, &oldIrql ); ! 6081: ! 6082: IoFreeAdapterChannel( ! 6083: controllerData->AdapterObject ); ! 6084: ! 6085: KeLowerIrql( oldIrql ); ! 6086: } ! 6087: ! 6088: break; ! 6089: } //end of case format ! 6090: } //end of switch controlcode ! 6091: } ! 6092: ! 6093: break; ! 6094: } //end of case IOCTL ! 6095: ! 6096: default: { ! 6097: ! 6098: FloppyDump( ! 6099: FLOPDBGP, ! 6100: ("Floppy: bad majorfunction %x\n",irpSp->MajorFunction) ! 6101: ); ! 6102: } ! 6103: ! 6104: } //end of switch on majorfunction ! 6105: ! 6106: // ! 6107: // All operations leave a final status in ntStatus. Copy it ! 6108: // to the IRP, and then complete the operation. ! 6109: // ! 6110: ! 6111: irp->IoStatus.Status = ntStatus; ! 6112: ! 6113: FlFinishOperation( irp, disketteExtension ); ! 6114: ! 6115: } //while there's packets to process ! 6116: ! 6117: controllerData->CurrentInterrupt = FALSE; ! 6118: ! 6119: (VOID) KeSetEvent( ! 6120: controllerData->ControllerEvent, ! 6121: (KPRIORITY) 0, ! 6122: FALSE); ! 6123: ! 6124: } ! 6125: ! 6126: } while ( TRUE ); ! 6127: } ! 6128: ! 6129: IO_ALLOCATION_ACTION ! 6130: FloppyAllocateAdapterChannel( ! 6131: IN PDEVICE_OBJECT DeviceObject, ! 6132: IN PIRP Irp, ! 6133: IN PVOID MapRegisterBase, ! 6134: IN PVOID Context ! 6135: ) ! 6136: ! 6137: /*++ ! 6138: ! 6139: Routine Description: ! 6140: ! 6141: This DPC is called whenever the floppy thread is trying to allocate ! 6142: the adapter channel (like before doing a read or write). It saves ! 6143: the MapRegisterBase in the controller data area, and sets the ! 6144: AllocateAdapterChannelEvent to awaken the thread. ! 6145: ! 6146: Arguments: ! 6147: ! 6148: DeviceObject - unused. ! 6149: ! 6150: Irp - unused. ! 6151: ! 6152: MapRegisterBase - the base of the map registers that can be used ! 6153: for this transfer. ! 6154: ! 6155: Context - a pointer to our controller data area. ! 6156: ! 6157: Return Value: ! 6158: ! 6159: Returns Allocation Action 'KeepObject' which means that the adapter ! 6160: object will be held for now (to be released explicitly later). ! 6161: ! 6162: --*/ ! 6163: { ! 6164: PCONTROLLER_DATA controllerData = Context; ! 6165: ! 6166: UNREFERENCED_PARAMETER( DeviceObject ); ! 6167: UNREFERENCED_PARAMETER( Irp ); ! 6168: ! 6169: controllerData->MapRegisterBase = MapRegisterBase; ! 6170: ! 6171: KeSetEvent( ! 6172: &controllerData->AllocateAdapterChannelEvent, ! 6173: 0L, ! 6174: FALSE ); ! 6175: ! 6176: return KeepObject; ! 6177: } ! 6178: ! 6179: NTSTATUS ! 6180: FlReadWrite( ! 6181: IN OUT PDISKETTE_EXTENSION DisketteExtension, ! 6182: IN OUT PIRP Irp ! 6183: ) ! 6184: ! 6185: /*++ ! 6186: ! 6187: Routine Description: ! 6188: ! 6189: This routine is called by the floppy thread to read/write data ! 6190: to/from the diskette. It breaks the request into pieces called ! 6191: "transfers" (their size depends on the buffer size, where the end of ! 6192: the track is, etc) and retries each transfer until it succeeds or ! 6193: the retry count is exceeded. ! 6194: ! 6195: Arguments: ! 6196: ! 6197: DisketteExtension - a pointer to our data area for the drive to be ! 6198: accessed. ! 6199: ! 6200: Irp - a pointer to the IO Request Packet. ! 6201: ! 6202: Return Value: ! 6203: ! 6204: STATUS_SUCCESS if the packet was successfully read or written; the ! 6205: appropriate error is propogated otherwise. ! 6206: ! 6207: --*/ ! 6208: ! 6209: { ! 6210: LARGE_INTEGER headSettleTime; ! 6211: PIO_STACK_LOCATION irpSp; ! 6212: PCONTROLLER_DATA controllerData; ! 6213: PDRIVE_MEDIA_CONSTANTS driveMediaConstants; ! 6214: PUCHAR userBuffer; ! 6215: NTSTATUS ntStatus; ! 6216: NTSTATUS ntStatus2; ! 6217: ULONG startingSectorOfTransfer; ! 6218: ULONG totalBytesOfTransfer; ! 6219: ULONG bytesTransferredSoFar = 0; ! 6220: ULONG numberOfPagesInTransfer; ! 6221: UCHAR transferCylinder; ! 6222: UCHAR transferSector; ! 6223: UCHAR transferHead; ! 6224: UCHAR byteToSectorShift; ! 6225: UCHAR retryCount; ! 6226: UCHAR secondaryRetryCount; ! 6227: UCHAR mediaDescriptor; ! 6228: DRIVE_MEDIA_TYPE driveMediaType; ! 6229: MEDIA_TYPE mediaType; ! 6230: BOOLEAN writeOperation; ! 6231: BOOLEAN fatalError; ! 6232: BOOLEAN needToUseBuffer; ! 6233: BOOLEAN fifoDisabled = FALSE; ! 6234: ! 6235: FloppyDump( ! 6236: FLOPSHOW, ! 6237: ("Floppy: FloppyReadWrite...\n") ! 6238: ); ! 6239: ! 6240: FloppyDump( ! 6241: FLOPIRPPATH, ! 6242: ("Floppy: Started read/write for irp %x extension %x\n", ! 6243: Irp,DisketteExtension) ! 6244: ); ! 6245: // ! 6246: // Get some useful pointers. ! 6247: // ! 6248: ! 6249: controllerData = DisketteExtension->ControllerData; ! 6250: irpSp = IoGetCurrentIrpStackLocation( Irp ); ! 6251: ! 6252: if ( irpSp->MajorFunction == IRP_MJ_WRITE ) { ! 6253: ! 6254: writeOperation = TRUE; ! 6255: ! 6256: } else { ! 6257: ! 6258: writeOperation = FALSE; ! 6259: } ! 6260: ! 6261: // ! 6262: // If the drive is not already running, wait for it to start up. If ! 6263: // we're writing, this will check to see if the diskette is protected. ! 6264: // ! 6265: ! 6266: FloppyDump( ! 6267: FLOPIRPPATH, ! 6268: ("Floppy: Waiting for drive to start for irp %x extension %x\n", ! 6269: Irp,DisketteExtension) ! 6270: ); ! 6271: ntStatus = FlStartDrive( DisketteExtension, ! 6272: writeOperation, ! 6273: TRUE, ! 6274: (BOOLEAN)!!(irpSp->Flags & SL_OVERRIDE_VERIFY_VOLUME)); ! 6275: if ( !NT_SUCCESS( ntStatus ) ) { ! 6276: ! 6277: FloppyDump( ! 6278: FLOPIRPPATH, ! 6279: ("Floppy: Couldnt start drive for irp %x extension %x\n", ! 6280: Irp,DisketteExtension) ! 6281: ); ! 6282: return ntStatus; ! 6283: } ! 6284: ! 6285: FloppyDump( ! 6286: FLOPIRPPATH, ! 6287: ("Floppy: Drive started for irp %x extension %x\n", ! 6288: Irp,DisketteExtension) ! 6289: ); ! 6290: ! 6291: if ( DisketteExtension->MediaType == Unknown ) { ! 6292: ! 6293: FloppyDump( ! 6294: FLOPWARN, ! 6295: ("Floppy: read/write: media type not determined, failing\n") ! 6296: ); ! 6297: ! 6298: FloppyDump( ! 6299: FLOPIRPPATH, ! 6300: ("Floppy: don't know media irp %x extension %x\n", ! 6301: Irp,DisketteExtension) ! 6302: ); ! 6303: return STATUS_UNRECOGNIZED_MEDIA; ! 6304: ! 6305: } ! 6306: ! 6307: // ! 6308: // Must get this pointer AFTER FlStartDrive, since DriveMediaType may ! 6309: // have been newly determined there. ! 6310: // ! 6311: ! 6312: driveMediaConstants = &DisketteExtension->DriveMediaConstants; ! 6313: ! 6314: // ! 6315: // Initialize variables to be used in the loop that transfers ! 6316: // portions of the request. ! 6317: // ! 6318: ! 6319: byteToSectorShift = (UCHAR)( SECTORLENGTHCODE_TO_BYTESHIFT + ! 6320: driveMediaConstants->SectorLengthCode ); ! 6321: ! 6322: fatalError = FALSE; ! 6323: ! 6324: userBuffer = (PUCHAR) MmGetSystemAddressForMdl( Irp->MdlAddress ); ! 6325: ! 6326: FloppyDump( ! 6327: FLOPSHOW, ! 6328: ("Floppy: Length of I/O is : %x\n" ! 6329: "------ userBuffer is : %lx\n", ! 6330: irpSp->Parameters.Read.Length, ! 6331: userBuffer) ! 6332: ); ! 6333: ! 6334: // ! 6335: // Transfer portions of the request until the request is done or failed ! 6336: // ! 6337: ! 6338: while ( ( bytesTransferredSoFar < irpSp->Parameters.Read.Length ) && ! 6339: !( fatalError ) ) { ! 6340: ! 6341: // ! 6342: // Determine the initial sector to be read from the diskette. ! 6343: // ! 6344: ! 6345: startingSectorOfTransfer = ! 6346: ( ( irpSp->Parameters.Read.ByteOffset ).LowPart + ! 6347: bytesTransferredSoFar ) >> byteToSectorShift; ! 6348: ! 6349: transferCylinder = (UCHAR)( startingSectorOfTransfer / ! 6350: ( driveMediaConstants->SectorsPerTrack * ! 6351: driveMediaConstants->NumberOfHeads ) ); ! 6352: ! 6353: transferSector = (UCHAR)( ( startingSectorOfTransfer % ! 6354: driveMediaConstants->SectorsPerTrack ) + 1 ); ! 6355: ! 6356: transferHead = (UCHAR)( ( startingSectorOfTransfer / ! 6357: driveMediaConstants->SectorsPerTrack ) % ! 6358: driveMediaConstants->NumberOfHeads ); ! 6359: ! 6360: totalBytesOfTransfer = irpSp->Parameters.Read.Length - ! 6361: bytesTransferredSoFar; ! 6362: ! 6363: FloppyDump( ! 6364: FLOPSHOW, ! 6365: ("Floppy: SectorsPerTrack = %x\n" ! 6366: "------ NumberOfHeads = %x\n" ! 6367: "------ startingSectorOfTransfer = %x\n" ! 6368: "------ transferCylinder = %x\n" ! 6369: "------ transferSector = %x\n" ! 6370: "------ transferHead = %x\n", ! 6371: driveMediaConstants->SectorsPerTrack, ! 6372: driveMediaConstants->NumberOfHeads, ! 6373: startingSectorOfTransfer, ! 6374: transferCylinder, ! 6375: transferSector, ! 6376: transferHead) ! 6377: ); ! 6378: ! 6379: // ! 6380: // Make sure the transfer doesn't go past the end of the track ! 6381: // ! 6382: ! 6383: if ( ( totalBytesOfTransfer >> byteToSectorShift ) > (ULONG) ! 6384: ( driveMediaConstants->SectorsPerTrack - transferSector + 1 ) ) { ! 6385: ! 6386: totalBytesOfTransfer = ( driveMediaConstants->SectorsPerTrack - ! 6387: transferSector + 1 ) << byteToSectorShift; ! 6388: } ! 6389: ! 6390: // ! 6391: // If there aren't enough map registers to handle the whole ! 6392: // transfer, then make the transfer size equal to the size of the ! 6393: // contiguous buffer. ! 6394: // ! 6395: ! 6396: numberOfPagesInTransfer = ADDRESS_AND_SIZE_TO_SPAN_PAGES( ! 6397: ( userBuffer + bytesTransferredSoFar ), ! 6398: totalBytesOfTransfer ); ! 6399: ! 6400: if ( numberOfPagesInTransfer <= ! 6401: (ULONG) controllerData->NumberOfMapRegisters ) { ! 6402: ! 6403: needToUseBuffer = FALSE; ! 6404: ! 6405: } else { ! 6406: ! 6407: FloppyDump( ! 6408: FLOPSHOW, ! 6409: ("Floppy: Not enough map registers, using own buffer\n") ! 6410: ); ! 6411: ! 6412: needToUseBuffer = TRUE; ! 6413: ! 6414: #ifdef KEEP_COUNTERS ! 6415: FloppyUsedBuffer++; ! 6416: #endif ! 6417: if ( totalBytesOfTransfer > controllerData->IoBufferSize ) { ! 6418: ! 6419: totalBytesOfTransfer = controllerData->IoBufferSize; ! 6420: } ! 6421: } ! 6422: ! 6423: FloppyDump( ! 6424: FLOPSHOW, ! 6425: ("Floppy: TransferLength = %lx\n", totalBytesOfTransfer) ! 6426: ); ! 6427: ! 6428: // ! 6429: // If this is a write and we have to use the contiguous buffer ! 6430: // (because we don't have enough map registers) then copy the ! 6431: // data from the user's buffer to the contiguous buffer. ! 6432: // ! 6433: ! 6434: if ( ( needToUseBuffer ) && ! 6435: ( writeOperation ) ) { ! 6436: ! 6437: FloppyDump( ! 6438: FLOPSHOW, ! 6439: ("Floppy: Writing from address %lx\n", ! 6440: userBuffer + bytesTransferredSoFar) ! 6441: ); ! 6442: ! 6443: RtlMoveMemory( ! 6444: controllerData->IoBuffer, ! 6445: (PVOID)( userBuffer + bytesTransferredSoFar ), ! 6446: totalBytesOfTransfer ); ! 6447: } ! 6448: ! 6449: retryCount = 0; ! 6450: secondaryRetryCount = 0; ! 6451: ! 6452: // ! 6453: // Try this transfer until it succeeds or is failed. ! 6454: // ! 6455: ! 6456: do { ! 6457: ! 6458: // ! 6459: // If the controller doesn't do an implicit seek, then do an ! 6460: // explicit one. ! 6461: // ! 6462: // Also do an explicit seek if this drive isn't set up to ! 6463: // seek properly on this media, as noted by CylinderShift. ! 6464: // (This happens for 360kb diskettes in 1.2Mb drives). ! 6465: // ! 6466: ! 6467: if ( ( !controllerData->ControllerConfigurable ) || ! 6468: ( driveMediaConstants->CylinderShift != 0 ) ) { ! 6469: ! 6470: controllerData->FifoBuffer[0] = (UCHAR) ! 6471: ( ( transferHead << 2 ) | DisketteExtension->DeviceUnit ); ! 6472: controllerData->FifoBuffer[1] = (UCHAR)( transferCylinder << ! 6473: driveMediaConstants->CylinderShift ); ! 6474: ! 6475: FloppyDump( ! 6476: FLOPSHOW, ! 6477: ("Floppy: Issuing SEEK to %x\n", ! 6478: controllerData->FifoBuffer[1]) ! 6479: ); ! 6480: ! 6481: #ifdef KEEP_COUNTERS ! 6482: FloppyUsedSeek++; ! 6483: #endif ! 6484: ! 6485: ntStatus = FlIssueCommand( COMMND_SEEK, DisketteExtension ); ! 6486: ! 6487: if ( !NT_SUCCESS( ntStatus ) ) { ! 6488: ! 6489: FloppyDump( ! 6490: FLOPWARN, ! 6491: ("Floppy: SEEK returned %x\n", ntStatus) ! 6492: ); ! 6493: } ! 6494: ! 6495: if ( NT_SUCCESS( ntStatus ) ) { ! 6496: ! 6497: FloppyDump( ! 6498: FLOPSHOW, ! 6499: ("Floppy: SEEK says we got to cylinder %x\n", ! 6500: controllerData->FifoBuffer[1]) ! 6501: ); ! 6502: ! 6503: if ( ( !( controllerData->FifoBuffer[0] & ! 6504: STREG0_SEEK_COMPLETE ) || ! 6505: ( controllerData->FifoBuffer[1] != (UCHAR) ! 6506: ( transferCylinder << ! 6507: driveMediaConstants->CylinderShift ) ) ) ) { ! 6508: ! 6509: FloppyDump( ! 6510: FLOPWARN, ! 6511: ("Floppy: Seek returned bad registers\n") ! 6512: ); ! 6513: ! 6514: controllerData->HardwareFailed = TRUE; ! 6515: ! 6516: ntStatus = STATUS_FLOPPY_BAD_REGISTERS; ! 6517: ! 6518: } else { ! 6519: ! 6520: // ! 6521: // Must delay HeadSettleTime milliseconds before ! 6522: // doing anything after a SEEK. ! 6523: // ! 6524: ! 6525: headSettleTime.LowPart = - ( 10 * 1000 * ! 6526: driveMediaConstants->HeadSettleTime ); ! 6527: headSettleTime.HighPart = -1; ! 6528: ! 6529: KeDelayExecutionThread( ! 6530: KernelMode, ! 6531: FALSE, ! 6532: &headSettleTime ); ! 6533: ! 6534: // ! 6535: // SEEKs should always be followed by a READID. ! 6536: // ! 6537: ! 6538: controllerData->FifoBuffer[0] = (UCHAR) ! 6539: ( ( transferHead << 2 ) | ! 6540: DisketteExtension->DeviceUnit ); ! 6541: ! 6542: ntStatus = FlIssueCommand( ! 6543: COMMND_READ_ID + COMMND_MFM, ! 6544: DisketteExtension ); ! 6545: ! 6546: if ( !NT_SUCCESS( ntStatus ) ) { ! 6547: ! 6548: FloppyDump( ! 6549: FLOPWARN, ! 6550: ("Floppy: READID after seek returned %x\n", ! 6551: ntStatus) ! 6552: ); ! 6553: } ! 6554: ! 6555: if ( NT_SUCCESS( ntStatus ) ) { ! 6556: ! 6557: FloppyDump( ! 6558: FLOPSHOW, ! 6559: ("Floppy: ReadID says we're on cylinder %x\n", ! 6560: controllerData->FifoBuffer[3]) ! 6561: ); ! 6562: ! 6563: if ( ( controllerData->FifoBuffer[0] != (UCHAR) ! 6564: ( ( transferHead << 2 ) | ! 6565: DisketteExtension->DeviceUnit ) ) || ! 6566: ( controllerData->FifoBuffer[1] != 0 ) || ! 6567: ( controllerData->FifoBuffer[2] != 0 ) || ! 6568: ( controllerData->FifoBuffer[3] != ! 6569: transferCylinder ) ) { ! 6570: ! 6571: FloppyDump( ! 6572: FLOPWARN, ! 6573: ("Floppy: READID returned bad registers\n" ! 6574: "------ StatusRegister0 = %x\n" ! 6575: "------ StatusRegister1 = %x\n" ! 6576: "------ StatusRegister2 = %x\n" ! 6577: "------ StatusRegister3 = %x\n" ! 6578: "------ actualCylinder = %x\n" ! 6579: "------ transferCylinder = %x\n", ! 6580: controllerData->FifoBuffer[0], ! 6581: controllerData->FifoBuffer[1], ! 6582: controllerData->FifoBuffer[2], ! 6583: controllerData->FifoBuffer[3], ! 6584: controllerData->FifoBuffer[3], ! 6585: transferCylinder) ! 6586: ); ! 6587: ! 6588: controllerData->HardwareFailed = TRUE; ! 6589: ! 6590: ntStatus = FlInterpretError( ! 6591: controllerData->FifoBuffer[1], ! 6592: controllerData->FifoBuffer[2] ); ! 6593: ! 6594: } ! 6595: } ! 6596: } ! 6597: } ! 6598: } else { ! 6599: ! 6600: #ifdef KEEP_COUNTERS ! 6601: FloppyNoSeek++; ! 6602: #endif ! 6603: ! 6604: } ! 6605: ! 6606: // ! 6607: // Start the operation on the DMA and floppy hardware. ! 6608: // ! 6609: ! 6610: if ( NT_SUCCESS( ntStatus ) ) { ! 6611: ! 6612: // ! 6613: // Map the transfer through the DMA hardware. How we do ! 6614: // it depends on whether we're using the user's buffer ! 6615: // or our own contiguous buffer. ! 6616: // ! 6617: ! 6618: if ( needToUseBuffer ) { ! 6619: ! 6620: KeFlushIoBuffers( ! 6621: controllerData->IoBufferMdl, ! 6622: !writeOperation, ! 6623: TRUE ); ! 6624: ! 6625: // ! 6626: // We can ignore the logical address returned by ! 6627: // IoMapTransfer, since we're not using busmaster ! 6628: // stuff. ! 6629: // ! 6630: ! 6631: IoMapTransfer( ! 6632: controllerData->AdapterObject, ! 6633: controllerData->IoBufferMdl, ! 6634: controllerData->MapRegisterBase, ! 6635: controllerData->IoBuffer, ! 6636: &totalBytesOfTransfer, ! 6637: (BOOLEAN)writeOperation); ! 6638: ! 6639: } else { ! 6640: ! 6641: KeFlushIoBuffers( Irp->MdlAddress, !writeOperation, TRUE ); ! 6642: ! 6643: IoMapTransfer( ! 6644: controllerData->AdapterObject, ! 6645: Irp->MdlAddress, ! 6646: controllerData->MapRegisterBase, ! 6647: (PVOID)( (ULONG) MmGetMdlVirtualAddress(Irp->MdlAddress) ! 6648: + bytesTransferredSoFar ), ! 6649: &totalBytesOfTransfer, ! 6650: (BOOLEAN)writeOperation); ! 6651: } ! 6652: ! 6653: // ! 6654: // Issue the READ or WRITE command ! 6655: // ! 6656: ! 6657: controllerData->FifoBuffer[0] = (UCHAR) ! 6658: ( ( transferHead << 2 ) | DisketteExtension->DeviceUnit ); ! 6659: controllerData->FifoBuffer[1] = transferCylinder; ! 6660: controllerData->FifoBuffer[2] = transferHead; ! 6661: controllerData->FifoBuffer[3] = transferSector; ! 6662: controllerData->FifoBuffer[4] = ! 6663: driveMediaConstants->SectorLengthCode; ! 6664: controllerData->FifoBuffer[5] = (UCHAR)( transferSector - 1 + ! 6665: ( totalBytesOfTransfer >> byteToSectorShift ) ); ! 6666: controllerData->FifoBuffer[6] = ! 6667: driveMediaConstants->ReadWriteGapLength; ! 6668: controllerData->FifoBuffer[7] = driveMediaConstants->DataLength; ! 6669: ! 6670: FloppyDump( ! 6671: FLOPSHOW, ! 6672: ("Floppy: R/W params:\n" ! 6673: "------ head+unit = %x\n" ! 6674: "------ cylinder = %x\n" ! 6675: "------ head = %x\n" ! 6676: "------ sector = %x\n" ! 6677: "------ seclen code = %x\n" ! 6678: "------ numsecs = %x\n" ! 6679: "------ rw gap len = %x\n" ! 6680: "------ datalen = %x\n", ! 6681: controllerData->FifoBuffer[0], ! 6682: controllerData->FifoBuffer[1], ! 6683: controllerData->FifoBuffer[2], ! 6684: controllerData->FifoBuffer[3], ! 6685: controllerData->FifoBuffer[4], ! 6686: controllerData->FifoBuffer[5], ! 6687: controllerData->FifoBuffer[6], ! 6688: controllerData->FifoBuffer[7]) ! 6689: ); ! 6690: ! 6691: if ( !writeOperation ) { ! 6692: ! 6693: ntStatus = FlIssueCommand( ! 6694: COMMND_READ_DATA + COMMND_MFM, ! 6695: DisketteExtension ); ! 6696: ! 6697: } else { ! 6698: ! 6699: ntStatus = FlIssueCommand( ! 6700: COMMND_WRITE_DATA + COMMND_MFM, ! 6701: DisketteExtension ); ! 6702: } ! 6703: ! 6704: if ( !NT_SUCCESS( ntStatus ) ) { ! 6705: ! 6706: FloppyDump( ! 6707: FLOPWARN, ! 6708: ("Floppy: read/write returned %x\n", ntStatus) ! 6709: ); ! 6710: } ! 6711: ! 6712: } ! 6713: ! 6714: if ( NT_SUCCESS( ntStatus ) ) { ! 6715: ! 6716: ! 6717: if ( ( ( controllerData->FifoBuffer[0] & STREG0_END_MASK ) != ! 6718: STREG0_END_NORMAL ) && ! 6719: ( ( ( controllerData->FifoBuffer[0] & STREG0_END_MASK ) != ! 6720: STREG0_END_ERROR ) || ! 6721: ( controllerData->FifoBuffer[1] != ! 6722: STREG1_END_OF_DISKETTE ) || ! 6723: ( controllerData->FifoBuffer[2] != STREG2_SUCCESS ) ) ) { ! 6724: ! 6725: FloppyDump( ! 6726: FLOPWARN, ! 6727: ("Floppy: Status registers wrong after I/O\n") ! 6728: ); ! 6729: ! 6730: controllerData->HardwareFailed = TRUE; ! 6731: ! 6732: ntStatus = FlInterpretError( ! 6733: controllerData->FifoBuffer[1], ! 6734: controllerData->FifoBuffer[2] ); ! 6735: ! 6736: FloppyDump( ! 6737: FLOPWARN, ! 6738: ("Floppy: Register values are\n" ! 6739: "------ StatusRegister0 = %x\n" ! 6740: "------ StatusRegister1 = %x\n" ! 6741: "------ StatusRegister2 = %x\n" ! 6742: "------ actualCylinder = %x\n" ! 6743: "------ actualHead = %x\n" ! 6744: "------ actualSector = %x\n" ! 6745: "------ actualSectorLengthCode = %x\n", ! 6746: controllerData->FifoBuffer[0], ! 6747: controllerData->FifoBuffer[1], ! 6748: controllerData->FifoBuffer[2], ! 6749: controllerData->FifoBuffer[3], ! 6750: controllerData->FifoBuffer[4], ! 6751: controllerData->FifoBuffer[5], ! 6752: controllerData->FifoBuffer[6]) ! 6753: ); ! 6754: } ! 6755: ! 6756: } ! 6757: ! 6758: if ( !NT_SUCCESS( ntStatus ) ) { ! 6759: ! 6760: // ! 6761: // Operation failed. Recalibrate drive & try again. ! 6762: // ! 6763: ! 6764: FloppyDump( ! 6765: FLOPWARN, ! 6766: ("Floppy: operation failed. Recalibrating...\n") ! 6767: ); ! 6768: ! 6769: ntStatus2 = FlRecalibrateDrive( DisketteExtension ); ! 6770: ! 6771: if ( NT_SUCCESS( ntStatus2 ) ) { ! 6772: ! 6773: retryCount++; ! 6774: ! 6775: } else { ! 6776: ! 6777: // ! 6778: // Ugh, we can't even recalibrate the drive. Force ! 6779: // ourselves out of this nasty loop. ! 6780: // ! 6781: ! 6782: retryCount = RECALIBRATE_RETRY_COUNT; ! 6783: ! 6784: fatalError = TRUE; ! 6785: ! 6786: FloppyDump( ! 6787: FLOPWARN, ! 6788: ("Floppy: Operation AND recalibrate failed\n") ! 6789: ); ! 6790: } ! 6791: } ! 6792: ! 6793: if ( retryCount == RECALIBRATE_RETRY_COUNT ) { ! 6794: ! 6795: // ! 6796: // The retry count is exhausted. If the FIFO has ! 6797: // overrun, reset the retry count and increment ! 6798: // the secondary retry count - FIFO overruns mean that ! 6799: // another device is hogging the DMA, so give the floppy ! 6800: // another chance to make good. ! 6801: // ! 6802: ! 6803: if ( controllerData->FifoBuffer[1] & STREG1_DATA_OVERRUN ) { ! 6804: ! 6805: if ( secondaryRetryCount < OVERRUN_RETRY_COUNT ) { ! 6806: ! 6807: secondaryRetryCount++; ! 6808: ! 6809: retryCount = 0; ! 6810: ! 6811: } else { ! 6812: ! 6813: // ! 6814: // It looks like another device is STILL hogging ! 6815: // the DMA. Before failing, try disabling the ! 6816: // FIFO, if it exists. ! 6817: // ! 6818: ! 6819: if ( controllerData->ControllerConfigurable ) { ! 6820: ! 6821: if ( fifoDisabled ) { ! 6822: ! 6823: // ! 6824: // We already disabled it, and still ! 6825: // failed. Exit with failure. ! 6826: // ! 6827: ! 6828: fatalError = TRUE; ! 6829: ! 6830: } else { ! 6831: ! 6832: FloppyDump( ! 6833: FLOPINFO, ! 6834: ("Floppy: disabling FIFO\n") ! 6835: ); ! 6836: ! 6837: controllerData->FifoBuffer[0] = 0; ! 6838: controllerData->FifoBuffer[1] = ! 6839: COMMND_CONFIGURE_IMPLIED_SEEKS + ! 6840: COMMND_CONFIGURE_DISABLE_FIFO + ! 6841: COMMND_CONFIGURE_DISABLE_POLLING; ! 6842: controllerData->FifoBuffer[2] = 0; ! 6843: ! 6844: ntStatus = FlIssueCommand( ! 6845: COMMND_CONFIGURE, ! 6846: DisketteExtension ); ! 6847: ! 6848: if ( NT_SUCCESS( ntStatus ) ) { ! 6849: ! 6850: fifoDisabled = TRUE; ! 6851: } ! 6852: } ! 6853: ! 6854: } else { ! 6855: ! 6856: // ! 6857: // No FIFO to disable. Just exit with error. ! 6858: // ! 6859: ! 6860: fatalError = TRUE; ! 6861: } ! 6862: } ! 6863: ! 6864: } else { ! 6865: ! 6866: // ! 6867: // Not an overrun error. ! 6868: // ! 6869: ! 6870: fatalError = TRUE; ! 6871: } ! 6872: } ! 6873: ! 6874: // ! 6875: // Flush the DMA adapter buffers. ! 6876: // ! 6877: ! 6878: if ( needToUseBuffer ) { ! 6879: ! 6880: IoFlushAdapterBuffers( ! 6881: controllerData->AdapterObject, ! 6882: controllerData->IoBufferMdl, ! 6883: controllerData->MapRegisterBase, ! 6884: controllerData->IoBuffer, ! 6885: totalBytesOfTransfer, ! 6886: (BOOLEAN)writeOperation); ! 6887: ! 6888: } else { ! 6889: ! 6890: IoFlushAdapterBuffers( ! 6891: controllerData->AdapterObject, ! 6892: Irp->MdlAddress, ! 6893: controllerData->MapRegisterBase, ! 6894: (PVOID)( (ULONG) MmGetMdlVirtualAddress( Irp->MdlAddress ) ! 6895: + bytesTransferredSoFar ), ! 6896: totalBytesOfTransfer, ! 6897: (BOOLEAN)writeOperation); ! 6898: } ! 6899: ! 6900: } while ( ( !NT_SUCCESS( ntStatus ) ) && ! 6901: ( retryCount < RECALIBRATE_RETRY_COUNT ) ); ! 6902: ! 6903: if ( NT_SUCCESS( ntStatus ) ) { ! 6904: ! 6905: if ( ( !writeOperation ) && ( needToUseBuffer ) ) { ! 6906: ! 6907: // ! 6908: // copy data from contiguous buffer ! 6909: // ! 6910: ! 6911: FloppyDump( ! 6912: FLOPSHOW, ! 6913: ("Floppy: Reading to address %lx\n", ! 6914: userBuffer + bytesTransferredSoFar) ! 6915: ); ! 6916: ! 6917: RtlMoveMemory( ! 6918: (PVOID)( userBuffer + bytesTransferredSoFar ), ! 6919: controllerData->IoBuffer, ! 6920: totalBytesOfTransfer ); ! 6921: } ! 6922: ! 6923: // ! 6924: // If this was a read of the very first sector, check the ! 6925: // media descriptor byte to verify that we have the right ! 6926: // media type. ! 6927: // ! 6928: ! 6929: if ( ( startingSectorOfTransfer == 0 ) && ( !writeOperation ) ) { ! 6930: ! 6931: mediaDescriptor = *( userBuffer + MEDIA_DESCRIPTOR_OFFSET ); ! 6932: FloppyDump( ! 6933: FLOPSHOW, ! 6934: ("Floppy: First sector read: media descriptor is: 0x%x\n", ! 6935: mediaDescriptor) ! 6936: ); ! 6937: ! 6938: mediaType = 0; ! 6939: ! 6940: switch ( mediaDescriptor ) { ! 6941: ! 6942: case MEDIA_DESCRIPTOR_160K: { ! 6943: ! 6944: mediaType = F5_160_512; ! 6945: break; ! 6946: } ! 6947: ! 6948: case MEDIA_DESCRIPTOR_180K: { ! 6949: ! 6950: mediaType = F5_180_512; ! 6951: break; ! 6952: } ! 6953: ! 6954: case MEDIA_DESCRIPTOR_320K: { ! 6955: ! 6956: mediaType = F5_320_512; ! 6957: break; ! 6958: } ! 6959: ! 6960: case MEDIA_DESCRIPTOR_360K: { ! 6961: ! 6962: mediaType = F5_360_512; ! 6963: break; ! 6964: } ! 6965: ! 6966: case MEDIA_DESCRIPTOR_720K_OR_1220K: { ! 6967: ! 6968: if ( DisketteExtension->DriveType == DRIVE_TYPE_1200 ) { ! 6969: ! 6970: FloppyDump( ! 6971: FLOPSHOW, ! 6972: ("FLOPPY: 720K or 1220K ambiguity - going for " ! 6973: "1.2\n") ! 6974: ); ! 6975: mediaType = F5_1Pt2_512; ! 6976: ! 6977: } else { ! 6978: ! 6979: FloppyDump( ! 6980: FLOPSHOW, ! 6981: ("FLOPPY: 720K or 1220K ambiguity - going for " ! 6982: "720\n") ! 6983: ); ! 6984: mediaType = F3_720_512; ! 6985: } ! 6986: ! 6987: break; ! 6988: } ! 6989: ! 6990: case MEDIA_DESCRIPTOR_1440K_OR_2880K: { ! 6991: ! 6992: if (DisketteExtension->DriveType == DRIVE_TYPE_1440) { ! 6993: ! 6994: FloppyDump( ! 6995: FLOPSHOW, ! 6996: ("FLOPPY: 1440/2880KB ambiguity - going for " ! 6997: "1440KB\n") ! 6998: ); ! 6999: mediaType = F3_1Pt44_512; ! 7000: ! 7001: } else { ! 7002: ! 7003: // ! 7004: // If the diskette media type is already 1.44 ! 7005: // then leave it that way. The reasoning ! 7006: // here is that if it was a 2.88 then we ! 7007: // would have already figured that out. ! 7008: // ! 7009: ! 7010: if (DisketteExtension->MediaType != ! 7011: F3_1Pt44_512) { ! 7012: ! 7013: FloppyDump( ! 7014: FLOPSHOW, ! 7015: ("FLOPPY: 1440/2880KB ambiguity - guess" ! 7016: " for 2880KB\n") ! 7017: ); ! 7018: mediaType = F3_2Pt88_512; ! 7019: ! 7020: } else { ! 7021: ! 7022: FloppyDump( ! 7023: FLOPSHOW, ! 7024: ("FLOPPY: 1440/2880KB ambiguity - deduce" ! 7025: " 1440KB\n") ! 7026: ); ! 7027: ! 7028: } ! 7029: ! 7030: } ! 7031: ! 7032: break; ! 7033: } ! 7034: ! 7035: default: { ! 7036: ! 7037: FloppyDump( ! 7038: FLOPDBGP, ! 7039: ("Floppy: unknown media descriptor %x\n", ! 7040: mediaDescriptor) ! 7041: ); ! 7042: } ! 7043: ! 7044: } ! 7045: FloppyDump( ! 7046: FLOPSHOW, ! 7047: ("FLOPPY: After switch media type is: %x\n",mediaType) ! 7048: ); ! 7049: if ( ( mediaType != 0 ) && ! 7050: ( mediaType != DisketteExtension->MediaType ) ) { ! 7051: ! 7052: FloppyDump( ! 7053: FLOPSHOW, ! 7054: ("FLOPPY: media type doesn't agree with previous\n" ! 7055: "------ readid determination\n") ! 7056: ); ! 7057: ! 7058: ! 7059: driveMediaType = DriveMediaLimits[ ! 7060: DisketteExtension->DriveType].HighestDriveMediaType; ! 7061: ! 7062: while ( ( DriveMediaConstants[driveMediaType].MediaType != ! 7063: mediaType ) && ! 7064: ( driveMediaType > DriveMediaLimits[DisketteExtension-> ! 7065: DriveType].LowestDriveMediaType ) ) { ! 7066: ! 7067: driveMediaType--; ! 7068: } ! 7069: // williamh - June 11 1993 ! 7070: // make sure the data we read from the media are consistent ! 7071: // with the new media ID we are going to use. ! 7072: // if they do not match with the new media type, ! 7073: // we have a bogus media and should leave it unchanged. ! 7074: // Actually, the right thing to do here is to derive ! 7075: // a correct media type from what we read(sector 0). ! 7076: // I simply have no time for this. ! 7077: ! 7078: if (DriveMediaConstants[driveMediaType].MediaType == ! 7079: mediaType && ! 7080: *(userBuffer+MEDIA_DESCRIPTOR_SECTORS_PER_TRACK) == ! 7081: DriveMediaConstants[driveMediaType].SectorsPerTrack && ! 7082: *(userBuffer + MEDIA_DESCRIPTOR_NUM_OF_HEADS) == ! 7083: DriveMediaConstants[driveMediaType].NumberOfHeads ! 7084: ){ ! 7085: ! 7086: // ! 7087: // We only want to reset if the media types ! 7088: // actually match up. If they don't match ! 7089: // up, the maximum size is as good a guess. ! 7090: // as any. ! 7091: // ! 7092: ! 7093: FloppyDump( ! 7094: FLOPWARN, ! 7095: ("Floppy: New media type after lookup %x\n", mediaType) ! 7096: ); ! 7097: ! 7098: DisketteExtension->MediaType = mediaType; ! 7099: DisketteExtension->DriveMediaType = driveMediaType; ! 7100: ! 7101: driveMediaConstants = ! 7102: &DriveMediaConstants[DisketteExtension->DriveMediaType]; ! 7103: ! 7104: DisketteExtension->BytesPerSector = ! 7105: driveMediaConstants->BytesPerSector; ! 7106: ! 7107: DisketteExtension->ByteCapacity = ! 7108: ( driveMediaConstants->BytesPerSector ) * ! 7109: driveMediaConstants->SectorsPerTrack * ! 7110: ( 1 + driveMediaConstants->MaximumTrack ) * ! 7111: driveMediaConstants->NumberOfHeads; ! 7112: ! 7113: // ! 7114: // Since the I/O returned without failure, the gap, ! 7115: // density and wait times are correct. Only the ! 7116: // sectors, cylinders, and heads need to change. ! 7117: // ! 7118: ! 7119: if ((mediaDescriptor == MEDIA_DESCRIPTOR_720K_OR_1220K) ! 7120: || ! 7121: (mediaDescriptor == MEDIA_DESCRIPTOR_1440K_OR_2880K) ! 7122: ) { ! 7123: ! 7124: // ! 7125: // The media indicator for 1.22 MB and 720KB are the ! 7126: // same, but it is possible to have a 1.44 floppy ! 7127: // formatted as a 1.22, so use the sectors per track ! 7128: // information from the floppy. ! 7129: // ! 7130: ! 7131: DisketteExtension->DriveMediaConstants ! 7132: .SectorsPerTrack = ! 7133: *( userBuffer + MEDIA_DESCRIPTOR_SECTORS_PER_TRACK ); ! 7134: ! 7135: } else { ! 7136: ! 7137: DisketteExtension->DriveMediaConstants ! 7138: .SectorsPerTrack = ! 7139: driveMediaConstants->SectorsPerTrack; ! 7140: ! 7141: } ! 7142: ! 7143: DisketteExtension->DriveMediaConstants.NumberOfHeads = ! 7144: driveMediaConstants->NumberOfHeads; ! 7145: DisketteExtension->DriveMediaConstants.MaximumTrack = ! 7146: driveMediaConstants->MaximumTrack; ! 7147: ! 7148: } else { ! 7149: ! 7150: FloppyDump( ! 7151: FLOPDBGP, ! 7152: ("Floppy: Bogus media descriptor for size\n" ! 7153: "------ Guessing that max is ok\n") ! 7154: ); ! 7155: ! 7156: } ! 7157: } ! 7158: } ! 7159: ! 7160: bytesTransferredSoFar += totalBytesOfTransfer; ! 7161: } ! 7162: ! 7163: } // while more transfers to be made for this request ! 7164: ! 7165: if ( fifoDisabled ) { ! 7166: ! 7167: // ! 7168: // We disabled the FIFO threshold. Restore it now. ! 7169: // ! 7170: ! 7171: controllerData->FifoBuffer[0] = 0; ! 7172: controllerData->FifoBuffer[1] = COMMND_CONFIGURE_IMPLIED_SEEKS + ! 7173: COMMND_CONFIGURE_FIFO_THRESHOLD + COMMND_CONFIGURE_DISABLE_POLLING; ! 7174: controllerData->FifoBuffer[2] = 0; ! 7175: ! 7176: ntStatus2 = FlIssueCommand( COMMND_CONFIGURE, DisketteExtension ); ! 7177: ! 7178: if ( !NT_SUCCESS( ntStatus2 ) ) { ! 7179: ! 7180: FloppyDump( ! 7181: FLOPDBGP, ! 7182: ("Floppy: restoring FIFO after r/w gave %x\n", ntStatus2) ! 7183: ); ! 7184: } ! 7185: ! 7186: } ! 7187: ! 7188: // ! 7189: // The bytesTransferred so far is correct even if there was an error. ! 7190: // ! 7191: ! 7192: Irp->IoStatus.Information = bytesTransferredSoFar; ! 7193: ! 7194: FloppyDump( ! 7195: FLOPIRPPATH, ! 7196: ("Floppy: done with read/write for irp %x extension %x\n", ! 7197: Irp,DisketteExtension) ! 7198: ); ! 7199: return ntStatus; ! 7200: } ! 7201: ! 7202: NTSTATUS ! 7203: FlFormat( ! 7204: IN PDISKETTE_EXTENSION DisketteExtension, ! 7205: IN PIRP Irp ! 7206: ) ! 7207: ! 7208: /*++ ! 7209: ! 7210: Routine Description: ! 7211: ! 7212: This routine is called by the floppy thread to format some tracks on ! 7213: the diskette. This won't take TOO long because the FORMAT utility ! 7214: is written to only format a few tracks at a time so that it can keep ! 7215: a display of what percentage of the disk has been formatted. ! 7216: ! 7217: Arguments: ! 7218: ! 7219: DisketteExtension - pointer to our data area for the diskette to be ! 7220: formatted. ! 7221: ! 7222: Irp - pointer to the IO Request Packet. ! 7223: ! 7224: Return Value: ! 7225: ! 7226: STATUS_SUCCESS if the tracks were formatted; appropriate error ! 7227: propogated otherwise. ! 7228: ! 7229: --*/ ! 7230: ! 7231: { ! 7232: LARGE_INTEGER headSettleTime; ! 7233: PCONTROLLER_DATA controllerData; ! 7234: PIO_STACK_LOCATION irpSp; ! 7235: PBAD_TRACK_NUMBER badTrackBuffer; ! 7236: PFORMAT_PARAMETERS formatParameters; ! 7237: PDRIVE_MEDIA_CONSTANTS driveMediaConstants; ! 7238: NTSTATUS ntStatus; ! 7239: ULONG badTrackBufferLength; ! 7240: DRIVE_MEDIA_TYPE driveMediaType; ! 7241: UCHAR driveStatus; ! 7242: UCHAR numberOfBadTracks = 0; ! 7243: UCHAR currentTrack; ! 7244: UCHAR endTrack; ! 7245: UCHAR whichSector; ! 7246: UCHAR retryCount; ! 7247: BOOLEAN bufferOverflow = FALSE; ! 7248: ! 7249: FloppyDump( ! 7250: FLOPSHOW, ! 7251: ("Floppy: FlFormat...\n") ! 7252: ); ! 7253: ! 7254: controllerData = DisketteExtension->ControllerData; ! 7255: formatParameters = (PFORMAT_PARAMETERS) Irp->AssociatedIrp.SystemBuffer; ! 7256: FloppyDump( ! 7257: FLOPFORMAT, ! 7258: ("Floppy: Format Params - MediaType: %d\n" ! 7259: "------ Start Cyl: %x\n" ! 7260: "------ End Cyl: %x\n" ! 7261: "------ Start Hd: %d\n" ! 7262: "------ End Hd: %d\n", ! 7263: formatParameters->MediaType, ! 7264: formatParameters->StartCylinderNumber, ! 7265: formatParameters->EndCylinderNumber, ! 7266: formatParameters->StartHeadNumber, ! 7267: formatParameters->EndHeadNumber) ! 7268: ); ! 7269: ! 7270: irpSp = IoGetCurrentIrpStackLocation( Irp ); ! 7271: badTrackBufferLength = ! 7272: irpSp->Parameters.DeviceIoControl.OutputBufferLength; ! 7273: ! 7274: // ! 7275: // Figure out which entry in the DriveMediaConstants table to use. ! 7276: // We know we'll find one, or FlCheckFormatParameters() would have ! 7277: // rejected the request. ! 7278: // ! 7279: ! 7280: driveMediaType = ! 7281: DriveMediaLimits[DisketteExtension->DriveType].HighestDriveMediaType; ! 7282: ! 7283: while ( ( DriveMediaConstants[driveMediaType].MediaType != ! 7284: formatParameters->MediaType ) && ! 7285: ( driveMediaType > DriveMediaLimits[DisketteExtension->DriveType]. ! 7286: LowestDriveMediaType ) ) { ! 7287: ! 7288: driveMediaType--; ! 7289: } ! 7290: ! 7291: driveMediaConstants = &DriveMediaConstants[driveMediaType]; ! 7292: ! 7293: // ! 7294: // Set some values in the diskette extension to indicate what we ! 7295: // know about the media type. ! 7296: // ! 7297: ! 7298: DisketteExtension->MediaType = formatParameters->MediaType; ! 7299: DisketteExtension->DriveMediaType = driveMediaType; ! 7300: DisketteExtension->DriveMediaConstants = DriveMediaConstants[driveMediaType]; ! 7301: ! 7302: driveMediaConstants = ! 7303: &DriveMediaConstants[DisketteExtension->DriveMediaType]; ! 7304: ! 7305: DisketteExtension->BytesPerSector = driveMediaConstants->BytesPerSector; ! 7306: ! 7307: DisketteExtension->ByteCapacity = ! 7308: ( driveMediaConstants->BytesPerSector ) * ! 7309: driveMediaConstants->SectorsPerTrack * ! 7310: ( 1 + driveMediaConstants->MaximumTrack ) * ! 7311: driveMediaConstants->NumberOfHeads; ! 7312: ! 7313: currentTrack = (UCHAR)( ( formatParameters->StartCylinderNumber * ! 7314: driveMediaConstants->NumberOfHeads ) + ! 7315: formatParameters->StartHeadNumber ); ! 7316: ! 7317: endTrack = (UCHAR)( ( formatParameters->EndCylinderNumber * ! 7318: driveMediaConstants->NumberOfHeads ) + ! 7319: formatParameters->EndHeadNumber ); ! 7320: ! 7321: FloppyDump( ! 7322: FLOPFORMAT, ! 7323: ("Floppy: Format - Starting/ending tracks: %x/%x\n", ! 7324: currentTrack, ! 7325: endTrack) ! 7326: ); ! 7327: ! 7328: // ! 7329: // Set the data rate (which depends on the drive/media ! 7330: // type). ! 7331: // ! 7332: ! 7333: if ( controllerData->LastDriveMediaType != driveMediaType ) { ! 7334: ! 7335: ntStatus = FlDatarateSpecifyConfigure( DisketteExtension ); ! 7336: ! 7337: if ( !NT_SUCCESS( ntStatus ) ) { ! 7338: ! 7339: return ntStatus; ! 7340: } ! 7341: } ! 7342: ! 7343: // ! 7344: // Format each track. ! 7345: // ! 7346: ! 7347: do { ! 7348: ! 7349: // ! 7350: // Seek to proper cylinder ! 7351: // ! 7352: ! 7353: controllerData->FifoBuffer[0] = DisketteExtension->DeviceUnit; ! 7354: controllerData->FifoBuffer[1] = (UCHAR)( ( currentTrack / ! 7355: driveMediaConstants->NumberOfHeads ) << ! 7356: driveMediaConstants->CylinderShift ); ! 7357: ! 7358: FloppyDump( ! 7359: FLOPFORMAT, ! 7360: ("Floppy: Format seek to cylinder: %x\n", ! 7361: controllerData->FifoBuffer[1]) ! 7362: ); ! 7363: ! 7364: ntStatus = FlIssueCommand( COMMND_SEEK, DisketteExtension ); ! 7365: ! 7366: if ( NT_SUCCESS( ntStatus ) ) { ! 7367: ! 7368: if ( ( controllerData->FifoBuffer[0] & STREG0_SEEK_COMPLETE ) && ! 7369: ( controllerData->FifoBuffer[1] == (UCHAR)( ( currentTrack / ! 7370: driveMediaConstants->NumberOfHeads ) << ! 7371: driveMediaConstants->CylinderShift ) ) ) { ! 7372: ! 7373: // ! 7374: // Must delay HeadSettleTime milliseconds before ! 7375: // doing anything after a SEEK. ! 7376: // ! 7377: ! 7378: headSettleTime.LowPart = - ( 10 * 1000 * ! 7379: driveMediaConstants->HeadSettleTime ); ! 7380: headSettleTime.HighPart = -1; ! 7381: ! 7382: KeDelayExecutionThread( ! 7383: KernelMode, ! 7384: FALSE, ! 7385: &headSettleTime ); ! 7386: ! 7387: // ! 7388: // Read ID. Note that we don't bother checking the return ! 7389: // registers, because if this media wasn't formatted we'd ! 7390: // get an error. ! 7391: // ! 7392: ! 7393: controllerData->FifoBuffer[0] = DisketteExtension->DeviceUnit; ! 7394: ! 7395: ntStatus = FlIssueCommand( ! 7396: COMMND_READ_ID + COMMND_MFM, ! 7397: DisketteExtension ); ! 7398: ! 7399: } else { ! 7400: ! 7401: FloppyDump( ! 7402: FLOPWARN, ! 7403: ("Floppy: format's seek returned bad registers\n" ! 7404: "------ Statusreg0 = %x\n" ! 7405: "------ Statusreg1 = %x\n", ! 7406: controllerData->FifoBuffer[0], ! 7407: controllerData->FifoBuffer[1]) ! 7408: ); ! 7409: ! 7410: controllerData->HardwareFailed = TRUE; ! 7411: ! 7412: ntStatus = STATUS_FLOPPY_BAD_REGISTERS; ! 7413: } ! 7414: } ! 7415: ! 7416: if ( !NT_SUCCESS( ntStatus ) ) { ! 7417: ! 7418: FloppyDump( ! 7419: FLOPWARN, ! 7420: ("Floppy: format's seek/readid returned %x\n", ntStatus) ! 7421: ); ! 7422: ! 7423: return ntStatus; ! 7424: } ! 7425: ! 7426: // ! 7427: // Fill the buffer with the format of this track. ! 7428: // ! 7429: ! 7430: for ( whichSector = 1; ! 7431: whichSector <= ! 7432: (UCHAR)( driveMediaConstants->SectorsPerTrack ); ! 7433: whichSector++ ) { ! 7434: ! 7435: controllerData->IoBuffer[( whichSector - 1 ) * 4] = ! 7436: currentTrack / driveMediaConstants->NumberOfHeads; ! 7437: controllerData->IoBuffer[( whichSector - 1 ) * 4 + 1] = ! 7438: currentTrack % driveMediaConstants->NumberOfHeads; ! 7439: controllerData->IoBuffer[( whichSector - 1 ) * 4 + 2] = ! 7440: whichSector; ! 7441: controllerData->IoBuffer[( whichSector - 1 ) * 4 + 3] = ! 7442: driveMediaConstants->SectorLengthCode; ! 7443: ! 7444: FloppyDump( ! 7445: FLOPFORMAT, ! 7446: ("Floppy - Format table entry %x - %x/%x/%x/%x\n", ! 7447: whichSector-1, ! 7448: controllerData->IoBuffer[(whichSector -1)*4], ! 7449: controllerData->IoBuffer[(whichSector -1)*4 + 1], ! 7450: controllerData->IoBuffer[(whichSector -1)*4 + 2], ! 7451: controllerData->IoBuffer[(whichSector -1)*4 + 3]) ! 7452: ); ! 7453: } ! 7454: ! 7455: // ! 7456: // Retry until success or too many retries. ! 7457: // ! 7458: ! 7459: retryCount = 0; ! 7460: ! 7461: do { ! 7462: ! 7463: ULONG length; ! 7464: ! 7465: length = driveMediaConstants->BytesPerSector; ! 7466: ! 7467: // ! 7468: // Map the transfer from the buffer to the disk. ! 7469: // ! 7470: ! 7471: KeFlushIoBuffers( controllerData->IoBufferMdl, FALSE, TRUE ); ! 7472: ! 7473: IoMapTransfer( ! 7474: controllerData->AdapterObject, ! 7475: controllerData->IoBufferMdl, ! 7476: controllerData->MapRegisterBase, ! 7477: controllerData->IoBuffer, ! 7478: &length, ! 7479: TRUE ); ! 7480: ! 7481: // ! 7482: // Issue command to format track ! 7483: // ! 7484: ! 7485: controllerData->FifoBuffer[0] = (UCHAR) ! 7486: ( ( ( currentTrack % driveMediaConstants->NumberOfHeads ) << 2 ) ! 7487: | DisketteExtension->DeviceUnit ); ! 7488: controllerData->FifoBuffer[1] = ! 7489: driveMediaConstants->SectorLengthCode; ! 7490: controllerData->FifoBuffer[2] = ! 7491: driveMediaConstants->SectorsPerTrack; ! 7492: controllerData->FifoBuffer[3] = ! 7493: driveMediaConstants->FormatGapLength; ! 7494: controllerData->FifoBuffer[4] = ! 7495: driveMediaConstants->FormatFillCharacter; ! 7496: ! 7497: FloppyDump( ! 7498: FLOPFORMAT, ! 7499: ("Floppy: format command parameters\n" ! 7500: "------ Head/Unit: %x\n" ! 7501: "------ Bytes/Sector: %x\n" ! 7502: "------ Sectors/Cylinder: %x\n" ! 7503: "------ Gap 3: %x\n" ! 7504: "------ Filler Byte: %x\n", ! 7505: controllerData->FifoBuffer[0], ! 7506: controllerData->FifoBuffer[1], ! 7507: controllerData->FifoBuffer[2], ! 7508: controllerData->FifoBuffer[3], ! 7509: controllerData->FifoBuffer[4]) ! 7510: ); ! 7511: ntStatus = FlIssueCommand( ! 7512: COMMND_FORMAT_TRACK + COMMND_MFM, ! 7513: DisketteExtension ); ! 7514: ! 7515: IoFlushAdapterBuffers( ! 7516: controllerData->AdapterObject, ! 7517: controllerData->IoBufferMdl, ! 7518: controllerData->MapRegisterBase, ! 7519: controllerData->IoBuffer, ! 7520: length, ! 7521: TRUE ); ! 7522: ! 7523: if ( !NT_SUCCESS( ntStatus ) ) { ! 7524: ! 7525: FloppyDump( ! 7526: FLOPDBGP, ! 7527: ("Floppy: format returned %x\n", ntStatus) ! 7528: ); ! 7529: } ! 7530: ! 7531: if ( NT_SUCCESS( ntStatus ) ) { ! 7532: ! 7533: // ! 7534: // Check the return bytes from the controller. ! 7535: // ! 7536: ! 7537: if ( ( controllerData->FifoBuffer[0] & ! 7538: ( STREG0_DRIVE_FAULT | ! 7539: STREG0_END_INVALID_COMMAND ) ) ! 7540: || ( controllerData->FifoBuffer[1] & ! 7541: STREG1_DATA_OVERRUN ) || ! 7542: ( controllerData->FifoBuffer[2] != 0 ) ) { ! 7543: ! 7544: FloppyDump( ! 7545: FLOPWARN, ! 7546: ("Floppy: format had bad registers\n" ! 7547: "------ Streg0 = %x\n" ! 7548: "------ Streg1 = %x\n" ! 7549: "------ Streg2 = %x\n", ! 7550: controllerData->FifoBuffer[0], ! 7551: controllerData->FifoBuffer[1], ! 7552: controllerData->FifoBuffer[2]) ! 7553: ); ! 7554: ! 7555: controllerData->HardwareFailed = TRUE; ! 7556: ! 7557: ntStatus = FlInterpretError( ! 7558: controllerData->FifoBuffer[1], ! 7559: controllerData->FifoBuffer[2] ); ! 7560: } ! 7561: } ! 7562: ! 7563: } while ( ( !NT_SUCCESS( ntStatus ) ) && ! 7564: ( retryCount++ < RECALIBRATE_RETRY_COUNT ) ); ! 7565: ! 7566: if ( !NT_SUCCESS( ntStatus ) ) { ! 7567: ! 7568: driveStatus = READ_CONTROLLER( ! 7569: &controllerData->ControllerAddress->DRDC.DiskChange ); ! 7570: ! 7571: if ( (DisketteExtension->DriveType != DRIVE_TYPE_0360) && ! 7572: (driveStatus & DSKCHG_DISKETTE_REMOVED) ) { ! 7573: ! 7574: // ! 7575: // The user apparently popped the floppy. Return error ! 7576: // rather than logging bad track. ! 7577: // ! 7578: ! 7579: return ntStatus; ! 7580: } ! 7581: ! 7582: // ! 7583: // Log the bad track. ! 7584: // ! 7585: ! 7586: FloppyDump( ! 7587: FLOPDBGP, ! 7588: ("Floppy: track %x is bad\n", currentTrack) ! 7589: ); ! 7590: ! 7591: if ( badTrackBufferLength >= (ULONG) ! 7592: ( ( numberOfBadTracks + 1 ) * sizeof( BAD_TRACK_NUMBER ) ) ) { ! 7593: ! 7594: badTrackBuffer = (PBAD_TRACK_NUMBER) ! 7595: Irp->AssociatedIrp.SystemBuffer; ! 7596: ! 7597: badTrackBuffer[numberOfBadTracks] = ( BAD_TRACK_NUMBER ) ! 7598: currentTrack; ! 7599: ! 7600: } else { ! 7601: ! 7602: bufferOverflow = TRUE; ! 7603: } ! 7604: ! 7605: numberOfBadTracks++; ! 7606: } ! 7607: ! 7608: currentTrack++; ! 7609: ! 7610: } while ( currentTrack <= endTrack ); ! 7611: ! 7612: if ( ( NT_SUCCESS( ntStatus ) ) && ( bufferOverflow ) ) { ! 7613: ! 7614: ntStatus = STATUS_BUFFER_OVERFLOW; ! 7615: } ! 7616: ! 7617: return ntStatus; ! 7618: } ! 7619: ! 7620: BOOLEAN ! 7621: FlCheckFormatParameters( ! 7622: IN PDISKETTE_EXTENSION DisketteExtension, ! 7623: IN PFORMAT_PARAMETERS FormatParameters ! 7624: ) ! 7625: ! 7626: /*++ ! 7627: ! 7628: Routine Description: ! 7629: ! 7630: This routine checks the supplied format parameters to make sure that ! 7631: they'll work on the drive to be formatted. ! 7632: ! 7633: Arguments: ! 7634: ! 7635: DisketteExtension - a pointer to our data area for the diskette to ! 7636: be formatted. ! 7637: ! 7638: FormatParameters - a pointer to the caller's parameters for the FORMAT. ! 7639: ! 7640: Return Value: ! 7641: ! 7642: TRUE if parameters are OK. ! 7643: FALSE if the parameters are bad. ! 7644: ! 7645: --*/ ! 7646: ! 7647: { ! 7648: PDRIVE_MEDIA_CONSTANTS driveMediaConstants; ! 7649: DRIVE_MEDIA_TYPE driveMediaType; ! 7650: ! 7651: // ! 7652: // Figure out which entry in the DriveMediaConstants table to use. ! 7653: // ! 7654: ! 7655: driveMediaType = ! 7656: DriveMediaLimits[DisketteExtension->DriveType].HighestDriveMediaType; ! 7657: ! 7658: while ( ( DriveMediaConstants[driveMediaType].MediaType != ! 7659: FormatParameters->MediaType ) && ! 7660: ( driveMediaType > DriveMediaLimits[DisketteExtension->DriveType]. ! 7661: LowestDriveMediaType ) ) { ! 7662: ! 7663: driveMediaType--; ! 7664: } ! 7665: ! 7666: if ( DriveMediaConstants[driveMediaType].MediaType != ! 7667: FormatParameters->MediaType ) { ! 7668: ! 7669: return FALSE; ! 7670: ! 7671: } else { ! 7672: ! 7673: driveMediaConstants = &DriveMediaConstants[driveMediaType]; ! 7674: ! 7675: if ( ( FormatParameters->StartHeadNumber > ! 7676: (ULONG)( driveMediaConstants->NumberOfHeads - 1 ) ) || ! 7677: ( FormatParameters->EndHeadNumber > ! 7678: (ULONG)( driveMediaConstants->NumberOfHeads - 1 ) ) || ! 7679: ( FormatParameters->StartCylinderNumber > ! 7680: driveMediaConstants->MaximumTrack ) || ! 7681: ( FormatParameters->EndCylinderNumber > ! 7682: driveMediaConstants->MaximumTrack ) || ! 7683: ( FormatParameters->EndCylinderNumber < ! 7684: FormatParameters->StartCylinderNumber ) ) { ! 7685: ! 7686: return FALSE; ! 7687: ! 7688: } else { ! 7689: ! 7690: return TRUE; ! 7691: } ! 7692: } ! 7693: } ! 7694: ! 7695: VOID ! 7696: FloppyUnloadDriver( ! 7697: IN PDRIVER_OBJECT DriverObject ! 7698: ) ! 7699: ! 7700: /*++ ! 7701: ! 7702: Routine Description: ! 7703: ! 7704: This routine is called by the system to remove the driver from memory. ! 7705: ! 7706: When this routine is called, there is no I/O being done to this device. ! 7707: The driver object is passed in, and from this the driver can find and ! 7708: delete all of its device objects, extensions, etc. ! 7709: ! 7710: Arguments: ! 7711: ! 7712: DriverObject - a pointer to the object associated with this device ! 7713: driver. ! 7714: ! 7715: Return Value: ! 7716: ! 7717: None. ! 7718: ! 7719: --*/ ! 7720: ! 7721: { ! 7722: UNREFERENCED_PARAMETER( DriverObject ); ! 7723: ! 7724: // signal FloppyThread() to unload itself ! 7725: // disable interrupts from controller(s?) ! 7726: // delete everything that's been allocated ! 7727: } ! 7728: ! 7729: PCONTROLLER ! 7730: FlGetControllerBase( ! 7731: IN INTERFACE_TYPE BusType, ! 7732: IN ULONG BusNumber, ! 7733: PHYSICAL_ADDRESS IoAddress, ! 7734: ULONG NumberOfBytes, ! 7735: BOOLEAN InIoSpace, ! 7736: PBOOLEAN MappedAddress ! 7737: ) ! 7738: ! 7739: /*++ ! 7740: ! 7741: Routine Description: ! 7742: ! 7743: This routine maps an IO address to system address space. ! 7744: ! 7745: Arguments: ! 7746: ! 7747: BusType - what type of bus - eisa, mca, isa ! 7748: IoBusNumber - which IO bus (for machines with multiple buses). ! 7749: IoAddress - base device address to be mapped. ! 7750: NumberOfBytes - number of bytes for which address is valid. ! 7751: InIoSpace - indicates an IO address. ! 7752: MappedAddress - indicates whether the address was mapped. ! 7753: This only has meaning if the address returned ! 7754: is non-null. ! 7755: ! 7756: Return Value: ! 7757: ! 7758: Mapped address ! 7759: ! 7760: --*/ ! 7761: ! 7762: { ! 7763: PHYSICAL_ADDRESS cardAddress; ! 7764: ULONG addressSpace = InIoSpace; ! 7765: PCONTROLLER Address; ! 7766: ! 7767: HalTranslateBusAddress( ! 7768: BusType, ! 7769: BusNumber, ! 7770: IoAddress, ! 7771: &addressSpace, ! 7772: &cardAddress ! 7773: ); ! 7774: ! 7775: // ! 7776: // Map the device base address into the virtual address space ! 7777: // if the address is in memory space. ! 7778: // ! 7779: ! 7780: if (!addressSpace) { ! 7781: ! 7782: Address = MmMapIoSpace( ! 7783: cardAddress, ! 7784: NumberOfBytes, ! 7785: FALSE ! 7786: ); ! 7787: ! 7788: *MappedAddress = !!Address; ! 7789: ! 7790: ! 7791: } else { ! 7792: ! 7793: Address = (PCONTROLLER)cardAddress.LowPart; ! 7794: *MappedAddress = FALSE; ! 7795: ! 7796: } ! 7797: ! 7798: return Address; ! 7799: ! 7800: } ! 7801: ! 7802: VOID ! 7803: FlLogErrorDpc( ! 7804: IN PKDPC Dpc, ! 7805: IN PVOID DeferredContext, ! 7806: IN PVOID SystemContext1, ! 7807: IN PVOID SystemContext2 ! 7808: ) ! 7809: ! 7810: /*++ ! 7811: ! 7812: Routine Description: ! 7813: ! 7814: This routine is merely used to log an error that we had to reset the device. ! 7815: ! 7816: Arguments: ! 7817: ! 7818: Dpc - The dpc object. ! 7819: ! 7820: DeferredContext - A pointer to the controller data. ! 7821: ! 7822: SystemContext1 - Unused. ! 7823: ! 7824: SystemContext2 - Unused. ! 7825: ! 7826: Return Value: ! 7827: ! 7828: Mapped address ! 7829: ! 7830: --*/ ! 7831: ! 7832: { ! 7833: ! 7834: PIO_ERROR_LOG_PACKET errorLogEntry; ! 7835: PCONTROLLER_DATA controllerData = DeferredContext; ! 7836: ! 7837: errorLogEntry = IoAllocateErrorLogEntry( ! 7838: controllerData->DriverObject, ! 7839: (UCHAR)(sizeof(IO_ERROR_LOG_PACKET)) ! 7840: ); ! 7841: ! 7842: if ( errorLogEntry != NULL) { ! 7843: ! 7844: errorLogEntry->ErrorCode = IO_ERR_RESET; ! 7845: errorLogEntry->SequenceNumber = 0; ! 7846: errorLogEntry->MajorFunctionCode = 0; ! 7847: errorLogEntry->RetryCount = 0; ! 7848: errorLogEntry->UniqueErrorValue = 0; ! 7849: errorLogEntry->FinalStatus = STATUS_SUCCESS; ! 7850: errorLogEntry->DumpDataSize = 0; ! 7851: ! 7852: IoWriteErrorLogEntry(errorLogEntry); ! 7853: ! 7854: } ! 7855: ! 7856: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.