Annotation of ntddk/src/scsi/floppy/floppy.c, revision 1.1

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:             &paramTable[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:                             &paramTable[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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.