]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/I2c/I2cDxe/I2cHost.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / I2c / I2cDxe / I2cHost.c
CommitLineData
43e543bc 1/** @file\r
d1102dba 2 This file implements I2C Host Protocol which provides callers with the ability to\r
43e543bc
EL
3 do I/O transactions to all of the devices on the I2C bus.\r
4\r
01331951 5 Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>\r
d1102dba 6 Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
43e543bc
EL
8\r
9**/\r
10\r
11#include "I2cDxe.h"\r
12\r
1436aea4 13EFI_DRIVER_BINDING_PROTOCOL gI2cHostDriverBinding = {\r
43e543bc
EL
14 I2cHostDriverSupported,\r
15 I2cHostDriverStart,\r
16 I2cHostDriverStop,\r
17 0x10,\r
18 NULL,\r
19 NULL\r
20};\r
21\r
22//\r
d1102dba 23// Driver name table\r
43e543bc 24//\r
1436aea4 25GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mI2cHostDriverNameTable[] = {\r
43e543bc 26 { "eng;en", L"I2c Host Driver" },\r
1436aea4 27 { NULL, NULL }\r
43e543bc
EL
28};\r
29\r
30//\r
31// EFI Component Name Protocol\r
32//\r
33GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gI2cHostComponentName = {\r
1436aea4
MK
34 (EFI_COMPONENT_NAME_GET_DRIVER_NAME)I2cHostComponentNameGetDriverName,\r
35 (EFI_COMPONENT_NAME_GET_CONTROLLER_NAME)I2cHostComponentNameGetControllerName,\r
43e543bc
EL
36 "eng"\r
37};\r
38\r
39//\r
40// EFI Component Name 2 Protocol\r
41//\r
1436aea4 42GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gI2cHostComponentName2 = {\r
43e543bc
EL
43 I2cHostComponentNameGetDriverName,\r
44 I2cHostComponentNameGetControllerName,\r
45 "en"\r
46};\r
47\r
48/**\r
49 Retrieves a Unicode string that is the user readable name of the driver.\r
50\r
51 This function retrieves the user readable name of a driver in the form of a\r
52 Unicode string. If the driver specified by This has a user readable name in\r
53 the language specified by Language, then a pointer to the driver name is\r
54 returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
55 by This does not support the language specified by Language,\r
56 then EFI_UNSUPPORTED is returned.\r
57\r
58 @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
59 EFI_COMPONENT_NAME_PROTOCOL instance.\r
60\r
61 @param Language[in] A pointer to a Null-terminated ASCII string\r
62 array indicating the language. This is the\r
63 language of the driver name that the caller is\r
64 requesting, and it must match one of the\r
65 languages specified in SupportedLanguages. The\r
66 number of languages supported by a driver is up\r
67 to the driver writer. Language is specified\r
68 in RFC 4646 or ISO 639-2 language code format.\r
69\r
70 @param DriverName[out] A pointer to the Unicode string to return.\r
71 This Unicode string is the name of the\r
72 driver specified by This in the language\r
73 specified by Language.\r
74\r
75 @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
76 This and the language specified by Language was\r
77 returned in DriverName.\r
78\r
79 @retval EFI_INVALID_PARAMETER Language is NULL.\r
80\r
81 @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
82\r
83 @retval EFI_UNSUPPORTED The driver specified by This does not support\r
84 the language specified by Language.\r
85\r
86**/\r
87EFI_STATUS\r
88EFIAPI\r
89I2cHostComponentNameGetDriverName (\r
90 IN EFI_COMPONENT_NAME2_PROTOCOL *This,\r
1436aea4
MK
91 IN CHAR8 *Language,\r
92 OUT CHAR16 **DriverName\r
43e543bc
EL
93 )\r
94{\r
95 return LookupUnicodeString2 (\r
96 Language,\r
97 This->SupportedLanguages,\r
98 mI2cHostDriverNameTable,\r
99 DriverName,\r
100 (BOOLEAN)(This != &gI2cHostComponentName2)\r
101 );\r
102}\r
103\r
104/**\r
105 Retrieves a Unicode string that is the user readable name of the controller\r
106 that is being managed by a driver.\r
107\r
108 This function retrieves the user readable name of the controller specified by\r
109 ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
110 driver specified by This has a user readable name in the language specified by\r
111 Language, then a pointer to the controller name is returned in ControllerName,\r
112 and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
113 managing the controller specified by ControllerHandle and ChildHandle,\r
114 then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
115 support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
116\r
117 @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
118 EFI_COMPONENT_NAME_PROTOCOL instance.\r
119\r
120 @param ControllerHandle[in] The handle of a controller that the driver\r
121 specified by This is managing. This handle\r
122 specifies the controller whose name is to be\r
123 returned.\r
124\r
125 @param ChildHandle[in] The handle of the child controller to retrieve\r
126 the name of. This is an optional parameter that\r
127 may be NULL. It will be NULL for device\r
128 drivers. It will also be NULL for a bus drivers\r
129 that wish to retrieve the name of the bus\r
130 controller. It will not be NULL for a bus\r
131 driver that wishes to retrieve the name of a\r
132 child controller.\r
133\r
134 @param Language[in] A pointer to a Null-terminated ASCII string\r
135 array indicating the language. This is the\r
136 language of the driver name that the caller is\r
137 requesting, and it must match one of the\r
138 languages specified in SupportedLanguages. The\r
139 number of languages supported by a driver is up\r
140 to the driver writer. Language is specified in\r
141 RFC 4646 or ISO 639-2 language code format.\r
142\r
143 @param ControllerName[out] A pointer to the Unicode string to return.\r
144 This Unicode string is the name of the\r
145 controller specified by ControllerHandle and\r
146 ChildHandle in the language specified by\r
147 Language from the point of view of the driver\r
148 specified by This.\r
149\r
150 @retval EFI_SUCCESS The Unicode string for the user readable name in\r
151 the language specified by Language for the\r
152 driver specified by This was returned in\r
153 DriverName.\r
154\r
155 @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
156\r
157 @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
158 EFI_HANDLE.\r
159\r
160 @retval EFI_INVALID_PARAMETER Language is NULL.\r
161\r
162 @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
163\r
164 @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
165 managing the controller specified by\r
166 ControllerHandle and ChildHandle.\r
167\r
168 @retval EFI_UNSUPPORTED The driver specified by This does not support\r
169 the language specified by Language.\r
170\r
171**/\r
172EFI_STATUS\r
173EFIAPI\r
174I2cHostComponentNameGetControllerName (\r
1436aea4
MK
175 IN EFI_COMPONENT_NAME2_PROTOCOL *This,\r
176 IN EFI_HANDLE ControllerHandle,\r
177 IN EFI_HANDLE ChildHandle OPTIONAL,\r
178 IN CHAR8 *Language,\r
179 OUT CHAR16 **ControllerName\r
43e543bc
EL
180 )\r
181{\r
182 return EFI_UNSUPPORTED;\r
183}\r
184\r
185/**\r
186 Tests to see if this driver supports a given controller. If a child device is provided,\r
187 it further tests to see if this driver supports creating a handle for the specified child device.\r
188\r
189 This function checks to see if the driver specified by This supports the device specified by\r
190 ControllerHandle. Drivers will typically use the device path attached to\r
191 ControllerHandle and/or the services from the bus I/O abstraction attached to\r
192 ControllerHandle to determine if the driver supports ControllerHandle. This function\r
193 may be called many times during platform initialization. In order to reduce boot times, the tests\r
194 performed by this function must be very small, and take as little time as possible to execute. This\r
195 function must not change the state of any hardware devices, and this function must be aware that the\r
196 device specified by ControllerHandle may already be managed by the same driver or a\r
197 different driver. This function must match its calls to AllocatePages() with FreePages(),\r
198 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
199 Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
200 already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
201 to guarantee the state of ControllerHandle is not modified by this function.\r
202\r
203 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
204 @param[in] ControllerHandle The handle of the controller to test. This handle\r
205 must support a protocol interface that supplies\r
206 an I/O abstraction to the driver.\r
207 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
208 parameter is ignored by device drivers, and is optional for bus\r
209 drivers. For bus drivers, if this parameter is not NULL, then\r
210 the bus driver must determine if the bus controller specified\r
211 by ControllerHandle and the child controller specified\r
212 by RemainingDevicePath are both supported by this\r
213 bus driver.\r
214\r
215 @retval EFI_SUCCESS The device specified by ControllerHandle and\r
216 RemainingDevicePath is supported by the driver specified by This.\r
217 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
218 RemainingDevicePath is already being managed by the driver\r
219 specified by This.\r
220 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
221 RemainingDevicePath is already being managed by a different\r
222 driver or an application that requires exclusive access.\r
223 Currently not implemented.\r
224 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
225 RemainingDevicePath is not supported by the driver specified by This.\r
226**/\r
227EFI_STATUS\r
228EFIAPI\r
229I2cHostDriverSupported (\r
230 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
231 IN EFI_HANDLE Controller,\r
232 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
233 )\r
234{\r
1436aea4
MK
235 EFI_I2C_MASTER_PROTOCOL *I2cMaster;\r
236 EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *I2cBusConfigurationManagement;\r
237 EFI_STATUS Status;\r
43e543bc
EL
238\r
239 //\r
240 // Locate I2C Bus Configuration Management Protocol\r
241 //\r
242 Status = gBS->OpenProtocol (\r
243 Controller,\r
244 &gEfiI2cBusConfigurationManagementProtocolGuid,\r
245 (VOID **)&I2cBusConfigurationManagement,\r
246 This->DriverBindingHandle,\r
247 Controller,\r
248 EFI_OPEN_PROTOCOL_BY_DRIVER\r
249 );\r
250 if (EFI_ERROR (Status)) {\r
251 return Status;\r
252 }\r
253\r
254 //\r
255 // Close the protocol because we don't use it here\r
256 //\r
257 gBS->CloseProtocol (\r
1436aea4
MK
258 Controller,\r
259 &gEfiI2cBusConfigurationManagementProtocolGuid,\r
260 This->DriverBindingHandle,\r
261 Controller\r
262 );\r
43e543bc
EL
263\r
264 //\r
265 // Locate I2C Master Protocol\r
266 //\r
267 Status = gBS->OpenProtocol (\r
268 Controller,\r
269 &gEfiI2cMasterProtocolGuid,\r
270 (VOID **)&I2cMaster,\r
271 This->DriverBindingHandle,\r
272 Controller,\r
273 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
274 );\r
275 if (EFI_ERROR (Status)) {\r
276 return Status;\r
277 }\r
278\r
279 return EFI_SUCCESS;\r
280}\r
281\r
282/**\r
283 Starts a device controller or a bus controller.\r
284\r
285 The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
286 As a result, much of the error checking on the parameters to Start() has been moved into this\r
287 common boot service. It is legal to call Start() from other locations,\r
288 but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
289 1. ControllerHandle must be a valid EFI_HANDLE.\r
290 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
291 EFI_DEVICE_PATH_PROTOCOL.\r
292 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
293 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
294\r
295 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
296 @param[in] ControllerHandle The handle of the controller to start. This handle\r
297 must support a protocol interface that supplies\r
298 an I/O abstraction to the driver.\r
299 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
300 parameter is ignored by device drivers, and is optional for bus\r
301 drivers. For a bus driver, if this parameter is NULL, then handles\r
302 for all the children of Controller are created by this driver.\r
303 If this parameter is not NULL and the first Device Path Node is\r
304 not the End of Device Path Node, then only the handle for the\r
305 child device specified by the first Device Path Node of\r
306 RemainingDevicePath is created by this driver.\r
307 If the first Device Path Node of RemainingDevicePath is\r
308 the End of Device Path Node, no child handle is created by this\r
309 driver.\r
310\r
311 @retval EFI_SUCCESS The device was started.\r
312 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
313 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
29f7ad8b 314 @retval Others The driver failed to start the device.\r
43e543bc
EL
315\r
316**/\r
317EFI_STATUS\r
318EFIAPI\r
319I2cHostDriverStart (\r
1436aea4
MK
320 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
321 IN EFI_HANDLE Controller,\r
322 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
43e543bc
EL
323 )\r
324{\r
1436aea4
MK
325 EFI_STATUS Status;\r
326 EFI_I2C_MASTER_PROTOCOL *I2cMaster;\r
327 EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *I2cBusConfigurationManagement;\r
328 I2C_HOST_CONTEXT *I2cHostContext;\r
43e543bc
EL
329\r
330 I2cMaster = NULL;\r
331 I2cHostContext = NULL;\r
332 I2cBusConfigurationManagement = NULL;\r
333\r
334 //\r
335 // Locate I2C Bus Configuration Management Protocol\r
336 //\r
337 Status = gBS->OpenProtocol (\r
338 Controller,\r
339 &gEfiI2cBusConfigurationManagementProtocolGuid,\r
340 (VOID **)&I2cBusConfigurationManagement,\r
341 This->DriverBindingHandle,\r
342 Controller,\r
343 EFI_OPEN_PROTOCOL_BY_DRIVER\r
344 );\r
345 if (EFI_ERROR (Status)) {\r
87000d77 346 DEBUG ((DEBUG_ERROR, "I2cHost: Open I2C bus configuration error, Status = %r\n", Status));\r
43e543bc
EL
347 return Status;\r
348 }\r
349\r
350 //\r
351 // Locate I2C Master Protocol\r
352 //\r
d1102dba 353 Status = gBS->OpenProtocol (\r
43e543bc
EL
354 Controller,\r
355 &gEfiI2cMasterProtocolGuid,\r
356 (VOID **)&I2cMaster,\r
357 This->DriverBindingHandle,\r
358 Controller,\r
359 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
360 );\r
361 if (EFI_ERROR (Status)) {\r
87000d77 362 DEBUG ((DEBUG_ERROR, "I2cHost: Open I2C master error, Status = %r\n", Status));\r
43e543bc
EL
363 goto Exit;\r
364 }\r
365\r
366 //\r
367 // Allocate the I2C Host Context structure\r
368 //\r
369 I2cHostContext = AllocateZeroPool (sizeof (I2C_HOST_CONTEXT));\r
370 if (I2cHostContext == NULL) {\r
87000d77 371 DEBUG ((DEBUG_ERROR, "I2cHost: there is no enough memory to allocate.\n"));\r
43e543bc
EL
372 Status = EFI_OUT_OF_RESOURCES;\r
373 goto Exit;\r
374 }\r
375\r
376 //\r
377 // Initialize the context structure for the current I2C Controller\r
378 //\r
379 I2cHostContext->Signature = I2C_HOST_SIGNATURE;\r
380 I2cHostContext->I2cMaster = I2cMaster;\r
381 I2cHostContext->I2cBusConfigurationManagement = I2cBusConfigurationManagement;\r
1436aea4
MK
382 I2cHostContext->I2cBusConfiguration = (UINTN)-1;\r
383 InitializeListHead (&I2cHostContext->RequestList);\r
43e543bc
EL
384\r
385 //\r
386 // Reset the controller\r
387 //\r
388 Status = I2cMaster->Reset (I2cMaster);\r
389 if (EFI_ERROR (Status)) {\r
87000d77 390 DEBUG ((DEBUG_ERROR, "I2cHost: I2C controller reset failed!\n"));\r
43e543bc
EL
391 goto Exit;\r
392 }\r
393\r
394 //\r
395 // Create the I2C transaction complete event\r
396 //\r
397 Status = gBS->CreateEvent (\r
398 EVT_NOTIFY_SIGNAL,\r
399 TPL_I2C_SYNC,\r
400 I2cHostRequestCompleteEvent,\r
401 I2cHostContext,\r
402 &I2cHostContext->I2cEvent\r
403 );\r
404 if (EFI_ERROR (Status)) {\r
87000d77 405 DEBUG ((DEBUG_ERROR, "I2cHost: create complete event error, Status = %r\n", Status));\r
43e543bc
EL
406 goto Exit;\r
407 }\r
408\r
409 //\r
410 // Get the bus management event\r
411 //\r
412 Status = gBS->CreateEvent (\r
413 EVT_NOTIFY_SIGNAL,\r
414 TPL_I2C_SYNC,\r
415 I2cHostI2cBusConfigurationAvailable,\r
416 I2cHostContext,\r
417 &I2cHostContext->I2cBusConfigurationEvent\r
418 );\r
419 if (EFI_ERROR (Status)) {\r
87000d77 420 DEBUG ((DEBUG_ERROR, "I2cHost: create bus available event error, Status = %r\n", Status));\r
43e543bc 421 goto Exit;\r
d1102dba 422 }\r
43e543bc
EL
423\r
424 //\r
425 // Build the I2C host protocol for the current I2C controller\r
426 //\r
427 I2cHostContext->I2cHost.QueueRequest = I2cHostQueueRequest;\r
428 I2cHostContext->I2cHost.I2cControllerCapabilities = I2cMaster->I2cControllerCapabilities;\r
429\r
430 //\r
431 // Install the driver protocol\r
432 //\r
433 Status = gBS->InstallMultipleProtocolInterfaces (\r
434 &Controller,\r
435 &gEfiI2cHostProtocolGuid,\r
436 &I2cHostContext->I2cHost,\r
437 NULL\r
438 );\r
439Exit:\r
440 if (EFI_ERROR (Status)) {\r
87000d77 441 DEBUG ((DEBUG_ERROR, "I2cHost: Start() function failed, Status = %r\n", Status));\r
43e543bc
EL
442 if (I2cBusConfigurationManagement != NULL) {\r
443 gBS->CloseProtocol (\r
1436aea4
MK
444 Controller,\r
445 &gEfiI2cBusConfigurationManagementProtocolGuid,\r
446 This->DriverBindingHandle,\r
447 Controller\r
448 );\r
43e543bc 449 }\r
d1102dba 450\r
43e543bc
EL
451 if ((I2cHostContext != NULL) && (I2cHostContext->I2cEvent != NULL)) {\r
452 gBS->CloseEvent (I2cHostContext->I2cEvent);\r
453 I2cHostContext->I2cEvent = NULL;\r
454 }\r
455\r
456 if ((I2cHostContext != NULL) && (I2cHostContext->I2cBusConfigurationEvent != NULL)) {\r
457 gBS->CloseEvent (I2cHostContext->I2cBusConfigurationEvent);\r
458 I2cHostContext->I2cBusConfigurationEvent = NULL;\r
459 }\r
460\r
461 //\r
462 // Release the context structure upon failure\r
463 //\r
464 if (I2cHostContext != NULL) {\r
465 FreePool (I2cHostContext);\r
466 }\r
467 }\r
468\r
469 //\r
470 // Return the operation status.\r
471 //\r
472 return Status;\r
473}\r
474\r
475/**\r
476 Stops a device controller or a bus controller.\r
477\r
478 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
479 As a result, much of the error checking on the parameters to Stop() has been moved\r
480 into this common boot service. It is legal to call Stop() from other locations,\r
481 but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
482 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
483 same driver's Start() function.\r
484 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
485 EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
486 Start() function, and the Start() function must have called OpenProtocol() on\r
487 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
488\r
489 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
490 @param[in] ControllerHandle A handle to the device being stopped. The handle must\r
491 support a bus specific I/O protocol for the driver\r
492 to use to stop the device.\r
493 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
494 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
495 if NumberOfChildren is 0.\r
496\r
497 @retval EFI_SUCCESS The device was stopped.\r
498 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
499\r
500**/\r
501EFI_STATUS\r
502EFIAPI\r
503I2cHostDriverStop (\r
1436aea4
MK
504 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
505 IN EFI_HANDLE Controller,\r
506 IN UINTN NumberOfChildren,\r
507 IN EFI_HANDLE *ChildHandleBuffer\r
43e543bc
EL
508 )\r
509{\r
1436aea4
MK
510 EFI_STATUS Status;\r
511 I2C_HOST_CONTEXT *I2cHostContext;\r
512 EFI_I2C_HOST_PROTOCOL *I2cHost;\r
513 EFI_TPL TplPrevious;\r
43e543bc
EL
514\r
515 TplPrevious = EfiGetCurrentTpl ();\r
516 if (TplPrevious > TPL_I2C_SYNC) {\r
87000d77 517 DEBUG ((DEBUG_ERROR, "I2cHost: TPL %d is too high in Stop.\n", TplPrevious));\r
43e543bc
EL
518 return EFI_DEVICE_ERROR;\r
519 }\r
520\r
521 Status = gBS->OpenProtocol (\r
522 Controller,\r
523 &gEfiI2cHostProtocolGuid,\r
1436aea4 524 (VOID **)&I2cHost,\r
43e543bc
EL
525 This->DriverBindingHandle,\r
526 Controller,\r
527 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
528 );\r
529\r
530 if (EFI_ERROR (Status)) {\r
531 return EFI_DEVICE_ERROR;\r
532 }\r
533\r
534 I2cHostContext = I2C_HOST_CONTEXT_FROM_PROTOCOL (I2cHost);\r
535\r
536 //\r
537 // Raise TPL for critical section\r
538 //\r
539 TplPrevious = gBS->RaiseTPL (TPL_I2C_SYNC);\r
d1102dba 540\r
43e543bc
EL
541 //\r
542 // If there is pending request or pending bus configuration, do not stop\r
543 //\r
544 Status = EFI_DEVICE_ERROR;\r
1436aea4
MK
545 if ( (!I2cHostContext->I2cBusConfigurationManagementPending)\r
546 && IsListEmpty (&I2cHostContext->RequestList))\r
547 {\r
43e543bc
EL
548 //\r
549 // Remove the I2C host protocol\r
550 //\r
551 Status = gBS->UninstallMultipleProtocolInterfaces (\r
552 Controller,\r
553 &gEfiI2cHostProtocolGuid,\r
554 I2cHost,\r
555 NULL\r
556 );\r
557 }\r
d1102dba 558\r
43e543bc
EL
559 //\r
560 // Leave critical section\r
561 //\r
562 gBS->RestoreTPL (TplPrevious);\r
563 if (!EFI_ERROR (Status)) {\r
564 gBS->CloseProtocol (\r
565 Controller,\r
566 &gEfiI2cBusConfigurationManagementProtocolGuid,\r
567 This->DriverBindingHandle,\r
568 Controller\r
569 );\r
570\r
571 //\r
572 // Release I2c Host resources\r
573 //\r
574 if (I2cHostContext->I2cBusConfigurationEvent != NULL) {\r
575 gBS->CloseEvent (I2cHostContext->I2cBusConfigurationEvent);\r
576 I2cHostContext->I2cBusConfigurationEvent = NULL;\r
577 }\r
d1102dba 578\r
43e543bc
EL
579 if (I2cHostContext->I2cEvent != NULL) {\r
580 gBS->CloseEvent (I2cHostContext->I2cEvent);\r
581 I2cHostContext->I2cEvent = NULL;\r
582 }\r
d1102dba 583\r
43e543bc
EL
584 FreePool (I2cHostContext);\r
585 }\r
586\r
587 //\r
588 // Return the stop status\r
589 //\r
590 return Status;\r
591}\r
592\r
593/**\r
594 Handle the I2C bus configuration available event\r
595\r
596 This routine is called at TPL_I2C_SYNC.\r
597\r
598 @param[in] Event Address of an EFI_EVENT handle\r
599 @param[in] Context Address of an I2C_HOST_CONTEXT structure\r
600\r
601**/\r
602VOID\r
603EFIAPI\r
604I2cHostI2cBusConfigurationAvailable (\r
1436aea4
MK
605 IN EFI_EVENT Event,\r
606 IN VOID *Context\r
43e543bc
EL
607 )\r
608{\r
1436aea4
MK
609 I2C_HOST_CONTEXT *I2cHostContext;\r
610 EFI_I2C_MASTER_PROTOCOL *I2cMaster;\r
611 I2C_REQUEST *I2cRequest;\r
612 LIST_ENTRY *EntryHeader;\r
613 LIST_ENTRY *Entry;\r
614 EFI_STATUS Status;\r
43e543bc
EL
615\r
616 //\r
617 // Mark this I2C bus configuration management operation as complete\r
618 //\r
619 I2cHostContext = (I2C_HOST_CONTEXT *)Context;\r
620 I2cMaster = I2cHostContext->I2cMaster;\r
621 ASSERT (I2cMaster != NULL);\r
622 //\r
623 // Clear flag to indicate I2C bus configuration is finished\r
624 //\r
625 I2cHostContext->I2cBusConfigurationManagementPending = FALSE;\r
626\r
627 //\r
628 // Validate the completion status\r
629 //\r
630 if (EFI_ERROR (I2cHostContext->Status)) {\r
631 //\r
632 // Setting I2C bus configuration failed before\r
633 //\r
634 I2cHostRequestComplete (I2cHostContext, I2cHostContext->Status);\r
635\r
636 //\r
637 // Unknown I2C bus configuration\r
638 // Force next operation to enable the I2C bus configuration\r
639 //\r
1436aea4 640 I2cHostContext->I2cBusConfiguration = (UINTN)-1;\r
d1102dba 641\r
43e543bc
EL
642 //\r
643 // Do not continue current I2C request\r
644 //\r
645 return;\r
646 }\r
647\r
648 //\r
649 // Get the first request in the link with FIFO order\r
650 //\r
651 EntryHeader = &I2cHostContext->RequestList;\r
1436aea4
MK
652 Entry = GetFirstNode (EntryHeader);\r
653 I2cRequest = I2C_REQUEST_FROM_ENTRY (Entry);\r
43e543bc
EL
654\r
655 //\r
656 // Update the I2C bus configuration of the current I2C request\r
657 //\r
658 I2cHostContext->I2cBusConfiguration = I2cRequest->I2cBusConfiguration;\r
659\r
660 //\r
661 // Start an I2C operation on the host, the status is returned by I2cHostContext->Status\r
662 //\r
d1102dba 663 Status = I2cMaster->StartRequest (\r
43e543bc
EL
664 I2cMaster,\r
665 I2cRequest->SlaveAddress,\r
666 I2cRequest->RequestPacket,\r
667 I2cHostContext->I2cEvent,\r
668 &I2cHostContext->Status\r
669 );\r
01331951
SEHM
670\r
671 if (EFI_ERROR (Status)) {\r
1436aea4 672 DEBUG ((DEBUG_ERROR, "I2cHostI2cBusConfigurationAvailable: Error starting I2C operation, %r\n", Status));\r
01331951 673 }\r
43e543bc
EL
674}\r
675\r
676/**\r
677 Complete the current request\r
678\r
679 This routine is called at TPL_I2C_SYNC.\r
680\r
681 @param[in] I2cHostContext Address of an I2C_HOST_CONTEXT structure.\r
682 @param[in] Status Status of the I2C operation.\r
683\r
684 @return This routine returns the input status value.\r
685\r
686**/\r
687EFI_STATUS\r
688I2cHostRequestComplete (\r
1436aea4
MK
689 I2C_HOST_CONTEXT *I2cHostContext,\r
690 EFI_STATUS Status\r
43e543bc
EL
691 )\r
692{\r
1436aea4
MK
693 I2C_REQUEST *I2cRequest;\r
694 LIST_ENTRY *EntryHeader;\r
695 LIST_ENTRY *Entry;\r
43e543bc
EL
696\r
697 //\r
698 // Remove the current I2C request from the list\r
699 //\r
700 EntryHeader = &I2cHostContext->RequestList;\r
1436aea4
MK
701 Entry = GetFirstNode (EntryHeader);\r
702 I2cRequest = I2C_REQUEST_FROM_ENTRY (Entry);\r
43e543bc
EL
703\r
704 //\r
705 // Save the status for QueueRequest\r
706 //\r
707 if ( NULL != I2cRequest->Status ) {\r
708 *I2cRequest->Status = Status;\r
709 }\r
710\r
711 //\r
712 // Notify the user of the I2C request completion\r
713 //\r
714 if ( NULL != I2cRequest->Event ) {\r
715 gBS->SignalEvent (I2cRequest->Event);\r
716 }\r
717\r
718 //\r
719 // Done with this request, remove the current request from list\r
720 //\r
721 RemoveEntryList (&I2cRequest->Link);\r
722 FreePool (I2cRequest->RequestPacket);\r
723 FreePool (I2cRequest);\r
724\r
725 //\r
726 // If there is more I2C request, start next one\r
727 //\r
1436aea4 728 if (!IsListEmpty (EntryHeader)) {\r
43e543bc
EL
729 I2cHostRequestEnable (I2cHostContext);\r
730 }\r
d1102dba 731\r
43e543bc
EL
732 return Status;\r
733}\r
734\r
735/**\r
736 Handle the bus available event\r
737\r
738 This routine is called at TPL_I2C_SYNC.\r
739\r
740 @param[in] Event Address of an EFI_EVENT handle\r
741 @param[in] Context Address of an I2C_HOST_CONTEXT structure\r
742\r
743**/\r
744VOID\r
745EFIAPI\r
746I2cHostRequestCompleteEvent (\r
1436aea4
MK
747 IN EFI_EVENT Event,\r
748 IN VOID *Context\r
43e543bc
EL
749 )\r
750{\r
1436aea4 751 I2C_HOST_CONTEXT *I2cHostContext;\r
43e543bc
EL
752\r
753 //\r
754 // Handle the completion event\r
755 //\r
756 I2cHostContext = (I2C_HOST_CONTEXT *)Context;\r
757 I2cHostRequestComplete (I2cHostContext, I2cHostContext->Status);\r
758}\r
759\r
760/**\r
761 Enable access to the I2C bus configuration\r
762\r
763 @param[in] I2cHostContext Address of an I2C_HOST_CONTEXT structure\r
764\r
765 @retval EFI_SUCCESS The operation completed successfully.\r
766 @retval EFI_ABORTED The request did not complete because the driver\r
767 was shutdown.\r
768 @retval EFI_BAD_BUFFER_SIZE The WriteBytes or ReadBytes buffer size is too large.\r
769 @retval EFI_DEVICE_ERROR There was an I2C error (NACK) during the operation.\r
770 This could indicate the slave device is not present.\r
771 @retval EFI_INVALID_PARAMETER RequestPacket is NULL\r
772 @retval EFI_NO_MAPPING Invalid I2cBusConfiguration value\r
773 @retval EFI_NO_RESPONSE The I2C device is not responding to the\r
774 slave address. EFI_DEVICE_ERROR may also be\r
775 returned if the controller can not distinguish\r
776 when the NACK occurred.\r
777 @retval EFI_NOT_FOUND I2C slave address exceeds maximum address\r
778 @retval EFI_NOT_READY I2C bus is busy or operation pending, wait for\r
779 the event and then read status.\r
780 @retval EFI_OUT_OF_RESOURCES Insufficient memory for I2C operation\r
781 @retval EFI_TIMEOUT The transaction did not complete within an internally\r
782 specified timeout period.\r
783\r
784**/\r
785EFI_STATUS\r
786I2cHostRequestEnable (\r
1436aea4 787 I2C_HOST_CONTEXT *I2cHostContext\r
43e543bc
EL
788 )\r
789{\r
1436aea4
MK
790 UINTN I2cBusConfiguration;\r
791 CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *I2cBusConfigurationManagement;\r
792 I2C_REQUEST *I2cRequest;\r
793 EFI_STATUS Status;\r
794 EFI_TPL TplPrevious;\r
795 LIST_ENTRY *EntryHeader;\r
796 LIST_ENTRY *Entry;\r
43e543bc
EL
797\r
798 //\r
799 // Assume pending request\r
800 //\r
801 Status = EFI_NOT_READY;\r
802\r
803 I2cBusConfigurationManagement = I2cHostContext->I2cBusConfigurationManagement;\r
804\r
805 //\r
806 // Validate the I2c bus configuration\r
807 //\r
808 EntryHeader = &I2cHostContext->RequestList;\r
809 Entry = GetFirstNode (EntryHeader);\r
1436aea4 810 I2cRequest = I2C_REQUEST_FROM_ENTRY (Entry);\r
43e543bc
EL
811\r
812 I2cBusConfiguration = I2cRequest->I2cBusConfiguration;\r
813\r
814 if (I2cHostContext->I2cBusConfiguration != I2cBusConfiguration ) {\r
815 //\r
816 // Set flag to indicate I2C bus configuration is in progress\r
817 //\r
818 I2cHostContext->I2cBusConfigurationManagementPending = TRUE;\r
819 //\r
820 // Update bus configuration for this device's requesting bus configuration\r
821 //\r
822 Status = I2cBusConfigurationManagement->EnableI2cBusConfiguration (\r
1436aea4
MK
823 I2cBusConfigurationManagement,\r
824 I2cBusConfiguration,\r
825 I2cHostContext->I2cBusConfigurationEvent,\r
826 &I2cHostContext->Status\r
827 );\r
43e543bc
EL
828 } else {\r
829 //\r
830 // I2C bus configuration is same, no need change configuration and start I2c transaction directly\r
831 //\r
1436aea4 832 TplPrevious = gBS->RaiseTPL (TPL_I2C_SYNC);\r
43e543bc
EL
833\r
834 //\r
835 // Same I2C bus configuration\r
836 //\r
837 I2cHostContext->Status = EFI_SUCCESS;\r
838 I2cHostI2cBusConfigurationAvailable (I2cHostContext->I2cBusConfigurationEvent, I2cHostContext);\r
839\r
840 //\r
841 // Release the thread synchronization\r
842 //\r
1436aea4 843 gBS->RestoreTPL (TplPrevious);\r
43e543bc 844 }\r
1436aea4 845\r
43e543bc
EL
846 return Status;\r
847}\r
848\r
849/**\r
850 Queue an I2C operation for execution on the I2C controller.\r
851\r
852 This routine must be called at or below TPL_NOTIFY. For synchronous\r
853 requests this routine must be called at or below TPL_CALLBACK.\r
854\r
855 N.B. The typical consumers of this API are the I2C bus driver and\r
856 on rare occasions the I2C test application. Extreme care must be\r
857 taken by other consumers of this API to prevent confusing the\r
858 third party I2C drivers due to a state change at the I2C device\r
859 which the third party I2C drivers did not initiate. I2C platform\r
860 drivers may use this API within these guidelines.\r
861\r
862 This layer uses the concept of I2C bus configurations to describe\r
863 the I2C bus. An I2C bus configuration is defined as a unique\r
864 setting of the multiplexers and switches in the I2C bus which\r
865 enable access to one or more I2C devices. When using a switch\r
866 to divide a bus, due to speed differences, the I2C platform layer\r
867 would define an I2C bus configuration for the I2C devices on each\r
868 side of the switch. When using a multiplexer, the I2C platform\r
869 layer defines an I2C bus configuration for each of the selector\r
870 values required to control the multiplexer. See Figure 1 in the\r
871 <a href="http://www.nxp.com/documents/user_manual/UM10204.pdf">I<sup>2</sup>C\r
872 Specification</a> for a complex I2C bus configuration.\r
873\r
874 The I2C host driver processes all operations in FIFO order. Prior to\r
875 performing the operation, the I2C host driver calls the I2C platform\r
876 driver to reconfigure the switches and multiplexers in the I2C bus\r
877 enabling access to the specified I2C device. The I2C platform driver\r
878 also selects the maximum bus speed for the device. After the I2C bus\r
879 is configured, the I2C host driver calls the I2C port driver to\r
880 initialize the I2C controller and start the I2C operation.\r
881\r
882 @param[in] This Address of an EFI_I2C_HOST_PROTOCOL instance.\r
883 @param[in] I2cBusConfiguration I2C bus configuration to access the I2C\r
884 device.\r
885 @param[in] SlaveAddress Address of the device on the I2C bus.\r
886 @param[in] Event Event to set for asynchronous operations,\r
887 NULL for synchronous operations\r
888 @param[in] RequestPacket Address of an EFI_I2C_REQUEST_PACKET\r
889 structure describing the I2C operation\r
890 @param[out] I2cStatus Optional buffer to receive the I2C operation\r
891 completion status\r
892\r
893 @retval EFI_SUCCESS The operation completed successfully.\r
43e543bc
EL
894 @retval EFI_BAD_BUFFER_SIZE The WriteBytes or ReadBytes buffer size is too large.\r
895 @retval EFI_DEVICE_ERROR There was an I2C error (NACK) during the operation.\r
896 This could indicate the slave device is not present.\r
897 @retval EFI_INVALID_PARAMETER RequestPacket is NULL\r
898 @retval EFI_INVALID_PARAMETER TPL is too high\r
899 @retval EFI_NO_MAPPING Invalid I2cBusConfiguration value\r
900 @retval EFI_NO_RESPONSE The I2C device is not responding to the\r
901 slave address. EFI_DEVICE_ERROR may also be\r
902 returned if the controller can not distinguish\r
903 when the NACK occurred.\r
904 @retval EFI_NOT_FOUND I2C slave address exceeds maximum address\r
905 @retval EFI_NOT_READY I2C bus is busy or operation pending, wait for\r
906 the event and then read status pointed to by\r
907 the request packet.\r
908 @retval EFI_OUT_OF_RESOURCES Insufficient memory for I2C operation\r
909 @retval EFI_TIMEOUT The transaction did not complete within an internally\r
910 specified timeout period.\r
911\r
912**/\r
913EFI_STATUS\r
914EFIAPI\r
915I2cHostQueueRequest (\r
916 IN CONST EFI_I2C_HOST_PROTOCOL *This,\r
917 IN UINTN I2cBusConfiguration,\r
918 IN UINTN SlaveAddress,\r
919 IN EFI_EVENT Event OPTIONAL,\r
920 IN EFI_I2C_REQUEST_PACKET *RequestPacket,\r
921 OUT EFI_STATUS *I2cStatus OPTIONAL\r
922 )\r
923{\r
924 EFI_STATUS Status;\r
925 EFI_EVENT SyncEvent;\r
926 EFI_TPL TplPrevious;\r
927 I2C_REQUEST *I2cRequest;\r
928 I2C_HOST_CONTEXT *I2cHostContext;\r
929 BOOLEAN FirstRequest;\r
930 UINTN RequestPacketSize;\r
62eeb52a 931 UINTN StartBit;\r
43e543bc
EL
932\r
933 SyncEvent = NULL;\r
934 FirstRequest = FALSE;\r
935 Status = EFI_SUCCESS;\r
936\r
937 if (RequestPacket == NULL) {\r
938 return EFI_INVALID_PARAMETER;\r
939 }\r
d1102dba 940\r
62eeb52a
EL
941 if ((SlaveAddress & I2C_ADDRESSING_10_BIT) != 0) {\r
942 //\r
943 // 10-bit address, bits 0-9 are used for 10-bit I2C slave addresses,\r
944 // bits 10-30 are reserved bits and must be zero\r
945 //\r
946 StartBit = 10;\r
947 } else {\r
948 //\r
949 // 7-bit address, Bits 0-6 are used for 7-bit I2C slave addresses,\r
950 // bits 7-30 are reserved bits and must be zero\r
951 //\r
952 StartBit = 7;\r
953 }\r
954\r
955 if (BitFieldRead32 ((UINT32)SlaveAddress, StartBit, 30) != 0) {\r
956 //\r
957 // Reserved bit set in the SlaveAddress parameter\r
958 //\r
959 return EFI_NOT_FOUND;\r
960 }\r
43e543bc
EL
961\r
962 I2cHostContext = I2C_HOST_CONTEXT_FROM_PROTOCOL (This);\r
963\r
964 if (Event == NULL) {\r
965 //\r
966 // For synchronous transaction, register an event used to wait for finishing synchronous transaction\r
967 //\r
d1102dba 968 Status = gBS->CreateEvent (\r
1436aea4
MK
969 0,\r
970 TPL_I2C_SYNC,\r
971 NULL,\r
972 NULL,\r
973 &SyncEvent\r
974 );\r
43e543bc
EL
975 if (EFI_ERROR (Status)) {\r
976 return Status;\r
977 }\r
978 }\r
d1102dba 979\r
43e543bc
EL
980 //\r
981 // TPL should be at or below TPL_NOTIFY.\r
982 // For synchronous requests this routine must be called at or below TPL_CALLBACK.\r
983 //\r
984 TplPrevious = EfiGetCurrentTpl ();\r
985 if ((TplPrevious > TPL_I2C_SYNC) || ((Event == NULL) && (TplPrevious > TPL_CALLBACK))) {\r
87000d77 986 DEBUG ((DEBUG_ERROR, "ERROR - TPL %d is too high!\n", TplPrevious));\r
43e543bc
EL
987 return EFI_INVALID_PARAMETER;\r
988 }\r
989\r
990 //\r
991 // Allocate the request structure\r
992 //\r
993 I2cRequest = AllocateZeroPool (sizeof (I2C_REQUEST));\r
994 if (I2cRequest == NULL) {\r
87000d77 995 DEBUG ((DEBUG_ERROR, "WARNING - Failed to allocate I2C_REQUEST!\n"));\r
43e543bc
EL
996 return EFI_OUT_OF_RESOURCES;\r
997 }\r
998\r
999 //\r
1000 // Initialize the request\r
1001 //\r
1002 I2cRequest->Signature = I2C_REQUEST_SIGNATURE;\r
1003 I2cRequest->I2cBusConfiguration = I2cBusConfiguration;\r
1004 I2cRequest->SlaveAddress = SlaveAddress;\r
1005 I2cRequest->Event = (Event == NULL) ? SyncEvent : Event;\r
1006 I2cRequest->Status = I2cStatus;\r
1007\r
1008 //\r
1009 // Copy request packet into private buffer, as RequestPacket may be freed during asynchronous transaction\r
1010 //\r
1436aea4 1011 RequestPacketSize = sizeof (UINTN) + RequestPacket->OperationCount * sizeof (EFI_I2C_OPERATION);\r
43e543bc 1012 I2cRequest->RequestPacket = AllocateZeroPool (RequestPacketSize);\r
4c7e997e 1013 ASSERT (I2cRequest->RequestPacket != NULL);\r
43e543bc
EL
1014 CopyMem (I2cRequest->RequestPacket, RequestPacket, RequestPacketSize);\r
1015\r
1016 //\r
1017 // Synchronize with the other threads\r
1018 //\r
1436aea4 1019 gBS->RaiseTPL (TPL_I2C_SYNC);\r
d1102dba 1020\r
43e543bc 1021 FirstRequest = IsListEmpty (&I2cHostContext->RequestList);\r
d1102dba 1022\r
43e543bc
EL
1023 //\r
1024 // Insert new I2C request in the list\r
1025 //\r
1026 InsertTailList (&I2cHostContext->RequestList, &I2cRequest->Link);\r
1027\r
1028 //\r
1029 // Release the thread synchronization\r
1030 //\r
1031 gBS->RestoreTPL (TplPrevious);\r
d1102dba 1032\r
43e543bc
EL
1033 if (FirstRequest) {\r
1034 //\r
1035 // Start the first I2C request, then the subsequent of I2C request will continue\r
1036 //\r
1037 Status = I2cHostRequestEnable (I2cHostContext);\r
1038 }\r
1039\r
1040 if (Event != NULL) {\r
1041 //\r
1042 // For asynchronous, return EFI_SUCCESS indicating that the asynchronously I2C transaction was queued.\r
1043 // No real I2C operation status in I2cStatus\r
1044 //\r
1045 return EFI_SUCCESS;\r
1046 }\r
1047\r
1048 //\r
1049 // For synchronous transaction, wait for the operation completion\r
1050 //\r
1051 do {\r
1052 Status = gBS->CheckEvent (SyncEvent);\r
1053 } while (Status == EFI_NOT_READY);\r
1054\r
1055 //\r
1056 // Get the I2C operation status\r
1057 //\r
1058 Status = I2cHostContext->Status;\r
1059\r
1060 //\r
1061 // Return the I2C operation status\r
1062 //\r
1063 if (I2cStatus != NULL) {\r
1064 *I2cStatus = Status;\r
1065 }\r
1066\r
1067 //\r
1068 // Close the event if necessary\r
1069 //\r
1070 if (SyncEvent != NULL) {\r
1071 gBS->CloseEvent (SyncEvent);\r
1072 }\r
1073\r
1074 return Status;\r
1075}\r
1076\r
1077/**\r
1078 The user Entry Point for I2C host module. The user code starts with this function.\r
1079\r
1080 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
1081 @param[in] SystemTable A pointer to the EFI System Table.\r
1082\r
1083 @retval EFI_SUCCESS The entry point is executed successfully.\r
1084 @retval other Some error occurs when executing this entry point.\r
1085\r
1086**/\r
1087EFI_STATUS\r
1088EFIAPI\r
1436aea4
MK
1089InitializeI2cHost (\r
1090 IN EFI_HANDLE ImageHandle,\r
1091 IN EFI_SYSTEM_TABLE *SystemTable\r
43e543bc
EL
1092 )\r
1093{\r
1436aea4 1094 EFI_STATUS Status;\r
43e543bc
EL
1095\r
1096 //\r
1097 // Install driver model protocol(s).\r
1098 //\r
1099 Status = EfiLibInstallDriverBindingComponentName2 (\r
1100 ImageHandle,\r
1101 SystemTable,\r
1102 &gI2cHostDriverBinding,\r
1103 ImageHandle,\r
1104 &gI2cHostComponentName,\r
1105 &gI2cHostComponentName2\r
1106 );\r
1107 ASSERT_EFI_ERROR (Status);\r
1108 return Status;\r
1109}\r
1110\r
1111/**\r
1112 This is the unload handle for I2C host module.\r
1113\r
1114 Disconnect the driver specified by ImageHandle from all the devices in the handle database.\r
1115 Uninstall all the protocols installed in the driver entry point.\r
1116\r
1117 @param[in] ImageHandle The drivers' driver image.\r
1118\r
1119 @retval EFI_SUCCESS The image is unloaded.\r
1120 @retval Others Failed to unload the image.\r
1121\r
1122**/\r
1123EFI_STATUS\r
1124EFIAPI\r
1125I2cHostUnload (\r
1436aea4 1126 IN EFI_HANDLE ImageHandle\r
43e543bc
EL
1127 )\r
1128{\r
1436aea4
MK
1129 EFI_STATUS Status;\r
1130 EFI_HANDLE *DeviceHandleBuffer;\r
1131 UINTN DeviceHandleCount;\r
1132 UINTN Index;\r
1133 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;\r
1134 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;\r
43e543bc
EL
1135\r
1136 //\r
1137 // Get the list of all I2C Controller handles in the handle database.\r
1138 // If there is an error getting the list, then the unload\r
1139 // operation fails.\r
1140 //\r
1141 Status = gBS->LocateHandleBuffer (\r
1142 ByProtocol,\r
1143 &gEfiI2cHostProtocolGuid,\r
1144 NULL,\r
1145 &DeviceHandleCount,\r
1146 &DeviceHandleBuffer\r
1147 );\r
1148\r
2fa77862
EL
1149 if (!EFI_ERROR (Status)) {\r
1150 //\r
1151 // Disconnect the driver specified by ImageHandle from all\r
1152 // the devices in the handle database.\r
1153 //\r
1154 for (Index = 0; Index < DeviceHandleCount; Index++) {\r
1155 Status = gBS->DisconnectController (\r
1156 DeviceHandleBuffer[Index],\r
1157 ImageHandle,\r
1158 NULL\r
1159 );\r
1160 if (EFI_ERROR (Status)) {\r
1161 goto Done;\r
1162 }\r
43e543bc
EL
1163 }\r
1164 }\r
1165\r
1166 //\r
1167 // Uninstall all the protocols installed in the driver entry point\r
1168 //\r
1169 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1170 gI2cHostDriverBinding.DriverBindingHandle,\r
1171 &gEfiDriverBindingProtocolGuid,\r
1172 &gI2cHostDriverBinding,\r
43e543bc
EL
1173 NULL\r
1174 );\r
1175 ASSERT_EFI_ERROR (Status);\r
1176\r
6f497f8f
EL
1177 //\r
1178 // Note we have to one by one uninstall the following protocols.\r
1179 // It's because some of them are optionally installed based on\r
1180 // the following PCD settings.\r
1181 // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnosticsDisable\r
1182 // gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable\r
1183 // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnostics2Disable\r
1184 // gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable\r
1185 //\r
1186 Status = gBS->HandleProtocol (\r
1187 gI2cHostDriverBinding.DriverBindingHandle,\r
1188 &gEfiComponentNameProtocolGuid,\r
1436aea4 1189 (VOID **)&ComponentName\r
6f497f8f
EL
1190 );\r
1191 if (!EFI_ERROR (Status)) {\r
1192 gBS->UninstallProtocolInterface (\r
1193 gI2cHostDriverBinding.DriverBindingHandle,\r
1194 &gEfiComponentNameProtocolGuid,\r
1195 ComponentName\r
1196 );\r
1197 }\r
1198\r
1199 Status = gBS->HandleProtocol (\r
1200 gI2cHostDriverBinding.DriverBindingHandle,\r
1201 &gEfiComponentName2ProtocolGuid,\r
1436aea4 1202 (VOID **)&ComponentName2\r
6f497f8f
EL
1203 );\r
1204 if (!EFI_ERROR (Status)) {\r
1205 gBS->UninstallProtocolInterface (\r
1206 gI2cHostDriverBinding.DriverBindingHandle,\r
1207 &gEfiComponentName2ProtocolGuid,\r
1208 ComponentName2\r
1209 );\r
1210 }\r
1211\r
1212 Status = EFI_SUCCESS;\r
1213\r
43e543bc
EL
1214Done:\r
1215 //\r
1216 // Free the buffer containing the list of handles from the handle database\r
1217 //\r
1218 if (DeviceHandleBuffer != NULL) {\r
1219 gBS->FreePool (DeviceHandleBuffer);\r
1220 }\r
1221\r
1222 return Status;\r
1223}\r