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