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