]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/I2c/I2cDxe/I2cHost.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[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
13EFI_DRIVER_BINDING_PROTOCOL gI2cHostDriverBinding = {\r
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
EL
24//\r
25GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mI2cHostDriverNameTable[] = {\r
26 { "eng;en", L"I2c Host Driver" },\r
27 { NULL , NULL }\r
28};\r
29\r
30//\r
31// EFI Component Name Protocol\r
32//\r
33GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gI2cHostComponentName = {\r
34 (EFI_COMPONENT_NAME_GET_DRIVER_NAME) I2cHostComponentNameGetDriverName,\r
35 (EFI_COMPONENT_NAME_GET_CONTROLLER_NAME) I2cHostComponentNameGetControllerName,\r
36 "eng"\r
37};\r
38\r
39//\r
40// EFI Component Name 2 Protocol\r
41//\r
42GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gI2cHostComponentName2 = {\r
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
91 IN CHAR8 *Language,\r
92 OUT CHAR16 **DriverName\r
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
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
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
235 EFI_I2C_MASTER_PROTOCOL *I2cMaster;\r
236 EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *I2cBusConfigurationManagement;\r
237 EFI_STATUS Status;\r
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
258 Controller,\r
259 &gEfiI2cBusConfigurationManagementProtocolGuid,\r
260 This->DriverBindingHandle,\r
261 Controller\r
262 );\r
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
314 @retval Others The driver failded to start the device.\r
315\r
316**/\r
317EFI_STATUS\r
318EFIAPI\r
319I2cHostDriverStart (\r
320 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
321 IN EFI_HANDLE Controller,\r
322 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
323 )\r
324{\r
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
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
346 DEBUG ((EFI_D_ERROR, "I2cHost: Open I2C bus configuration error, Status = %r\n", Status));\r
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
362 DEBUG ((EFI_D_ERROR, "I2cHost: Open I2C master error, Status = %r\n", Status));\r
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
371 DEBUG ((EFI_D_ERROR, "I2cHost: there is no enough memory to allocate.\n"));\r
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
382 I2cHostContext->I2cBusConfiguration = (UINTN) -1;\r
383 InitializeListHead(&I2cHostContext->RequestList);\r
384\r
385 //\r
386 // Reset the controller\r
387 //\r
388 Status = I2cMaster->Reset (I2cMaster);\r
389 if (EFI_ERROR (Status)) {\r
390 DEBUG ((EFI_D_ERROR, "I2cHost: I2C controller reset failed!\n"));\r
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
405 DEBUG ((EFI_D_ERROR, "I2cHost: create complete event error, Status = %r\n", Status));\r
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
420 DEBUG ((EFI_D_ERROR, "I2cHost: create bus available event error, Status = %r\n", Status));\r
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
441 DEBUG ((EFI_D_ERROR, "I2cHost: Start() function failed, Status = %r\n", Status));\r
442 if (I2cBusConfigurationManagement != NULL) {\r
443 gBS->CloseProtocol (\r
444 Controller,\r
445 &gEfiI2cBusConfigurationManagementProtocolGuid,\r
446 This->DriverBindingHandle,\r
447 Controller\r
d1102dba 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
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
508 )\r
509{\r
d1102dba 510 EFI_STATUS Status;\r
43e543bc
EL
511 I2C_HOST_CONTEXT *I2cHostContext;\r
512 EFI_I2C_HOST_PROTOCOL *I2cHost;\r
513 EFI_TPL TplPrevious;\r
514\r
515 TplPrevious = EfiGetCurrentTpl ();\r
516 if (TplPrevious > TPL_I2C_SYNC) {\r
517 DEBUG ((EFI_D_ERROR, "I2cHost: TPL %d is too high in Stop.\n", TplPrevious));\r
518 return EFI_DEVICE_ERROR;\r
519 }\r
520\r
521 Status = gBS->OpenProtocol (\r
522 Controller,\r
523 &gEfiI2cHostProtocolGuid,\r
524 (VOID **) &I2cHost,\r
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
545 if (( !I2cHostContext->I2cBusConfigurationManagementPending )\r
546 && IsListEmpty (&I2cHostContext->RequestList)) {\r
d1102dba 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
605 IN EFI_EVENT Event,\r
606 IN VOID *Context\r
607 )\r
608{\r
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
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
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
652 Entry = GetFirstNode (EntryHeader);\r
653 I2cRequest = I2C_REQUEST_FROM_ENTRY (Entry);\r
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
672 DEBUG((DEBUG_ERROR, "I2cHostI2cBusConfigurationAvailable: Error starting I2C operation, %r\n", Status));\r
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
689 I2C_HOST_CONTEXT *I2cHostContext,\r
690 EFI_STATUS Status\r
691 )\r
692{\r
693 I2C_REQUEST *I2cRequest;\r
694 LIST_ENTRY *EntryHeader;\r
695 LIST_ENTRY *Entry;\r
696\r
697 //\r
698 // Remove the current I2C request from the list\r
699 //\r
700 EntryHeader = &I2cHostContext->RequestList;\r
701 Entry = GetFirstNode (EntryHeader);\r
702 I2cRequest = I2C_REQUEST_FROM_ENTRY (Entry);\r
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
728 if(!IsListEmpty (EntryHeader)) {\r
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
747 IN EFI_EVENT Event,\r
748 IN VOID *Context\r
749 )\r
750{\r
751 I2C_HOST_CONTEXT *I2cHostContext;\r
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
787 I2C_HOST_CONTEXT *I2cHostContext\r
788 )\r
789{\r
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
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
810 I2cRequest = I2C_REQUEST_FROM_ENTRY (Entry);\r
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
823 I2cBusConfigurationManagement,\r
824 I2cBusConfiguration,\r
825 I2cHostContext->I2cBusConfigurationEvent,\r
826 &I2cHostContext->Status\r
827 );\r
828 } else {\r
829 //\r
830 // I2C bus configuration is same, no need change configuration and start I2c transaction directly\r
831 //\r
832 TplPrevious = gBS->RaiseTPL ( TPL_I2C_SYNC );\r
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
843 gBS->RestoreTPL ( TplPrevious );\r
844 }\r
845 return Status;\r
846}\r
847\r
848/**\r
849 Queue an I2C operation for execution on the I2C controller.\r
850\r
851 This routine must be called at or below TPL_NOTIFY. For synchronous\r
852 requests this routine must be called at or below TPL_CALLBACK.\r
853\r
854 N.B. The typical consumers of this API are the I2C bus driver and\r
855 on rare occasions the I2C test application. Extreme care must be\r
856 taken by other consumers of this API to prevent confusing the\r
857 third party I2C drivers due to a state change at the I2C device\r
858 which the third party I2C drivers did not initiate. I2C platform\r
859 drivers may use this API within these guidelines.\r
860\r
861 This layer uses the concept of I2C bus configurations to describe\r
862 the I2C bus. An I2C bus configuration is defined as a unique\r
863 setting of the multiplexers and switches in the I2C bus which\r
864 enable access to one or more I2C devices. When using a switch\r
865 to divide a bus, due to speed differences, the I2C platform layer\r
866 would define an I2C bus configuration for the I2C devices on each\r
867 side of the switch. When using a multiplexer, the I2C platform\r
868 layer defines an I2C bus configuration for each of the selector\r
869 values required to control the multiplexer. See Figure 1 in the\r
870 <a href="http://www.nxp.com/documents/user_manual/UM10204.pdf">I<sup>2</sup>C\r
871 Specification</a> for a complex I2C bus configuration.\r
872\r
873 The I2C host driver processes all operations in FIFO order. Prior to\r
874 performing the operation, the I2C host driver calls the I2C platform\r
875 driver to reconfigure the switches and multiplexers in the I2C bus\r
876 enabling access to the specified I2C device. The I2C platform driver\r
877 also selects the maximum bus speed for the device. After the I2C bus\r
878 is configured, the I2C host driver calls the I2C port driver to\r
879 initialize the I2C controller and start the I2C operation.\r
880\r
881 @param[in] This Address of an EFI_I2C_HOST_PROTOCOL instance.\r
882 @param[in] I2cBusConfiguration I2C bus configuration to access the I2C\r
883 device.\r
884 @param[in] SlaveAddress Address of the device on the I2C bus.\r
885 @param[in] Event Event to set for asynchronous operations,\r
886 NULL for synchronous operations\r
887 @param[in] RequestPacket Address of an EFI_I2C_REQUEST_PACKET\r
888 structure describing the I2C operation\r
889 @param[out] I2cStatus Optional buffer to receive the I2C operation\r
890 completion status\r
891\r
892 @retval EFI_SUCCESS The operation completed successfully.\r
43e543bc
EL
893 @retval EFI_BAD_BUFFER_SIZE The WriteBytes or ReadBytes buffer size is too large.\r
894 @retval EFI_DEVICE_ERROR There was an I2C error (NACK) during the operation.\r
895 This could indicate the slave device is not present.\r
896 @retval EFI_INVALID_PARAMETER RequestPacket is NULL\r
897 @retval EFI_INVALID_PARAMETER TPL is too high\r
898 @retval EFI_NO_MAPPING Invalid I2cBusConfiguration value\r
899 @retval EFI_NO_RESPONSE The I2C device is not responding to the\r
900 slave address. EFI_DEVICE_ERROR may also be\r
901 returned if the controller can not distinguish\r
902 when the NACK occurred.\r
903 @retval EFI_NOT_FOUND I2C slave address exceeds maximum address\r
904 @retval EFI_NOT_READY I2C bus is busy or operation pending, wait for\r
905 the event and then read status pointed to by\r
906 the request packet.\r
907 @retval EFI_OUT_OF_RESOURCES Insufficient memory for I2C operation\r
908 @retval EFI_TIMEOUT The transaction did not complete within an internally\r
909 specified timeout period.\r
910\r
911**/\r
912EFI_STATUS\r
913EFIAPI\r
914I2cHostQueueRequest (\r
915 IN CONST EFI_I2C_HOST_PROTOCOL *This,\r
916 IN UINTN I2cBusConfiguration,\r
917 IN UINTN SlaveAddress,\r
918 IN EFI_EVENT Event OPTIONAL,\r
919 IN EFI_I2C_REQUEST_PACKET *RequestPacket,\r
920 OUT EFI_STATUS *I2cStatus OPTIONAL\r
921 )\r
922{\r
923 EFI_STATUS Status;\r
924 EFI_EVENT SyncEvent;\r
925 EFI_TPL TplPrevious;\r
926 I2C_REQUEST *I2cRequest;\r
927 I2C_HOST_CONTEXT *I2cHostContext;\r
928 BOOLEAN FirstRequest;\r
929 UINTN RequestPacketSize;\r
62eeb52a 930 UINTN StartBit;\r
43e543bc
EL
931\r
932 SyncEvent = NULL;\r
933 FirstRequest = FALSE;\r
934 Status = EFI_SUCCESS;\r
935\r
936 if (RequestPacket == NULL) {\r
937 return EFI_INVALID_PARAMETER;\r
938 }\r
d1102dba 939\r
62eeb52a
EL
940 if ((SlaveAddress & I2C_ADDRESSING_10_BIT) != 0) {\r
941 //\r
942 // 10-bit address, bits 0-9 are used for 10-bit I2C slave addresses,\r
943 // bits 10-30 are reserved bits and must be zero\r
944 //\r
945 StartBit = 10;\r
946 } else {\r
947 //\r
948 // 7-bit address, Bits 0-6 are used for 7-bit I2C slave addresses,\r
949 // bits 7-30 are reserved bits and must be zero\r
950 //\r
951 StartBit = 7;\r
952 }\r
953\r
954 if (BitFieldRead32 ((UINT32)SlaveAddress, StartBit, 30) != 0) {\r
955 //\r
956 // Reserved bit set in the SlaveAddress parameter\r
957 //\r
958 return EFI_NOT_FOUND;\r
959 }\r
43e543bc
EL
960\r
961 I2cHostContext = I2C_HOST_CONTEXT_FROM_PROTOCOL (This);\r
962\r
963 if (Event == NULL) {\r
964 //\r
965 // For synchronous transaction, register an event used to wait for finishing synchronous transaction\r
966 //\r
d1102dba 967 Status = gBS->CreateEvent (\r
43e543bc
EL
968 0,\r
969 TPL_I2C_SYNC,\r
970 NULL,\r
971 NULL,\r
972 &SyncEvent\r
973 );\r
974 if (EFI_ERROR (Status)) {\r
975 return Status;\r
976 }\r
977 }\r
d1102dba 978\r
43e543bc
EL
979 //\r
980 // TPL should be at or below TPL_NOTIFY.\r
981 // For synchronous requests this routine must be called at or below TPL_CALLBACK.\r
982 //\r
983 TplPrevious = EfiGetCurrentTpl ();\r
984 if ((TplPrevious > TPL_I2C_SYNC) || ((Event == NULL) && (TplPrevious > TPL_CALLBACK))) {\r
985 DEBUG ((EFI_D_ERROR, "ERROR - TPL %d is too high!\n", TplPrevious));\r
986 return EFI_INVALID_PARAMETER;\r
987 }\r
988\r
989 //\r
990 // Allocate the request structure\r
991 //\r
992 I2cRequest = AllocateZeroPool (sizeof (I2C_REQUEST));\r
993 if (I2cRequest == NULL) {\r
994 DEBUG ((EFI_D_ERROR, "WARNING - Failed to allocate I2C_REQUEST!\n"));\r
995 return EFI_OUT_OF_RESOURCES;\r
996 }\r
997\r
998 //\r
999 // Initialize the request\r
1000 //\r
1001 I2cRequest->Signature = I2C_REQUEST_SIGNATURE;\r
1002 I2cRequest->I2cBusConfiguration = I2cBusConfiguration;\r
1003 I2cRequest->SlaveAddress = SlaveAddress;\r
1004 I2cRequest->Event = (Event == NULL) ? SyncEvent : Event;\r
1005 I2cRequest->Status = I2cStatus;\r
1006\r
1007 //\r
1008 // Copy request packet into private buffer, as RequestPacket may be freed during asynchronous transaction\r
1009 //\r
1010 RequestPacketSize = sizeof (UINTN) + RequestPacket->OperationCount * sizeof (EFI_I2C_OPERATION);\r
1011 I2cRequest->RequestPacket = AllocateZeroPool (RequestPacketSize);\r
4c7e997e 1012 ASSERT (I2cRequest->RequestPacket != NULL);\r
43e543bc
EL
1013 CopyMem (I2cRequest->RequestPacket, RequestPacket, RequestPacketSize);\r
1014\r
1015 //\r
1016 // Synchronize with the other threads\r
1017 //\r
1018 gBS->RaiseTPL ( TPL_I2C_SYNC );\r
d1102dba 1019\r
43e543bc 1020 FirstRequest = IsListEmpty (&I2cHostContext->RequestList);\r
d1102dba 1021\r
43e543bc
EL
1022 //\r
1023 // Insert new I2C request in the list\r
1024 //\r
1025 InsertTailList (&I2cHostContext->RequestList, &I2cRequest->Link);\r
1026\r
1027 //\r
1028 // Release the thread synchronization\r
1029 //\r
1030 gBS->RestoreTPL (TplPrevious);\r
d1102dba 1031\r
43e543bc
EL
1032 if (FirstRequest) {\r
1033 //\r
1034 // Start the first I2C request, then the subsequent of I2C request will continue\r
1035 //\r
1036 Status = I2cHostRequestEnable (I2cHostContext);\r
1037 }\r
1038\r
1039 if (Event != NULL) {\r
1040 //\r
1041 // For asynchronous, return EFI_SUCCESS indicating that the asynchronously I2C transaction was queued.\r
1042 // No real I2C operation status in I2cStatus\r
1043 //\r
1044 return EFI_SUCCESS;\r
1045 }\r
1046\r
1047 //\r
1048 // For synchronous transaction, wait for the operation completion\r
1049 //\r
1050 do {\r
1051 Status = gBS->CheckEvent (SyncEvent);\r
1052 } while (Status == EFI_NOT_READY);\r
1053\r
1054 //\r
1055 // Get the I2C operation status\r
1056 //\r
1057 Status = I2cHostContext->Status;\r
1058\r
1059 //\r
1060 // Return the I2C operation status\r
1061 //\r
1062 if (I2cStatus != NULL) {\r
1063 *I2cStatus = Status;\r
1064 }\r
1065\r
1066 //\r
1067 // Close the event if necessary\r
1068 //\r
1069 if (SyncEvent != NULL) {\r
1070 gBS->CloseEvent (SyncEvent);\r
1071 }\r
1072\r
1073 return Status;\r
1074}\r
1075\r
1076/**\r
1077 The user Entry Point for I2C host module. The user code starts with this function.\r
1078\r
1079 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
1080 @param[in] SystemTable A pointer to the EFI System Table.\r
1081\r
1082 @retval EFI_SUCCESS The entry point is executed successfully.\r
1083 @retval other Some error occurs when executing this entry point.\r
1084\r
1085**/\r
1086EFI_STATUS\r
1087EFIAPI\r
1088InitializeI2cHost(\r
1089 IN EFI_HANDLE ImageHandle,\r
1090 IN EFI_SYSTEM_TABLE *SystemTable\r
1091 )\r
1092{\r
1093 EFI_STATUS Status;\r
1094\r
1095 //\r
1096 // Install driver model protocol(s).\r
1097 //\r
1098 Status = EfiLibInstallDriverBindingComponentName2 (\r
1099 ImageHandle,\r
1100 SystemTable,\r
1101 &gI2cHostDriverBinding,\r
1102 ImageHandle,\r
1103 &gI2cHostComponentName,\r
1104 &gI2cHostComponentName2\r
1105 );\r
1106 ASSERT_EFI_ERROR (Status);\r
1107 return Status;\r
1108}\r
1109\r
1110/**\r
1111 This is the unload handle for I2C host module.\r
1112\r
1113 Disconnect the driver specified by ImageHandle from all the devices in the handle database.\r
1114 Uninstall all the protocols installed in the driver entry point.\r
1115\r
1116 @param[in] ImageHandle The drivers' driver image.\r
1117\r
1118 @retval EFI_SUCCESS The image is unloaded.\r
1119 @retval Others Failed to unload the image.\r
1120\r
1121**/\r
1122EFI_STATUS\r
1123EFIAPI\r
1124I2cHostUnload (\r
1125 IN EFI_HANDLE ImageHandle\r
1126 )\r
1127{\r
1128 EFI_STATUS Status;\r
1129 EFI_HANDLE *DeviceHandleBuffer;\r
1130 UINTN DeviceHandleCount;\r
1131 UINTN Index;\r
6f497f8f
EL
1132 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;\r
1133 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;\r
43e543bc
EL
1134\r
1135 //\r
1136 // Get the list of all I2C Controller handles in the handle database.\r
1137 // If there is an error getting the list, then the unload\r
1138 // operation fails.\r
1139 //\r
1140 Status = gBS->LocateHandleBuffer (\r
1141 ByProtocol,\r
1142 &gEfiI2cHostProtocolGuid,\r
1143 NULL,\r
1144 &DeviceHandleCount,\r
1145 &DeviceHandleBuffer\r
1146 );\r
1147\r
2fa77862
EL
1148 if (!EFI_ERROR (Status)) {\r
1149 //\r
1150 // Disconnect the driver specified by ImageHandle from all\r
1151 // the devices in the handle database.\r
1152 //\r
1153 for (Index = 0; Index < DeviceHandleCount; Index++) {\r
1154 Status = gBS->DisconnectController (\r
1155 DeviceHandleBuffer[Index],\r
1156 ImageHandle,\r
1157 NULL\r
1158 );\r
1159 if (EFI_ERROR (Status)) {\r
1160 goto Done;\r
1161 }\r
43e543bc
EL
1162 }\r
1163 }\r
1164\r
1165 //\r
1166 // Uninstall all the protocols installed in the driver entry point\r
1167 //\r
1168 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1169 gI2cHostDriverBinding.DriverBindingHandle,\r
1170 &gEfiDriverBindingProtocolGuid,\r
1171 &gI2cHostDriverBinding,\r
43e543bc
EL
1172 NULL\r
1173 );\r
1174 ASSERT_EFI_ERROR (Status);\r
1175\r
6f497f8f
EL
1176 //\r
1177 // Note we have to one by one uninstall the following protocols.\r
1178 // It's because some of them are optionally installed based on\r
1179 // the following PCD settings.\r
1180 // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnosticsDisable\r
1181 // gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable\r
1182 // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnostics2Disable\r
1183 // gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable\r
1184 //\r
1185 Status = gBS->HandleProtocol (\r
1186 gI2cHostDriverBinding.DriverBindingHandle,\r
1187 &gEfiComponentNameProtocolGuid,\r
1188 (VOID **) &ComponentName\r
1189 );\r
1190 if (!EFI_ERROR (Status)) {\r
1191 gBS->UninstallProtocolInterface (\r
1192 gI2cHostDriverBinding.DriverBindingHandle,\r
1193 &gEfiComponentNameProtocolGuid,\r
1194 ComponentName\r
1195 );\r
1196 }\r
1197\r
1198 Status = gBS->HandleProtocol (\r
1199 gI2cHostDriverBinding.DriverBindingHandle,\r
1200 &gEfiComponentName2ProtocolGuid,\r
1201 (VOID **) &ComponentName2\r
1202 );\r
1203 if (!EFI_ERROR (Status)) {\r
1204 gBS->UninstallProtocolInterface (\r
1205 gI2cHostDriverBinding.DriverBindingHandle,\r
1206 &gEfiComponentName2ProtocolGuid,\r
1207 ComponentName2\r
1208 );\r
1209 }\r
1210\r
1211 Status = EFI_SUCCESS;\r
1212\r
43e543bc
EL
1213Done:\r
1214 //\r
1215 // Free the buffer containing the list of handles from the handle database\r
1216 //\r
1217 if (DeviceHandleBuffer != NULL) {\r
1218 gBS->FreePool (DeviceHandleBuffer);\r
1219 }\r
1220\r
1221 return Status;\r
1222}\r