]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyCtrl.c
Fix a bug which leave BLOCKSIZE of BloIO produced by IsaFloppy to be zero when the...
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Isa / IsaFloppyDxe / IsaFloppyCtrl.c
CommitLineData
f8cd287b 1/**@file\r
11f43dfd 2 ISA Floppy Driver\r
ae5852b2 3 1. Support two types diskette drive\r
11f43dfd 4 1.44M drive and 2.88M drive (and now only support 1.44M)\r
5 2. Support two diskette drives\r
6 3. Use DMA channel 2 to transfer data\r
7 4. Do not use interrupt\r
8 5. Support diskette change line signal and write protect\r
ae5852b2 9\r
11f43dfd 10 The internal function for the floppy driver\r
f8cd287b 11 \r
12Copyright (c) 2006 - 2007, Intel Corporation.<BR>\r
13All rights reserved. This program and the accompanying materials\r
14are licensed and made available under the terms and conditions of the BSD License\r
15which accompanies this distribution. The full text of the license may be found at\r
16http://opensource.org/licenses/bsd-license.php\r
11f43dfd 17\r
f8cd287b 18THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
19WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11f43dfd 20\r
f8cd287b 21**/\r
11f43dfd 22\r
23#include "IsaFloppy.h"\r
24\r
25EFI_STATUS\r
26DiscoverFddDevice (\r
27 IN FDC_BLK_IO_DEV *FdcDev\r
28 )\r
29/*++\r
30\r
ae5852b2 31 Routine Description: Detect the floppy drive is presented or not\r
11f43dfd 32 Parameters:\r
ae5852b2 33 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV\r
11f43dfd 34 Returns:\r
ae5852b2 35 EFI_SUCCESS Drive is presented\r
11f43dfd 36 EFI_NOT_FOUND Drive is not presented\r
37\r
38--*/\r
39// GC_TODO: function comment is missing 'Arguments:'\r
40// GC_TODO: FdcDev - add argument and description to function comment\r
41{\r
42 EFI_STATUS Status;\r
43\r
44 FdcDev->BlkIo.Media = &FdcDev->BlkMedia;\r
45\r
46 //\r
47 // Call FddIndentify subroutine\r
48 //\r
49 Status = FddIdentify (FdcDev);\r
50 if (EFI_ERROR (Status)) {\r
51 return EFI_NOT_FOUND;\r
52 }\r
53\r
54 FdcDev->BlkIo.Reset = FdcReset;\r
55 FdcDev->BlkIo.FlushBlocks = FddFlushBlocks;\r
56 FdcDev->BlkIo.ReadBlocks = FddReadBlocks;\r
57 FdcDev->BlkIo.WriteBlocks = FddWriteBlocks;\r
58 FdcDev->BlkMedia.LogicalPartition = FALSE;\r
59 FdcDev->BlkMedia.WriteCaching = FALSE;\r
60\r
61 return EFI_SUCCESS;\r
62}\r
63\r
64EFI_STATUS\r
65FddIdentify (\r
66 IN FDC_BLK_IO_DEV *FdcDev\r
67 )\r
68/*++\r
69\r
70 Routine Description: Do recalibrate and see the drive is presented or not\r
71 Set the media parameters\r
72 Parameters:\r
ae5852b2 73 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV\r
11f43dfd 74 Returns:\r
ae5852b2 75 EFI_SUCCESS:\r
76 EFI_DEVICE_ERROR:\r
11f43dfd 77\r
78--*/\r
79// GC_TODO: function comment is missing 'Arguments:'\r
80// GC_TODO: FdcDev - add argument and description to function comment\r
81{\r
82 EFI_STATUS Status;\r
83\r
84 //\r
85 // Set Floppy Disk Controller's motor on\r
86 //\r
87 Status = MotorOn (FdcDev);\r
88 if (EFI_ERROR (Status)) {\r
89 return EFI_DEVICE_ERROR;\r
90 }\r
91\r
92 Status = Recalibrate (FdcDev);\r
93\r
94 if (EFI_ERROR (Status)) {\r
95 MotorOff (FdcDev);\r
96 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
97 return EFI_DEVICE_ERROR;\r
98 }\r
99 //\r
100 // Set Media Parameter\r
101 //\r
102 FdcDev->BlkIo.Media->RemovableMedia = TRUE;\r
103 FdcDev->BlkIo.Media->MediaPresent = TRUE;\r
104 //\r
105 // investigate\r
106 //\r
107 FdcDev->BlkIo.Media->MediaId = 0;\r
108\r
109 //\r
110 // Check Media\r
111 //\r
112 Status = DisketChanged (FdcDev);\r
11f43dfd 113\r
ae5852b2 114 if (Status == EFI_NO_MEDIA) {\r
115 FdcDev->BlkIo.Media->MediaPresent = FALSE;\r
179a2e97 116 } else if ((Status != EFI_MEDIA_CHANGED) &&\r
117 (Status != EFI_SUCCESS)) {\r
11f43dfd 118 MotorOff (FdcDev);\r
119 return Status;\r
120 }\r
ae5852b2 121\r
11f43dfd 122 //\r
123 // Check Disk Write Protected\r
124 //\r
125 Status = SenseDrvStatus (FdcDev, 0);\r
11f43dfd 126\r
ae5852b2 127 if (Status == EFI_WRITE_PROTECTED) {\r
128 FdcDev->BlkIo.Media->ReadOnly = TRUE;\r
129 } else if (Status == EFI_SUCCESS) {\r
11f43dfd 130 FdcDev->BlkIo.Media->ReadOnly = FALSE;\r
ae5852b2 131 } else {\r
11f43dfd 132 return EFI_DEVICE_ERROR;\r
11f43dfd 133 }\r
134\r
135 MotorOff (FdcDev);\r
136\r
137 //\r
138 // Set Media Default Type\r
139 //\r
140 FdcDev->BlkIo.Media->BlockSize = DISK_1440K_BYTEPERSECTOR;\r
141 FdcDev->BlkIo.Media->LastBlock = DISK_1440K_EOT * 2 * (DISK_1440K_MAXTRACKNUM + 1) - 1;\r
142\r
143 return EFI_SUCCESS;\r
144}\r
145\r
146EFI_STATUS\r
147FddReset (\r
148 IN FDC_BLK_IO_DEV *FdcDev\r
149 )\r
150/*++\r
151\r
ae5852b2 152 Routine Description: Reset the Floppy Logic Drive\r
11f43dfd 153 Parameters:\r
ae5852b2 154 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV\r
11f43dfd 155 Returns:\r
156 EFI_SUCCESS: The Floppy Logic Drive is reset\r
ae5852b2 157 EFI_DEVICE_ERROR: The Floppy Logic Drive is not functioning correctly and\r
11f43dfd 158 can not be reset\r
159\r
160--*/\r
161// GC_TODO: function comment is missing 'Arguments:'\r
162// GC_TODO: FdcDev - add argument and description to function comment\r
163{\r
164 UINT8 data;\r
165 UINT8 StatusRegister0;\r
166 UINT8 PresentCylinderNumber;\r
167 UINTN Index;\r
168\r
169 //\r
170 // Report reset progress code\r
171 //\r
172 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
173 EFI_PROGRESS_CODE,\r
174 EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_RESET,\r
175 FdcDev->DevicePath\r
176 );\r
177\r
178 //\r
179 // Reset specified Floppy Logic Drive according to FdcDev -> Disk\r
180 // Set Digital Output Register(DOR) to do reset work\r
181 // bit0 & bit1 of DOR : Drive Select\r
182 // bit2 : Reset bit\r
183 // bit3 : DMA and Int bit\r
184 // Reset : a "0" written to bit2 resets the FDC, this reset will remain\r
185 // active until\r
186 // a "1" is written to this bit.\r
187 // Reset step 1:\r
188 // use bit0 & bit1 to select the logic drive\r
189 // write "0" to bit2\r
190 //\r
191 data = 0x0;\r
192 data = (UINT8) (data | (SELECT_DRV & FdcDev->Disk));\r
193 FdcWritePort (FdcDev, FDC_REGISTER_DOR, data);\r
194\r
195 //\r
196 // wait some time,at least 120us\r
197 //\r
198 MicroSecondDelay (500);\r
199\r
200 //\r
201 // Reset step 2:\r
202 // write "1" to bit2\r
203 // write "1" to bit3 : enable DMA\r
204 //\r
205 data |= 0x0C;\r
206 FdcWritePort (FdcDev, FDC_REGISTER_DOR, data);\r
207\r
208 //\r
209 // Experience value\r
210 //\r
211 MicroSecondDelay (2000);\r
212\r
213 //\r
214 // wait specified floppy logic drive is not busy\r
215 //\r
216 if (EFI_ERROR (FddWaitForBSYClear (FdcDev, 1))) {\r
217 return EFI_DEVICE_ERROR;\r
218 }\r
219 //\r
220 // Set the Transfer Data Rate\r
221 //\r
222 FdcWritePort (FdcDev, FDC_REGISTER_CCR, 0x0);\r
223\r
224 //\r
225 // Experience value\r
226 //\r
227 MicroSecondDelay (100);\r
228\r
229 //\r
230 // Issue Sense interrupt command for each drive (total 4 drives)\r
231 //\r
232 for (Index = 0; Index < 4; Index++) {\r
233 if (EFI_ERROR (SenseIntStatus (FdcDev, &StatusRegister0, &PresentCylinderNumber))) {\r
234 return EFI_DEVICE_ERROR;\r
235 }\r
236 }\r
237 //\r
238 // issue Specify command\r
239 //\r
240 if (EFI_ERROR (Specify (FdcDev))) {\r
241 return EFI_DEVICE_ERROR;\r
242 }\r
243\r
244 return EFI_SUCCESS;\r
245}\r
246\r
247EFI_STATUS\r
248MotorOn (\r
249 IN FDC_BLK_IO_DEV *FdcDev\r
250 )\r
251/*++\r
252\r
253 Routine Description: Turn the drive's motor on\r
ae5852b2 254 The drive's motor must be on before any command can be executed\r
11f43dfd 255 Parameters:\r
ae5852b2 256 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV\r
11f43dfd 257 Returns:\r
258 EFI_SUCCESS: Turn the drive's motor on successfully\r
ae5852b2 259 EFI_DEVICE_ERROR: The drive is busy, so can not turn motor on\r
260 EFI_INVALID_PARAMETER: Fail to Set timer(Cancel timer)\r
11f43dfd 261\r
262--*/\r
263// GC_TODO: function comment is missing 'Arguments:'\r
264// GC_TODO: FdcDev - add argument and description to function comment\r
265{\r
266 EFI_STATUS Status;\r
267 UINT8 data;\r
268\r
269 //\r
270 // Control of the floppy drive motors is a big pain. If motor is off, you have\r
271 // to turn it on first. But you can not leave the motor on all the time, since\r
272 // that would wear out the disk. On the other hand, if you turn the motor off\r
273 // after each operation, the system performance will be awful. The compromise\r
274 // used in this driver is to leave the motor on for 2 seconds after\r
275 // each operation. If a new operation is started in that interval(2s),\r
276 // the motor need not be turned on again. If no new operation is started,\r
277 // a timer goes off and the motor is turned off\r
278 //\r
279 //\r
280 // Cancel the timer\r
281 //\r
282 Status = gBS->SetTimer (FdcDev->Event, TimerCancel, 0);\r
283\r
284 if (EFI_ERROR (Status)) {\r
285 return EFI_INVALID_PARAMETER;\r
286 }\r
287 //\r
288 // Get the motor status\r
289 //\r
290 data = FdcReadPort (FdcDev, FDC_REGISTER_DOR);\r
291\r
292 if (((FdcDev->Disk == FDC_DISK0) && ((data & 0x10) == 0x10)) ||\r
293 ((FdcDev->Disk == FDC_DISK1) && ((data & 0x21) == 0x21))\r
294 ) {\r
295 return EFI_SUCCESS;\r
296 }\r
297 //\r
298 // The drive's motor is off, so need turn it on\r
299 // first look at command and drive are busy or not\r
300 //\r
301 if (EFI_ERROR (FddWaitForBSYClear (FdcDev, 1))) {\r
302 return EFI_DEVICE_ERROR;\r
303 }\r
304 //\r
305 // for drive A: 1CH, drive B: 2DH\r
306 //\r
307 data = 0x0C;\r
308 data = (UINT8) (data | (SELECT_DRV & FdcDev->Disk));\r
309 if (FdcDev->Disk == FDC_DISK0) {\r
310 //\r
311 // drive A\r
312 //\r
313 data |= DRVA_MOTOR_ON;\r
314 } else {\r
315 //\r
316 // drive B\r
317 //\r
318 data |= DRVB_MOTOR_ON;\r
319 }\r
320\r
321 FdcWritePort (FdcDev, FDC_REGISTER_DOR, data);\r
322\r
323 //\r
324 // Experience value\r
325 //\r
326 MicroSecondDelay (4000);\r
327\r
328 return EFI_SUCCESS;\r
329}\r
330\r
331EFI_STATUS\r
332MotorOff (\r
333 IN FDC_BLK_IO_DEV *FdcDev\r
334 )\r
335/*++\r
336\r
337 Routine Description: Set a Timer and when Timer goes off, turn the motor off\r
338 Parameters:\r
ae5852b2 339 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV\r
11f43dfd 340 Returns:\r
341 EFI_SUCCESS: Set the Timer successfully\r
ae5852b2 342 EFI_INVALID_PARAMETER: Fail to Set the timer\r
11f43dfd 343\r
344--*/\r
345// GC_TODO: function comment is missing 'Arguments:'\r
346// GC_TODO: FdcDev - add argument and description to function comment\r
347{\r
348 //\r
349 // Set the timer : 2s\r
350 //\r
351 return gBS->SetTimer (FdcDev->Event, TimerRelative, 20000000);\r
352}\r
353\r
354EFI_STATUS\r
355DisketChanged (\r
356 IN FDC_BLK_IO_DEV *FdcDev\r
357 )\r
358/*++\r
359\r
360 Routine Description: Detect the disk in the drive is changed or not\r
361 Parameters:\r
ae5852b2 362 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV\r
11f43dfd 363 Returns:\r
364 EFI_SUCCESS: No disk media change\r
365 EFI_DEVICE_ERROR: Fail to do the recalibrate or seek operation\r
366 EFI_NO_MEDIA: No disk in the drive\r
367 EFI_MEDIA_CHANGED: There is a new disk in the drive\r
368\r
369--*/\r
370// GC_TODO: function comment is missing 'Arguments:'\r
371// GC_TODO: FdcDev - add argument and description to function comment\r
372{\r
373 EFI_STATUS Status;\r
374 UINT8 data;\r
375\r
376 //\r
377 // Check change line\r
378 //\r
379 data = FdcReadPort (FdcDev, FDC_REGISTER_DIR);\r
380\r
381 //\r
382 // Io delay\r
383 //\r
384 MicroSecondDelay (50);\r
385\r
386 if ((data & DIR_DCL) == 0x80) {\r
387 //\r
388 // disk change line is active\r
389 //\r
390 if (FdcDev->PresentCylinderNumber != 0) {\r
391 Status = Recalibrate (FdcDev);\r
392 } else {\r
393 Status = Seek (FdcDev, 0x30);\r
394 }\r
395\r
396 if (EFI_ERROR (Status)) {\r
397 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
398 return EFI_DEVICE_ERROR;\r
399 //\r
400 // Fail to do the seek or recalibrate operation\r
401 //\r
402 }\r
403\r
404 data = FdcReadPort (FdcDev, FDC_REGISTER_DIR);\r
405\r
406 //\r
407 // Io delay\r
408 //\r
409 MicroSecondDelay (50);\r
410\r
411 if ((data & DIR_DCL) == 0x80) {\r
412 return EFI_NO_MEDIA;\r
413 }\r
414\r
415 return EFI_MEDIA_CHANGED;\r
416 }\r
417\r
418 return EFI_SUCCESS;\r
419}\r
420\r
421EFI_STATUS\r
422Specify (\r
423 IN FDC_BLK_IO_DEV *FdcDev\r
424 )\r
425/*++\r
426\r
427 Routine Description: Do the Specify command, this command sets DMA operation\r
ae5852b2 428 and the initial values for each of the three internal\r
11f43dfd 429 times: HUT, SRT and HLT\r
430 Parameters:\r
431 None\r
432 Returns:\r
433 EFI_SUCCESS: Execute the Specify command successfully\r
434 EFI_DEVICE_ERROR: Fail to execute the command\r
435\r
436--*/\r
437// GC_TODO: function comment is missing 'Arguments:'\r
438// GC_TODO: FdcDev - add argument and description to function comment\r
439{\r
440 FDD_SPECIFY_CMD Command;\r
441 UINTN Index;\r
442 UINT8 *CommandPointer;\r
443\r
444 ZeroMem (&Command, sizeof (FDD_SPECIFY_CMD));\r
445 Command.CommandCode = SPECIFY_CMD;\r
446 //\r
447 // set SRT, HUT\r
448 //\r
449 Command.SrtHut = 0xdf;\r
450 //\r
451 // 0xdf;\r
452 //\r
453 // set HLT and DMA\r
454 //\r
455 Command.HltNd = 0x02;\r
456\r
457 CommandPointer = (UINT8 *) (&Command);\r
458 for (Index = 0; Index < sizeof (FDD_SPECIFY_CMD); Index++) {\r
459 if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {\r
460 return EFI_DEVICE_ERROR;\r
461 }\r
462 }\r
463\r
464 return EFI_SUCCESS;\r
465}\r
466\r
467EFI_STATUS\r
468Recalibrate (\r
469 IN FDC_BLK_IO_DEV *FdcDev\r
470 )\r
471/*++\r
472\r
473 Routine Description: Set the head of floppy drive to track 0\r
474 Parameters:\r
475 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV\r
476 Returns:\r
477 EFI_SUCCESS: Execute the Recalibrate operation successfully\r
478 EFI_DEVICE_ERROR: Fail to execute the Recalibrate operation\r
479\r
480--*/\r
481// GC_TODO: function comment is missing 'Arguments:'\r
482// GC_TODO: FdcDev - add argument and description to function comment\r
483{\r
484 FDD_COMMAND_PACKET2 Command;\r
485 UINTN Index;\r
486 UINT8 StatusRegister0;\r
487 UINT8 PresentCylinderNumber;\r
488 UINT8 *CommandPointer;\r
489 UINT8 Count;\r
490\r
491 Count = 2;\r
492\r
493 while (Count > 0) {\r
494 ZeroMem (&Command, sizeof (FDD_COMMAND_PACKET2));\r
495 Command.CommandCode = RECALIBRATE_CMD;\r
496 //\r
497 // drive select\r
498 //\r
499 if (FdcDev->Disk == FDC_DISK0) {\r
500 Command.DiskHeadSel = 0;\r
501 //\r
502 // 0\r
503 //\r
504 } else {\r
505 Command.DiskHeadSel = 1;\r
506 //\r
507 // 1\r
508 //\r
509 }\r
510\r
511 CommandPointer = (UINT8 *) (&Command);\r
512 for (Index = 0; Index < sizeof (FDD_COMMAND_PACKET2); Index++) {\r
513 if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {\r
514 return EFI_DEVICE_ERROR;\r
515 }\r
516 }\r
517 //\r
518 // Experience value\r
519 //\r
520 MicroSecondDelay (250000);\r
521 //\r
522 // need modify according to 1.44M or 2.88M\r
523 //\r
524 if (EFI_ERROR (SenseIntStatus (FdcDev, &StatusRegister0, &PresentCylinderNumber))) {\r
525 return EFI_DEVICE_ERROR;\r
526 }\r
527\r
528 if ((StatusRegister0 & 0xf0) == 0x20 && PresentCylinderNumber == 0) {\r
529 FdcDev->PresentCylinderNumber = 0;\r
530 FdcDev->ControllerState->NeedRecalibrate = FALSE;\r
531 return EFI_SUCCESS;\r
532 } else {\r
533 Count--;\r
534 if (Count == 0) {\r
535 return EFI_DEVICE_ERROR;\r
536 }\r
537 }\r
538 }\r
539 //\r
540 // end while\r
541 //\r
542 return EFI_SUCCESS;\r
543}\r
544\r
545EFI_STATUS\r
546Seek (\r
547 IN FDC_BLK_IO_DEV *FdcDev,\r
548 IN EFI_LBA Lba\r
549 )\r
550/*++\r
551\r
552 Routine Description: Set the head of floppy drive to the new cylinder\r
553 Parameters:\r
554 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV\r
555 Lba EFI_LBA : The logic block address want to seek\r
556 Returns:\r
557 EFI_SUCCESS: Execute the Seek operation successfully\r
558 EFI_DEVICE_ERROR: Fail to execute the Seek operation\r
559\r
560--*/\r
561// GC_TODO: function comment is missing 'Arguments:'\r
562// GC_TODO: FdcDev - add argument and description to function comment\r
563// GC_TODO: Lba - add argument and description to function comment\r
564{\r
565 FDD_SEEK_CMD Command;\r
566 UINT8 EndOfTrack;\r
567 UINT8 Head;\r
568 UINT8 Cylinder;\r
569 UINT8 StatusRegister0;\r
570 UINT8 *CommandPointer;\r
571 UINT8 PresentCylinderNumber;\r
572 UINTN Index;\r
573 UINT8 DelayTime;\r
574\r
575 if (FdcDev->ControllerState->NeedRecalibrate) {\r
576 if (EFI_ERROR (Recalibrate (FdcDev))) {\r
577 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
578 return EFI_DEVICE_ERROR;\r
579 }\r
580 }\r
581\r
582 EndOfTrack = DISK_1440K_EOT;\r
583 //\r
584 // Calculate cylinder based on Lba and EOT\r
585 //\r
586 Cylinder = (UINT8) ((UINTN) Lba / EndOfTrack / 2);\r
587\r
588 //\r
589 // if the destination cylinder is the present cylinder, unnecessary to do the\r
590 // seek operation\r
591 //\r
592 if (FdcDev->PresentCylinderNumber == Cylinder) {\r
593 return EFI_SUCCESS;\r
594 }\r
595 //\r
596 // Calculate the head : 0 or 1\r
597 //\r
598 Head = (UINT8) ((UINTN) Lba / EndOfTrack % 2);\r
599\r
600 ZeroMem (&Command, sizeof (FDD_SEEK_CMD));\r
601 Command.CommandCode = SEEK_CMD;\r
602 if (FdcDev->Disk == FDC_DISK0) {\r
603 Command.DiskHeadSel = 0;\r
604 //\r
605 // 0\r
606 //\r
607 } else {\r
608 Command.DiskHeadSel = 1;\r
609 //\r
610 // 1\r
611 //\r
612 }\r
613\r
614 Command.DiskHeadSel = (UINT8) (Command.DiskHeadSel | (Head << 2));\r
615 Command.NewCylinder = Cylinder;\r
616\r
617 CommandPointer = (UINT8 *) (&Command);\r
618 for (Index = 0; Index < sizeof (FDD_SEEK_CMD); Index++) {\r
619 if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {\r
620 return EFI_DEVICE_ERROR;\r
621 }\r
622 }\r
623 //\r
624 // Io delay\r
625 //\r
626 MicroSecondDelay (100);\r
627\r
628 //\r
629 // Calculate waiting time\r
630 //\r
631 if (FdcDev->PresentCylinderNumber > Cylinder) {\r
632 DelayTime = (UINT8) (FdcDev->PresentCylinderNumber - Cylinder);\r
633 } else {\r
634 DelayTime = (UINT8) (Cylinder - FdcDev->PresentCylinderNumber);\r
635 }\r
636\r
637 MicroSecondDelay ((DelayTime + 1) * 4000);\r
638\r
639 if (EFI_ERROR (SenseIntStatus (FdcDev, &StatusRegister0, &PresentCylinderNumber))) {\r
640 return EFI_DEVICE_ERROR;\r
641 }\r
642\r
643 if ((StatusRegister0 & 0xf0) == 0x20) {\r
644 FdcDev->PresentCylinderNumber = Command.NewCylinder;\r
645 return EFI_SUCCESS;\r
646 } else {\r
647 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
648 return EFI_DEVICE_ERROR;\r
649 }\r
650}\r
651\r
652EFI_STATUS\r
653SenseIntStatus (\r
654 IN FDC_BLK_IO_DEV *FdcDev,\r
655 IN OUT UINT8 *StatusRegister0,\r
656 IN OUT UINT8 *PresentCylinderNumber\r
657 )\r
658/*++\r
659\r
ae5852b2 660 Routine Description: Do the Sense Interrupt Status command, this command\r
11f43dfd 661 resets the interrupt signal\r
662 Parameters:\r
ae5852b2 663 StatusRegister0 UINT8 *: Be used to save Status Register 0 read from FDC\r
664 PresentCylinderNumber UINT8 *: Be used to save present cylinder number\r
11f43dfd 665 read from FDC\r
666 Returns:\r
667 EFI_SUCCESS: Execute the Sense Interrupt Status command successfully\r
668 EFI_DEVICE_ERROR: Fail to execute the command\r
669\r
670--*/\r
671// GC_TODO: function comment is missing 'Arguments:'\r
672// GC_TODO: FdcDev - add argument and description to function comment\r
673// GC_TODO: StatusRegister0 - add argument and description to function comment\r
674// GC_TODO: PresentCylinderNumber - add argument and description to function comment\r
675{\r
676 UINT8 command;\r
677\r
678 command = SENSE_INT_STATUS_CMD;\r
679 if (EFI_ERROR (DataOutByte (FdcDev, &command))) {\r
680 return EFI_DEVICE_ERROR;\r
681 }\r
682\r
683 if (EFI_ERROR (DataInByte (FdcDev, StatusRegister0))) {\r
684 return EFI_DEVICE_ERROR;\r
685 }\r
686\r
687 if (EFI_ERROR (DataInByte (FdcDev, PresentCylinderNumber))) {\r
688 return EFI_DEVICE_ERROR;\r
689 }\r
690\r
691 return EFI_SUCCESS;\r
692}\r
693\r
694EFI_STATUS\r
695SenseDrvStatus (\r
696 IN FDC_BLK_IO_DEV *FdcDev,\r
697 IN EFI_LBA Lba\r
698 )\r
699/*++\r
700\r
701 Routine Description: Do the Sense Drive Status command\r
702 Parameters:\r
ae5852b2 703 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV\r
11f43dfd 704 Lba EFI_LBA : Logic block address\r
705 Returns:\r
706 EFI_SUCCESS: Execute the Sense Drive Status command successfully\r
707 EFI_DEVICE_ERROR: Fail to execute the command\r
ae5852b2 708 EFI_WRITE_PROTECTED:The disk is write protected\r
11f43dfd 709\r
710--*/\r
711// GC_TODO: function comment is missing 'Arguments:'\r
712// GC_TODO: FdcDev - add argument and description to function comment\r
713// GC_TODO: Lba - add argument and description to function comment\r
714{\r
715 FDD_COMMAND_PACKET2 Command;\r
716 UINT8 Head;\r
717 UINT8 EndOfTrack;\r
718 UINTN Index;\r
719 UINT8 StatusRegister3;\r
720 UINT8 *CommandPointer;\r
721\r
722 //\r
723 // Sense Drive Status command obtains drive status information,\r
724 // it has not execution phase and goes directly to the result phase from the\r
725 // command phase, Status Register 3 contains the drive status information\r
726 //\r
727 ZeroMem (&Command, sizeof (FDD_COMMAND_PACKET2));\r
728 Command.CommandCode = SENSE_DRV_STATUS_CMD;\r
729\r
730 if (FdcDev->Disk == FDC_DISK0) {\r
731 Command.DiskHeadSel = 0;\r
732 } else {\r
733 Command.DiskHeadSel = 1;\r
734 }\r
735\r
736 EndOfTrack = DISK_1440K_EOT;\r
737 Head = (UINT8) ((UINTN) Lba / EndOfTrack % 2);\r
738 Command.DiskHeadSel = (UINT8) (Command.DiskHeadSel | (Head << 2));\r
739\r
740 CommandPointer = (UINT8 *) (&Command);\r
741 for (Index = 0; Index < sizeof (FDD_COMMAND_PACKET2); Index++) {\r
742 if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {\r
743 return EFI_DEVICE_ERROR;\r
744 }\r
745 }\r
746\r
747 if (EFI_ERROR (DataInByte (FdcDev, &StatusRegister3))) {\r
748 return EFI_DEVICE_ERROR;\r
749 }\r
750 //\r
751 // Io delay\r
752 //\r
753 MicroSecondDelay (50);\r
754\r
755 //\r
756 // Check Status Register 3 to get drive status information\r
757 //\r
758 return CheckStatus3 (StatusRegister3);\r
759}\r
760\r
761EFI_STATUS\r
762DetectMedia (\r
763 IN FDC_BLK_IO_DEV *FdcDev\r
764 )\r
765/*++\r
766\r
ae5852b2 767 Routine Description: Update the disk media properties and if necessary\r
11f43dfd 768 reinstall Block I/O interface\r
769 Parameters:\r
ae5852b2 770 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV\r
11f43dfd 771 Returns:\r
772 EFI_SUCCESS: Do the operation successfully\r
773 EFI_DEVICE_ERROR: Fail to the operation\r
774\r
775--*/\r
776// GC_TODO: function comment is missing 'Arguments:'\r
777// GC_TODO: FdcDev - add argument and description to function comment\r
778{\r
779 EFI_STATUS Status;\r
780 BOOLEAN bReset;\r
781 BOOLEAN bReadOnlyLastTime;\r
782 BOOLEAN bMediaPresentLastTime;\r
783\r
784 bReset = FALSE;\r
785 bReadOnlyLastTime = FdcDev->BlkIo.Media->ReadOnly;\r
786 bMediaPresentLastTime = FdcDev->BlkIo.Media->MediaPresent;\r
787\r
788 //\r
789 // Check disk change\r
790 //\r
791 Status = DisketChanged (FdcDev);\r
ae5852b2 792\r
793 if (Status == EFI_MEDIA_CHANGED) {\r
11f43dfd 794 FdcDev->BlkIo.Media->MediaId++;\r
795 FdcDev->BlkIo.Media->MediaPresent = TRUE;\r
796 bReset = TRUE;\r
ae5852b2 797 } else if (Status == EFI_NO_MEDIA) {\r
11f43dfd 798 FdcDev->BlkIo.Media->MediaPresent = FALSE;\r
ae5852b2 799 } else if (Status != EFI_SUCCESS) {\r
11f43dfd 800 MotorOff (FdcDev);\r
801 return Status;\r
802 //\r
803 // EFI_DEVICE_ERROR\r
804 //\r
805 }\r
806\r
807 if (FdcDev->BlkIo.Media->MediaPresent) {\r
808 //\r
809 // Check disk write protected\r
810 //\r
811 Status = SenseDrvStatus (FdcDev, 0);\r
812 if (Status == EFI_WRITE_PROTECTED) {\r
813 FdcDev->BlkIo.Media->ReadOnly = TRUE;\r
814 } else {\r
815 FdcDev->BlkIo.Media->ReadOnly = FALSE;\r
816 }\r
817 }\r
818\r
819 if (FdcDev->BlkIo.Media->MediaPresent && (bReadOnlyLastTime != FdcDev->BlkIo.Media->ReadOnly)) {\r
820 bReset = TRUE;\r
821 }\r
822\r
823 if (bMediaPresentLastTime != FdcDev->BlkIo.Media->MediaPresent) {\r
824 bReset = TRUE;\r
825 }\r
826\r
827 if (bReset) {\r
828 Status = gBS->ReinstallProtocolInterface (\r
829 FdcDev->Handle,\r
830 &gEfiBlockIoProtocolGuid,\r
831 &FdcDev->BlkIo,\r
832 &FdcDev->BlkIo\r
833 );\r
834\r
835 if (EFI_ERROR (Status)) {\r
836 return Status;\r
837 }\r
838 }\r
839\r
840 return EFI_SUCCESS;\r
841}\r
842\r
843EFI_STATUS\r
844Setup (\r
845 IN FDC_BLK_IO_DEV *FdcDev\r
846 )\r
847/*++\r
848\r
849 Routine Description: Set the data rate and so on\r
850 Parameters:\r
ae5852b2 851 None\r
11f43dfd 852 Returns:\r
ae5852b2 853 EFI_SUCCESS:\r
11f43dfd 854\r
855--*/\r
856// GC_TODO: function comment is missing 'Arguments:'\r
857// GC_TODO: FdcDev - add argument and description to function comment\r
858// GC_TODO: EFI_DEVICE_ERROR - add return value to function comment\r
859{\r
860 EFI_STATUS Status;\r
861\r
862 //\r
863 // Set data rate 500kbs\r
864 //\r
865 FdcWritePort (FdcDev, FDC_REGISTER_CCR, 0x0);\r
866\r
867 //\r
868 // Io delay\r
869 //\r
870 MicroSecondDelay (50);\r
871\r
872 Status = Specify (FdcDev);\r
873\r
874 if (EFI_ERROR (Status)) {\r
875 return EFI_DEVICE_ERROR;\r
876 }\r
877\r
878 return EFI_SUCCESS;\r
879}\r
880\r
881EFI_STATUS\r
882ReadWriteDataSector (\r
883 IN FDC_BLK_IO_DEV *FdcDev,\r
884 IN VOID *HostAddress,\r
885 IN EFI_LBA Lba,\r
886 IN UINTN NumberOfBlocks,\r
887 IN BOOLEAN Read\r
888 )\r
889/*++\r
890\r
891 Routine Description: Read or Write a number of blocks in the same cylinder\r
892 Parameters:\r
893 FdcDev FDC_BLK_IO_DEV * : A pointer to Data Structure FDC_BLK_IO_DEV\r
894 Buffer VOID *:\r
895 Lba EFI_LBA:\r
896 NumberOfBlocks UINTN:\r
ae5852b2 897 Read BOOLEAN:\r
11f43dfd 898 Returns:\r
ae5852b2 899 EFI_SUCCESS:\r
11f43dfd 900\r
901--*/\r
902// GC_TODO: function comment is missing 'Arguments:'\r
903// GC_TODO: FdcDev - add argument and description to function comment\r
904// GC_TODO: HostAddress - add argument and description to function comment\r
905// GC_TODO: Lba - add argument and description to function comment\r
906// GC_TODO: NumberOfBlocks - add argument and description to function comment\r
907// GC_TODO: Read - add argument and description to function comment\r
908// GC_TODO: EFI_DEVICE_ERROR - add return value to function comment\r
909// GC_TODO: EFI_DEVICE_ERROR - add return value to function comment\r
910// GC_TODO: EFI_DEVICE_ERROR - add return value to function comment\r
911// GC_TODO: EFI_TIMEOUT - add return value to function comment\r
912// GC_TODO: EFI_DEVICE_ERROR - add return value to function comment\r
913{\r
914 EFI_STATUS Status;\r
915 FDD_COMMAND_PACKET1 Command;\r
916 FDD_RESULT_PACKET Result;\r
917 UINTN Index;\r
918 UINTN Times;\r
919 UINT8 *CommandPointer;\r
920\r
921 EFI_PHYSICAL_ADDRESS DeviceAddress;\r
922 EFI_ISA_IO_PROTOCOL *IsaIo;\r
923 UINTN NumberofBytes;\r
924 VOID *Mapping;\r
925 EFI_ISA_IO_PROTOCOL_OPERATION Operation;\r
926 EFI_STATUS Status1;\r
927 UINT8 Channel;\r
928 EFI_ISA_ACPI_RESOURCE *ResourceItem;\r
929 UINT32 Attribute;\r
930\r
931 Status = Seek (FdcDev, Lba);\r
932 if (EFI_ERROR (Status)) {\r
933 return EFI_DEVICE_ERROR;\r
934 }\r
935 //\r
936 // Map Dma\r
937 //\r
938 IsaIo = FdcDev->IsaIo;\r
939 NumberofBytes = NumberOfBlocks * 512;\r
940 if (Read == READ) {\r
941 Operation = EfiIsaIoOperationSlaveWrite;\r
942 } else {\r
943 Operation = EfiIsaIoOperationSlaveRead;\r
944 }\r
945\r
946 ResourceItem = IsaIo->ResourceList->ResourceItem;\r
947 Index = 0;\r
948 while (ResourceItem[Index].Type != EfiIsaAcpiResourceEndOfList) {\r
949 if (ResourceItem[Index].Type == EfiIsaAcpiResourceDma) {\r
950 break;\r
951 }\r
952\r
953 Index++;\r
954 }\r
955\r
956 if (ResourceItem[Index].Type == EfiIsaAcpiResourceEndOfList) {\r
957 return EFI_DEVICE_ERROR;\r
958 }\r
959\r
960 Channel = (UINT8) IsaIo->ResourceList->ResourceItem[Index].StartRange;\r
961 Attribute = IsaIo->ResourceList->ResourceItem[Index].Attribute;\r
962\r
963 Status1 = IsaIo->Map (\r
964 IsaIo,\r
965 Operation,\r
966 Channel,\r
967 Attribute,\r
968 HostAddress,\r
969 &NumberofBytes,\r
970 &DeviceAddress,\r
971 &Mapping\r
972 );\r
973 if (EFI_ERROR (Status1)) {\r
974 return Status1;\r
975 }\r
976\r
977 //\r
978 // Allocate Read or Write command packet\r
979 //\r
980 ZeroMem (&Command, sizeof (FDD_COMMAND_PACKET1));\r
981 if (Read == READ) {\r
982 Command.CommandCode = READ_DATA_CMD | CMD_MT | CMD_MFM | CMD_SK;\r
983 } else {\r
984 Command.CommandCode = WRITE_DATA_CMD | CMD_MT | CMD_MFM;\r
985 }\r
986\r
987 FillPara (FdcDev, Lba, &Command);\r
988\r
989 //\r
990 // Write command bytes to FDC\r
991 //\r
992 CommandPointer = (UINT8 *) (&Command);\r
993 for (Index = 0; Index < sizeof (FDD_COMMAND_PACKET1); Index++) {\r
994 if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {\r
995 return EFI_DEVICE_ERROR;\r
996 }\r
997 }\r
998 //\r
999 // wait for some time\r
1000 //\r
1001 Times = (STALL_1_SECOND / 50) + 1;\r
1002 do {\r
1003 if ((FdcReadPort (FdcDev, FDC_REGISTER_MSR) & 0xc0) == 0xc0) {\r
1004 break;\r
1005 }\r
1006\r
1007 MicroSecondDelay (50);\r
1008 Times = Times - 1;\r
1009 } while (Times);\r
1010\r
1011 if (Times == 0) {\r
1012 return EFI_TIMEOUT;\r
1013 }\r
1014 //\r
1015 // Read result bytes from FDC\r
1016 //\r
1017 CommandPointer = (UINT8 *) (&Result);\r
1018 for (Index = 0; Index < sizeof (FDD_RESULT_PACKET); Index++) {\r
1019 if (EFI_ERROR (DataInByte (FdcDev, CommandPointer++))) {\r
1020 return EFI_DEVICE_ERROR;\r
1021 }\r
1022 }\r
1023 //\r
1024 // Flush before Unmap\r
1025 //\r
1026 if (Read == READ) {\r
1027 Status1 = IsaIo->Flush (IsaIo);\r
1028 if (EFI_ERROR (Status1)) {\r
1029 return Status1;\r
1030 }\r
1031 }\r
1032 //\r
1033 // Unmap Dma\r
1034 //\r
1035 Status1 = IsaIo->Unmap (IsaIo, Mapping);\r
1036 if (EFI_ERROR (Status1)) {\r
1037 return Status1;\r
1038 }\r
1039\r
1040 return CheckResult (&Result, FdcDev);\r
1041}\r
1042\r
1043VOID\r
1044FillPara (\r
1045 IN FDC_BLK_IO_DEV *FdcDev,\r
1046 IN EFI_LBA Lba,\r
1047 IN FDD_COMMAND_PACKET1 *Command\r
1048 )\r
1049/*++\r
1050\r
1051 Routine Description: Fill in Parameter\r
1052 Parameters:\r
1053 Returns:\r
ae5852b2 1054\r
11f43dfd 1055--*/\r
1056// GC_TODO: function comment is missing 'Arguments:'\r
1057// GC_TODO: FdcDev - add argument and description to function comment\r
1058// GC_TODO: Lba - add argument and description to function comment\r
1059// GC_TODO: Command - add argument and description to function comment\r
1060{\r
1061 UINT8 EndOfTrack;\r
1062\r
1063 //\r
1064 // Get EndOfTrack from the Para table\r
1065 //\r
1066 EndOfTrack = DISK_1440K_EOT;\r
1067\r
1068 //\r
1069 // Fill the command parameter\r
1070 //\r
1071 if (FdcDev->Disk == FDC_DISK0) {\r
1072 Command->DiskHeadSel = 0;\r
1073 } else {\r
1074 Command->DiskHeadSel = 1;\r
1075 }\r
1076\r
1077 Command->Cylinder = (UINT8) ((UINTN) Lba / EndOfTrack / 2);\r
1078 Command->Head = (UINT8) ((UINTN) Lba / EndOfTrack % 2);\r
1079 Command->Sector = (UINT8) ((UINT8) ((UINTN) Lba % EndOfTrack) + 1);\r
1080 Command->DiskHeadSel = (UINT8) (Command->DiskHeadSel | (Command->Head << 2));\r
1081 Command->Number = DISK_1440K_NUMBER;\r
1082 Command->EndOfTrack = DISK_1440K_EOT;\r
1083 Command->GapLength = DISK_1440K_GPL;\r
1084 Command->DataLength = DISK_1440K_DTL;\r
1085}\r
1086\r
1087EFI_STATUS\r
1088DataInByte (\r
1089 IN FDC_BLK_IO_DEV *FdcDev,\r
1090 IN OUT UINT8 *Pointer\r
1091 )\r
1092/*++\r
1093\r
1094 Routine Description: Read result byte from Data Register of FDC\r
1095 Parameters:\r
ae5852b2 1096 Pointer UINT8 *: Be used to save result byte read from FDC\r
11f43dfd 1097 Returns:\r
1098 EFI_SUCCESS: Read result byte from FDC successfully\r
1099 EFI_DEVICE_ERROR: The FDC is not ready to be read\r
1100\r
1101--*/\r
1102// GC_TODO: function comment is missing 'Arguments:'\r
1103// GC_TODO: FdcDev - add argument and description to function comment\r
1104// GC_TODO: Pointer - add argument and description to function comment\r
1105{\r
1106 UINT8 data;\r
1107\r
1108 //\r
1109 // wait for 1ms and detect the FDC is ready to be read\r
1110 //\r
1111 if (EFI_ERROR (FddDRQReady (FdcDev, DATA_IN, 1))) {\r
1112 return EFI_DEVICE_ERROR;\r
1113 //\r
1114 // is not ready\r
1115 //\r
1116 }\r
1117\r
1118 data = FdcReadPort (FdcDev, FDC_REGISTER_DTR);\r
1119\r
1120 //\r
1121 // Io delay\r
1122 //\r
1123 MicroSecondDelay (50);\r
1124\r
1125 *Pointer = data;\r
1126 return EFI_SUCCESS;\r
1127}\r
1128\r
1129EFI_STATUS\r
1130DataOutByte (\r
1131 IN FDC_BLK_IO_DEV *FdcDev,\r
1132 IN UINT8 *Pointer\r
1133 )\r
1134/*++\r
1135\r
1136 Routine Description: Write command byte to Data Register of FDC\r
1137 Parameters:\r
ae5852b2 1138 Pointer UINT8 *: Be used to save command byte written to FDC\r
11f43dfd 1139 Returns:\r
1140 EFI_SUCCESS: Write command byte to FDC successfully\r
1141 EFI_DEVICE_ERROR: The FDC is not ready to be written\r
1142\r
1143--*/\r
1144// GC_TODO: function comment is missing 'Arguments:'\r
1145// GC_TODO: FdcDev - add argument and description to function comment\r
1146// GC_TODO: Pointer - add argument and description to function comment\r
1147{\r
1148 UINT8 data;\r
1149\r
1150 //\r
1151 // wait for 1ms and detect the FDC is ready to be written\r
1152 //\r
1153 if (EFI_ERROR (FddDRQReady (FdcDev, DATA_OUT, 1))) {\r
1154 return EFI_DEVICE_ERROR;\r
1155 //\r
1156 // is not ready\r
1157 //\r
1158 }\r
1159\r
1160 data = *Pointer;\r
1161\r
1162 FdcWritePort (FdcDev, FDC_REGISTER_DTR, data);\r
1163\r
1164 //\r
1165 // Io delay\r
1166 //\r
1167 MicroSecondDelay (50);\r
1168\r
1169 return EFI_SUCCESS;\r
1170}\r
1171\r
1172EFI_STATUS\r
1173FddWaitForBSYClear (\r
1174 IN FDC_BLK_IO_DEV *FdcDev,\r
1175 IN UINTN TimeoutInSeconds\r
1176 )\r
1177/*++\r
1178\r
ae5852b2 1179 Routine Description: Detect the specified floppy logic drive is busy or\r
11f43dfd 1180 not within a period of time\r
1181 Parameters:\r
1182 Disk EFI_FDC_DISK: Indicate it is drive A or drive B\r
ae5852b2 1183 TimeoutInSeconds UINTN: the time period for waiting\r
11f43dfd 1184 Returns:\r
1185 EFI_SUCCESS: The drive and command are not busy\r
ae5852b2 1186 EFI_TIMEOUT: The drive or command is still busy after a period time that\r
11f43dfd 1187 set by TimeoutInSeconds\r
1188\r
1189--*/\r
1190// GC_TODO: function comment is missing 'Arguments:'\r
1191// GC_TODO: FdcDev - add argument and description to function comment\r
1192// GC_TODO: TimeoutInSeconds - add argument and description to function comment\r
1193{\r
1194 UINTN Delay;\r
1195 UINT8 StatusRegister;\r
1196 UINT8 Mask;\r
1197\r
1198 //\r
1199 // How to determine drive and command are busy or not: by the bits of\r
1200 // Main Status Register\r
1201 // bit0: Drive 0 busy (drive A)\r
1202 // bit1: Drive 1 busy (drive B)\r
1203 // bit4: Command busy\r
1204 //\r
1205 //\r
1206 // set mask: for drive A set bit0 & bit4; for drive B set bit1 & bit4\r
1207 //\r
1208 Mask = (UINT8) ((FdcDev->Disk == FDC_DISK0 ? MSR_DAB : MSR_DBB) | MSR_CB);\r
1209\r
1210 Delay = ((TimeoutInSeconds * STALL_1_MSECOND) / 50) + 1;\r
1211 do {\r
1212 StatusRegister = FdcReadPort (FdcDev, FDC_REGISTER_MSR);\r
1213 if ((StatusRegister & Mask) == 0x00) {\r
1214 break;\r
1215 //\r
1216 // not busy\r
1217 //\r
1218 }\r
1219\r
1220 MicroSecondDelay (50);\r
1221 Delay = Delay - 1;\r
1222 } while (Delay);\r
1223\r
1224 if (Delay == 0) {\r
1225 return EFI_TIMEOUT;\r
1226 }\r
1227\r
1228 return EFI_SUCCESS;\r
1229}\r
1230\r
1231EFI_STATUS\r
1232FddDRQReady (\r
1233 IN FDC_BLK_IO_DEV *FdcDev,\r
1234 IN BOOLEAN Dio,\r
1235 IN UINTN TimeoutInSeconds\r
1236 )\r
1237/*++\r
1238\r
1239 Routine Description: Determine whether FDC is ready to write or read\r
1240 Parameters:\r
1241 Dio BOOLEAN: Indicate the FDC is waiting to write or read\r
ae5852b2 1242 TimeoutInSeconds UINTN: The time period for waiting\r
11f43dfd 1243 Returns:\r
1244 EFI_SUCCESS: FDC is ready to write or read\r
1245 EFI_NOT_READY: FDC is not ready within the specified time period\r
1246\r
1247--*/\r
1248// GC_TODO: function comment is missing 'Arguments:'\r
1249// GC_TODO: FdcDev - add argument and description to function comment\r
1250// GC_TODO: Dio - add argument and description to function comment\r
1251// GC_TODO: TimeoutInSeconds - add argument and description to function comment\r
1252{\r
1253 UINTN Delay;\r
1254 UINT8 StatusRegister;\r
1255 UINT8 DataInOut;\r
1256\r
1257 //\r
1258 // Before writing to FDC or reading from FDC, the Host must examine\r
1259 // the bit7(RQM) and bit6(DIO) of the Main Status Register.\r
1260 // That is to say:\r
1261 // command bytes can not be written to Data Register\r
1262 // unless RQM is 1 and DIO is 0\r
1263 // result bytes can not be read from Data Register\r
1264 // unless RQM is 1 and DIO is 1\r
1265 //\r
1266 DataInOut = (UINT8) (Dio << 6);\r
1267 //\r
1268 // in order to compare bit6\r
1269 //\r
1270 Delay = ((TimeoutInSeconds * STALL_1_MSECOND) / 50) + 1;\r
1271 do {\r
1272 StatusRegister = FdcReadPort (FdcDev, FDC_REGISTER_MSR);\r
1273 if ((StatusRegister & MSR_RQM) == MSR_RQM && (StatusRegister & MSR_DIO) == DataInOut) {\r
1274 break;\r
1275 //\r
1276 // FDC is ready\r
1277 //\r
1278 }\r
1279\r
1280 MicroSecondDelay (50);\r
1281 //\r
1282 // Stall for 50 us\r
1283 //\r
1284 Delay = Delay - 1;\r
1285 } while (Delay);\r
1286\r
1287 if (Delay == 0) {\r
1288 return EFI_NOT_READY;\r
1289 //\r
1290 // FDC is not ready within the specified time period\r
1291 //\r
1292 }\r
1293\r
1294 return EFI_SUCCESS;\r
1295}\r
1296\r
1297EFI_STATUS\r
1298CheckResult (\r
1299 IN FDD_RESULT_PACKET *Result,\r
1300 IN OUT FDC_BLK_IO_DEV *FdcDev\r
1301 )\r
1302/*++\r
1303\r
1304Routine Description:\r
1305\r
1306 GC_TODO: Add function description\r
1307\r
1308Arguments:\r
1309\r
1310 Result - GC_TODO: add argument description\r
1311 FdcDev - GC_TODO: add argument description\r
1312\r
1313Returns:\r
1314\r
1315 EFI_DEVICE_ERROR - GC_TODO: Add description for return value\r
1316 EFI_DEVICE_ERROR - GC_TODO: Add description for return value\r
1317 EFI_DEVICE_ERROR - GC_TODO: Add description for return value\r
1318 EFI_SUCCESS - GC_TODO: Add description for return value\r
1319\r
1320--*/\r
1321{\r
1322 //\r
1323 // Check Status Register0\r
1324 //\r
1325 if ((Result->Status0 & STS0_IC) != IC_NT) {\r
1326 if ((Result->Status0 & STS0_SE) == 0x20) {\r
1327 //\r
1328 // seek error\r
1329 //\r
1330 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
1331 }\r
1332\r
1333 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
1334 return EFI_DEVICE_ERROR;\r
1335 }\r
1336 //\r
1337 // Check Status Register1\r
1338 //\r
1339 if (Result->Status1 & (STS1_EN | STS1_DE | STS1_OR | STS1_ND | STS1_NW | STS1_MA)) {\r
1340 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
1341 return EFI_DEVICE_ERROR;\r
1342 }\r
1343 //\r
1344 // Check Status Register2\r
1345 //\r
1346 if (Result->Status2 & (STS2_CM | STS2_DD | STS2_WC | STS2_BC | STS2_MD)) {\r
1347 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
1348 return EFI_DEVICE_ERROR;\r
1349 }\r
1350\r
1351 return EFI_SUCCESS;\r
1352}\r
1353\r
1354EFI_STATUS\r
1355CheckStatus3 (\r
1356 IN UINT8 StatusRegister3\r
1357 )\r
1358/*++\r
1359\r
1360 Routine Description: Check the drive status information\r
1361 Parameters:\r
ae5852b2 1362 StatusRegister3 UINT8: the value of Status Register 3\r
11f43dfd 1363 Returns:\r
ae5852b2 1364 EFI_SUCCESS:\r
11f43dfd 1365 EFI_WRITE_PROTECTED: The disk is write protected\r
1366\r
1367--*/\r
1368// GC_TODO: function comment is missing 'Arguments:'\r
1369// GC_TODO: StatusRegister3 - add argument and description to function comment\r
1370{\r
1371 if (StatusRegister3 & STS3_WP) {\r
1372 return EFI_WRITE_PROTECTED;\r
1373 }\r
1374\r
1375 return EFI_SUCCESS;\r
1376}\r
1377\r
1378UINTN\r
1379GetTransferBlockCount (\r
1380 IN FDC_BLK_IO_DEV *FdcDev,\r
1381 IN EFI_LBA LBA,\r
1382 IN UINTN NumberOfBlocks\r
1383 )\r
1384/*++\r
1385\r
ae5852b2 1386 Routine Description: Calculate the number of block in the same cylinder\r
11f43dfd 1387 according to LBA\r
1388 Parameters:\r
1389 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV\r
ae5852b2 1390 LBA EFI_LBA: The starting logic block address\r
11f43dfd 1391 NumberOfBlocks UINTN: The number of blocks\r
1392 Returns:\r
ae5852b2 1393 UINTN : The number of blocks in the same cylinder which the starting\r
11f43dfd 1394 logic block address is LBA\r
1395\r
1396--*/\r
1397// GC_TODO: function comment is missing 'Arguments:'\r
1398// GC_TODO: FdcDev - add argument and description to function comment\r
1399// GC_TODO: LBA - add argument and description to function comment\r
1400// GC_TODO: NumberOfBlocks - add argument and description to function comment\r
1401{\r
1402 UINT8 EndOfTrack;\r
1403 UINT8 Head;\r
1404 UINT8 SectorsInTrack;\r
1405\r
1406 //\r
1407 // Calculate the number of block in the same cylinder\r
1408 //\r
1409 EndOfTrack = DISK_1440K_EOT;\r
1410 Head = (UINT8) ((UINTN) LBA / EndOfTrack % 2);\r
1411\r
1412 SectorsInTrack = (UINT8) (EndOfTrack * (2 - Head) - (UINT8) ((UINTN) LBA % EndOfTrack));\r
1413 if (SectorsInTrack < NumberOfBlocks) {\r
1414 return SectorsInTrack;\r
1415 } else {\r
1416 return NumberOfBlocks;\r
1417 }\r
1418}\r
1419\r
1420VOID\r
1421EFIAPI\r
1422FddTimerProc (\r
1423 IN EFI_EVENT Event,\r
1424 IN VOID *Context\r
1425 )\r
1426/*++\r
1427\r
1428 Routine Description: When the Timer(2s) off, turn the drive's motor off\r
1429 Parameters:\r
ae5852b2 1430 Event EFI_EVENT: Event(the timer) whose notification function is being\r
11f43dfd 1431 invoked\r
ae5852b2 1432 Context VOID *: Pointer to the notification function's context\r
11f43dfd 1433 Returns:\r
1434 VOID\r
1435\r
1436--*/\r
1437// GC_TODO: function comment is missing 'Arguments:'\r
1438// GC_TODO: Event - add argument and description to function comment\r
1439// GC_TODO: Context - add argument and description to function comment\r
1440{\r
1441 FDC_BLK_IO_DEV *FdcDev;\r
1442 UINT8 data;\r
1443\r
1444 FdcDev = (FDC_BLK_IO_DEV *) Context;\r
1445\r
1446 //\r
1447 // Get the motor status\r
1448 //\r
1449 data = FdcReadPort (FdcDev, FDC_REGISTER_DOR);\r
1450\r
1451 if (((FdcDev->Disk == FDC_DISK0) && ((data & 0x10) != 0x10)) ||\r
1452 ((FdcDev->Disk == FDC_DISK1) && ((data & 0x21) != 0x21))\r
1453 ) {\r
1454 return ;\r
1455 }\r
1456 //\r
1457 // the motor is on, so need motor off\r
1458 //\r
1459 data = 0x0C;\r
1460 data = (UINT8) (data | (SELECT_DRV & FdcDev->Disk));\r
1461 FdcWritePort (FdcDev, FDC_REGISTER_DOR, data);\r
1462 MicroSecondDelay (500);\r
1463}\r
1464\r
1465UINT8\r
1466FdcReadPort (\r
1467 IN FDC_BLK_IO_DEV *FdcDev,\r
1468 IN UINT32 Offset\r
1469 )\r
1470/*++\r
1471\r
ae5852b2 1472 Routine Description: Read I/O port for FDC\r
11f43dfd 1473 Parameters:\r
1474 Returns:\r
ae5852b2 1475\r
11f43dfd 1476--*/\r
1477// GC_TODO: function comment is missing 'Arguments:'\r
1478// GC_TODO: FdcDev - add argument and description to function comment\r
1479// GC_TODO: Offset - add argument and description to function comment\r
1480{\r
1481 UINT8 Data;\r
1482\r
1483 //\r
1484 // Call IsaIo\r
1485 //\r
1486 FdcDev->IsaIo->Io.Read (\r
1487 FdcDev->IsaIo,\r
1488 EfiIsaIoWidthUint8,\r
1489 FdcDev->BaseAddress + Offset,\r
1490 1,\r
1491 &Data\r
1492 );\r
1493\r
1494 return Data;\r
1495}\r
1496\r
1497VOID\r
1498FdcWritePort (\r
1499 IN FDC_BLK_IO_DEV *FdcDev,\r
1500 IN UINT32 Offset,\r
1501 IN UINT8 Data\r
1502 )\r
1503/*++\r
1504\r
ae5852b2 1505 Routine Description: Write I/O port for FDC\r
11f43dfd 1506 Parameters:\r
1507 Returns:\r
ae5852b2 1508\r
11f43dfd 1509--*/\r
1510// GC_TODO: function comment is missing 'Arguments:'\r
1511// GC_TODO: FdcDev - add argument and description to function comment\r
1512// GC_TODO: Offset - add argument and description to function comment\r
1513// GC_TODO: Data - add argument and description to function comment\r
1514{\r
1515\r
1516 //\r
1517 // Call IsaIo\r
1518 //\r
1519 FdcDev->IsaIo->Io.Write (\r
1520 FdcDev->IsaIo,\r
1521 EfiIsaIoWidthUint8,\r
1522 FdcDev->BaseAddress + Offset,\r
1523 1,\r
1524 &Data\r
1525 );\r
1526}\r