]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ide.c
IntelFrameworkModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / IdeBusDxe / Ide.c
... / ...
CommitLineData
1/** @file\r
2 The file ontaining the helper functions implement of the Ide Bus driver\r
3\r
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include "IdeBus.h"\r
10\r
11BOOLEAN ChannelDeviceDetected = FALSE;\r
12BOOLEAN SlaveDeviceExist = FALSE;\r
13UINT8 SlaveDeviceType = INVALID_DEVICE_TYPE;\r
14BOOLEAN MasterDeviceExist = FALSE;\r
15UINT8 MasterDeviceType = INVALID_DEVICE_TYPE;\r
16\r
17/**\r
18 read a one-byte data from a IDE port.\r
19\r
20 @param PciIo The PCI IO protocol instance\r
21 @param Port the IDE Port number\r
22\r
23 @return the one-byte data read from IDE port\r
24**/\r
25UINT8\r
26IDEReadPortB (\r
27 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
28 IN UINT16 Port\r
29 )\r
30{\r
31 UINT8 Data;\r
32\r
33 Data = 0;\r
34 //\r
35 // perform 1-byte data read from register\r
36 //\r
37 PciIo->Io.Read (\r
38 PciIo,\r
39 EfiPciIoWidthUint8,\r
40 EFI_PCI_IO_PASS_THROUGH_BAR,\r
41 (UINT64) Port,\r
42 1,\r
43 &Data\r
44 );\r
45 return Data;\r
46}\r
47/**\r
48 Reads multiple words of data from the IDE data port.\r
49 Call the IO abstraction once to do the complete read,\r
50 not one word at a time\r
51\r
52 @param PciIo Pointer to the EFI_PCI_IO instance\r
53 @param Port IO port to read\r
54 @param Count No. of UINT16's to read\r
55 @param Buffer Pointer to the data buffer for read\r
56\r
57**/\r
58VOID\r
59IDEReadPortWMultiple (\r
60 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
61 IN UINT16 Port,\r
62 IN UINTN Count,\r
63 OUT VOID *Buffer\r
64 )\r
65{\r
66 UINT16 *AlignedBuffer;\r
67 UINT16 *WorkingBuffer;\r
68 UINTN Size;\r
69\r
70 //\r
71 // Prepare an 16-bit alligned working buffer. CpuIo will return failure and\r
72 // not perform actual I/O operations if buffer pointer passed in is not at\r
73 // natural boundary. The "Buffer" argument is passed in by user and may not\r
74 // at 16-bit natural boundary.\r
75 //\r
76 Size = sizeof (UINT16) * Count;\r
77\r
78 gBS->AllocatePool (\r
79 EfiBootServicesData,\r
80 Size + 1,\r
81 (VOID**)&WorkingBuffer\r
82 );\r
83\r
84 AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));\r
85\r
86 //\r
87 // Perform UINT16 data read from FIFO\r
88 //\r
89 PciIo->Io.Read (\r
90 PciIo,\r
91 EfiPciIoWidthFifoUint16,\r
92 EFI_PCI_IO_PASS_THROUGH_BAR,\r
93 (UINT64) Port,\r
94 Count,\r
95 (UINT16*)AlignedBuffer\r
96 );\r
97\r
98 //\r
99 // Copy data to user buffer\r
100 //\r
101 CopyMem (Buffer, (UINT16*)AlignedBuffer, Size);\r
102 gBS->FreePool (WorkingBuffer);\r
103}\r
104\r
105/**\r
106 write a 1-byte data to a specific IDE port.\r
107\r
108 @param PciIo PCI IO protocol instance\r
109 @param Port The IDE port to be writen\r
110 @param Data The data to write to the port\r
111**/\r
112VOID\r
113IDEWritePortB (\r
114 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
115 IN UINT16 Port,\r
116 IN UINT8 Data\r
117 )\r
118{\r
119 //\r
120 // perform 1-byte data write to register\r
121 //\r
122 PciIo->Io.Write (\r
123 PciIo,\r
124 EfiPciIoWidthUint8,\r
125 EFI_PCI_IO_PASS_THROUGH_BAR,\r
126 (UINT64) Port,\r
127 1,\r
128 &Data\r
129 );\r
130\r
131}\r
132\r
133/**\r
134 write a 1-word data to a specific IDE port.\r
135\r
136 @param PciIo PCI IO protocol instance\r
137 @param Port The IDE port to be writen\r
138 @param Data The data to write to the port\r
139**/\r
140VOID\r
141IDEWritePortW (\r
142 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
143 IN UINT16 Port,\r
144 IN UINT16 Data\r
145 )\r
146{\r
147 //\r
148 // perform 1-word data write to register\r
149 //\r
150 PciIo->Io.Write (\r
151 PciIo,\r
152 EfiPciIoWidthUint16,\r
153 EFI_PCI_IO_PASS_THROUGH_BAR,\r
154 (UINT64) Port,\r
155 1,\r
156 &Data\r
157 );\r
158}\r
159\r
160/**\r
161 Write multiple words of data to the IDE data port.\r
162 Call the IO abstraction once to do the complete read,\r
163 not one word at a time\r
164\r
165 @param PciIo Pointer to the EFI_PCI_IO instance\r
166 @param Port IO port to read\r
167 @param Count No. of UINT16's to read\r
168 @param Buffer Pointer to the data buffer for read\r
169\r
170**/\r
171VOID\r
172IDEWritePortWMultiple (\r
173 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
174 IN UINT16 Port,\r
175 IN UINTN Count,\r
176 IN VOID *Buffer\r
177 )\r
178{\r
179 UINT16 *AlignedBuffer;\r
180 UINT32 *WorkingBuffer;\r
181 UINTN Size;\r
182\r
183 //\r
184 // Prepare an 16-bit alligned working buffer. CpuIo will return failure and\r
185 // not perform actual I/O operations if buffer pointer passed in is not at\r
186 // natural boundary. The "Buffer" argument is passed in by user and may not\r
187 // at 16-bit natural boundary.\r
188 //\r
189 Size = sizeof (UINT16) * Count;\r
190\r
191 gBS->AllocatePool (\r
192 EfiBootServicesData,\r
193 Size + 1,\r
194 (VOID **) &WorkingBuffer\r
195 );\r
196\r
197 AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));\r
198\r
199 //\r
200 // Copy data from user buffer to working buffer\r
201 //\r
202 CopyMem ((UINT16 *) AlignedBuffer, Buffer, Size);\r
203\r
204 //\r
205 // perform UINT16 data write to the FIFO\r
206 //\r
207 PciIo->Io.Write (\r
208 PciIo,\r
209 EfiPciIoWidthFifoUint16,\r
210 EFI_PCI_IO_PASS_THROUGH_BAR,\r
211 (UINT64) Port,\r
212 Count,\r
213 (UINT16 *) AlignedBuffer\r
214 );\r
215\r
216 gBS->FreePool (WorkingBuffer);\r
217}\r
218/**\r
219 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,\r
220 use fixed addresses. In Native-PCI mode, get base addresses from BARs in\r
221 the PCI IDE controller's Configuration Space.\r
222\r
223 The steps to get IDE IO port registers' base addresses for each channel\r
224 as follows:\r
225\r
226 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE\r
227 controller's Configuration Space to determine the operating mode.\r
228\r
229 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.\r
230 <pre>\r
231 ___________________________________________\r
232 | | Command Block | Control Block |\r
233 | Channel | Registers | Registers |\r
234 |___________|_______________|_______________|\r
235 | Primary | 1F0h - 1F7h | 3F6h - 3F7h |\r
236 |___________|_______________|_______________|\r
237 | Secondary | 170h - 177h | 376h - 377h |\r
238 |___________|_______________|_______________|\r
239\r
240 Table 1. Compatibility resource mappings\r
241 </pre>\r
242\r
243 b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs\r
244 in IDE controller's PCI Configuration Space, shown in the Table 2 below.\r
245 <pre>\r
246 ___________________________________________________\r
247 | | Command Block | Control Block |\r
248 | Channel | Registers | Registers |\r
249 |___________|___________________|___________________|\r
250 | Primary | BAR at offset 0x10| BAR at offset 0x14|\r
251 |___________|___________________|___________________|\r
252 | Secondary | BAR at offset 0x18| BAR at offset 0x1C|\r
253 |___________|___________________|___________________|\r
254\r
255 Table 2. BARs for Register Mapping\r
256 </pre>\r
257 @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for\r
258 primary, 0374h for secondary. So 2 bytes extra offset should be\r
259 added to the base addresses read from BARs.\r
260\r
261 For more details, please refer to PCI IDE Controller Specification and Intel\r
262 ICH4 Datasheet.\r
263\r
264 @param PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance\r
265 @param IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to\r
266 receive IDE IO port registers' base addresses\r
267\r
268 @retval EFI_UNSUPPORTED return this value when the BARs is not IO type\r
269 @retval EFI_SUCCESS Get the Base address successfully\r
270 @retval other read the pci configureation data error\r
271\r
272**/\r
273EFI_STATUS\r
274GetIdeRegistersBaseAddr (\r
275 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
276 OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr\r
277 )\r
278{\r
279 EFI_STATUS Status;\r
280 PCI_TYPE00 PciData;\r
281\r
282 Status = PciIo->Pci.Read (\r
283 PciIo,\r
284 EfiPciIoWidthUint8,\r
285 0,\r
286 sizeof (PciData),\r
287 &PciData\r
288 );\r
289\r
290 if (EFI_ERROR (Status)) {\r
291 return Status;\r
292 }\r
293\r
294 if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {\r
295 IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = 0x1f0;\r
296 IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = 0x3f6;\r
297 IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =\r
298 (UINT16)((PciData.Device.Bar[4] & 0x0000fff0));\r
299 } else {\r
300 //\r
301 // The BARs should be of IO type\r
302 //\r
303 if ((PciData.Device.Bar[0] & BIT0) == 0 ||\r
304 (PciData.Device.Bar[1] & BIT0) == 0) {\r
305 return EFI_UNSUPPORTED;\r
306 }\r
307\r
308 IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr =\r
309 (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);\r
310 IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr =\r
311 (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);\r
312 IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =\r
313 (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
314 }\r
315\r
316 if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {\r
317 IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr = 0x170;\r
318 IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr = 0x376;\r
319 IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =\r
320 (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
321 } else {\r
322 //\r
323 // The BARs should be of IO type\r
324 //\r
325 if ((PciData.Device.Bar[2] & BIT0) == 0 ||\r
326 (PciData.Device.Bar[3] & BIT0) == 0) {\r
327 return EFI_UNSUPPORTED;\r
328 }\r
329\r
330 IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr =\r
331 (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);\r
332 IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr =\r
333 (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);\r
334 IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =\r
335 (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
336 }\r
337\r
338 return EFI_SUCCESS;\r
339}\r
340\r
341/**\r
342 This function is used to requery IDE resources. The IDE controller will\r
343 probably switch between native and legacy modes during the EFI->CSM->OS\r
344 transfer. We do this everytime before an BlkIo operation to ensure its\r
345 succeess.\r
346\r
347 @param IdeDev The BLK_IO private data which specifies the IDE device\r
348\r
349 @retval EFI_INVALID_PARAMETER return this value when the channel is invalid\r
350 @retval EFI_SUCCESS reassign the IDE IO resource successfully\r
351 @retval other get the IDE current base address effor\r
352\r
353**/\r
354EFI_STATUS\r
355ReassignIdeResources (\r
356 IN IDE_BLK_IO_DEV *IdeDev\r
357 )\r
358{\r
359 EFI_STATUS Status;\r
360 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel];\r
361 UINT16 CommandBlockBaseAddr;\r
362 UINT16 ControlBlockBaseAddr;\r
363\r
364 if (IdeDev->Channel >= IdeMaxChannel) {\r
365 return EFI_INVALID_PARAMETER;\r
366 }\r
367\r
368 //\r
369 // Requery IDE IO port registers' base addresses in case of the switch of\r
370 // native and legacy modes\r
371 //\r
372 Status = GetIdeRegistersBaseAddr (IdeDev->PciIo, IdeRegsBaseAddr);\r
373 if (EFI_ERROR (Status)) {\r
374 return Status;\r
375 }\r
376\r
377 ZeroMem (IdeDev->IoPort, sizeof (IDE_BASE_REGISTERS));\r
378 CommandBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].CommandBlockBaseAddr;\r
379 ControlBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].ControlBlockBaseAddr;\r
380\r
381 IdeDev->IoPort->Data = CommandBlockBaseAddr;\r
382 (*(UINT16 *) &IdeDev->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);\r
383 IdeDev->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);\r
384 IdeDev->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);\r
385 IdeDev->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);\r
386 IdeDev->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);\r
387 IdeDev->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06);\r
388\r
389 (*(UINT16 *) &IdeDev->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);\r
390 (*(UINT16 *) &IdeDev->IoPort->Alt) = ControlBlockBaseAddr;\r
391 IdeDev->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);\r
392 IdeDev->IoPort->MasterSlave = (UINT16) ((IdeDev->Device == IdeMaster) ? 1 : 0);\r
393\r
394 IdeDev->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].BusMasterBaseAddr;\r
395 return EFI_SUCCESS;\r
396}\r
397\r
398/**\r
399 This function is called by DiscoverIdeDevice(). It is used for detect\r
400 whether the IDE device exists in the specified Channel as the specified\r
401 Device Number.\r
402\r
403 There is two IDE channels: one is Primary Channel, the other is\r
404 Secondary Channel.(Channel is the logical name for the physical "Cable".)\r
405 Different channel has different register group.\r
406\r
407 On each IDE channel, at most two IDE devices attach,\r
408 one is called Device 0 (Master device), the other is called Device 1\r
409 (Slave device). The devices on the same channel co-use the same register\r
410 group, so before sending out a command for a specified device via command\r
411 register, it is a must to select the current device to accept the command\r
412 by set the device number in the Head/Device Register.\r
413\r
414 @param IdeDev pointer to IDE_BLK_IO_DEV data structure, used to record all the\r
415 information of the IDE device.\r
416\r
417 @retval EFI_SUCCESS successfully detects device.\r
418\r
419 @retval other any failure during detection process will return this value.\r
420\r
421**/\r
422EFI_STATUS\r
423DetectIDEController (\r
424 IN IDE_BLK_IO_DEV *IdeDev\r
425 )\r
426{\r
427 EFI_STATUS Status;\r
428 UINT8 SectorCountReg;\r
429 UINT8 LBALowReg;\r
430 UINT8 LBAMidReg;\r
431 UINT8 LBAHighReg;\r
432 UINT8 InitStatusReg;\r
433 UINT8 StatusReg;\r
434\r
435 //\r
436 // Select slave device\r
437 //\r
438 IDEWritePortB (\r
439 IdeDev->PciIo,\r
440 IdeDev->IoPort->Head,\r
441 (UINT8) ((1 << 4) | 0xe0)\r
442 );\r
443 gBS->Stall (100);\r
444\r
445 //\r
446 // Save the init slave status register\r
447 //\r
448 InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
449\r
450 //\r
451 // Select Master back\r
452 //\r
453 IDEWritePortB (\r
454 IdeDev->PciIo,\r
455 IdeDev->IoPort->Head,\r
456 (UINT8) ((0 << 4) | 0xe0)\r
457 );\r
458 gBS->Stall (100);\r
459\r
460 //\r
461 // Send ATA Device Execut Diagnostic command.\r
462 // This command should work no matter DRDY is ready or not\r
463 //\r
464 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90);\r
465\r
466 Status = WaitForBSYClear (IdeDev, 3500);\r
467 if (EFI_ERROR (Status)) {\r
468 DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));\r
469 return Status;\r
470 }\r
471 //\r
472 // Read device signature\r
473 //\r
474 //\r
475 // Select Master\r
476 //\r
477 IDEWritePortB (\r
478 IdeDev->PciIo,\r
479 IdeDev->IoPort->Head,\r
480 (UINT8) ((0 << 4) | 0xe0)\r
481 );\r
482 gBS->Stall (100);\r
483 SectorCountReg = IDEReadPortB (\r
484 IdeDev->PciIo,\r
485 IdeDev->IoPort->SectorCount\r
486 );\r
487 LBALowReg = IDEReadPortB (\r
488 IdeDev->PciIo,\r
489 IdeDev->IoPort->SectorNumber\r
490 );\r
491 LBAMidReg = IDEReadPortB (\r
492 IdeDev->PciIo,\r
493 IdeDev->IoPort->CylinderLsb\r
494 );\r
495 LBAHighReg = IDEReadPortB (\r
496 IdeDev->PciIo,\r
497 IdeDev->IoPort->CylinderMsb\r
498 );\r
499 if ((SectorCountReg == 0x1) &&\r
500 (LBALowReg == 0x1) &&\r
501 (LBAMidReg == 0x0) &&\r
502 (LBAHighReg == 0x0)) {\r
503 MasterDeviceExist = TRUE;\r
504 MasterDeviceType = ATA_DEVICE_TYPE;\r
505 } else {\r
506 if ((LBAMidReg == 0x14) &&\r
507 (LBAHighReg == 0xeb)) {\r
508 MasterDeviceExist = TRUE;\r
509 MasterDeviceType = ATAPI_DEVICE_TYPE;\r
510 }\r
511 }\r
512\r
513 //\r
514 // For some Hard Drive, it takes some time to get\r
515 // the right signature when operating in single slave mode.\r
516 // We stall 20ms to work around this.\r
517 //\r
518 if (!MasterDeviceExist) {\r
519 gBS->Stall (20000);\r
520 }\r
521\r
522 //\r
523 // Select Slave\r
524 //\r
525 IDEWritePortB (\r
526 IdeDev->PciIo,\r
527 IdeDev->IoPort->Head,\r
528 (UINT8) ((1 << 4) | 0xe0)\r
529 );\r
530 gBS->Stall (100);\r
531 SectorCountReg = IDEReadPortB (\r
532 IdeDev->PciIo,\r
533 IdeDev->IoPort->SectorCount\r
534 );\r
535 LBALowReg = IDEReadPortB (\r
536 IdeDev->PciIo,\r
537 IdeDev->IoPort->SectorNumber\r
538 );\r
539 LBAMidReg = IDEReadPortB (\r
540 IdeDev->PciIo,\r
541 IdeDev->IoPort->CylinderLsb\r
542 );\r
543 LBAHighReg = IDEReadPortB (\r
544 IdeDev->PciIo,\r
545 IdeDev->IoPort->CylinderMsb\r
546 );\r
547 StatusReg = IDEReadPortB (\r
548 IdeDev->PciIo,\r
549 IdeDev->IoPort->Reg.Status\r
550 );\r
551 if ((SectorCountReg == 0x1) &&\r
552 (LBALowReg == 0x1) &&\r
553 (LBAMidReg == 0x0) &&\r
554 (LBAHighReg == 0x0)) {\r
555 SlaveDeviceExist = TRUE;\r
556 SlaveDeviceType = ATA_DEVICE_TYPE;\r
557 } else {\r
558 if ((LBAMidReg == 0x14) &&\r
559 (LBAHighReg == 0xeb)) {\r
560 SlaveDeviceExist = TRUE;\r
561 SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
562 }\r
563 }\r
564\r
565 //\r
566 // When single master is plugged, slave device\r
567 // will be wrongly detected. Here's the workaround\r
568 // for ATA devices by detecting DRY bit in status\r
569 // register.\r
570 // NOTE: This workaround doesn't apply to ATAPI.\r
571 //\r
572 if (MasterDeviceExist && SlaveDeviceExist &&\r
573 (StatusReg & ATA_STSREG_DRDY) == 0 &&\r
574 (InitStatusReg & ATA_STSREG_DRDY) == 0 &&\r
575 MasterDeviceType == SlaveDeviceType &&\r
576 SlaveDeviceType != ATAPI_DEVICE_TYPE) {\r
577 SlaveDeviceExist = FALSE;\r
578 }\r
579\r
580 //\r
581 // Indicate this channel has been detected\r
582 //\r
583 ChannelDeviceDetected = TRUE;\r
584 return EFI_SUCCESS;\r
585}\r
586/**\r
587 Detect if there is disk attached to this port\r
588\r
589 @param IdeDev The BLK_IO private data which specifies the IDE device.\r
590\r
591 @retval EFI_NOT_FOUND The device or channel is not found\r
592 @retval EFI_SUCCESS The device is found\r
593\r
594**/\r
595EFI_STATUS\r
596DiscoverIdeDevice (\r
597 IN IDE_BLK_IO_DEV *IdeDev\r
598 )\r
599{\r
600 EFI_STATUS Status;\r
601 EFI_STATUS LongPhyStatus;\r
602\r
603 //\r
604 // If a channel has not been checked, check it now. Then set it to "checked" state\r
605 // After this step, all devices in this channel have been checked.\r
606 //\r
607 if (!ChannelDeviceDetected) {\r
608 Status = DetectIDEController (IdeDev);\r
609 if (EFI_ERROR (Status)) {\r
610 return EFI_NOT_FOUND;\r
611 }\r
612 }\r
613\r
614 Status = EFI_NOT_FOUND;\r
615\r
616 //\r
617 // Device exists. test if it is an ATA device.\r
618 // Prefer the result from DetectIDEController,\r
619 // if failed, try another device type to handle\r
620 // devices that not follow the spec.\r
621 //\r
622 if ((IdeDev->Device == IdeMaster) && (MasterDeviceExist)) {\r
623 if (MasterDeviceType == ATA_DEVICE_TYPE) {\r
624 Status = ATAIdentify (IdeDev);\r
625 if (EFI_ERROR (Status)) {\r
626 Status = ATAPIIdentify (IdeDev);\r
627 if (!EFI_ERROR (Status)) {\r
628 MasterDeviceType = ATAPI_DEVICE_TYPE;\r
629 }\r
630 }\r
631 } else {\r
632 Status = ATAPIIdentify (IdeDev);\r
633 if (EFI_ERROR (Status)) {\r
634 Status = ATAIdentify (IdeDev);\r
635 if (!EFI_ERROR (Status)) {\r
636 MasterDeviceType = ATA_DEVICE_TYPE;\r
637 }\r
638 }\r
639 }\r
640 }\r
641 if ((IdeDev->Device == IdeSlave) && (SlaveDeviceExist)) {\r
642 if (SlaveDeviceType == ATA_DEVICE_TYPE) {\r
643 Status = ATAIdentify (IdeDev);\r
644 if (EFI_ERROR (Status)) {\r
645 Status = ATAPIIdentify (IdeDev);\r
646 if (!EFI_ERROR (Status)) {\r
647 SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
648 }\r
649 }\r
650 } else {\r
651 Status = ATAPIIdentify (IdeDev);\r
652 if (EFI_ERROR (Status)) {\r
653 Status = ATAIdentify (IdeDev);\r
654 if (!EFI_ERROR (Status)) {\r
655 SlaveDeviceType = ATA_DEVICE_TYPE;\r
656 }\r
657 }\r
658 }\r
659 }\r
660 if (EFI_ERROR (Status)) {\r
661 return EFI_NOT_FOUND;\r
662 }\r
663 //\r
664 // Init Block I/O interface\r
665 //\r
666 LongPhyStatus = AtaEnableLongPhysicalSector (IdeDev);\r
667 if (!EFI_ERROR (LongPhyStatus)) {\r
668 IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;\r
669 } else {\r
670 IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;\r
671 }\r
672 IdeDev->BlkIo.Reset = IDEBlkIoReset;\r
673 IdeDev->BlkIo.ReadBlocks = IDEBlkIoReadBlocks;\r
674 IdeDev->BlkIo.WriteBlocks = IDEBlkIoWriteBlocks;\r
675 IdeDev->BlkIo.FlushBlocks = IDEBlkIoFlushBlocks;\r
676\r
677 IdeDev->BlkMedia.LogicalPartition = FALSE;\r
678 IdeDev->BlkMedia.WriteCaching = FALSE;\r
679\r
680 //\r
681 // Init Disk Info interface\r
682 //\r
683 gBS->CopyMem (&IdeDev->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid, sizeof (EFI_GUID));\r
684 IdeDev->DiskInfo.Inquiry = IDEDiskInfoInquiry;\r
685 IdeDev->DiskInfo.Identify = IDEDiskInfoIdentify;\r
686 IdeDev->DiskInfo.SenseData = IDEDiskInfoSenseData;\r
687 IdeDev->DiskInfo.WhichIde = IDEDiskInfoWhichIde;\r
688\r
689 return EFI_SUCCESS;\r
690}\r
691\r
692/**\r
693 This interface is used to initialize all state data related to the detection of one\r
694 channel.\r
695**/\r
696VOID\r
697InitializeIDEChannelData (\r
698 VOID\r
699 )\r
700{\r
701 ChannelDeviceDetected = FALSE;\r
702 MasterDeviceExist = FALSE;\r
703 MasterDeviceType = 0xff;\r
704 SlaveDeviceExist = FALSE;\r
705 SlaveDeviceType = 0xff;\r
706}\r
707/**\r
708 This function is used to poll for the DRQ bit clear in the Status\r
709 Register. DRQ is cleared when the device is finished transferring data.\r
710 So this function is called after data transfer is finished.\r
711\r
712 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
713 to record all the information of the IDE device.\r
714 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.\r
715\r
716 @retval EFI_SUCCESS DRQ bit clear within the time out.\r
717\r
718 @retval EFI_TIMEOUT DRQ bit not clear within the time out.\r
719\r
720 @note\r
721 Read Status Register will clear interrupt status.\r
722\r
723**/\r
724EFI_STATUS\r
725DRQClear (\r
726 IN IDE_BLK_IO_DEV *IdeDev,\r
727 IN UINTN TimeoutInMilliSeconds\r
728 )\r
729{\r
730 UINT32 Delay;\r
731 UINT8 StatusRegister;\r
732 UINT8 ErrorRegister;\r
733\r
734 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
735 do {\r
736\r
737 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
738\r
739 //\r
740 // wait for BSY == 0 and DRQ == 0\r
741 //\r
742 if ((StatusRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
743 break;\r
744 }\r
745\r
746 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
747\r
748 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
749 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
750 return EFI_ABORTED;\r
751 }\r
752 }\r
753\r
754 //\r
755 // Stall for 30 us\r
756 //\r
757 gBS->Stall (30);\r
758\r
759 Delay--;\r
760\r
761 } while (Delay > 0);\r
762\r
763 if (Delay == 0) {\r
764 return EFI_TIMEOUT;\r
765 }\r
766\r
767 return EFI_SUCCESS;\r
768}\r
769/**\r
770 This function is used to poll for the DRQ bit clear in the Alternate\r
771 Status Register. DRQ is cleared when the device is finished\r
772 transferring data. So this function is called after data transfer\r
773 is finished.\r
774\r
775 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
776 to record all the information of the IDE device.\r
777\r
778 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.\r
779\r
780 @retval EFI_SUCCESS DRQ bit clear within the time out.\r
781\r
782 @retval EFI_TIMEOUT DRQ bit not clear within the time out.\r
783 @note Read Alternate Status Register will not clear interrupt status.\r
784\r
785**/\r
786EFI_STATUS\r
787DRQClear2 (\r
788 IN IDE_BLK_IO_DEV *IdeDev,\r
789 IN UINTN TimeoutInMilliSeconds\r
790 )\r
791{\r
792 UINT32 Delay;\r
793 UINT8 AltRegister;\r
794 UINT8 ErrorRegister;\r
795\r
796 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
797 do {\r
798\r
799 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
800\r
801 //\r
802 // wait for BSY == 0 and DRQ == 0\r
803 //\r
804 if ((AltRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
805 break;\r
806 }\r
807\r
808 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
809\r
810 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
811 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
812 return EFI_ABORTED;\r
813 }\r
814 }\r
815\r
816 //\r
817 // Stall for 30 us\r
818 //\r
819 gBS->Stall (30);\r
820\r
821 Delay--;\r
822\r
823 } while (Delay > 0);\r
824\r
825 if (Delay == 0) {\r
826 return EFI_TIMEOUT;\r
827 }\r
828\r
829 return EFI_SUCCESS;\r
830}\r
831\r
832/**\r
833 This function is used to poll for the DRQ bit set in the\r
834 Status Register.\r
835 DRQ is set when the device is ready to transfer data. So this function\r
836 is called after the command is sent to the device and before required\r
837 data is transferred.\r
838\r
839 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to\r
840 record all the information of the IDE device.\r
841 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.\r
842\r
843 @retval EFI_SUCCESS DRQ bit set within the time out.\r
844 @retval EFI_TIMEOUT DRQ bit not set within the time out.\r
845 @retval EFI_ABORTED DRQ bit not set caused by the command abort.\r
846\r
847 @note Read Status Register will clear interrupt status.\r
848\r
849**/\r
850EFI_STATUS\r
851DRQReady (\r
852 IN IDE_BLK_IO_DEV *IdeDev,\r
853 IN UINTN TimeoutInMilliSeconds\r
854 )\r
855{\r
856 UINT32 Delay;\r
857 UINT8 StatusRegister;\r
858 UINT8 ErrorRegister;\r
859\r
860 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
861 do {\r
862 //\r
863 // read Status Register will clear interrupt\r
864 //\r
865 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
866\r
867 //\r
868 // BSY==0,DRQ==1\r
869 //\r
870 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
871 break;\r
872 }\r
873\r
874 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
875\r
876 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
877 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
878 return EFI_ABORTED;\r
879 }\r
880 }\r
881\r
882 //\r
883 // Stall for 30 us\r
884 //\r
885 gBS->Stall (30);\r
886\r
887 Delay--;\r
888 } while (Delay > 0);\r
889\r
890 if (Delay == 0) {\r
891 return EFI_TIMEOUT;\r
892 }\r
893\r
894 return EFI_SUCCESS;\r
895}\r
896/**\r
897 This function is used to poll for the DRQ bit set in the Alternate Status Register.\r
898 DRQ is set when the device is ready to transfer data. So this function is called after\r
899 the command is sent to the device and before required data is transferred.\r
900\r
901 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to\r
902 record all the information of the IDE device.\r
903\r
904 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.\r
905\r
906 @retval EFI_SUCCESS DRQ bit set within the time out.\r
907 @retval EFI_TIMEOUT DRQ bit not set within the time out.\r
908 @retval EFI_ABORTED DRQ bit not set caused by the command abort.\r
909 @note Read Alternate Status Register will not clear interrupt status.\r
910\r
911**/\r
912EFI_STATUS\r
913DRQReady2 (\r
914 IN IDE_BLK_IO_DEV *IdeDev,\r
915 IN UINTN TimeoutInMilliSeconds\r
916 )\r
917{\r
918 UINT32 Delay;\r
919 UINT8 AltRegister;\r
920 UINT8 ErrorRegister;\r
921\r
922 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
923\r
924 do {\r
925 //\r
926 // Read Alternate Status Register will not clear interrupt status\r
927 //\r
928 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
929 //\r
930 // BSY == 0 , DRQ == 1\r
931 //\r
932 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
933 break;\r
934 }\r
935\r
936 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
937\r
938 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
939 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
940 return EFI_ABORTED;\r
941 }\r
942 }\r
943\r
944 //\r
945 // Stall for 30 us\r
946 //\r
947 gBS->Stall (30);\r
948\r
949 Delay--;\r
950 } while (Delay > 0);\r
951\r
952 if (Delay == 0) {\r
953 return EFI_TIMEOUT;\r
954 }\r
955\r
956 return EFI_SUCCESS;\r
957}\r
958\r
959/**\r
960 This function is used to poll for the BSY bit clear in the Status Register. BSY\r
961 is clear when the device is not busy. Every command must be sent after device is not busy.\r
962\r
963 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
964 to record all the information of the IDE device.\r
965 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.\r
966\r
967 @retval EFI_SUCCESS BSY bit clear within the time out.\r
968 @retval EFI_TIMEOUT BSY bit not clear within the time out.\r
969\r
970 @note Read Status Register will clear interrupt status.\r
971**/\r
972EFI_STATUS\r
973WaitForBSYClear (\r
974 IN IDE_BLK_IO_DEV *IdeDev,\r
975 IN UINTN TimeoutInMilliSeconds\r
976 )\r
977{\r
978 UINT32 Delay;\r
979 UINT8 StatusRegister;\r
980\r
981 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
982 do {\r
983\r
984 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
985 if ((StatusRegister & ATA_STSREG_BSY) == 0x00) {\r
986 break;\r
987 }\r
988\r
989 //\r
990 // Stall for 30 us\r
991 //\r
992 gBS->Stall (30);\r
993\r
994 Delay--;\r
995\r
996 } while (Delay > 0);\r
997\r
998 if (Delay == 0) {\r
999 return EFI_TIMEOUT;\r
1000 }\r
1001\r
1002 return EFI_SUCCESS;\r
1003}\r
1004/**\r
1005 This function is used to poll for the BSY bit clear in the Alternate Status Register.\r
1006 BSY is clear when the device is not busy. Every command must be sent after device is\r
1007 not busy.\r
1008\r
1009 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record\r
1010 all the information of the IDE device.\r
1011 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.\r
1012\r
1013 @retval EFI_SUCCESS BSY bit clear within the time out.\r
1014 @retval EFI_TIMEOUT BSY bit not clear within the time out.\r
1015 @note Read Alternate Status Register will not clear interrupt status.\r
1016\r
1017**/\r
1018EFI_STATUS\r
1019WaitForBSYClear2 (\r
1020 IN IDE_BLK_IO_DEV *IdeDev,\r
1021 IN UINTN TimeoutInMilliSeconds\r
1022 )\r
1023{\r
1024 UINT32 Delay;\r
1025 UINT8 AltRegister;\r
1026\r
1027 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1028 do {\r
1029 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
1030 if ((AltRegister & ATA_STSREG_BSY) == 0x00) {\r
1031 break;\r
1032 }\r
1033\r
1034 gBS->Stall (30);\r
1035\r
1036 Delay--;\r
1037\r
1038 } while (Delay > 0);\r
1039\r
1040 if (Delay == 0) {\r
1041 return EFI_TIMEOUT;\r
1042 }\r
1043\r
1044 return EFI_SUCCESS;\r
1045}\r
1046/**\r
1047 This function is used to poll for the DRDY bit set in the Status Register. DRDY\r
1048 bit is set when the device is ready to accept command. Most ATA commands must be\r
1049 sent after DRDY set except the ATAPI Packet Command.\r
1050\r
1051 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1052 to record all the information of the IDE device.\r
1053 @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.\r
1054\r
1055 @retval EFI_SUCCESS DRDY bit set within the time out.\r
1056 @retval EFI_TIMEOUT DRDY bit not set within the time out.\r
1057\r
1058 @note Read Status Register will clear interrupt status.\r
1059**/\r
1060EFI_STATUS\r
1061DRDYReady (\r
1062 IN IDE_BLK_IO_DEV *IdeDev,\r
1063 IN UINTN DelayInMilliSeconds\r
1064 )\r
1065{\r
1066 UINT32 Delay;\r
1067 UINT8 StatusRegister;\r
1068 UINT8 ErrorRegister;\r
1069\r
1070 Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1071 do {\r
1072 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
1073 //\r
1074 // BSY == 0 , DRDY == 1\r
1075 //\r
1076 if ((StatusRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
1077 break;\r
1078 }\r
1079\r
1080 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
1081\r
1082 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1083 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
1084 return EFI_ABORTED;\r
1085 }\r
1086 }\r
1087\r
1088 gBS->Stall (30);\r
1089\r
1090 Delay--;\r
1091 } while (Delay > 0);\r
1092\r
1093 if (Delay == 0) {\r
1094 return EFI_TIMEOUT;\r
1095 }\r
1096\r
1097 return EFI_SUCCESS;\r
1098}\r
1099/**\r
1100 This function is used to poll for the DRDY bit set in the Alternate Status Register.\r
1101 DRDY bit is set when the device is ready to accept command. Most ATA commands must\r
1102 be sent after DRDY set except the ATAPI Packet Command.\r
1103\r
1104 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1105 to record all the information of the IDE device.\r
1106 @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.\r
1107\r
1108 @retval EFI_SUCCESS DRDY bit set within the time out.\r
1109 @retval EFI_TIMEOUT DRDY bit not set within the time out.\r
1110\r
1111 @note Read Alternate Status Register will clear interrupt status.\r
1112\r
1113**/\r
1114EFI_STATUS\r
1115DRDYReady2 (\r
1116 IN IDE_BLK_IO_DEV *IdeDev,\r
1117 IN UINTN DelayInMilliSeconds\r
1118 )\r
1119{\r
1120 UINT32 Delay;\r
1121 UINT8 AltRegister;\r
1122 UINT8 ErrorRegister;\r
1123\r
1124 Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1125 do {\r
1126 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
1127 //\r
1128 // BSY == 0 , DRDY == 1\r
1129 //\r
1130 if ((AltRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
1131 break;\r
1132 }\r
1133\r
1134 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
1135\r
1136 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1137 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
1138 return EFI_ABORTED;\r
1139 }\r
1140 }\r
1141\r
1142 gBS->Stall (30);\r
1143\r
1144 Delay--;\r
1145 } while (Delay > 0);\r
1146\r
1147 if (Delay == 0) {\r
1148 return EFI_TIMEOUT;\r
1149 }\r
1150\r
1151 return EFI_SUCCESS;\r
1152}\r
1153/**\r
1154 Release resources of an IDE device before stopping it.\r
1155\r
1156 @param IdeBlkIoDevice Standard IDE device private data structure\r
1157\r
1158**/\r
1159VOID\r
1160ReleaseIdeResources (\r
1161 IN IDE_BLK_IO_DEV *IdeBlkIoDevice\r
1162 )\r
1163{\r
1164 if (IdeBlkIoDevice == NULL) {\r
1165 return ;\r
1166 }\r
1167\r
1168 //\r
1169 // Release all the resourses occupied by the IDE_BLK_IO_DEV\r
1170 //\r
1171\r
1172 if (IdeBlkIoDevice->SenseData != NULL) {\r
1173 gBS->FreePool (IdeBlkIoDevice->SenseData);\r
1174 IdeBlkIoDevice->SenseData = NULL;\r
1175 }\r
1176\r
1177 if (IdeBlkIoDevice->Cache != NULL) {\r
1178 gBS->FreePool (IdeBlkIoDevice->Cache);\r
1179 IdeBlkIoDevice->Cache = NULL;\r
1180 }\r
1181\r
1182 if (IdeBlkIoDevice->IdData != NULL) {\r
1183 gBS->FreePool (IdeBlkIoDevice->IdData);\r
1184 IdeBlkIoDevice->IdData = NULL;\r
1185 }\r
1186\r
1187 if (IdeBlkIoDevice->InquiryData != NULL) {\r
1188 gBS->FreePool (IdeBlkIoDevice->InquiryData);\r
1189 IdeBlkIoDevice->InquiryData = NULL;\r
1190 }\r
1191\r
1192 if (IdeBlkIoDevice->ControllerNameTable != NULL) {\r
1193 FreeUnicodeStringTable (IdeBlkIoDevice->ControllerNameTable);\r
1194 IdeBlkIoDevice->ControllerNameTable = NULL;\r
1195 }\r
1196\r
1197 if (IdeBlkIoDevice->IoPort != NULL) {\r
1198 gBS->FreePool (IdeBlkIoDevice->IoPort);\r
1199 }\r
1200\r
1201 if (IdeBlkIoDevice->DevicePath != NULL) {\r
1202 gBS->FreePool (IdeBlkIoDevice->DevicePath);\r
1203 }\r
1204\r
1205 if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) {\r
1206 gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent);\r
1207 IdeBlkIoDevice->ExitBootServiceEvent = NULL;\r
1208 }\r
1209\r
1210 gBS->FreePool (IdeBlkIoDevice);\r
1211 IdeBlkIoDevice = NULL;\r
1212\r
1213 return ;\r
1214}\r
1215/**\r
1216 Set the calculated Best transfer mode to a detected device.\r
1217\r
1218 @param IdeDev Standard IDE device private data structure\r
1219 @param TransferMode The device transfer mode to be set\r
1220 @return Set transfer mode Command execute status.\r
1221\r
1222**/\r
1223EFI_STATUS\r
1224SetDeviceTransferMode (\r
1225 IN IDE_BLK_IO_DEV *IdeDev,\r
1226 IN ATA_TRANSFER_MODE *TransferMode\r
1227 )\r
1228{\r
1229 EFI_STATUS Status;\r
1230 UINT8 DeviceSelect;\r
1231 UINT8 SectorCount;\r
1232\r
1233 DeviceSelect = 0;\r
1234 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
1235 SectorCount = *((UINT8 *) TransferMode);\r
1236\r
1237 //\r
1238 // Send SET FEATURE command (sub command 0x03) to set pio mode.\r
1239 //\r
1240 Status = AtaNonDataCommandIn (\r
1241 IdeDev,\r
1242 ATA_CMD_SET_FEATURES,\r
1243 DeviceSelect,\r
1244 0x03,\r
1245 SectorCount,\r
1246 0,\r
1247 0,\r
1248 0\r
1249 );\r
1250\r
1251 return Status;\r
1252}\r
1253/**\r
1254 Set drive parameters for devices not support PACKETS command.\r
1255\r
1256 @param IdeDev Standard IDE device private data structure\r
1257 @param DriveParameters The device parameters to be set into the disk\r
1258 @return SetParameters Command execute status.\r
1259\r
1260**/\r
1261EFI_STATUS\r
1262SetDriveParameters (\r
1263 IN IDE_BLK_IO_DEV *IdeDev,\r
1264 IN ATA_DRIVE_PARMS *DriveParameters\r
1265 )\r
1266{\r
1267 EFI_STATUS Status;\r
1268 UINT8 DeviceSelect;\r
1269\r
1270 DeviceSelect = 0;\r
1271 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
1272\r
1273 //\r
1274 // Send Init drive parameters\r
1275 //\r
1276 Status = AtaNonDataCommandIn (\r
1277 IdeDev,\r
1278 ATA_CMD_INIT_DRIVE_PARAM,\r
1279 (UINT8) (DeviceSelect + DriveParameters->Heads),\r
1280 0,\r
1281 DriveParameters->Sector,\r
1282 0,\r
1283 0,\r
1284 0\r
1285 );\r
1286\r
1287 //\r
1288 // Send Set Multiple parameters\r
1289 //\r
1290 Status = AtaNonDataCommandIn (\r
1291 IdeDev,\r
1292 ATA_CMD_SET_MULTIPLE_MODE,\r
1293 DeviceSelect,\r
1294 0,\r
1295 DriveParameters->MultipleSector,\r
1296 0,\r
1297 0,\r
1298 0\r
1299 );\r
1300 return Status;\r
1301}\r
1302\r
1303/**\r
1304 Enable Interrupt on IDE controller.\r
1305\r
1306 @param IdeDev Standard IDE device private data structure\r
1307\r
1308 @retval EFI_SUCCESS Enable Interrupt successfully\r
1309**/\r
1310EFI_STATUS\r
1311EnableInterrupt (\r
1312 IN IDE_BLK_IO_DEV *IdeDev\r
1313 )\r
1314{\r
1315 UINT8 DeviceControl;\r
1316\r
1317 //\r
1318 // Enable interrupt for DMA operation\r
1319 //\r
1320 DeviceControl = 0;\r
1321 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
1322\r
1323 return EFI_SUCCESS;\r
1324}\r