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