]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Drivers/PL180MciDxe/PL180Mci.c
EmbeddedPkg/MmcDxe: Add 'This' pointer attribute to protocol function
[mirror_edk2.git] / ArmPlatformPkg / Drivers / PL180MciDxe / PL180Mci.c
1 /** @file
2 This file implement the MMC Host Protocol for the ARM PrimeCell PL180.
3
4 Copyright (c) 2011, ARM Limited. All rights reserved.
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "PL180Mci.h"
17
18 #include <Library/DevicePathLib.h>
19 #include <Library/BaseMemoryLib.h>
20
21 EFI_MMC_HOST_PROTOCOL *gpMmcHost;
22
23 // Untested ...
24 //#define USE_STREAM
25
26 #define MMCI0_BLOCKLEN 512
27 #define MMCI0_POW2_BLOCKLEN 9
28 #define MMCI0_TIMEOUT 1000
29
30 BOOLEAN
31 MciIsPowerOn (
32 VOID
33 )
34 {
35 return ((MmioRead32(MCI_POWER_CONTROL_REG) & 0x3) == MCI_POWER_ON);
36 }
37
38 EFI_STATUS
39 MciInitialize (
40 VOID
41 )
42 {
43 MCI_TRACE("MciInitialize()");
44 return EFI_SUCCESS;
45 }
46
47 BOOLEAN
48 MciIsCardPresent (
49 IN EFI_MMC_HOST_PROTOCOL *This
50 )
51 {
52 return (MmioRead32(FixedPcdGet32(PcdPL180SysMciRegAddress)) & 1);
53 }
54
55 BOOLEAN
56 MciIsReadOnly (
57 IN EFI_MMC_HOST_PROTOCOL *This
58 )
59 {
60 return (MmioRead32(FixedPcdGet32(PcdPL180SysMciRegAddress)) & 2);
61 }
62
63 #if 0
64 //Note: This function has been commented out because it is not used yet.
65 // This function could be used to remove the hardcoded BlockLen used
66 // in MciPrepareDataPath
67
68 // Convert block size to 2^n
69 STATIC
70 UINT32
71 GetPow2BlockLen (
72 IN UINT32 BlockLen
73 )
74 {
75 UINTN Loop;
76 UINTN Pow2BlockLen;
77
78 Loop = 0x8000;
79 Pow2BlockLen = 15;
80 do {
81 Loop = (Loop >> 1) & 0xFFFF;
82 Pow2BlockLen--;
83 } while (Pow2BlockLen && (!(Loop & BlockLen)));
84
85 return Pow2BlockLen;
86 }
87 #endif
88
89 VOID
90 MciPrepareDataPath (
91 IN UINTN TransferDirection
92 )
93 {
94 // Set Data Length & Data Timer
95 MmioWrite32 (MCI_DATA_TIMER_REG,0xFFFFFFF);
96 MmioWrite32 (MCI_DATA_LENGTH_REG,MMCI0_BLOCKLEN);
97
98 #ifndef USE_STREAM
99 //Note: we are using a hardcoded BlockLen (=512). If we decide to use a variable size, we could
100 // compute the pow2 of BlockLen with the above function GetPow2BlockLen()
101 MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_DMA_ENABLE | TransferDirection | (MMCI0_POW2_BLOCKLEN << 4));
102 #else
103 MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_DMA_ENABLE | TransferDirection | MCI_DATACTL_STREAM_TRANS);
104 #endif
105 }
106
107 EFI_STATUS
108 MciSendCommand (
109 IN EFI_MMC_HOST_PROTOCOL *This,
110 IN MMC_CMD MmcCmd,
111 IN UINT32 Argument
112 )
113 {
114 UINT32 Status;
115 UINT32 Cmd;
116 UINTN RetVal;
117 UINTN CmdCtrlReg;
118
119 RetVal = EFI_SUCCESS;
120
121 if ((MmcCmd == MMC_CMD17) || (MmcCmd == MMC_CMD11)) {
122 MciPrepareDataPath(MCI_DATACTL_CARD_TO_CONT);
123 } else if ((MmcCmd == MMC_CMD24) || (MmcCmd == MMC_CMD20)) {
124 MciPrepareDataPath(MCI_DATACTL_CONT_TO_CARD);
125 }
126
127 // Create Command for PL180
128 Cmd = (MMC_GET_INDX(MmcCmd) & INDX_MASK) | MCI_CPSM_ENABLED;
129 if (MmcCmd & MMC_CMD_WAIT_RESPONSE) {
130 Cmd |= MCI_CPSM_WAIT_RESPONSE;
131 }
132
133 if (MmcCmd & MMC_CMD_LONG_RESPONSE) {
134 Cmd |= MCI_CPSM_LONG_RESPONSE;
135 }
136
137 // Clear Status register static flags
138 MmioWrite32(MCI_CLEAR_STATUS_REG,0x7FF);
139
140 //Write to command argument register
141 MmioWrite32(MCI_ARGUMENT_REG,Argument);
142
143 //Write to command register
144 MmioWrite32(MCI_COMMAND_REG,Cmd);
145
146 if (Cmd & MCI_CPSM_WAIT_RESPONSE) {
147 Status = MmioRead32(MCI_STATUS_REG);
148 while (!(Status & (MCI_STATUS_CMD_RESPEND | MCI_STATUS_CMD_CMDCRCFAIL | MCI_STATUS_CMD_CMDTIMEOUT | MCI_STATUS_CMD_START_BIT_ERROR))) {
149 Status = MmioRead32(MCI_STATUS_REG);
150 }
151
152 if ((Status & MCI_STATUS_CMD_START_BIT_ERROR)) {
153 DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) Start bit Error! Response:0x%X Status:0x%x\n",(Cmd & 0x3F),MmioRead32(MCI_RESPONSE0_REG),Status));
154 RetVal = EFI_NO_RESPONSE;
155 goto Exit;
156 } else if ((Status & MCI_STATUS_CMD_CMDTIMEOUT)) {
157 //DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) TIMEOUT! Response:0x%X Status:0x%x\n",(Cmd & 0x3F),MmioRead32(MCI_RESPONSE0_REG),Status));
158 RetVal = EFI_TIMEOUT;
159 goto Exit;
160 } else if ((!(MmcCmd & MMC_CMD_NO_CRC_RESPONSE)) && (Status & MCI_STATUS_CMD_CMDCRCFAIL)) {
161 // The CMD1 and response type R3 do not contain CRC. We should ignore the CRC failed Status.
162 RetVal = EFI_CRC_ERROR;
163 goto Exit;
164 } else {
165 RetVal = EFI_SUCCESS;
166 goto Exit;
167 }
168 } else {
169 Status = MmioRead32(MCI_STATUS_REG);
170 while (!(Status & (MCI_STATUS_CMD_SENT | MCI_STATUS_CMD_CMDCRCFAIL | MCI_STATUS_CMD_CMDTIMEOUT| MCI_STATUS_CMD_START_BIT_ERROR))) {
171 Status = MmioRead32(MCI_STATUS_REG);
172 }
173
174 if ((Status & MCI_STATUS_CMD_START_BIT_ERROR)) {
175 DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) Start bit Error! Response:0x%X Status:0x%x\n",(Cmd & 0x3F),MmioRead32(MCI_RESPONSE0_REG),Status));
176 RetVal = EFI_NO_RESPONSE;
177 goto Exit;
178 } else if ((Status & MCI_STATUS_CMD_CMDTIMEOUT)) {
179 //DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) TIMEOUT! Response:0x%X Status:0x%x\n",(Cmd & 0x3F),MmioRead32(MCI_RESPONSE0_REG),Status));
180 RetVal = EFI_TIMEOUT;
181 goto Exit;
182 } else
183 if ((!(MmcCmd & MMC_CMD_NO_CRC_RESPONSE)) && (Status & MCI_STATUS_CMD_CMDCRCFAIL)) {
184 // The CMD1 does not contain CRC. We should ignore the CRC failed Status.
185 RetVal = EFI_CRC_ERROR;
186 goto Exit;
187 } else {
188 RetVal = EFI_SUCCESS;
189 goto Exit;
190 }
191 }
192
193 Exit:
194 // Disable Command Path
195 CmdCtrlReg = MmioRead32(MCI_COMMAND_REG);
196 MmioWrite32(MCI_COMMAND_REG, (CmdCtrlReg & ~MCI_CPSM_ENABLED));
197 return RetVal;
198 }
199
200 EFI_STATUS
201 MciReceiveResponse (
202 IN EFI_MMC_HOST_PROTOCOL *This,
203 IN MMC_RESPONSE_TYPE Type,
204 IN UINT32* Buffer
205 )
206 {
207 if (Buffer == NULL) {
208 return EFI_INVALID_PARAMETER;
209 }
210
211 if ((Type == MMC_RESPONSE_TYPE_R1) || (Type == MMC_RESPONSE_TYPE_R1b) ||
212 (Type == MMC_RESPONSE_TYPE_R3) || (Type == MMC_RESPONSE_TYPE_R6) ||
213 (Type == MMC_RESPONSE_TYPE_R7))
214 {
215 Buffer[0] = MmioRead32(MCI_RESPONSE3_REG);
216 } else if (Type == MMC_RESPONSE_TYPE_R2) {
217 Buffer[0] = MmioRead32(MCI_RESPONSE0_REG);
218 Buffer[1] = MmioRead32(MCI_RESPONSE1_REG);
219 Buffer[2] = MmioRead32(MCI_RESPONSE2_REG);
220 Buffer[3] = MmioRead32(MCI_RESPONSE3_REG);
221 }
222
223 return EFI_SUCCESS;
224 }
225
226 EFI_STATUS
227 MciReadBlockData (
228 IN EFI_MMC_HOST_PROTOCOL *This,
229 IN EFI_LBA Lba,
230 IN UINTN Length,
231 IN UINT32* Buffer
232 )
233 {
234 UINTN Loop;
235 UINTN Finish;
236 UINTN Status;
237 EFI_STATUS RetVal;
238 UINTN DataCtrlReg;
239
240 RetVal = EFI_SUCCESS;
241
242 // Read data from the RX FIFO
243 Loop = 0;
244 Finish = MMCI0_BLOCKLEN / 4;
245 do {
246 // Read the Status flags
247 Status = MmioRead32(MCI_STATUS_REG);
248
249 // Do eight reads if possible else a single read
250 if (Status & MCI_STATUS_CMD_RXFIFOHALFFULL) {
251 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
252 Loop++;
253 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
254 Loop++;
255 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
256 Loop++;
257 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
258 Loop++;
259 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
260 Loop++;
261 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
262 Loop++;
263 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
264 Loop++;
265 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
266 Loop++;
267 } else if (Status & MCI_STATUS_CMD_RXDATAAVAILBL) {
268 Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
269 Loop++;
270 } else {
271 //Check for error conditions and timeouts
272 if(Status & MCI_STATUS_CMD_DATATIMEOUT) {
273 DEBUG ((EFI_D_ERROR, "MciReadBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n",MmioRead32(MCI_RESPONSE0_REG),Status));
274 RetVal = EFI_TIMEOUT;
275 break;
276 } else if(Status & MCI_STATUS_CMD_DATACRCFAIL) {
277 DEBUG ((EFI_D_ERROR, "MciReadBlockData(): CRC Error! Response:0x%X Status:0x%x\n",MmioRead32(MCI_RESPONSE0_REG),Status));
278 RetVal = EFI_CRC_ERROR;
279 break;
280 } else if(Status & MCI_STATUS_CMD_START_BIT_ERROR) {
281 DEBUG ((EFI_D_ERROR, "MciReadBlockData(): Start-bit Error! Response:0x%X Status:0x%x\n",MmioRead32(MCI_RESPONSE0_REG),Status));
282 RetVal = EFI_NO_RESPONSE;
283 break;
284 }
285 }
286 //clear RX over run flag
287 if(Status & MCI_STATUS_CMD_RXOVERRUN) {
288 MmioWrite32(MCI_CLEAR_STATUS_REG, MCI_STATUS_CMD_RXOVERRUN);
289 }
290 } while ((Loop < Finish));
291
292 //Clear Status flags
293 MmioWrite32(MCI_CLEAR_STATUS_REG, 0x7FF);
294
295 //Disable Data path
296 DataCtrlReg = MmioRead32(MCI_DATA_CTL_REG);
297 MmioWrite32(MCI_DATA_CTL_REG, (DataCtrlReg & 0xFE));
298
299 return RetVal;
300 }
301
302 EFI_STATUS
303 MciWriteBlockData (
304 IN EFI_MMC_HOST_PROTOCOL *This,
305 IN EFI_LBA Lba,
306 IN UINTN Length,
307 IN UINT32* Buffer
308 )
309 {
310 UINTN Loop;
311 UINTN Finish;
312 UINTN Timer;
313 UINTN Status;
314 EFI_STATUS RetVal;
315 UINTN DataCtrlReg;
316
317 RetVal = EFI_SUCCESS;
318
319 // Write the data to the TX FIFO
320 Loop = 0;
321 Finish = MMCI0_BLOCKLEN / 4;
322 Timer = MMCI0_TIMEOUT * 100;
323 do {
324 // Read the Status flags
325 Status = MmioRead32(MCI_STATUS_REG);
326
327 // Do eight writes if possible else a single write
328 if (Status & MCI_STATUS_CMD_TXFIFOHALFEMPTY) {
329 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
330 Loop++;
331 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
332 Loop++;
333 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
334 Loop++;
335 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
336 Loop++;
337 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
338 Loop++;
339 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
340 Loop++;
341 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
342 Loop++;
343 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
344 Loop++;
345 } else if ((Status & MCI_STATUS_CMD_TXFIFOEMPTY)) {
346 MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
347 Loop++;
348 } else {
349 //Check for error conditions and timeouts
350 if(Status & MCI_STATUS_CMD_DATATIMEOUT) {
351 DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n",MmioRead32(MCI_RESPONSE0_REG),Status));
352 RetVal = EFI_TIMEOUT;
353 goto Exit;
354 } else if(Status & MCI_STATUS_CMD_DATACRCFAIL) {
355 DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): CRC Error! Response:0x%X Status:0x%x\n",MmioRead32(MCI_RESPONSE0_REG),Status));
356 RetVal = EFI_CRC_ERROR;
357 goto Exit;
358 } else if(Status & MCI_STATUS_CMD_TX_UNDERRUN) {
359 DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): TX buffer Underrun! Response:0x%X Status:0x%x, Number of bytes written 0x%x\n",MmioRead32(MCI_RESPONSE0_REG),Status, Loop));
360 RetVal = EFI_BUFFER_TOO_SMALL;
361 ASSERT(0);
362 goto Exit;
363 }
364 }
365 } while (Loop < Finish);
366
367 // Wait for FIFO to drain
368 Timer = MMCI0_TIMEOUT * 60;
369 Status = MmioRead32(MCI_STATUS_REG);
370 #ifndef USE_STREAM
371 // Single block
372 while (((Status & MCI_STATUS_CMD_TXDONE) != MCI_STATUS_CMD_TXDONE) && Timer) {
373 #else
374 // Stream
375 while (((Status & MCI_STATUS_CMD_DATAEND) != MCI_STATUS_CMD_DATAEND) && Timer) {
376 #endif
377 NanoSecondDelay(10);
378 Status = MmioRead32(MCI_STATUS_REG);
379 Timer--;
380 }
381
382 if(Timer == 0) {
383 DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): Data End timeout Number of bytes written 0x%x\n",Loop));
384 ASSERT(Timer > 0);
385 return EFI_TIMEOUT;
386 }
387
388 //Clear Status flags
389 MmioWrite32(MCI_CLEAR_STATUS_REG, 0x7FF);
390 if (Timer == 0) {
391 RetVal = EFI_TIMEOUT;
392 }
393
394 Exit:
395 //Disable Data path
396 DataCtrlReg = MmioRead32(MCI_DATA_CTL_REG);
397 MmioWrite32(MCI_DATA_CTL_REG, (DataCtrlReg & 0xFE));
398 return RetVal;
399 }
400
401 EFI_STATUS
402 MciNotifyState (
403 IN EFI_MMC_HOST_PROTOCOL *This,
404 IN MMC_STATE State
405 )
406 {
407 UINT32 Data32;
408
409 switch(State) {
410 case MmcInvalidState:
411 ASSERT(0);
412 break;
413 case MmcHwInitializationState:
414 // If device already turn on then restart it
415 Data32 = MmioRead32(MCI_POWER_CONTROL_REG);
416 if ((Data32 & 0x2) == MCI_POWER_UP) {
417 MCI_TRACE("MciNotifyState(MmcHwInitializationState): TurnOff MCI");
418
419 // Turn off
420 MmioWrite32(MCI_CLOCK_CONTROL_REG, 0);
421 MmioWrite32(MCI_POWER_CONTROL_REG, 0);
422 MicroSecondDelay(100);
423 }
424
425 MCI_TRACE("MciNotifyState(MmcHwInitializationState): TurnOn MCI");
426 // Setup clock
427 // - 0x1D = 29 => should be the clock divider to be less than 400kHz at MCLK = 24Mhz
428 MmioWrite32(MCI_CLOCK_CONTROL_REG,0x1D | MCI_CLOCK_ENABLE | MCI_CLOCK_POWERSAVE);
429 //MmioWrite32(MCI_CLOCK_CONTROL_REG,0x1D | MCI_CLOCK_ENABLE);
430
431 // Set the voltage
432 MmioWrite32(MCI_POWER_CONTROL_REG,MCI_POWER_OPENDRAIN | (15<<2));
433 MmioWrite32(MCI_POWER_CONTROL_REG,MCI_POWER_ROD | MCI_POWER_OPENDRAIN | (15<<2) | MCI_POWER_UP);
434 MicroSecondDelay(10);
435 MmioWrite32(MCI_POWER_CONTROL_REG,MCI_POWER_ROD | MCI_POWER_OPENDRAIN | (15<<2) | MCI_POWER_ON);
436 MicroSecondDelay(100);
437
438 // Set Data Length & Data Timer
439 MmioWrite32(MCI_DATA_TIMER_REG,0xFFFFF);
440 MmioWrite32(MCI_DATA_LENGTH_REG,8);
441
442 ASSERT((MmioRead32(MCI_POWER_CONTROL_REG) & 0x3) == MCI_POWER_ON);
443 break;
444 case MmcIdleState:
445 MCI_TRACE("MciNotifyState(MmcIdleState)");
446 break;
447 case MmcReadyState:
448 MCI_TRACE("MciNotifyState(MmcReadyState)");
449 break;
450 case MmcIdentificationState:
451 MCI_TRACE("MciNotifyState(MmcIdentificationState)");
452 break;
453 case MmcStandByState:{
454 volatile UINT32 PwrCtrlReg;
455 MCI_TRACE("MciNotifyState(MmcStandByState)");
456
457 // Enable MCICMD push-pull drive
458 PwrCtrlReg = MmioRead32(MCI_POWER_CONTROL_REG);
459 //Disable Open Drain output
460 PwrCtrlReg &=~(MCI_POWER_OPENDRAIN);
461 MmioWrite32(MCI_POWER_CONTROL_REG,PwrCtrlReg);
462
463 // Set MMCI0 clock to 4MHz (24MHz may be possible with cache enabled)
464 //
465 // Note: Increasing clock speed causes TX FIFO under-run errors.
466 // So careful when optimising this driver for higher performance.
467 //
468 MmioWrite32(MCI_CLOCK_CONTROL_REG,0x02 | MCI_CLOCK_ENABLE | MCI_CLOCK_POWERSAVE);
469 // Set MMCI0 clock to 24MHz (by bypassing the divider)
470 //MmioWrite32(MCI_CLOCK_CONTROL_REG,MCI_CLOCK_BYPASS | MCI_CLOCK_ENABLE);
471 break;
472 }
473 case MmcTransferState:
474 //MCI_TRACE("MciNotifyState(MmcTransferState)");
475 break;
476 case MmcSendingDataState:
477 MCI_TRACE("MciNotifyState(MmcSendingDataState)");
478 break;
479 case MmcReceiveDataState:
480 MCI_TRACE("MciNotifyState(MmcReceiveDataState)");
481 break;
482 case MmcProgrammingState:
483 MCI_TRACE("MciNotifyState(MmcProgrammingState)");
484 break;
485 case MmcDisconnectState:
486 MCI_TRACE("MciNotifyState(MmcDisconnectState)");
487 break;
488 default:
489 ASSERT(0);
490 }
491 return EFI_SUCCESS;
492 }
493
494 EFI_GUID mPL180MciDevicePathGuid = EFI_CALLER_ID_GUID;
495
496 EFI_STATUS
497 MciBuildDevicePath (
498 IN EFI_MMC_HOST_PROTOCOL *This,
499 IN EFI_DEVICE_PATH_PROTOCOL **DevicePath
500 )
501 {
502 EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;
503
504 NewDevicePathNode = CreateDeviceNode(HARDWARE_DEVICE_PATH,HW_VENDOR_DP,sizeof(VENDOR_DEVICE_PATH));
505 CopyGuid(&((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid,&mPL180MciDevicePathGuid);
506
507 *DevicePath = NewDevicePathNode;
508 return EFI_SUCCESS;
509 }
510
511 EFI_MMC_HOST_PROTOCOL gMciHost = {
512 MMC_HOST_PROTOCOL_REVISION,
513 MciIsCardPresent,
514 MciIsReadOnly,
515 MciBuildDevicePath,
516 MciNotifyState,
517 MciSendCommand,
518 MciReceiveResponse,
519 MciReadBlockData,
520 MciWriteBlockData
521 };
522
523 EFI_STATUS
524 PL180MciDxeInitialize (
525 IN EFI_HANDLE ImageHandle,
526 IN EFI_SYSTEM_TABLE *SystemTable
527 )
528 {
529 EFI_STATUS Status;
530 EFI_HANDLE Handle = NULL;
531
532 MCI_TRACE("PL180MciDxeInitialize()");
533
534 //Publish Component Name, BlockIO protocol interfaces
535 Status = gBS->InstallMultipleProtocolInterfaces (
536 &Handle,
537 &gEfiMmcHostProtocolGuid, &gMciHost,
538 NULL
539 );
540 ASSERT_EFI_ERROR (Status);
541
542 return EFI_SUCCESS;
543 }