ReactOS 0.4.15-dev-7788-g1ad9096
readwrite.c
Go to the documentation of this file.
1/*
2 * ReactOS Floppy Driver
3 * Copyright (C) 2004, Vizzini (vizzini@plasmic.com)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * PROJECT: ReactOS Floppy Driver
20 * FILE: readwrite.c
21 * PURPOSE: Read/Write handler routines
22 * PROGRAMMER: Vizzini (vizzini@plasmic.com)
23 * REVISIONS:
24 * 15-Feb-2004 vizzini - Created
25 * NOTES:
26 *
27 * READ/WRITE PROCESS
28 *
29 * This process is extracted from the Intel datasheet for the floppy controller.
30 *
31 * - Turn on the motor and set turnoff time
32 * - Program the drive's data rate
33 * - Seek
34 * - Read ID
35 * - Set up DMA
36 * - Send read/write command to FDC
37 * - Read result bytes
38 *
39 * This is mostly implemented in one big function, which watis on the SynchEvent
40 * as many times as necessary to get through the process. See ReadWritePassive() for
41 * more details.
42 *
43 * NOTES:
44 * - Currently doesn't support partial-sector transfers, which is really just a failing
45 * of RWComputeCHS. I've never seen Windows send a partial-sector request, though, so
46 * this may not be a bad thing. Should be looked into, regardless.
47 *
48 * TODO: Break up ReadWritePassive and handle errors better
49 * TODO: Figure out data rate issues
50 * TODO: Media type detection
51 * TODO: Figure out perf issue - waiting after call to read/write for about a second each time
52 * TODO: Figure out specify timings
53 */
54
55#include "precomp.h"
56
57#include <debug.h>
58
61 PIRP Irp,
64/*
65 * FUNCTION: Acquire map registers in prep for DMA
66 * ARGUMENTS:
67 * DeviceObject: unused
68 * Irp: unused
69 * MapRegisterBase: returned to blocked thread via a member var
70 * Context: contains a pointer to the right ControllerInfo
71 * struct
72 * RETURNS:
73 * KeepObject, because that's what the DDK says to do
74 */
75{
79
80 TRACE_(FLOPPY, "MapRegisterCallback Called\n");
81
82 ControllerInfo->MapRegisterBase = MapRegisterBase;
83 KeSetEvent(&ControllerInfo->SynchEvent, 0, FALSE);
84
85 return KeepObject;
86}
87
88
91/*
92 * FUNCTION: Dispatch routine called for read or write IRPs
93 * ARGUMENTS:
94 * RETURNS:
95 * STATUS_PENDING if the IRP is queued
96 * STATUS_INVALID_PARAMETER if IRP is set up wrong
97 * NOTES:
98 * - This function validates arguments to the IRP and then queues it
99 * - Note that this function is implicitly serialized by the queue logic. Only
100 * one of these at a time is active in the system, no matter how many processors
101 * and threads we have.
102 * - This function stores the DeviceObject in the IRP's context area before dropping
103 * it onto the irp queue
104 */
105{
106 TRACE_(FLOPPY, "ReadWrite called\n");
107
109 ASSERT(Irp);
110
111 if(!Irp->MdlAddress)
112 {
113 WARN_(FLOPPY, "ReadWrite(): MDL not found in IRP - Completing with STATUS_INVALID_PARAMETER\n");
114 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
115 Irp->IoStatus.Information = 0;
118 }
119
120 /*
121 * Queue the irp to the thread.
122 * The de-queue thread will look in DriverContext[0] for the Device Object.
123 */
124 Irp->Tail.Overlay.DriverContext[0] = DeviceObject;
126
127 return STATUS_PENDING;
128}
129
130
131static VOID NTAPI
133/*
134 * FUNCTION: Free the adapter DMA channel that we allocated
135 * ARGUMENTS:
136 * AdapterObject: the object with the map registers to free
137 * NOTES:
138 * - This function is primarily needed because IoFreeAdapterChannel wants to
139 * be called at DISPATCH_LEVEL
140 */
141{
142 KIRQL Irql;
143
145
147 IoFreeAdapterChannel(AdapterObject);
149}
150
151
154/*
155 * FUNCTION: Determine the media type of the disk in the drive and fill in the geometry
156 * ARGUMENTS:
157 * DriveInfo: drive to look at
158 * RETURNS:
159 * STATUS_SUCCESS if the media was recognized and the geometry struct was filled in
160 * STATUS_UNRECOGNIZED_MEDIA if not
161 * STATUS_UNSUCCESSFUL if the controller can't be talked to
162 * NOTES:
163 * - Expects the motor to already be running
164 * - Currently only supports 1.44MB 3.5" disks
165 * - PAGED_CODE because it waits
166 * TODO:
167 * - Support more disk types
168 */
169{
170 UCHAR HeadLoadTime;
171 UCHAR HeadUnloadTime;
172 UCHAR StepRateTime;
174
175 PAGED_CODE();
176
177 TRACE_(FLOPPY, "RWDetermineMediaType called\n");
178
179 /*
180 * This algorithm assumes that a 1.44MB floppy is in the drive. If it's not,
181 * it works backwards until the read works unless OneShot try is asked.
182 * Note that only 1.44 has been tested at all.
183 */
184
185 Timeout.QuadPart = -10000000; /* 1 second. Is that enough? */
186
187 do
188 {
189 int i;
191
192 /* Program data rate */
194 {
195 WARN_(FLOPPY, "RWDetermineMediaType(): unable to set data rate\n");
196 return STATUS_UNSUCCESSFUL;
197 }
198
199 /* Specify */
200 HeadLoadTime = SPECIFY_HLT_500K;
201 HeadUnloadTime = SPECIFY_HUT_500K;
202 StepRateTime = SPECIFY_SRT_500K;
203
204 /* Don't disable DMA --> enable dma (dumb & confusing) */
205 if(HwSpecify(DriveInfo->ControllerInfo, HeadLoadTime, HeadUnloadTime, StepRateTime, FALSE) != STATUS_SUCCESS)
206 {
207 WARN_(FLOPPY, "RWDetermineMediaType(): specify failed\n");
208 return STATUS_UNSUCCESSFUL;
209 }
210
211 /* clear any spurious interrupts in preparation for recalibrate */
212 KeClearEvent(&DriveInfo->ControllerInfo->SynchEvent);
213
214 /* Recalibrate --> head over first track */
215 for(i=0; i < 2; i++)
216 {
217 NTSTATUS RecalStatus;
218
219 if(HwRecalibrate(DriveInfo) != STATUS_SUCCESS)
220 {
221 WARN_(FLOPPY, "RWDetermineMediaType(): Recalibrate failed\n");
222 return STATUS_UNSUCCESSFUL;
223 }
224
225 /* Wait for the recalibrate to finish */
227
228 RecalStatus = HwRecalibrateResult(DriveInfo->ControllerInfo);
229
230 if(RecalStatus == STATUS_SUCCESS)
231 break;
232
233 if(i == 1) /* failed for 2nd time */
234 {
235 WARN_(FLOPPY, "RWDetermineMediaType(): RecalibrateResult failed\n");
236 return STATUS_UNSUCCESSFUL;
237 }
238 }
239
240 /* clear any spurious interrupts */
241 KeClearEvent(&DriveInfo->ControllerInfo->SynchEvent);
242
243 /* Try to read an ID */
244 if(HwReadId(DriveInfo, 0) != STATUS_SUCCESS) /* read the first ID we find, from head 0 */
245 {
246 WARN_(FLOPPY, "RWDetermineMediaType(): ReadId failed\n");
247 return STATUS_UNSUCCESSFUL; /* if we can't even write to the controller, it's hopeless */
248 }
249
250 /* Wait for the ReadID to finish */
252
254 {
255 WARN_(FLOPPY, "RWDetermineMediaType(): ReadIdResult failed; continuing\n");
256 if (OneShot)
257 break;
258 else
259 continue;
260 }
261
262 /* Found the media; populate the geometry now */
263 WARN_(FLOPPY, "Hardcoded media type!\n");
264 INFO_(FLOPPY, "RWDetermineMediaType(): Found 1.44 media; returning success\n");
271 return STATUS_SUCCESS;
272 }
273 while(TRUE);
274
275 TRACE_(FLOPPY, "RWDetermineMediaType(): failed to find media\n");
277}
278
279
280static NTSTATUS NTAPI
282/*
283 * FUNCTION: Seek a particular drive to a particular track
284 * ARGUMENTS:
285 * DriveInfo: Drive to seek
286 * Cylinder: track to seek to
287 * RETURNS:
288 * STATUS_SUCCESS if the head was successfully seeked
289 * STATUS_UNSUCCESSFUL if not
290 * NOTES:
291 * - PAGED_CODE because it blocks
292 */
293{
294 UCHAR CurCylinder;
295
296 PAGED_CODE();
297
298 TRACE_(FLOPPY, "RWSeekToCylinder called drive 0x%p cylinder %d\n", DriveInfo, Cylinder);
299
300 /* Clear any spurious interrupts */
301 KeClearEvent(&DriveInfo->ControllerInfo->SynchEvent);
302
303 /* queue seek command */
304 if(HwSeek(DriveInfo, Cylinder) != STATUS_SUCCESS)
305 {
306 WARN_(FLOPPY, "RWSeekToTrack(): unable to seek\n");
307 return STATUS_UNSUCCESSFUL;
308 }
309
311
313 {
314 WARN_(FLOPPY, "RWSeekToTrack(): unable to get seek results\n");
315 return STATUS_UNSUCCESSFUL;
316 }
317
318 /* read ID mark from head 0 to verify */
319 if(HwReadId(DriveInfo, 0) != STATUS_SUCCESS)
320 {
321 WARN_(FLOPPY, "RWSeekToTrack(): unable to queue ReadId\n");
322 return STATUS_UNSUCCESSFUL;
323 }
324
326
327 if(HwReadIdResult(DriveInfo->ControllerInfo, &CurCylinder, NULL) != STATUS_SUCCESS)
328 {
329 WARN_(FLOPPY, "RWSeekToTrack(): unable to get ReadId result\n");
330 return STATUS_UNSUCCESSFUL;
331 }
332
333 if(CurCylinder != Cylinder)
334 {
335 WARN_(FLOPPY, "RWSeekToTrack(): Seek to track failed; current cylinder is 0x%x\n", CurCylinder);
336 return STATUS_UNSUCCESSFUL;
337 }
338
339 INFO_(FLOPPY, "RWSeekToCylinder: returning successfully, now on cyl %d\n", Cylinder);
340
341 return STATUS_SUCCESS;
342}
343
344
345static NTSTATUS NTAPI
347 ULONG IN DiskByteOffset,
348 PUCHAR OUT Cylinder,
349 PUCHAR OUT Head,
350 PUCHAR OUT Sector)
351/*
352 * FUNCTION: Compute the CHS from the absolute byte offset on disk
353 * ARGUMENTS:
354 * DriveInfo: Drive to compute on
355 * DiskByteOffset: Absolute offset on disk of the starting byte
356 * Cylinder: Cylinder that the byte is on
357 * Head: Head that the byte is on
358 * Sector: Sector that the byte is on
359 * RETURNS:
360 * STATUS_SUCCESS if CHS are determined correctly
361 * STATUS_UNSUCCESSFUL otherwise
362 * NOTES:
363 * - Lots of ugly typecasts here
364 * - Sectors are 1-based!
365 * - This is really crummy code. Please FIXME.
366 */
367{
368 ULONG AbsoluteSector;
369 UCHAR SectorsPerCylinder = (UCHAR)DriveInfo->DiskGeometry.SectorsPerTrack * (UCHAR)DriveInfo->DiskGeometry.TracksPerCylinder;
370
371 TRACE_(FLOPPY, "RWComputeCHS: Called with offset 0x%x\n", DiskByteOffset);
372
373 /* First calculate the 1-based "absolute sector" based on the byte offset */
374 ASSERT(!(DiskByteOffset % DriveInfo->DiskGeometry.BytesPerSector)); /* FIXME: Only handle full sector transfers atm */
375
376 /* AbsoluteSector is zero-based to make the math a little easier */
377 AbsoluteSector = DiskByteOffset / DriveInfo->DiskGeometry.BytesPerSector; /* Num full sectors */
378
379 /* Cylinder number is floor(AbsoluteSector / SectorsPerCylinder) */
380 *Cylinder = (CHAR)(AbsoluteSector / SectorsPerCylinder);
381
382 /* Head number is 0 if the sector within the cylinder < SectorsPerTrack; 1 otherwise */
383 *Head = AbsoluteSector % SectorsPerCylinder < DriveInfo->DiskGeometry.SectorsPerTrack ? 0 : 1;
384
385 /*
386 * Sector number is the sector within the cylinder if on head 0; that minus SectorsPerTrack if it's on head 1
387 * (lots of casts to placate msvc). 1-based!
388 */
389 *Sector = ((UCHAR)(AbsoluteSector % SectorsPerCylinder) + 1) - ((*Head) * (UCHAR)DriveInfo->DiskGeometry.SectorsPerTrack);
390
391 INFO_(FLOPPY, "RWComputeCHS: offset 0x%x is c:0x%x h:0x%x s:0x%x\n", DiskByteOffset, *Cylinder, *Head, *Sector);
392
393 /* Sanity checking */
394 ASSERT(*Cylinder <= DriveInfo->DiskGeometry.Cylinders.QuadPart);
395 ASSERT(*Head <= DriveInfo->DiskGeometry.TracksPerCylinder);
396 ASSERT(*Sector <= DriveInfo->DiskGeometry.SectorsPerTrack);
397
398 return STATUS_SUCCESS;
399}
400
401
404/*
405 * FUNCTION: Handle the first phase of a read or write IRP
406 * ARGUMENTS:
407 * DeviceObject: DeviceObject that is the target of the IRP
408 * Irp: IRP to process
409 * RETURNS:
410 * STATUS_VERIFY_REQUIRED if the media has changed and we need the filesystems to re-synch
411 * STATUS_SUCCESS otherwise
412 * NOTES:
413 * - Must be called at PASSIVE_LEVEL
414 * - This function is about 250 lines longer than I wanted it to be. Sorry.
415 *
416 * DETAILS:
417 * This routine manages the whole process of servicing a read or write request. It goes like this:
418 * 1) Check the DO_VERIFY_VOLUME flag and return if it's set
419 * 2) Check the disk change line and notify the OS if it's set and return
420 * 3) Detect the media if we haven't already
421 * 4) Set up DiskByteOffset, Length, and WriteToDevice parameters
422 * 5) Get DMA map registers
423 * 6) Then, in a loop for each track, until all bytes are transferred:
424 * a) Compute the current CHS to set the read/write head to
425 * b) Seek to that spot
426 * c) Compute the last sector to transfer on that track
427 * d) Map the transfer through DMA
428 * e) Send the read or write command to the controller
429 * f) Read the results of the command
430 */
431{
436 ULONG DiskByteOffset;
439 BOOLEAN DiskChanged;
440 ULONG_PTR TransferByteOffset;
441 UCHAR Gap;
442
443 PAGED_CODE();
444
445 TRACE_(FLOPPY, "ReadWritePassive called to %s 0x%x bytes from offset 0x%x\n",
446 (Stack->MajorFunction == IRP_MJ_READ ? "read" : "write"),
447 (Stack->MajorFunction == IRP_MJ_READ ? Stack->Parameters.Read.Length : Stack->Parameters.Write.Length),
448 (Stack->MajorFunction == IRP_MJ_READ ? Stack->Parameters.Read.ByteOffset.u.LowPart :
449 Stack->Parameters.Write.ByteOffset.u.LowPart));
450
451 /* Default return codes */
452 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
453 Irp->IoStatus.Information = 0;
454
455 /*
456 * Check to see if the volume needs to be verified. If so,
457 * we can get out of here quickly.
458 */
460 {
461 INFO_(FLOPPY, "ReadWritePassive(): DO_VERIFY_VOLUME set; Completing with STATUS_VERIFY_REQUIRED\n");
462 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
464 return;
465 }
466
467 /*
468 * Check the change line, and if it's set, return
469 */
470 StartMotor(DriveInfo);
471 if(HwDiskChanged(DeviceObject->DeviceExtension, &DiskChanged) != STATUS_SUCCESS)
472 {
473 WARN_(FLOPPY, "ReadWritePassive(): unable to detect disk change; Completing with STATUS_UNSUCCESSFUL\n");
475 StopMotor(DriveInfo->ControllerInfo);
476 return;
477 }
478
479 if(DiskChanged)
480 {
481 INFO_(FLOPPY, "ReadWritePhase1(): detected disk changed: signalling media change and completing\n");
482
483 /* The following call sets IoStatus.Status and IoStatus.Information */
485 ResetChangeFlag(DriveInfo);
486
488 StopMotor(DriveInfo->ControllerInfo);
489 return;
490 }
491
492 /*
493 * Figure out the media type, if we don't know it already
494 */
495 if(DriveInfo->DiskGeometry.MediaType == Unknown)
496 {
497 if(RWDetermineMediaType(DriveInfo, FALSE) != STATUS_SUCCESS)
498 {
499 WARN_(FLOPPY, "ReadWritePassive(): unable to determine media type; completing with STATUS_UNSUCCESSFUL\n");
501 StopMotor(DriveInfo->ControllerInfo);
502 return;
503 }
504
505 if(DriveInfo->DiskGeometry.MediaType == Unknown)
506 {
507 WARN_(FLOPPY, "ReadWritePassive(): Unknown media in drive; completing with STATUS_UNRECOGNIZED_MEDIA\n");
508 Irp->IoStatus.Status = STATUS_UNRECOGNIZED_MEDIA;
510 StopMotor(DriveInfo->ControllerInfo);
511 return;
512 }
513 }
514
515 /* Set up parameters for read or write */
516 if(Stack->MajorFunction == IRP_MJ_READ)
517 {
518 Length = Stack->Parameters.Read.Length;
519 DiskByteOffset = Stack->Parameters.Read.ByteOffset.u.LowPart;
521 }
522 else
523 {
524 Length = Stack->Parameters.Write.Length;
525 DiskByteOffset = Stack->Parameters.Write.ByteOffset.u.LowPart;
527 }
528
529 /*
530 * FIXME:
531 * FloppyDeviceData.ReadWriteGapLength specify the value for the physical drive.
532 * We should set this value depend on the format of the inserted disk and possible
533 * depend on the request (read or write). A value of 0 results in one rotation
534 * between the sectors (7.2sec for reading a track).
535 */
536 Gap = DriveInfo->FloppyDeviceData.ReadWriteGapLength;
537
538 /*
539 * Set up DMA transfer
540 *
541 * This is as good of a place as any to document something that used to confuse me
542 * greatly (and I even wrote some of the kernel's DMA code, so if it confuses me, it
543 * probably confuses at least a couple of other people too).
544 *
545 * MmGetMdlVirtualAddress() returns the virtual address, as mapped in the buffer's original
546 * process context, of the MDL. In other words: say you start with a buffer at address X, then
547 * you build an MDL out of that buffer called Mdl. If you call MmGetMdlVirtualAddress(Mdl), it
548 * will return X.
549 *
550 * There are two parameters that the function looks at to produce X again, given the MDL: the
551 * first is the StartVa, which is the base virtual address of the page that the buffer starts
552 * in. If your buffer's virtual address is 0x12345678, StartVa will be 0x12345000, assuming 4K pages
553 * (which is (almost) always the case on x86). Note well: this address is only valid in the
554 * process context that you initially built the MDL from. The physical pages that make up
555 * the MDL might perhaps be mapped in other process contexts too (or even in the system space,
556 * above 0x80000000 (default; 0xc0000000 on current ReactOS or /3GB Windows)), but it will
557 * (possibly) be mapped at a different address.
558 *
559 * The second parameter is the ByteOffset. Given an original buffer address of 0x12345678,
560 * the ByteOffset would be 0x678. Because MDLs can only describe full pages (and therefore
561 * StartVa always points to the start address of a page), the ByteOffset must be used to
562 * find the real start of the buffer.
563 *
564 * In general, if you add the StartVa and ByteOffset together, you get back your original
565 * buffer pointer, which you are free to use if you're sure you're in the right process
566 * context. You could tell by accessing the (hidden and not-to-be-used) Process member of
567 * the MDL, but in general, if you have to ask whether or not you are in the right context,
568 * then you shouldn't be using this address for anything anyway. There are also security implications
569 * (big ones, really, I wouldn't kid about this) to directly accessing a user's buffer by VA, so
570 * Don't Do That.
571 *
572 * There is a somewhat weird but very common use of the virtual address associated with a MDL
573 * that pops up often in the context of DMA. DMA APIs (particularly MapTransfer()) need to
574 * know where the memory is that they should DMA into and out of. This memory is described
575 * by a MDL. The controller eventually needs to know a physical address on the host side,
576 * which is generally a 32-bit linear address (on x86), and not just a page address. Therefore,
577 * the DMA APIs look at the ByteOffset field of the MDL to reconstruct the real address that
578 * should be programmed into the DMA controller.
579 *
580 * It is often the case that a transfer needs to be broken down over more than one DMA operation,
581 * particularly when it is a big transfer and the HAL doesn't give you enough map registers
582 * to map the whole thing at once. Therefore, the APIs need a way to tell how far into the MDL
583 * they should look to transfer the next chunk of bytes. Now, Microsoft could have designed
584 * MapTransfer to take a "MDL offset" argument, starting with 0, for how far into the buffer to
585 * start, but it didn't. Instead, MapTransfer asks for the virtual address of the MDL as an "index" into
586 * the MDL. The way it computes how far into the page to start the transfer is by masking off all but
587 * the bottom 12 bits (on x86) of the number you supply as the CurrentVa and using *that* as the
588 * ByteOffset instead of the one in the MDL. (OK, this varies a bit by OS and version, but this
589 * is the effect).
590 *
591 * In other words, you get a number back from MmGetMdlVirtualAddress that represents the start of your
592 * buffer, and you pass it to the first MapTransfer call. Then, for each successive operation
593 * on the same buffer, you increment that address to point to the next spot in the MDL that
594 * you want to DMA to/from. The fact that the virtual address you're manipulating is probably not
595 * mapped into the process context that you're running in is irrelevant, since it's only being
596 * used to index into the MDL.
597 */
598
599 /* Get map registers for DMA */
601 Status = IoAllocateAdapterChannel(DriveInfo->ControllerInfo->AdapterObject, DeviceObject,
602 DriveInfo->ControllerInfo->MapRegisters, MapRegisterCallback, DriveInfo->ControllerInfo);
604
606 {
607 WARN_(FLOPPY, "ReadWritePassive(): unable allocate an adapter channel; completing with STATUS_UNSUCCESSFUL\n");
609 StopMotor(DriveInfo->ControllerInfo);
610 return ;
611 }
612
613
614 /*
615 * Read from (or write to) the device
616 *
617 * This has to be called in a loop, as you can only transfer data to/from a single track at
618 * a time.
619 */
620 TransferByteOffset = 0;
621 while(TransferByteOffset < Length)
622 {
623 UCHAR Cylinder;
624 UCHAR Head;
625 UCHAR StartSector;
626 ULONG CurrentTransferBytes;
627 UCHAR CurrentTransferSectors;
628
629 INFO_(FLOPPY, "ReadWritePassive(): iterating in while (TransferByteOffset = 0x%x of 0x%x total) - allocating %d registers\n",
630 TransferByteOffset, Length, DriveInfo->ControllerInfo->MapRegisters);
631
632 KeClearEvent(&DriveInfo->ControllerInfo->SynchEvent);
633
634 /*
635 * Compute starting CHS
636 */
637 if(RWComputeCHS(DriveInfo, DiskByteOffset+TransferByteOffset, &Cylinder, &Head, &StartSector) != STATUS_SUCCESS)
638 {
639 WARN_(FLOPPY, "ReadWritePassive(): unable to compute CHS; completing with STATUS_UNSUCCESSFUL\n");
640 RWFreeAdapterChannel(DriveInfo->ControllerInfo->AdapterObject);
642 StopMotor(DriveInfo->ControllerInfo);
643 return;
644 }
645
646 /*
647 * Seek to the right track
648 */
649 if(!DriveInfo->ControllerInfo->ImpliedSeeks)
650 {
651 if(RWSeekToCylinder(DriveInfo, Cylinder) != STATUS_SUCCESS)
652 {
653 WARN_(FLOPPY, "ReadWritePassive(): unable to seek; completing with STATUS_UNSUCCESSFUL\n");
654 RWFreeAdapterChannel(DriveInfo->ControllerInfo->AdapterObject);
656 StopMotor(DriveInfo->ControllerInfo);
657 return ;
658 }
659 }
660
661 /*
662 * Compute last sector
663 *
664 * We can only ask for a transfer up to the end of the track. Then we have to re-seek and do more.
665 * TODO: Support the MT bit
666 */
667 INFO_(FLOPPY, "ReadWritePassive(): computing number of sectors to transfer (StartSector 0x%x): ", StartSector);
668
669 /* 1-based sector number */
670 if( (((DriveInfo->DiskGeometry.TracksPerCylinder - Head) * DriveInfo->DiskGeometry.SectorsPerTrack - StartSector) + 1 ) <
671 (Length - TransferByteOffset) / DriveInfo->DiskGeometry.BytesPerSector)
672 {
673 CurrentTransferSectors = (UCHAR)((DriveInfo->DiskGeometry.TracksPerCylinder - Head) * DriveInfo->DiskGeometry.SectorsPerTrack - StartSector) + 1;
674 }
675 else
676 {
677 CurrentTransferSectors = (UCHAR)((Length - TransferByteOffset) / DriveInfo->DiskGeometry.BytesPerSector);
678 }
679
680 INFO_(FLOPPY, "0x%x\n", CurrentTransferSectors);
681
682 CurrentTransferBytes = CurrentTransferSectors * DriveInfo->DiskGeometry.BytesPerSector;
683
684 /*
685 * Adjust to map registers
686 * BUG: Does this take into account page crossings?
687 */
688 INFO_(FLOPPY, "ReadWritePassive(): Trying to transfer 0x%x bytes\n", CurrentTransferBytes);
689
690 ASSERT(CurrentTransferBytes);
691
692 if(BYTES_TO_PAGES(CurrentTransferBytes) > DriveInfo->ControllerInfo->MapRegisters)
693 {
694 CurrentTransferSectors = (UCHAR)((DriveInfo->ControllerInfo->MapRegisters * PAGE_SIZE) /
695 DriveInfo->DiskGeometry.BytesPerSector);
696
697 CurrentTransferBytes = CurrentTransferSectors * DriveInfo->DiskGeometry.BytesPerSector;
698
699 INFO_(FLOPPY, "ReadWritePassive: limiting transfer to 0x%x bytes (0x%x sectors) due to map registers\n",
700 CurrentTransferBytes, CurrentTransferSectors);
701 }
702
703 /* set up this round's dma operation */
704 /* param 2 is ReadOperation --> opposite of WriteToDevice that IoMapTransfer takes. BAD MS. */
705 KeFlushIoBuffers(Irp->MdlAddress, !WriteToDevice, TRUE);
706
707 IoMapTransfer(DriveInfo->ControllerInfo->AdapterObject, Irp->MdlAddress,
708 DriveInfo->ControllerInfo->MapRegisterBase,
709 (PVOID)((ULONG_PTR)MmGetMdlVirtualAddress(Irp->MdlAddress) + TransferByteOffset),
710 &CurrentTransferBytes, WriteToDevice);
711
712 /*
713 * Read or Write
714 */
715 KeClearEvent(&DriveInfo->ControllerInfo->SynchEvent);
716
717 /* Issue the read/write command to the controller. Note that it expects the opposite of WriteToDevice. */
718 if(HwReadWriteData(DriveInfo->ControllerInfo, !WriteToDevice, DriveInfo->UnitNumber, Cylinder, Head, StartSector,
719 DriveInfo->BytesPerSectorCode, DriveInfo->DiskGeometry.SectorsPerTrack, Gap, 0xff) != STATUS_SUCCESS)
720 {
721 WARN_(FLOPPY, "ReadWritePassive(): HwReadWriteData returned failure; unable to read; completing with STATUS_UNSUCCESSFUL\n");
722 RWFreeAdapterChannel(DriveInfo->ControllerInfo->AdapterObject);
724 StopMotor(DriveInfo->ControllerInfo);
725 return ;
726 }
727
728 INFO_(FLOPPY, "ReadWritePassive(): HwReadWriteData returned -- waiting on event\n");
729
730 /*
731 * At this point, we block and wait for an interrupt
732 * FIXME: this seems to take too long
733 */
735
736 /* Read is complete; flush & free adapter channel */
737 IoFlushAdapterBuffers(DriveInfo->ControllerInfo->AdapterObject, Irp->MdlAddress,
738 DriveInfo->ControllerInfo->MapRegisterBase,
739 (PVOID)((ULONG_PTR)MmGetMdlVirtualAddress(Irp->MdlAddress) + TransferByteOffset),
740 CurrentTransferBytes, WriteToDevice);
741
742 /* Read the results from the drive */
744 {
745 WARN_(FLOPPY, "ReadWritePassive(): HwReadWriteResult returned failure; unable to read; completing with STATUS_UNSUCCESSFUL\n");
747 RWFreeAdapterChannel(DriveInfo->ControllerInfo->AdapterObject);
749 StopMotor(DriveInfo->ControllerInfo);
750 return ;
751 }
752
753 TransferByteOffset += CurrentTransferBytes;
754 }
755
756 RWFreeAdapterChannel(DriveInfo->ControllerInfo->AdapterObject);
757
758 /* That's all folks! */
759 INFO_(FLOPPY, "ReadWritePassive(): success; Completing with STATUS_SUCCESS\n");
760 Irp->IoStatus.Status = STATUS_SUCCESS;
761 Irp->IoStatus.Information = Length;
763 StopMotor(DriveInfo->ControllerInfo);
764}
#define PAGED_CODE()
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
#define CHAR(Char)
return
Definition: dirsup.c:529
_In_ PSCSI_REQUEST_BLOCK _In_opt_ PVOID _In_ ULONG _In_ BOOLEAN WriteToDevice
Definition: cdrom.h:992
_In_ PIRP Irp
Definition: csq.h:116
_Out_ PKIRQL Irql
Definition: csq.h:179
NTKERNELAPI VOID NTAPI IoCsqInsertIrp(_Inout_ PIO_CSQ Csq, _Inout_ PIRP Irp, _Out_opt_ PIO_CSQ_IRP_CONTEXT Context)
Insert an IRP into the CSQ.
Definition: csq.c:177
IO_CSQ Csq
Definition: csqrtns.c:46
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define TRACE_(x)
Definition: compat.h:76
struct _CONTROLLER_INFO * PCONTROLLER_INFO
NTSTATUS NTAPI HwReadWriteResult(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:462
NTSTATUS NTAPI HwRecalibrateResult(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:394
VOID NTAPI HwDumpRegisters(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:1029
NTSTATUS NTAPI HwSeek(PDRIVE_INFO DriveInfo, UCHAR Cylinder)
Definition: hardware.c:659
NTSTATUS NTAPI HwSetDataRate(PCONTROLLER_INFO ControllerInfo, UCHAR DataRate)
Definition: hardware.c:204
NTSTATUS NTAPI HwRecalibrate(PDRIVE_INFO DriveInfo)
Definition: hardware.c:503
NTSTATUS NTAPI HwSpecify(PCONTROLLER_INFO ControllerInfo, UCHAR HeadLoadTime, UCHAR HeadUnloadTime, UCHAR StepRateTime, BOOLEAN NonDma)
Definition: hardware.c:925
NTSTATUS NTAPI HwReadId(PDRIVE_INFO DriveInfo, UCHAR Head)
Definition: hardware.c:576
NTSTATUS NTAPI HwReadWriteData(PCONTROLLER_INFO ControllerInfo, BOOLEAN Read, UCHAR Unit, UCHAR Cylinder, UCHAR Head, UCHAR Sector, UCHAR BytesPerSector, UCHAR EndOfTrack, UCHAR Gap3Length, UCHAR DataLength)
Definition: hardware.c:322
NTSTATUS NTAPI HwSenseInterruptStatus(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:539
NTSTATUS NTAPI HwDiskChanged(PDRIVE_INFO DriveInfo, PBOOLEAN DiskChanged)
Definition: hardware.c:785
NTSTATUS NTAPI HwReadIdResult(PCONTROLLER_INFO ControllerInfo, PUCHAR CurCylinder, PUCHAR CurHead)
Definition: hardware.c:864
#define HW_512_BYTES_PER_SECTOR
Definition: hardware.h:259
#define SPECIFY_HLT_500K
Definition: hardware.h:219
#define SPECIFY_HUT_500K
Definition: hardware.h:223
#define DRSR_DSEL_500KBPS
Definition: hardware.h:106
#define SPECIFY_SRT_500K
Definition: hardware.h:227
static IO_ALLOCATION_ACTION NTAPI MapRegisterCallback(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID MapRegisterBase, PVOID Context)
Definition: readwrite.c:60
static NTSTATUS NTAPI RWComputeCHS(PDRIVE_INFO IN DriveInfo, ULONG IN DiskByteOffset, PUCHAR OUT Cylinder, PUCHAR OUT Head, PUCHAR OUT Sector)
Definition: readwrite.c:346
VOID NTAPI ReadWritePassive(PDRIVE_INFO DriveInfo, PIRP Irp)
Definition: readwrite.c:403
static VOID NTAPI RWFreeAdapterChannel(PADAPTER_OBJECT AdapterObject)
Definition: readwrite.c:132
NTSTATUS NTAPI RWDetermineMediaType(PDRIVE_INFO DriveInfo, BOOLEAN OneShot)
Definition: readwrite.c:153
static NTSTATUS NTAPI RWSeekToCylinder(PDRIVE_INFO DriveInfo, UCHAR Cylinder)
Definition: readwrite.c:281
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
#define DO_VERIFY_VOLUME
Definition: env_spec_w32.h:393
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
NTSTATUS NTAPI WaitForControllerInterrupt(PCONTROLLER_INFO ControllerInfo, PLARGE_INTEGER Timeout)
Definition: floppy.c:163
NTSTATUS NTAPI ResetChangeFlag(PDRIVE_INFO DriveInfo)
Definition: floppy.c:291
VOID NTAPI SignalMediaChanged(PDEVICE_OBJECT DeviceObject, PIRP Irp)
Definition: floppy.c:1097
VOID NTAPI StartMotor(PDRIVE_INFO DriveInfo)
Definition: floppy.c:96
VOID NTAPI StopMotor(PCONTROLLER_INFO ControllerInfo)
Definition: floppy.c:135
#define GEOMETRY_144_SECTORSPERTRACK
Definition: floppy.h:126
#define GEOMETRY_144_MEDIATYPE
Definition: floppy.h:123
#define GEOMETRY_144_CYLINDERS
Definition: floppy.h:124
#define GEOMETRY_144_TRACKSPERCYLINDER
Definition: floppy.h:125
#define GEOMETRY_144_BYTESPERSECTOR
Definition: floppy.h:127
Status
Definition: gdiplustypes.h:25
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
BOOLEAN NTAPI IoFlushAdapterBuffers(IN PADAPTER_OBJECT AdapterObject, IN PMDL Mdl, IN PVOID MapRegisterBase, IN PVOID CurrentVa, IN ULONG Length, IN BOOLEAN WriteToDevice)
Definition: dma.c:127
PHYSICAL_ADDRESS NTAPI IoMapTransfer(IN PADAPTER_OBJECT AdapterObject, IN PMDL Mdl, IN PVOID MapRegisterBase, IN PVOID CurrentVa, IN OUT PULONG Length, IN BOOLEAN WriteToDevice)
Definition: dma.c:144
VOID NTAPI IoFreeAdapterChannel(IN PADAPTER_OBJECT AdapterObject)
Definition: dma.c:103
@ Unknown
Definition: i8042prt.h:114
#define ASSERT(a)
Definition: mode.c:44
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
NTSTATUS NTAPI IoAllocateAdapterChannel(IN PADAPTER_OBJECT AdapterObject, IN PDEVICE_OBJECT DeviceObject, IN ULONG NumberOfMapRegisters, IN PDRIVER_CONTROL ExecutionRoutine, IN PVOID Context)
Definition: adapter.c:30
#define IoCompleteRequest
Definition: irp.c:1240
#define STATUS_TIMEOUT
Definition: ntstatus.h:81
#define STATUS_PENDING
Definition: ntstatus.h:82
static ULONG Timeout
Definition: ping.c:61
#define IRP_MJ_READ
Definition: rdpdr.c:46
DRIVER_DISPATCH ReadWrite
Definition: readwrite.h:29
#define INFO_(ch,...)
Definition: debug.h:159
#define WARN_(ch,...)
Definition: debug.h:157
#define KeFlushIoBuffers(_Mdl, _ReadOperation, _DmaOperation)
Definition: ke.h:174
#define STATUS_SUCCESS
Definition: shellext.h:65
KEVENT SynchEvent
Definition: floppy.h:74
PVOID MapRegisterBase
Definition: floppy.h:72
MEDIA_TYPE MediaType
Definition: ntdddisk.h:406
LARGE_INTEGER Cylinders
Definition: ntdddisk.h:405
ULONG TracksPerCylinder
Definition: ntdddisk.h:407
ULONG SectorsPerTrack
Definition: ntdddisk.h:408
ULONG BytesPerSector
Definition: ntdddisk.h:409
struct _CONTROLLER_INFO * ControllerInfo
Definition: fdc.h:23
PDEVICE_OBJECT DeviceObject
Definition: fdc.h:26
CM_FLOPPY_DEVICE_DATA FloppyDeviceData
Definition: fdc.h:27
UCHAR BytesPerSectorCode
Definition: floppy.h:50
DISK_GEOMETRY DiskGeometry
Definition: floppy.h:49
UCHAR UnitNumber
Definition: fdc.h:24
#define NTAPI
Definition: typedefs.h:36
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#define STATUS_UNRECOGNIZED_MEDIA
Definition: udferr_usr.h:142
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define STATUS_VERIFY_REQUIRED
Definition: udferr_usr.h:130
LONGLONG QuadPart
Definition: typedefs.h:114
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
_In_ WDFREQUEST _In_ PIO_STACK_LOCATION Stack
Definition: wdfrequest.h:639
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2793
#define SL_OVERRIDE_VERIFY_VOLUME
Definition: iotypes.h:1823
#define IO_NO_INCREMENT
Definition: iotypes.h:598
_Inout_ struct _IRP _In_ PVOID MapRegisterBase
Definition: iotypes.h:213
enum _IO_ALLOCATION_ACTION IO_ALLOCATION_ACTION
@ KeepObject
Definition: iotypes.h:202
#define IO_DISK_INCREMENT
Definition: iotypes.h:600
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
#define MmGetMdlVirtualAddress(_Mdl)
#define BYTES_TO_PAGES(Size)
unsigned char UCHAR
Definition: xmlstorage.h:181