ReactOS  0.4.15-dev-5461-g062a8f2
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 {
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);
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 
605  if(Status != STATUS_SUCCESS)
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");
746  HwDumpRegisters(DriveInfo->ControllerInfo);
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 }
NTSTATUS NTAPI WaitForControllerInterrupt(PCONTROLLER_INFO ControllerInfo, PLARGE_INTEGER Timeout)
Definition: floppy.c:163
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
enum _IO_ALLOCATION_ACTION IO_ALLOCATION_ACTION
NTSTATUS NTAPI HwSetDataRate(PCONTROLLER_INFO ControllerInfo, UCHAR DataRate)
Definition: hardware.c:204
#define IN
Definition: typedefs.h:39
return
Definition: dirsup.c:529
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
VOID NTAPI StopMotor(PCONTROLLER_INFO ControllerInfo)
Definition: floppy.c:135
#define INFO_(ch,...)
Definition: debug.h:159
#define MmGetMdlVirtualAddress(_Mdl)
#define TRUE
Definition: types.h:120
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
#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 HwRecalibrateResult(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:394
VOID NTAPI ReadWritePassive(PDRIVE_INFO DriveInfo, PIRP Irp)
Definition: readwrite.c:403
#define DO_VERIFY_VOLUME
Definition: env_spec_w32.h:393
ULONG BytesPerSector
Definition: ntdddisk.h:409
ULONG TracksPerCylinder
Definition: ntdddisk.h:407
#define SPECIFY_HLT_500K
Definition: hardware.h:219
#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
_Out_ PKIRQL Irql
Definition: csq.h:179
#define GEOMETRY_144_MEDIATYPE
Definition: floppy.h:123
struct _CONTROLLER_INFO * ControllerInfo
Definition: fdc.h:23
#define STATUS_UNRECOGNIZED_MEDIA
Definition: udferr_usr.h:142
NTSTATUS NTAPI HwReadWriteResult(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:462
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define STATUS_TIMEOUT
Definition: ntstatus.h:81
_In_ WDFREQUEST _In_ PIO_STACK_LOCATION Stack
Definition: wdfrequest.h:636
UCHAR KIRQL
Definition: env_spec_w32.h:591
static VOID NTAPI RWFreeAdapterChannel(PADAPTER_OBJECT AdapterObject)
Definition: readwrite.c:132
PDEVICE_OBJECT DeviceObject
Definition: fdc.h:26
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
#define IO_DISK_INCREMENT
Definition: iotypes.h:600
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
_In_ PIRP Irp
Definition: csq.h:116
#define GEOMETRY_144_BYTESPERSECTOR
Definition: floppy.h:127
unsigned char BOOLEAN
#define IoCompleteRequest
Definition: irp.c:1240
#define SL_OVERRIDE_VERIFY_VOLUME
Definition: iotypes.h:1823
#define GEOMETRY_144_TRACKSPERCYLINDER
Definition: floppy.h:125
VOID NTAPI IoFreeAdapterChannel(IN PADAPTER_OBJECT AdapterObject)
Definition: dma.c:103
static NTSTATUS NTAPI RWSeekToCylinder(PDRIVE_INFO DriveInfo, UCHAR Cylinder)
Definition: readwrite.c:281
NTSTATUS NTAPI ReadWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp)
Definition: readwrite.c:90
NTSTATUS NTAPI HwReadIdResult(PCONTROLLER_INFO ControllerInfo, PUCHAR CurCylinder, PUCHAR CurHead)
Definition: hardware.c:864
Status
Definition: gdiplustypes.h:24
static IO_ALLOCATION_ACTION NTAPI MapRegisterCallback(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID MapRegisterBase, PVOID Context)
Definition: readwrite.c:60
#define TRACE_(x)
Definition: compat.h:76
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 ASSERT(a)
Definition: mode.c:44
#define STATUS_PENDING
Definition: ntstatus.h:82
#define SPECIFY_SRT_500K
Definition: hardware.h:227
LARGE_INTEGER Cylinders
Definition: ntdddisk.h:405
ULONG SectorsPerTrack
Definition: ntdddisk.h:408
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:406
NTSTATUS NTAPI HwReadId(PDRIVE_INFO DriveInfo, UCHAR Head)
Definition: hardware.c:576
struct _CONTROLLER_INFO * PCONTROLLER_INFO
VOID NTAPI HwDumpRegisters(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:1029
NTSTATUS NTAPI HwSenseInterruptStatus(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:539
#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
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:792
#define PAGE_SIZE
Definition: env_spec_w32.h:49
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
#define GEOMETRY_144_SECTORSPERTRACK
Definition: floppy.h:126
DISK_GEOMETRY DiskGeometry
Definition: floppy.h:49
UCHAR UnitNumber
Definition: fdc.h:24
NTSTATUS NTAPI HwDiskChanged(PDRIVE_INFO DriveInfo, PBOOLEAN DiskChanged)
Definition: hardware.c:785
_In_ PSCSI_REQUEST_BLOCK _In_opt_ PVOID _In_ ULONG _In_ BOOLEAN WriteToDevice
Definition: cdrom.h:989
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
NTSTATUS NTAPI ResetChangeFlag(PDRIVE_INFO DriveInfo)
Definition: floppy.c:291
NTSTATUS NTAPI HwRecalibrate(PDRIVE_INFO DriveInfo)
Definition: hardware.c:503
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2793
VOID NTAPI StartMotor(PDRIVE_INFO DriveInfo)
Definition: floppy.c:96
_Inout_ struct _IRP _In_ PVOID MapRegisterBase
Definition: iotypes.h:212
#define KeFlushIoBuffers(_Mdl, _ReadOperation, _DmaOperation)
Definition: ke.h:170
static ULONG Timeout
Definition: ping.c:61
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
static NTSTATUS NTAPI RWComputeCHS(PDRIVE_INFO IN DriveInfo, ULONG IN DiskByteOffset, PUCHAR OUT Cylinder, PUCHAR OUT Head, PUCHAR OUT Sector)
Definition: readwrite.c:346
NTSTATUS NTAPI HwSeek(PDRIVE_INFO DriveInfo, UCHAR Cylinder)
Definition: hardware.c:659
#define NULL
Definition: types.h:112
VOID NTAPI KeRaiseIrql(KIRQL NewIrql, PKIRQL OldIrql)
Definition: spinlock.c:27
KEVENT SynchEvent
Definition: floppy.h:74
VOID NTAPI SignalMediaChanged(PDEVICE_OBJECT DeviceObject, PIRP Irp)
Definition: floppy.c:1090
#define IRP_MJ_READ
Definition: rdpdr.c:46
NTSTATUS NTAPI RWDetermineMediaType(PDRIVE_INFO DriveInfo, BOOLEAN OneShot)
Definition: readwrite.c:153
#define SPECIFY_HUT_500K
Definition: hardware.h:223
IO_CSQ Csq
Definition: csqrtns.c:46
PVOID MapRegisterBase
Definition: floppy.h:72
#define OUT
Definition: typedefs.h:40
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:598
#define STATUS_SUCCESS
Definition: shellext.h:65
#define GEOMETRY_144_CYLINDERS
Definition: floppy.h:124
VOID NTAPI KeLowerIrql(KIRQL NewIrql)
Definition: spinlock.c:39
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
#define CHAR(Char)
#define DRSR_DSEL_500KBPS
Definition: hardware.h:106
#define WARN_(ch,...)
Definition: debug.h:157
UCHAR BytesPerSectorCode
Definition: floppy.h:50
NTSTATUS NTAPI HwSpecify(PCONTROLLER_INFO ControllerInfo, UCHAR HeadLoadTime, UCHAR HeadUnloadTime, UCHAR StepRateTime, BOOLEAN NonDma)
Definition: hardware.c:925
LONGLONG QuadPart
Definition: typedefs.h:114
#define HW_512_BYTES_PER_SECTOR
Definition: hardware.h:259
#define PAGED_CODE()