ReactOS  0.4.13-dev-257-gfabbd7c
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,
63  PVOID Context)
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 {
76  PCONTROLLER_INFO ControllerInfo = (PCONTROLLER_INFO)Context;
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 
131 static 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);
148  KeLowerIrql(Irql);
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 
280 static NTSTATUS NTAPI
281 RWSeekToCylinder(PDRIVE_INFO DriveInfo, UCHAR Cylinder)
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 
345 static 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 
402 VOID NTAPI
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 {
434  BOOLEAN WriteToDevice;
435  ULONG Length;
436  ULONG DiskByteOffset;
437  KIRQL OldIrql;
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);
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(): signalling media changed; Completing with STATUS_MEDIA_CHANGED\n");
482 
483  /* The following call sets IoStatus.Status and IoStatus.Information */
485 
486  /*
487  * Guessing at something... see ioctl.c for more info
488  */
490  Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;
491 
493  StopMotor(DriveInfo->ControllerInfo);
494  return;
495  }
496 
497  /*
498  * Figure out the media type, if we don't know it already
499  */
500  if(DriveInfo->DiskGeometry.MediaType == Unknown)
501  {
502  if(RWDetermineMediaType(DriveInfo, FALSE) != STATUS_SUCCESS)
503  {
504  WARN_(FLOPPY, "ReadWritePassive(): unable to determine media type; completing with STATUS_UNSUCCESSFUL\n");
506  StopMotor(DriveInfo->ControllerInfo);
507  return;
508  }
509 
510  if(DriveInfo->DiskGeometry.MediaType == Unknown)
511  {
512  WARN_(FLOPPY, "ReadWritePassive(): Unknown media in drive; completing with STATUS_UNRECOGNIZED_MEDIA\n");
513  Irp->IoStatus.Status = STATUS_UNRECOGNIZED_MEDIA;
515  StopMotor(DriveInfo->ControllerInfo);
516  return;
517  }
518  }
519 
520  /* Set up parameters for read or write */
521  if(Stack->MajorFunction == IRP_MJ_READ)
522  {
523  Length = Stack->Parameters.Read.Length;
524  DiskByteOffset = Stack->Parameters.Read.ByteOffset.u.LowPart;
525  WriteToDevice = FALSE;
526  }
527  else
528  {
529  Length = Stack->Parameters.Write.Length;
530  DiskByteOffset = Stack->Parameters.Write.ByteOffset.u.LowPart;
531  WriteToDevice = TRUE;
532  }
533 
534  /*
535  * FIXME:
536  * FloppyDeviceData.ReadWriteGapLength specify the value for the physical drive.
537  * We should set this value depend on the format of the inserted disk and possible
538  * depend on the request (read or write). A value of 0 results in one rotation
539  * between the sectors (7.2sec for reading a track).
540  */
541  Gap = DriveInfo->FloppyDeviceData.ReadWriteGapLength;
542 
543  /*
544  * Set up DMA transfer
545  *
546  * This is as good of a place as any to document something that used to confuse me
547  * greatly (and I even wrote some of the kernel's DMA code, so if it confuses me, it
548  * probably confuses at least a couple of other people too).
549  *
550  * MmGetMdlVirtualAddress() returns the virtual address, as mapped in the buffer's original
551  * process context, of the MDL. In other words: say you start with a buffer at address X, then
552  * you build an MDL out of that buffer called Mdl. If you call MmGetMdlVirtualAddress(Mdl), it
553  * will return X.
554  *
555  * There are two parameters that the function looks at to produce X again, given the MDL: the
556  * first is the StartVa, which is the base virtual address of the page that the buffer starts
557  * in. If your buffer's virtual address is 0x12345678, StartVa will be 0x12345000, assuming 4K pages
558  * (which is (almost) always the case on x86). Note well: this address is only valid in the
559  * process context that you initially built the MDL from. The physical pages that make up
560  * the MDL might perhaps be mapped in other process contexts too (or even in the system space,
561  * above 0x80000000 (default; 0xc0000000 on current ReactOS or /3GB Windows)), but it will
562  * (possibly) be mapped at a different address.
563  *
564  * The second parameter is the ByteOffset. Given an original buffer address of 0x12345678,
565  * the ByteOffset would be 0x678. Because MDLs can only describe full pages (and therefore
566  * StartVa always points to the start address of a page), the ByteOffset must be used to
567  * find the real start of the buffer.
568  *
569  * In general, if you add the StartVa and ByteOffset together, you get back your original
570  * buffer pointer, which you are free to use if you're sure you're in the right process
571  * context. You could tell by accessing the (hidden and not-to-be-used) Process member of
572  * the MDL, but in general, if you have to ask whether or not you are in the right context,
573  * then you shouldn't be using this address for anything anyway. There are also security implications
574  * (big ones, really, I wouldn't kid about this) to directly accessing a user's buffer by VA, so
575  * Don't Do That.
576  *
577  * There is a somewhat weird but very common use of the virtual address associated with a MDL
578  * that pops up often in the context of DMA. DMA APIs (particularly MapTransfer()) need to
579  * know where the memory is that they should DMA into and out of. This memory is described
580  * by a MDL. The controller eventually needs to know a physical address on the host side,
581  * which is generally a 32-bit linear address (on x86), and not just a page address. Therefore,
582  * the DMA APIs look at the ByteOffset field of the MDL to reconstruct the real address that
583  * should be programmed into the DMA controller.
584  *
585  * It is often the case that a transfer needs to be broken down over more than one DMA operation,
586  * particularly when it is a big transfer and the HAL doesn't give you enough map registers
587  * to map the whole thing at once. Therefore, the APIs need a way to tell how far into the MDL
588  * they should look to transfer the next chunk of bytes. Now, Microsoft could have designed
589  * MapTransfer to take a "MDL offset" argument, starting with 0, for how far into the buffer to
590  * start, but it didn't. Instead, MapTransfer asks for the virtual address of the MDL as an "index" into
591  * the MDL. The way it computes how far into the page to start the transfer is by masking off all but
592  * the bottom 12 bits (on x86) of the number you supply as the CurrentVa and using *that* as the
593  * ByteOffset instead of the one in the MDL. (OK, this varies a bit by OS and version, but this
594  * is the effect).
595  *
596  * In other words, you get a number back from MmGetMdlVirtualAddress that represents the start of your
597  * buffer, and you pass it to the first MapTransfer call. Then, for each successive operation
598  * on the same buffer, you increment that address to point to the next spot in the MDL that
599  * you want to DMA to/from. The fact that the virtual address you're manipulating is probably not
600  * mapped into the process context that you're running in is irrelevant, since it's only being
601  * used to index into the MDL.
602  */
603 
604  /* Get map registers for DMA */
606  Status = IoAllocateAdapterChannel(DriveInfo->ControllerInfo->AdapterObject, DeviceObject,
607  DriveInfo->ControllerInfo->MapRegisters, MapRegisterCallback, DriveInfo->ControllerInfo);
609 
610  if(Status != STATUS_SUCCESS)
611  {
612  WARN_(FLOPPY, "ReadWritePassive(): unable allocate an adapter channel; completing with STATUS_UNSUCCESSFUL\n");
614  StopMotor(DriveInfo->ControllerInfo);
615  return ;
616  }
617 
618 
619  /*
620  * Read from (or write to) the device
621  *
622  * This has to be called in a loop, as you can only transfer data to/from a single track at
623  * a time.
624  */
625  TransferByteOffset = 0;
626  while(TransferByteOffset < Length)
627  {
628  UCHAR Cylinder;
629  UCHAR Head;
630  UCHAR StartSector;
631  ULONG CurrentTransferBytes;
632  UCHAR CurrentTransferSectors;
633 
634  INFO_(FLOPPY, "ReadWritePassive(): iterating in while (TransferByteOffset = 0x%x of 0x%x total) - allocating %d registers\n",
635  TransferByteOffset, Length, DriveInfo->ControllerInfo->MapRegisters);
636 
637  KeClearEvent(&DriveInfo->ControllerInfo->SynchEvent);
638 
639  /*
640  * Compute starting CHS
641  */
642  if(RWComputeCHS(DriveInfo, DiskByteOffset+TransferByteOffset, &Cylinder, &Head, &StartSector) != STATUS_SUCCESS)
643  {
644  WARN_(FLOPPY, "ReadWritePassive(): unable to compute CHS; completing with STATUS_UNSUCCESSFUL\n");
645  RWFreeAdapterChannel(DriveInfo->ControllerInfo->AdapterObject);
647  StopMotor(DriveInfo->ControllerInfo);
648  return;
649  }
650 
651  /*
652  * Seek to the right track
653  */
654  if(!DriveInfo->ControllerInfo->ImpliedSeeks)
655  {
656  if(RWSeekToCylinder(DriveInfo, Cylinder) != STATUS_SUCCESS)
657  {
658  WARN_(FLOPPY, "ReadWritePassive(): unable to seek; completing with STATUS_UNSUCCESSFUL\n");
659  RWFreeAdapterChannel(DriveInfo->ControllerInfo->AdapterObject);
661  StopMotor(DriveInfo->ControllerInfo);
662  return ;
663  }
664  }
665 
666  /*
667  * Compute last sector
668  *
669  * We can only ask for a transfer up to the end of the track. Then we have to re-seek and do more.
670  * TODO: Support the MT bit
671  */
672  INFO_(FLOPPY, "ReadWritePassive(): computing number of sectors to transfer (StartSector 0x%x): ", StartSector);
673 
674  /* 1-based sector number */
675  if( (((DriveInfo->DiskGeometry.TracksPerCylinder - Head) * DriveInfo->DiskGeometry.SectorsPerTrack - StartSector) + 1 ) <
676  (Length - TransferByteOffset) / DriveInfo->DiskGeometry.BytesPerSector)
677  {
678  CurrentTransferSectors = (UCHAR)((DriveInfo->DiskGeometry.TracksPerCylinder - Head) * DriveInfo->DiskGeometry.SectorsPerTrack - StartSector) + 1;
679  }
680  else
681  {
682  CurrentTransferSectors = (UCHAR)((Length - TransferByteOffset) / DriveInfo->DiskGeometry.BytesPerSector);
683  }
684 
685  INFO_(FLOPPY, "0x%x\n", CurrentTransferSectors);
686 
687  CurrentTransferBytes = CurrentTransferSectors * DriveInfo->DiskGeometry.BytesPerSector;
688 
689  /*
690  * Adjust to map registers
691  * BUG: Does this take into account page crossings?
692  */
693  INFO_(FLOPPY, "ReadWritePassive(): Trying to transfer 0x%x bytes\n", CurrentTransferBytes);
694 
695  ASSERT(CurrentTransferBytes);
696 
697  if(BYTES_TO_PAGES(CurrentTransferBytes) > DriveInfo->ControllerInfo->MapRegisters)
698  {
699  CurrentTransferSectors = (UCHAR)((DriveInfo->ControllerInfo->MapRegisters * PAGE_SIZE) /
700  DriveInfo->DiskGeometry.BytesPerSector);
701 
702  CurrentTransferBytes = CurrentTransferSectors * DriveInfo->DiskGeometry.BytesPerSector;
703 
704  INFO_(FLOPPY, "ReadWritePassive: limiting transfer to 0x%x bytes (0x%x sectors) due to map registers\n",
705  CurrentTransferBytes, CurrentTransferSectors);
706  }
707 
708  /* set up this round's dma operation */
709  /* param 2 is ReadOperation --> opposite of WriteToDevice that IoMapTransfer takes. BAD MS. */
710  KeFlushIoBuffers(Irp->MdlAddress, !WriteToDevice, TRUE);
711 
712  IoMapTransfer(DriveInfo->ControllerInfo->AdapterObject, Irp->MdlAddress,
713  DriveInfo->ControllerInfo->MapRegisterBase,
714  (PVOID)((ULONG_PTR)MmGetMdlVirtualAddress(Irp->MdlAddress) + TransferByteOffset),
715  &CurrentTransferBytes, WriteToDevice);
716 
717  /*
718  * Read or Write
719  */
720  KeClearEvent(&DriveInfo->ControllerInfo->SynchEvent);
721 
722  /* Issue the read/write command to the controller. Note that it expects the opposite of WriteToDevice. */
723  if(HwReadWriteData(DriveInfo->ControllerInfo, !WriteToDevice, DriveInfo->UnitNumber, Cylinder, Head, StartSector,
724  DriveInfo->BytesPerSectorCode, DriveInfo->DiskGeometry.SectorsPerTrack, Gap, 0xff) != STATUS_SUCCESS)
725  {
726  WARN_(FLOPPY, "ReadWritePassive(): HwReadWriteData returned failure; unable to read; completing with STATUS_UNSUCCESSFUL\n");
727  RWFreeAdapterChannel(DriveInfo->ControllerInfo->AdapterObject);
729  StopMotor(DriveInfo->ControllerInfo);
730  return ;
731  }
732 
733  INFO_(FLOPPY, "ReadWritePassive(): HwReadWriteData returned -- waiting on event\n");
734 
735  /*
736  * At this point, we block and wait for an interrupt
737  * FIXME: this seems to take too long
738  */
740 
741  /* Read is complete; flush & free adapter channel */
742  IoFlushAdapterBuffers(DriveInfo->ControllerInfo->AdapterObject, Irp->MdlAddress,
743  DriveInfo->ControllerInfo->MapRegisterBase,
744  (PVOID)((ULONG_PTR)MmGetMdlVirtualAddress(Irp->MdlAddress) + TransferByteOffset),
745  CurrentTransferBytes, WriteToDevice);
746 
747  /* Read the results from the drive */
749  {
750  WARN_(FLOPPY, "ReadWritePassive(): HwReadWriteResult returned failure; unable to read; completing with STATUS_UNSUCCESSFUL\n");
751  HwDumpRegisters(DriveInfo->ControllerInfo);
752  RWFreeAdapterChannel(DriveInfo->ControllerInfo->AdapterObject);
754  StopMotor(DriveInfo->ControllerInfo);
755  return ;
756  }
757 
758  TransferByteOffset += CurrentTransferBytes;
759  }
760 
761  RWFreeAdapterChannel(DriveInfo->ControllerInfo->AdapterObject);
762 
763  /* That's all folks! */
764  INFO_(FLOPPY, "ReadWritePassive(): success; Completing with STATUS_SUCCESS\n");
765  Irp->IoStatus.Status = STATUS_SUCCESS;
766  Irp->IoStatus.Information = Length;
768  StopMotor(DriveInfo->ControllerInfo);
769 }
NTSTATUS NTAPI RWDetermineMediaType(PDRIVE_INFO DriveInfo, BOOLEAN OneShot)
Definition: readwrite.c:153
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
VOID NTAPI ReadWritePassive(PDRIVE_INFO DriveInfo, PIRP Irp)
Definition: readwrite.c:403
enum _IO_ALLOCATION_ACTION IO_ALLOCATION_ACTION
struct _CONTROLLER_INFO * PCONTROLLER_INFO
#define IN
Definition: typedefs.h:38
return
Definition: dirsup.c:529
#define STATUS_NO_MEDIA_IN_DEVICE
Definition: udferr_usr.h:141
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
#define TRUE
Definition: types.h:120
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define INFO_(ch,...)
Definition: debug.h:159
NTSTATUS NTAPI WaitForControllerInterrupt(PCONTROLLER_INFO ControllerInfo, PLARGE_INTEGER Timeout)
Definition: floppy.c:163
#define MmGetMdlVirtualAddress(_Mdl)
#define SPECIFY_HLT_500K
Definition: hardware.h:219
_In_ PIRP Irp
Definition: csq.h:116
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
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
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
unsigned char * PUCHAR
Definition: retypes.h:3
LONG NTSTATUS
Definition: precomp.h:26
NTSTATUS NTAPI HwReadIdResult(PCONTROLLER_INFO ControllerInfo, PUCHAR CurCylinder, PUCHAR CurHead)
Definition: hardware.c:864
#define DO_VERIFY_VOLUME
Definition: env_spec_w32.h:393
#define SPECIFY_SRT_500K
Definition: hardware.h:227
NTSTATUS NTAPI HwDiskChanged(PDRIVE_INFO DriveInfo, PBOOLEAN DiskChanged)
Definition: hardware.c:785
VOID NTAPI StopMotor(PCONTROLLER_INFO ControllerInfo)
Definition: floppy.c:135
ULONG BytesPerSector
Definition: ntdddisk.h:376
NTSTATUS NTAPI ReadWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp)
Definition: readwrite.c:90
VOID NTAPI HwDumpRegisters(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:1029
ULONG TracksPerCylinder
Definition: ntdddisk.h:374
#define STATUS_VERIFY_REQUIRED
Definition: udferr_usr.h:130
LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
Definition: eventobj.c:159
static VOID NTAPI RWFreeAdapterChannel(PADAPTER_OBJECT AdapterObject)
Definition: readwrite.c:132
_Out_ PKIRQL Irql
Definition: csq.h:179
#define GEOMETRY_144_MEDIATYPE
Definition: floppy.h:123
struct _CONTROLLER_INFO * ControllerInfo
Definition: fdc.h:23
#define PAGED_CODE()
Definition: video.h:57
#define STATUS_UNRECOGNIZED_MEDIA
Definition: udferr_usr.h:142
uint32_t ULONG_PTR
Definition: typedefs.h:63
#define STATUS_TIMEOUT
Definition: ntstatus.h:81
UCHAR KIRQL
Definition: env_spec_w32.h:591
PDEVICE_OBJECT DeviceObject
Definition: fdc.h:26
NTSTATUS NTAPI HwSetDataRate(PCONTROLLER_INFO ControllerInfo, UCHAR DataRate)
Definition: hardware.c:204
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
#define IO_DISK_INCREMENT
Definition: iotypes.h:567
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define GEOMETRY_144_BYTESPERSECTOR
Definition: floppy.h:127
PVOID DeviceExtension
Definition: env_spec_w32.h:418
unsigned char BOOLEAN
NTSTATUS NTAPI HwReadId(PDRIVE_INFO DriveInfo, UCHAR Head)
Definition: hardware.c:576
smooth NULL
Definition: ftsmooth.c:416
#define IoCompleteRequest
Definition: irp.c:1240
#define SL_OVERRIDE_VERIFY_VOLUME
Definition: iotypes.h:1779
NTSTATUS NTAPI HwRecalibrateResult(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:394
#define GEOMETRY_144_TRACKSPERCYLINDER
Definition: floppy.h:125
VOID NTAPI IoFreeAdapterChannel(IN PADAPTER_OBJECT AdapterObject)
Definition: dma.c:103
NTSTATUS NTAPI HwSenseInterruptStatus(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:539
#define TRACE_(x)
Definition: compat.h:66
NTSTATUS NTAPI ResetChangeFlag(PDRIVE_INFO DriveInfo)
Definition: floppy.c:291
NTSTATUS NTAPI HwSeek(PDRIVE_INFO DriveInfo, UCHAR Cylinder)
Definition: hardware.c:659
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 STATUS_PENDING
Definition: ntstatus.h:82
LARGE_INTEGER Cylinders
Definition: ntdddisk.h:372
ULONG SectorsPerTrack
Definition: ntdddisk.h:375
static IO_ALLOCATION_ACTION NTAPI MapRegisterCallback(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID MapRegisterBase, PVOID Context)
Definition: readwrite.c:60
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
MEDIA_TYPE MediaType
Definition: ntdddisk.h:373
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define BYTES_TO_PAGES(Size)
unsigned char UCHAR
Definition: xmlstorage.h:181
CM_FLOPPY_DEVICE_DATA FloppyDeviceData
Definition: fdc.h:27
#define HW_512_BYTES_PER_SECTOR
Definition: hardware.h:259
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define GEOMETRY_144_SECTORSPERTRACK
Definition: floppy.h:126
DISK_GEOMETRY DiskGeometry
Definition: floppy.h:49
UCHAR UnitNumber
Definition: fdc.h:24
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
Status
Definition: gdiplustypes.h:24
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
IN PDEVICE_OBJECT DeviceObject
Definition: fatprocs.h:1560
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2745
_Inout_ struct _IRP _In_ PVOID MapRegisterBase
Definition: iotypes.h:189
#define KeFlushIoBuffers(_Mdl, _ReadOperation, _DmaOperation)
Definition: ke.h:161
static ULONG Timeout
Definition: ping.c:61
NTSTATUS NTAPI HwRecalibrate(PDRIVE_INFO DriveInfo)
Definition: hardware.c:503
KEVENT SynchEvent
Definition: floppy.h:74
#define IRP_MJ_READ
Definition: rdpdr.c:46
IO_CSQ Csq
Definition: csqrtns.c:46
PVOID MapRegisterBase
Definition: floppy.h:72
#define DRSR_DSEL_500KBPS
Definition: hardware.h:106
#define OUT
Definition: typedefs.h:39
#define SPECIFY_HUT_500K
Definition: hardware.h:223
NTSTATUS NTAPI HwSpecify(PCONTROLLER_INFO ControllerInfo, UCHAR HeadLoadTime, UCHAR HeadUnloadTime, UCHAR StepRateTime, BOOLEAN NonDma)
Definition: hardware.c:925
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:565
NTSTATUS NTAPI HwReadWriteResult(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:462
static NTSTATUS NTAPI RWSeekToCylinder(PDRIVE_INFO DriveInfo, UCHAR Cylinder)
Definition: readwrite.c:281
#define GEOMETRY_144_CYLINDERS
Definition: floppy.h:124
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:2771
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
return STATUS_SUCCESS
Definition: btrfs.c:2745
#define CHAR(Char)
#define WARN_(ch,...)
Definition: debug.h:157
VOID NTAPI SignalMediaChanged(PDEVICE_OBJECT DeviceObject, PIRP Irp)
Definition: floppy.c:1010
UCHAR BytesPerSectorCode
Definition: floppy.h:50
VOID NTAPI StartMotor(PDRIVE_INFO DriveInfo)
Definition: floppy.c:96
LONGLONG QuadPart
Definition: typedefs.h:112
static NTSTATUS NTAPI RWComputeCHS(PDRIVE_INFO IN DriveInfo, ULONG IN DiskByteOffset, PUCHAR OUT Cylinder, PUCHAR OUT Head, PUCHAR OUT Sector)
Definition: readwrite.c:346