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