]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/I2c/I2cDxe/I2cBus.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / I2c / I2cDxe / I2cBus.c
CommitLineData
43e543bc 1/** @file\r
d1102dba 2 This file implements I2C IO Protocol which enables the user to manipulate a single\r
43e543bc
EL
3 I2C device independent of the host controller and I2C design.\r
4\r
d1102dba 5 Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
43e543bc
EL
7\r
8**/\r
9\r
10#include "I2cDxe.h"\r
11\r
12//\r
13// EFI_DRIVER_BINDING_PROTOCOL instance\r
14//\r
1436aea4 15EFI_DRIVER_BINDING_PROTOCOL gI2cBusDriverBinding = {\r
43e543bc
EL
16 I2cBusDriverSupported,\r
17 I2cBusDriverStart,\r
18 I2cBusDriverStop,\r
19 0x10,\r
20 NULL,\r
21 NULL\r
22};\r
23\r
24//\r
25// Template for I2C Bus Child Device.\r
26//\r
1436aea4 27I2C_DEVICE_CONTEXT gI2cDeviceContextTemplate = {\r
43e543bc
EL
28 I2C_DEVICE_SIGNATURE,\r
29 NULL,\r
30 { // I2cIo Protocol\r
31 I2cBusQueueRequest, // QueueRequest\r
32 NULL, // DeviceGuid\r
33 0, // DeviceIndex\r
34 0, // HardwareRevision\r
35 NULL // I2cControllerCapabilities\r
36 },\r
37 NULL, // DevicePath\r
38 NULL, // I2cDevice\r
39 NULL, // I2cBusContext\r
40};\r
41\r
42//\r
43// Template for controller device path node.\r
44//\r
1436aea4 45CONTROLLER_DEVICE_PATH gControllerDevicePathTemplate = {\r
43e543bc
EL
46 {\r
47 HARDWARE_DEVICE_PATH,\r
48 HW_CONTROLLER_DP,\r
49 {\r
1436aea4
MK
50 (UINT8)(sizeof (CONTROLLER_DEVICE_PATH)),\r
51 (UINT8)((sizeof (CONTROLLER_DEVICE_PATH)) >> 8)\r
43e543bc
EL
52 }\r
53 },\r
54 0\r
55};\r
56\r
57//\r
58// Template for vendor device path node.\r
59//\r
1436aea4 60VENDOR_DEVICE_PATH gVendorDevicePathTemplate = {\r
43e543bc
EL
61 {\r
62 HARDWARE_DEVICE_PATH,\r
63 HW_VENDOR_DP,\r
64 {\r
1436aea4
MK
65 (UINT8)(sizeof (VENDOR_DEVICE_PATH)),\r
66 (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)\r
43e543bc
EL
67 }\r
68 },\r
1436aea4
MK
69 { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\r
70 }\r
43e543bc
EL
71};\r
72\r
73//\r
d1102dba 74// Driver name table\r
43e543bc 75//\r
1436aea4
MK
76GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mI2cBusDriverNameTable[] = {\r
77 { "eng;en", (CHAR16 *)L"I2C Bus Driver" },\r
78 { NULL, NULL }\r
43e543bc
EL
79};\r
80\r
81//\r
82// EFI Component Name Protocol\r
83//\r
84GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gI2cBusComponentName = {\r
1436aea4
MK
85 (EFI_COMPONENT_NAME_GET_DRIVER_NAME)I2cBusComponentNameGetDriverName,\r
86 (EFI_COMPONENT_NAME_GET_CONTROLLER_NAME)I2cBusComponentNameGetControllerName,\r
43e543bc
EL
87 "eng"\r
88};\r
89\r
90//\r
91// EFI Component Name 2 Protocol\r
92//\r
1436aea4 93GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gI2cBusComponentName2 = {\r
43e543bc
EL
94 I2cBusComponentNameGetDriverName,\r
95 I2cBusComponentNameGetControllerName,\r
96 "en"\r
97};\r
98\r
99/**\r
100 Retrieves a Unicode string that is the user readable name of the driver.\r
101\r
102 This function retrieves the user readable name of a driver in the form of a\r
103 Unicode string. If the driver specified by This has a user readable name in\r
104 the language specified by Language, then a pointer to the driver name is\r
105 returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
106 by This does not support the language specified by Language,\r
107 then EFI_UNSUPPORTED is returned.\r
108\r
109 @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
110 EFI_COMPONENT_NAME_PROTOCOL instance.\r
111\r
112 @param Language[in] A pointer to a Null-terminated ASCII string\r
113 array indicating the language. This is the\r
114 language of the driver name that the caller is\r
115 requesting, and it must match one of the\r
116 languages specified in SupportedLanguages. The\r
117 number of languages supported by a driver is up\r
118 to the driver writer. Language is specified\r
119 in RFC 4646 or ISO 639-2 language code format.\r
120\r
121 @param DriverName[out] A pointer to the Unicode string to return.\r
122 This Unicode string is the name of the\r
123 driver specified by This in the language\r
124 specified by Language.\r
125\r
126 @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
127 This and the language specified by Language was\r
128 returned in DriverName.\r
129\r
130 @retval EFI_INVALID_PARAMETER Language is NULL.\r
131\r
132 @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
133\r
134 @retval EFI_UNSUPPORTED The driver specified by This does not support\r
135 the language specified by Language.\r
136\r
137**/\r
138EFI_STATUS\r
139EFIAPI\r
140I2cBusComponentNameGetDriverName (\r
141 IN EFI_COMPONENT_NAME2_PROTOCOL *This,\r
1436aea4
MK
142 IN CHAR8 *Language,\r
143 OUT CHAR16 **DriverName\r
43e543bc
EL
144 )\r
145{\r
146 return LookupUnicodeString2 (\r
147 Language,\r
148 This->SupportedLanguages,\r
149 mI2cBusDriverNameTable,\r
150 DriverName,\r
151 (BOOLEAN)(This != &gI2cBusComponentName2)\r
152 );\r
153}\r
154\r
155/**\r
156 Retrieves a Unicode string that is the user readable name of the controller\r
157 that is being managed by a driver.\r
158\r
159 This function retrieves the user readable name of the controller specified by\r
160 ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
161 driver specified by This has a user readable name in the language specified by\r
162 Language, then a pointer to the controller name is returned in ControllerName,\r
163 and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
164 managing the controller specified by ControllerHandle and ChildHandle,\r
165 then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
166 support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
167\r
168 @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
169 EFI_COMPONENT_NAME_PROTOCOL instance.\r
170\r
171 @param ControllerHandle[in] The handle of a controller that the driver\r
172 specified by This is managing. This handle\r
173 specifies the controller whose name is to be\r
174 returned.\r
175\r
176 @param ChildHandle[in] The handle of the child controller to retrieve\r
177 the name of. This is an optional parameter that\r
178 may be NULL. It will be NULL for device\r
179 drivers. It will also be NULL for a bus drivers\r
180 that wish to retrieve the name of the bus\r
181 controller. It will not be NULL for a bus\r
182 driver that wishes to retrieve the name of a\r
183 child controller.\r
184\r
185 @param Language[in] A pointer to a Null-terminated ASCII string\r
186 array indicating the language. This is the\r
187 language of the driver name that the caller is\r
188 requesting, and it must match one of the\r
189 languages specified in SupportedLanguages. The\r
190 number of languages supported by a driver is up\r
191 to the driver writer. Language is specified in\r
192 RFC 4646 or ISO 639-2 language code format.\r
193\r
194 @param ControllerName[out] A pointer to the Unicode string to return.\r
195 This Unicode string is the name of the\r
196 controller specified by ControllerHandle and\r
197 ChildHandle in the language specified by\r
198 Language from the point of view of the driver\r
199 specified by This.\r
200\r
201 @retval EFI_SUCCESS The Unicode string for the user readable name in\r
202 the language specified by Language for the\r
203 driver specified by This was returned in\r
204 DriverName.\r
205\r
206 @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
207\r
208 @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
209 EFI_HANDLE.\r
210\r
211 @retval EFI_INVALID_PARAMETER Language is NULL.\r
212\r
213 @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
214\r
215 @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
216 managing the controller specified by\r
217 ControllerHandle and ChildHandle.\r
218\r
219 @retval EFI_UNSUPPORTED The driver specified by This does not support\r
220 the language specified by Language.\r
221\r
222**/\r
223EFI_STATUS\r
224EFIAPI\r
225I2cBusComponentNameGetControllerName (\r
1436aea4
MK
226 IN EFI_COMPONENT_NAME2_PROTOCOL *This,\r
227 IN EFI_HANDLE ControllerHandle,\r
228 IN EFI_HANDLE ChildHandle OPTIONAL,\r
229 IN CHAR8 *Language,\r
230 OUT CHAR16 **ControllerName\r
43e543bc
EL
231 )\r
232{\r
233 return EFI_UNSUPPORTED;\r
234}\r
235\r
236/**\r
237 Check if the child of I2C controller has been created.\r
238\r
d1102dba 239 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
43e543bc
EL
240 @param[in] Controller I2C controller handle.\r
241 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.\r
242 @param[in] RemainingHasControllerNode Indicate if RemainingDevicePath contains CONTROLLER_DEVICE_PATH.\r
243 @param[in] RemainingControllerNumber Controller number in CONTROLLER_DEVICE_PATH.\r
d1102dba 244\r
43e543bc
EL
245 @retval EFI_SUCCESS The child of I2C controller is not created.\r
246 @retval Others The child of I2C controller has been created or other errors happen.\r
247\r
248**/\r
249EFI_STATUS\r
250CheckRemainingDevicePath (\r
251 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
252 IN EFI_HANDLE Controller,\r
253 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,\r
254 IN BOOLEAN RemainingHasControllerNode,\r
255 IN UINT32 RemainingControllerNumber\r
256 )\r
257{\r
1436aea4
MK
258 EFI_STATUS Status;\r
259 EFI_DEVICE_PATH_PROTOCOL *SystemDevicePath;\r
260 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
261 UINTN EntryCount;\r
262 UINTN Index;\r
263 BOOLEAN SystemHasControllerNode;\r
264 UINT32 SystemControllerNumber;\r
43e543bc
EL
265\r
266 SystemHasControllerNode = FALSE;\r
1436aea4 267 SystemControllerNumber = 0;\r
d1102dba 268\r
43e543bc
EL
269 Status = gBS->OpenProtocolInformation (\r
270 Controller,\r
271 &gEfiI2cHostProtocolGuid,\r
272 &OpenInfoBuffer,\r
273 &EntryCount\r
274 );\r
275 if (EFI_ERROR (Status)) {\r
276 return Status;\r
277 }\r
d1102dba 278\r
43e543bc
EL
279 for (Index = 0; Index < EntryCount; Index++) {\r
280 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
281 Status = gBS->OpenProtocol (\r
282 OpenInfoBuffer[Index].ControllerHandle,\r
283 &gEfiDevicePathProtocolGuid,\r
1436aea4 284 (VOID **)&SystemDevicePath,\r
43e543bc
EL
285 This->DriverBindingHandle,\r
286 Controller,\r
287 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
288 );\r
289 if (!EFI_ERROR (Status)) {\r
290 //\r
291 // Find vendor device path node and compare\r
d1102dba 292 //\r
43e543bc
EL
293 while (!IsDevicePathEnd (SystemDevicePath)) {\r
294 if ((DevicePathType (SystemDevicePath) == HARDWARE_DEVICE_PATH) &&\r
1436aea4
MK
295 (DevicePathSubType (SystemDevicePath) == HW_VENDOR_DP))\r
296 {\r
43e543bc
EL
297 //\r
298 // Check if vendor device path is same between system device path and remaining device path\r
299 //\r
300 if (CompareMem (SystemDevicePath, RemainingDevicePath, sizeof (VENDOR_DEVICE_PATH)) == 0) {\r
301 //\r
302 // Get controller node appended after vendor node\r
303 //\r
304 SystemDevicePath = NextDevicePathNode (SystemDevicePath);\r
305 if ((DevicePathType (SystemDevicePath) == HARDWARE_DEVICE_PATH) &&\r
1436aea4
MK
306 (DevicePathSubType (SystemDevicePath) == HW_CONTROLLER_DP))\r
307 {\r
43e543bc 308 SystemHasControllerNode = TRUE;\r
1436aea4 309 SystemControllerNumber = ((CONTROLLER_DEVICE_PATH *)SystemDevicePath)->ControllerNumber;\r
43e543bc
EL
310 } else {\r
311 SystemHasControllerNode = FALSE;\r
1436aea4 312 SystemControllerNumber = 0;\r
43e543bc 313 }\r
1436aea4 314\r
43e543bc
EL
315 if (((SystemHasControllerNode) && (!RemainingHasControllerNode) && (SystemControllerNumber == 0)) ||\r
316 ((!SystemHasControllerNode) && (RemainingHasControllerNode) && (RemainingControllerNumber == 0)) ||\r
317 ((SystemHasControllerNode) && (RemainingHasControllerNode) && (SystemControllerNumber == RemainingControllerNumber)) ||\r
1436aea4
MK
318 ((!SystemHasControllerNode) && (!RemainingHasControllerNode)))\r
319 {\r
320 DEBUG ((DEBUG_ERROR, "This I2C device has been already started.\n"));\r
321 Status = EFI_UNSUPPORTED;\r
322 break;\r
43e543bc
EL
323 }\r
324 }\r
325 }\r
1436aea4 326\r
43e543bc
EL
327 SystemDevicePath = NextDevicePathNode (SystemDevicePath);\r
328 }\r
1436aea4 329\r
43e543bc
EL
330 if (EFI_ERROR (Status)) {\r
331 break;\r
332 }\r
333 }\r
334 }\r
335 }\r
1436aea4 336\r
43e543bc
EL
337 FreePool (OpenInfoBuffer);\r
338 return Status;\r
339}\r
340\r
341/**\r
342 Tests to see if this driver supports a given controller. If a child device is provided,\r
343 it further tests to see if this driver supports creating a handle for the specified child device.\r
344\r
345 This function checks to see if the driver specified by This supports the device specified by\r
346 ControllerHandle. Drivers will typically use the device path attached to\r
347 ControllerHandle and/or the services from the bus I/O abstraction attached to\r
348 ControllerHandle to determine if the driver supports ControllerHandle. This function\r
349 may be called many times during platform initialization. In order to reduce boot times, the tests\r
350 performed by this function must be very small, and take as little time as possible to execute. This\r
351 function must not change the state of any hardware devices, and this function must be aware that the\r
352 device specified by ControllerHandle may already be managed by the same driver or a\r
353 different driver. This function must match its calls to AllocatePages() with FreePages(),\r
354 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
355 Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
356 already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
357 to guarantee the state of ControllerHandle is not modified by this function.\r
358\r
359 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
360 @param[in] ControllerHandle The handle of the controller to test. This handle\r
361 must support a protocol interface that supplies\r
362 an I/O abstraction to the driver.\r
363 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
364 parameter is ignored by device drivers, and is optional for bus\r
365 drivers. For bus drivers, if this parameter is not NULL, then\r
366 the bus driver must determine if the bus controller specified\r
367 by ControllerHandle and the child controller specified\r
368 by RemainingDevicePath are both supported by this\r
369 bus driver.\r
370\r
371 @retval EFI_SUCCESS The device specified by ControllerHandle and\r
372 RemainingDevicePath is supported by the driver specified by This.\r
373 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
374 RemainingDevicePath is already being managed by the driver\r
375 specified by This.\r
376 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
377 RemainingDevicePath is already being managed by a different\r
378 driver or an application that requires exclusive access.\r
379 Currently not implemented.\r
380 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
381 RemainingDevicePath is not supported by the driver specified by This.\r
382**/\r
383EFI_STATUS\r
384EFIAPI\r
385I2cBusDriverSupported (\r
386 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
387 IN EFI_HANDLE Controller,\r
388 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
389 )\r
390{\r
1436aea4
MK
391 EFI_STATUS Status;\r
392 EFI_I2C_ENUMERATE_PROTOCOL *I2cEnumerate;\r
393 EFI_I2C_HOST_PROTOCOL *I2cHost;\r
394 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
395 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;\r
396 BOOLEAN RemainingHasControllerNode;\r
397 UINT32 RemainingControllerNumber;\r
43e543bc
EL
398\r
399 RemainingHasControllerNode = FALSE;\r
1436aea4 400 RemainingControllerNumber = 0;\r
43e543bc
EL
401\r
402 //\r
403 // Determine if the I2c Enumerate Protocol is available\r
404 //\r
405 Status = gBS->OpenProtocol (\r
406 Controller,\r
407 &gEfiI2cEnumerateProtocolGuid,\r
1436aea4 408 (VOID **)&I2cEnumerate,\r
43e543bc
EL
409 This->DriverBindingHandle,\r
410 Controller,\r
411 EFI_OPEN_PROTOCOL_BY_DRIVER\r
412 );\r
413 if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {\r
414 return Status;\r
415 }\r
416\r
417 if (!EFI_ERROR (Status)) {\r
418 gBS->CloseProtocol (\r
1436aea4
MK
419 Controller,\r
420 &gEfiI2cEnumerateProtocolGuid,\r
421 This->DriverBindingHandle,\r
422 Controller\r
423 );\r
43e543bc
EL
424 }\r
425\r
426 Status = gBS->OpenProtocol (\r
427 Controller,\r
428 &gEfiDevicePathProtocolGuid,\r
1436aea4 429 (VOID **)&ParentDevicePath,\r
43e543bc
EL
430 This->DriverBindingHandle,\r
431 Controller,\r
432 EFI_OPEN_PROTOCOL_BY_DRIVER\r
433 );\r
434\r
435 if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {\r
436 return Status;\r
437 }\r
438\r
439 if (!EFI_ERROR (Status)) {\r
440 gBS->CloseProtocol (\r
1436aea4
MK
441 Controller,\r
442 &gEfiDevicePathProtocolGuid,\r
443 This->DriverBindingHandle,\r
444 Controller\r
445 );\r
43e543bc
EL
446 }\r
447\r
448 if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {\r
449 //\r
450 // Check if the first node of RemainingDevicePath is a hardware vendor device path\r
451 //\r
452 if ((DevicePathType (RemainingDevicePath) != HARDWARE_DEVICE_PATH) ||\r
1436aea4
MK
453 (DevicePathSubType (RemainingDevicePath) != HW_VENDOR_DP))\r
454 {\r
43e543bc
EL
455 return EFI_UNSUPPORTED;\r
456 }\r
1436aea4 457\r
43e543bc
EL
458 //\r
459 // Check if the second node of RemainingDevicePath is a controller node\r
460 //\r
461 DevPathNode = NextDevicePathNode (RemainingDevicePath);\r
462 if (!IsDevicePathEnd (DevPathNode)) {\r
463 if ((DevicePathType (DevPathNode) != HARDWARE_DEVICE_PATH) ||\r
1436aea4
MK
464 (DevicePathSubType (DevPathNode) != HW_CONTROLLER_DP))\r
465 {\r
43e543bc
EL
466 return EFI_UNSUPPORTED;\r
467 } else {\r
468 RemainingHasControllerNode = TRUE;\r
1436aea4 469 RemainingControllerNumber = ((CONTROLLER_DEVICE_PATH *)DevPathNode)->ControllerNumber;\r
43e543bc
EL
470 }\r
471 }\r
472 }\r
473\r
474 //\r
475 // Determine if the I2C Host Protocol is available\r
476 //\r
d1102dba 477 Status = gBS->OpenProtocol (\r
43e543bc
EL
478 Controller,\r
479 &gEfiI2cHostProtocolGuid,\r
1436aea4 480 (VOID **)&I2cHost,\r
43e543bc
EL
481 This->DriverBindingHandle,\r
482 Controller,\r
483 EFI_OPEN_PROTOCOL_BY_DRIVER\r
484 );\r
485\r
486 if (!EFI_ERROR (Status)) {\r
487 gBS->CloseProtocol (\r
1436aea4
MK
488 Controller,\r
489 &gEfiI2cHostProtocolGuid,\r
490 This->DriverBindingHandle,\r
491 Controller\r
492 );\r
43e543bc
EL
493 }\r
494\r
43e543bc 495 if (Status == EFI_ALREADY_STARTED) {\r
d1102dba 496 if ((RemainingDevicePath == NULL) ||\r
1436aea4
MK
497 ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)))\r
498 {\r
43e543bc
EL
499 //\r
500 // If RemainingDevicePath is NULL or is the End of Device Path Node, return EFI_SUCCESS.\r
501 //\r
502 Status = EFI_SUCCESS;\r
503 } else {\r
504 //\r
505 // Test if the child with the RemainingDevicePath has already been created.\r
d1102dba 506 //\r
43e543bc
EL
507 Status = CheckRemainingDevicePath (\r
508 This,\r
509 Controller,\r
510 RemainingDevicePath,\r
511 RemainingHasControllerNode,\r
512 RemainingControllerNumber\r
513 );\r
514 }\r
515 }\r
516\r
517 return Status;\r
518}\r
519\r
520/**\r
521 Starts a device controller or a bus controller.\r
522\r
523 The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
524 As a result, much of the error checking on the parameters to Start() has been moved into this\r
525 common boot service. It is legal to call Start() from other locations,\r
526 but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
527 1. ControllerHandle must be a valid EFI_HANDLE.\r
528 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
529 EFI_DEVICE_PATH_PROTOCOL.\r
530 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
531 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
532\r
533 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
534 @param[in] ControllerHandle The handle of the controller to start. This handle\r
535 must support a protocol interface that supplies\r
536 an I/O abstraction to the driver.\r
537 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
538 parameter is ignored by device drivers, and is optional for bus\r
539 drivers. For a bus driver, if this parameter is NULL, then handles\r
540 for all the children of Controller are created by this driver.\r
541 If this parameter is not NULL and the first Device Path Node is\r
542 not the End of Device Path Node, then only the handle for the\r
543 child device specified by the first Device Path Node of\r
544 RemainingDevicePath is created by this driver.\r
545 If the first Device Path Node of RemainingDevicePath is\r
546 the End of Device Path Node, no child handle is created by this\r
547 driver.\r
548\r
549 @retval EFI_SUCCESS The device was started.\r
550 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
551 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
29f7ad8b 552 @retval Others The driver failed to start the device.\r
43e543bc
EL
553\r
554**/\r
555EFI_STATUS\r
556EFIAPI\r
557I2cBusDriverStart (\r
558 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
559 IN EFI_HANDLE Controller,\r
560 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
561 )\r
562{\r
1436aea4
MK
563 EFI_I2C_ENUMERATE_PROTOCOL *I2cEnumerate;\r
564 EFI_I2C_HOST_PROTOCOL *I2cHost;\r
565 I2C_BUS_CONTEXT *I2cBusContext;\r
566 EFI_STATUS Status;\r
567 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
43e543bc 568\r
1436aea4
MK
569 I2cBusContext = NULL;\r
570 ParentDevicePath = NULL;\r
571 I2cEnumerate = NULL;\r
572 I2cHost = NULL;\r
43e543bc
EL
573\r
574 //\r
575 // Determine if the I2C controller is available\r
576 //\r
577 Status = gBS->OpenProtocol (\r
578 Controller,\r
579 &gEfiI2cHostProtocolGuid,\r
1436aea4 580 (VOID **)&I2cHost,\r
43e543bc
EL
581 This->DriverBindingHandle,\r
582 Controller,\r
583 EFI_OPEN_PROTOCOL_BY_DRIVER\r
584 );\r
585 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
87000d77 586 DEBUG ((DEBUG_ERROR, "I2cBus: open I2C host error, Status = %r\n", Status));\r
43e543bc
EL
587 return Status;\r
588 }\r
589\r
590 if (Status == EFI_ALREADY_STARTED) {\r
591 Status = gBS->OpenProtocol (\r
592 Controller,\r
593 &gEfiCallerIdGuid,\r
1436aea4 594 (VOID **)&I2cBusContext,\r
43e543bc
EL
595 This->DriverBindingHandle,\r
596 Controller,\r
597 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
598 );\r
599 if (EFI_ERROR (Status)) {\r
87000d77 600 DEBUG ((DEBUG_ERROR, "I2cBus: open private protocol error, Status = %r.\n", Status));\r
43e543bc
EL
601 return Status;\r
602 }\r
603 }\r
604\r
605 //\r
606 // Get the I2C bus enumeration API\r
607 //\r
608 Status = gBS->OpenProtocol (\r
609 Controller,\r
610 &gEfiI2cEnumerateProtocolGuid,\r
1436aea4 611 (VOID **)&I2cEnumerate,\r
43e543bc
EL
612 This->DriverBindingHandle,\r
613 Controller,\r
614 EFI_OPEN_PROTOCOL_BY_DRIVER\r
615 );\r
616 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
87000d77 617 DEBUG ((DEBUG_ERROR, "I2cBus: open I2C enumerate error, Status = %r\n", Status));\r
43e543bc
EL
618 goto Error;\r
619 }\r
620\r
621 Status = gBS->OpenProtocol (\r
1436aea4
MK
622 Controller,\r
623 &gEfiDevicePathProtocolGuid,\r
624 (VOID **)&ParentDevicePath,\r
625 This->DriverBindingHandle,\r
626 Controller,\r
627 EFI_OPEN_PROTOCOL_BY_DRIVER\r
628 );\r
43e543bc 629 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
87000d77 630 DEBUG ((DEBUG_ERROR, "I2cBus: open device path error, Status = %r\n", Status));\r
43e543bc
EL
631 goto Error;\r
632 }\r
633\r
634 if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {\r
635 //\r
636 // If RemainingDevicePath is the End of Device Path Node,\r
29f7ad8b 637 // don't create any child device and return EFI_SUCCESS\r
43e543bc
EL
638 //\r
639 return EFI_SUCCESS;\r
640 }\r
641\r
642 //\r
643 // Allocate the buffer for I2C_BUS_CONTEXT if it is not allocated before.\r
644 //\r
645 if (I2cBusContext == NULL) {\r
646 //\r
647 // Allocate the I2C context structure for the current I2C controller\r
648 //\r
649 I2cBusContext = AllocateZeroPool (sizeof (I2C_BUS_CONTEXT));\r
650 if (I2cBusContext == NULL) {\r
87000d77 651 DEBUG ((DEBUG_ERROR, "I2cBus: there is no enough memory to allocate.\n"));\r
43e543bc
EL
652 Status = EFI_OUT_OF_RESOURCES;\r
653 goto Error;\r
654 }\r
d1102dba 655\r
43e543bc
EL
656 /*\r
657 +----------------+\r
658 .->| I2C_BUS_CONTEXT|<----- This file Protocol (gEfiCallerIdGuid) installed on I2C Controller handle\r
659 | +----------------+\r
660 |\r
661 | +----------------------------+\r
662 | | I2C_DEVICE_CONTEXT |\r
663 `--| |\r
664 | |\r
665 | I2C IO Protocol Structure | <----- I2C IO Protocol\r
666 | |\r
667 +----------------------------+\r
d1102dba 668\r
43e543bc
EL
669 */\r
670 I2cBusContext->I2cHost = I2cHost;\r
671 I2cBusContext->I2cEnumerate = I2cEnumerate;\r
672 //\r
673 // Parent controller used to create children\r
674 //\r
1436aea4 675 I2cBusContext->Controller = Controller;\r
43e543bc
EL
676 //\r
677 // Parent controller device path used to create children device path\r
678 //\r
679 I2cBusContext->ParentDevicePath = ParentDevicePath;\r
d1102dba 680\r
43e543bc 681 I2cBusContext->DriverBindingHandle = This->DriverBindingHandle;\r
d1102dba 682\r
43e543bc
EL
683 Status = gBS->InstallMultipleProtocolInterfaces (\r
684 &Controller,\r
685 &gEfiCallerIdGuid,\r
686 I2cBusContext,\r
687 NULL\r
688 );\r
689 if (EFI_ERROR (Status)) {\r
87000d77 690 DEBUG ((DEBUG_ERROR, "I2cBus: install private protocol error, Status = %r.\n", Status));\r
43e543bc
EL
691 goto Error;\r
692 }\r
693 }\r
694\r
695 //\r
696 // Start the driver\r
697 //\r
698 Status = RegisterI2cDevice (I2cBusContext, Controller, RemainingDevicePath);\r
699\r
700 return Status;\r
701\r
702Error:\r
703 if (EFI_ERROR (Status)) {\r
87000d77 704 DEBUG ((DEBUG_ERROR, "I2cBus: Start() function failed, Status = %r\n", Status));\r
43e543bc 705 if (ParentDevicePath != NULL) {\r
d1102dba 706 gBS->CloseProtocol (\r
1436aea4
MK
707 Controller,\r
708 &gEfiDevicePathProtocolGuid,\r
709 This->DriverBindingHandle,\r
710 Controller\r
711 );\r
43e543bc
EL
712 }\r
713\r
714 if (I2cHost != NULL) {\r
715 gBS->CloseProtocol (\r
1436aea4
MK
716 Controller,\r
717 &gEfiI2cHostProtocolGuid,\r
718 This->DriverBindingHandle,\r
719 Controller\r
720 );\r
43e543bc
EL
721 }\r
722\r
723 if (I2cEnumerate != NULL) {\r
d1102dba 724 gBS->CloseProtocol (\r
1436aea4
MK
725 Controller,\r
726 &gEfiI2cEnumerateProtocolGuid,\r
727 This->DriverBindingHandle,\r
728 Controller\r
729 );\r
43e543bc 730 }\r
d1102dba 731\r
43e543bc
EL
732 if (I2cBusContext != NULL) {\r
733 Status = gBS->UninstallMultipleProtocolInterfaces (\r
9388c6b1 734 Controller,\r
43e543bc
EL
735 gEfiCallerIdGuid,\r
736 I2cBusContext,\r
737 NULL\r
738 );\r
739 FreePool (I2cBusContext);\r
740 }\r
741 }\r
742\r
743 //\r
744 // Return the operation status.\r
745 //\r
746 return Status;\r
747}\r
748\r
43e543bc
EL
749/**\r
750 Stops a device controller or a bus controller.\r
751\r
752 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
753 As a result, much of the error checking on the parameters to Stop() has been moved\r
754 into this common boot service. It is legal to call Stop() from other locations,\r
755 but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
756 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
757 same driver's Start() function.\r
758 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
759 EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
760 Start() function, and the Start() function must have called OpenProtocol() on\r
761 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
762\r
763 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
764 @param[in] ControllerHandle A handle to the device being stopped. The handle must\r
765 support a bus specific I/O protocol for the driver\r
766 to use to stop the device.\r
767 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
768 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
769 if NumberOfChildren is 0.\r
770\r
771 @retval EFI_SUCCESS The device was stopped.\r
772 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
773\r
774**/\r
775EFI_STATUS\r
776EFIAPI\r
777I2cBusDriverStop (\r
778 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
779 IN EFI_HANDLE Controller,\r
780 IN UINTN NumberOfChildren,\r
781 IN EFI_HANDLE *ChildHandleBuffer\r
782 )\r
783{\r
1436aea4
MK
784 I2C_BUS_CONTEXT *I2cBusContext;\r
785 EFI_STATUS Status;\r
786 BOOLEAN AllChildrenStopped;\r
787 UINTN Index;\r
43e543bc
EL
788\r
789 if (NumberOfChildren == 0) {\r
d1102dba 790 gBS->CloseProtocol (\r
1436aea4
MK
791 Controller,\r
792 &gEfiDevicePathProtocolGuid,\r
793 This->DriverBindingHandle,\r
794 Controller\r
795 );\r
43e543bc
EL
796\r
797 gBS->CloseProtocol (\r
1436aea4
MK
798 Controller,\r
799 &gEfiI2cHostProtocolGuid,\r
800 This->DriverBindingHandle,\r
801 Controller\r
802 );\r
43e543bc
EL
803\r
804 gBS->CloseProtocol (\r
1436aea4
MK
805 Controller,\r
806 &gEfiI2cEnumerateProtocolGuid,\r
807 This->DriverBindingHandle,\r
808 Controller\r
809 );\r
43e543bc
EL
810\r
811 Status = gBS->OpenProtocol (\r
812 Controller,\r
813 &gEfiCallerIdGuid,\r
1436aea4 814 (VOID **)&I2cBusContext,\r
43e543bc
EL
815 This->DriverBindingHandle,\r
816 Controller,\r
817 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
818 );\r
819 if (!EFI_ERROR (Status)) {\r
820 gBS->UninstallMultipleProtocolInterfaces (\r
1436aea4
MK
821 Controller,\r
822 &gEfiCallerIdGuid,\r
823 I2cBusContext,\r
824 NULL\r
825 );\r
43e543bc
EL
826 //\r
827 // No more child now, free bus context data.\r
828 //\r
829 FreePool (I2cBusContext);\r
830 }\r
1436aea4 831\r
43e543bc
EL
832 return Status;\r
833 }\r
834\r
835 AllChildrenStopped = TRUE;\r
836\r
837 for (Index = 0; Index < NumberOfChildren; Index++) {\r
43e543bc
EL
838 Status = UnRegisterI2cDevice (This, Controller, ChildHandleBuffer[Index]);\r
839 if (EFI_ERROR (Status)) {\r
840 AllChildrenStopped = FALSE;\r
841 }\r
842 }\r
843\r
844 if (!AllChildrenStopped) {\r
845 return EFI_DEVICE_ERROR;\r
846 }\r
1436aea4 847\r
43e543bc
EL
848 return EFI_SUCCESS;\r
849}\r
850\r
851/**\r
852 Enumerate the I2C bus\r
853\r
854 This routine walks the platform specific data describing the\r
855 I2C bus to create the I2C devices where driver GUIDs were\r
856 specified.\r
857\r
858 @param[in] I2cBusContext Address of an I2C_BUS_CONTEXT structure\r
859 @param[in] Controller Handle to the controller\r
860 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.\r
861\r
862 @retval EFI_SUCCESS The bus is successfully configured\r
863\r
864**/\r
865EFI_STATUS\r
866RegisterI2cDevice (\r
1436aea4
MK
867 IN I2C_BUS_CONTEXT *I2cBusContext,\r
868 IN EFI_HANDLE Controller,\r
869 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
43e543bc
EL
870 )\r
871{\r
1436aea4
MK
872 I2C_DEVICE_CONTEXT *I2cDeviceContext;\r
873 EFI_STATUS Status;\r
874 CONST EFI_I2C_DEVICE *Device;\r
875 CONST EFI_I2C_DEVICE *TempDevice;\r
876 UINT32 RemainingPathDeviceIndex;\r
877 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;\r
878 BOOLEAN BuildControllerNode;\r
879 UINTN Count;\r
880\r
881 Status = EFI_SUCCESS;\r
882 BuildControllerNode = TRUE;\r
43e543bc
EL
883\r
884 //\r
885 // Default DeviceIndex\r
886 //\r
887 RemainingPathDeviceIndex = 0;\r
d1102dba 888\r
43e543bc
EL
889 //\r
890 // Determine the controller number in Controller Node Device Path when RemainingDevicePath is not NULL.\r
891 //\r
892 if (RemainingDevicePath != NULL) {\r
893 //\r
894 // Check if there is a controller node appended after vendor node\r
d1102dba 895 //\r
43e543bc
EL
896 DevPathNode = NextDevicePathNode (RemainingDevicePath);\r
897 if ((DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH) &&\r
1436aea4
MK
898 (DevicePathSubType (DevPathNode) == HW_CONTROLLER_DP))\r
899 {\r
43e543bc
EL
900 //\r
901 // RemainingDevicePath != NULL and RemainingDevicePath contains Controller Node,\r
902 // add Controller Node to Device Path on child handle.\r
903 //\r
1436aea4 904 RemainingPathDeviceIndex = ((CONTROLLER_DEVICE_PATH *)DevPathNode)->ControllerNumber;\r
43e543bc
EL
905 } else {\r
906 //\r
907 // RemainingDevicePath != NULL and RemainingDevicePath does not contain Controller Node,\r
908 // do not add controller node to Device Path on child handle.\r
909 //\r
910 BuildControllerNode = FALSE;\r
911 }\r
912 }\r
913\r
914 //\r
915 // Walk the list of I2C devices on this bus\r
916 //\r
917 Device = NULL;\r
918 while (TRUE) {\r
919 //\r
920 // Get the next I2C device\r
921 //\r
922 Status = I2cBusContext->I2cEnumerate->Enumerate (I2cBusContext->I2cEnumerate, &Device);\r
1436aea4 923 if (EFI_ERROR (Status) || (Device == NULL)) {\r
43e543bc
EL
924 if (RemainingDevicePath != NULL) {\r
925 Status = EFI_NOT_FOUND;\r
926 } else {\r
927 Status = EFI_SUCCESS;\r
928 }\r
1436aea4 929\r
43e543bc
EL
930 break;\r
931 }\r
932\r
933 //\r
934 // Determine if the device info is valid\r
935 //\r
936 if ((Device->DeviceGuid == NULL) || (Device->SlaveAddressCount == 0) || (Device->SlaveAddressArray == NULL)) {\r
87000d77 937 DEBUG ((DEBUG_ERROR, "Invalid EFI_I2C_DEVICE reported by I2c Enumerate protocol.\n"));\r
43e543bc
EL
938 continue;\r
939 }\r
940\r
941 if (RemainingDevicePath == NULL) {\r
942 if (Device->DeviceIndex == 0) {\r
943 //\r
944 // Determine if the controller node is necessary when controller number is zero in I2C device\r
945 //\r
946 TempDevice = NULL;\r
947 Count = 0;\r
948 while (TRUE) {\r
949 //\r
950 // Get the next I2C device\r
951 //\r
952 Status = I2cBusContext->I2cEnumerate->Enumerate (I2cBusContext->I2cEnumerate, &TempDevice);\r
1436aea4 953 if (EFI_ERROR (Status) || (TempDevice == NULL)) {\r
43e543bc
EL
954 Status = EFI_SUCCESS;\r
955 break;\r
956 }\r
1436aea4 957\r
43e543bc
EL
958 if (CompareGuid (Device->DeviceGuid, TempDevice->DeviceGuid)) {\r
959 Count++;\r
960 }\r
961 }\r
1436aea4 962\r
43e543bc
EL
963 if (Count == 1) {\r
964 //\r
965 // RemainingDevicePath == NULL and only DeviceIndex 0 is present on the I2C bus,\r
966 // do not add Controller Node to Device Path on child handle.\r
967 //\r
968 BuildControllerNode = FALSE;\r
969 }\r
970 }\r
971 } else {\r
972 //\r
973 // Find I2C device reported in Remaining Device Path\r
974 //\r
975 if ((!CompareGuid (&((VENDOR_DEVICE_PATH *)RemainingDevicePath)->Guid, Device->DeviceGuid)) ||\r
1436aea4
MK
976 (RemainingPathDeviceIndex != Device->DeviceIndex))\r
977 {\r
d1102dba 978 continue;\r
43e543bc
EL
979 }\r
980 }\r
981\r
982 //\r
983 // Build the device context for current I2C device.\r
984 //\r
985 I2cDeviceContext = NULL;\r
986 I2cDeviceContext = AllocateCopyPool (sizeof (I2C_DEVICE_CONTEXT), &gI2cDeviceContextTemplate);\r
987 ASSERT (I2cDeviceContext != NULL);\r
988 if (I2cDeviceContext == NULL) {\r
989 continue;\r
990 }\r
991\r
992 //\r
993 // Initialize the specific device context\r
994 //\r
1436aea4
MK
995 I2cDeviceContext->I2cBusContext = I2cBusContext;\r
996 I2cDeviceContext->I2cDevice = Device;\r
997 I2cDeviceContext->I2cIo.DeviceGuid = Device->DeviceGuid;\r
998 I2cDeviceContext->I2cIo.DeviceIndex = Device->DeviceIndex;\r
999 I2cDeviceContext->I2cIo.HardwareRevision = Device->HardwareRevision;\r
43e543bc
EL
1000 I2cDeviceContext->I2cIo.I2cControllerCapabilities = I2cBusContext->I2cHost->I2cControllerCapabilities;\r
1001\r
1002 //\r
1003 // Build the device path\r
1004 //\r
1005 Status = I2cBusDevicePathAppend (I2cDeviceContext, BuildControllerNode);\r
1006 ASSERT_EFI_ERROR (Status);\r
1007 if (EFI_ERROR (Status)) {\r
1008 continue;\r
1009 }\r
1010\r
1011 //\r
1012 // Install the protocol\r
1013 //\r
1014 Status = gBS->InstallMultipleProtocolInterfaces (\r
1436aea4
MK
1015 &I2cDeviceContext->Handle,\r
1016 &gEfiI2cIoProtocolGuid,\r
1017 &I2cDeviceContext->I2cIo,\r
1018 &gEfiDevicePathProtocolGuid,\r
1019 I2cDeviceContext->DevicePath,\r
1020 NULL\r
1021 );\r
43e543bc
EL
1022 if (EFI_ERROR (Status)) {\r
1023 //\r
1024 // Free resources for this I2C device\r
1025 //\r
1026 ReleaseI2cDeviceContext (I2cDeviceContext);\r
1027 continue;\r
1028 }\r
d1102dba 1029\r
43e543bc
EL
1030 //\r
1031 // Create the child handle\r
1032 //\r
1033 Status = gBS->OpenProtocol (\r
1034 Controller,\r
1035 &gEfiI2cHostProtocolGuid,\r
1436aea4 1036 (VOID **)&I2cBusContext->I2cHost,\r
43e543bc
EL
1037 I2cBusContext->DriverBindingHandle,\r
1038 I2cDeviceContext->Handle,\r
1039 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
1040 );\r
1041 if (EFI_ERROR (Status)) {\r
1042 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1043 I2cDeviceContext->Handle,\r
1044 &gEfiDevicePathProtocolGuid,\r
1045 I2cDeviceContext->DevicePath,\r
1046 &gEfiI2cIoProtocolGuid,\r
1047 &I2cDeviceContext->I2cIo,\r
1048 NULL\r
1049 );\r
1050 //\r
1051 // Free resources for this I2C device\r
1052 //\r
1053 ReleaseI2cDeviceContext (I2cDeviceContext);\r
d1102dba 1054 continue;\r
43e543bc
EL
1055 }\r
1056\r
1057 if (RemainingDevicePath != NULL) {\r
1058 //\r
1059 // Child has been created successfully\r
1060 //\r
1061 break;\r
1062 }\r
1063 }\r
1064\r
1065 return Status;\r
1066}\r
1067\r
43e543bc
EL
1068/**\r
1069 Queue an I2C transaction for execution on the I2C device.\r
1070\r
1071 This routine must be called at or below TPL_NOTIFY. For synchronous\r
1072 requests this routine must be called at or below TPL_CALLBACK.\r
1073\r
1074 This routine queues an I2C transaction to the I2C controller for\r
1075 execution on the I2C bus.\r
1076\r
1077 When Event is NULL, QueueRequest() operates synchronously and returns\r
1078 the I2C completion status as its return value.\r
1079\r
1080 When Event is not NULL, QueueRequest() synchronously returns EFI_SUCCESS\r
1081 indicating that the asynchronous I2C transaction was queued. The values\r
1082 above are returned in the buffer pointed to by I2cStatus upon the\r
1083 completion of the I2C transaction when I2cStatus is not NULL.\r
1084\r
1085 The upper layer driver writer provides the following to the platform\r
1086 vendor:\r
d1102dba 1087\r
43e543bc
EL
1088 1. Vendor specific GUID for the I2C part\r
1089 2. Guidance on proper construction of the slave address array when the\r
1090 I2C device uses more than one slave address. The I2C bus protocol\r
1091 uses the SlaveAddressIndex to perform relative to physical address\r
1092 translation to access the blocks of hardware within the I2C device.\r
1093\r
1094 @param[in] This Pointer to an EFI_I2C_IO_PROTOCOL structure.\r
1095 @param[in] SlaveAddressIndex Index value into an array of slave addresses\r
1096 for the I2C device. The values in the array\r
1097 are specified by the board designer, with the\r
1098 third party I2C device driver writer providing\r
1099 the slave address order.\r
1100\r
1101 For devices that have a single slave address,\r
1102 this value must be zero. If the I2C device\r
1103 uses more than one slave address then the\r
1104 third party (upper level) I2C driver writer\r
1105 needs to specify the order of entries in the\r
1106 slave address array.\r
1107\r
1108 \ref ThirdPartyI2cDrivers "Third Party I2C\r
1109 Drivers" section in I2cMaster.h.\r
1110 @param[in] Event Event to signal for asynchronous transactions,\r
1111 NULL for synchronous transactions\r
1112 @param[in] RequestPacket Pointer to an EFI_I2C_REQUEST_PACKET structure\r
1113 describing the I2C transaction\r
1114 @param[out] I2cStatus Optional buffer to receive the I2C transaction\r
1115 completion status\r
1116\r
1117 @retval EFI_SUCCESS The asynchronous transaction was successfully\r
1118 queued when Event is not NULL.\r
1119 @retval EFI_SUCCESS The transaction completed successfully when\r
1120 Event is NULL.\r
43e543bc
EL
1121 @retval EFI_BAD_BUFFER_SIZE The RequestPacket->LengthInBytes value is too\r
1122 large.\r
1123 @retval EFI_DEVICE_ERROR There was an I2C error (NACK) during the\r
1124 transaction.\r
1125 @retval EFI_INVALID_PARAMETER RequestPacket is NULL\r
43e543bc
EL
1126 @retval EFI_NO_MAPPING The EFI_I2C_HOST_PROTOCOL could not set the\r
1127 bus configuration required to access this I2C\r
1128 device.\r
1129 @retval EFI_NO_RESPONSE The I2C device is not responding to the slave\r
1130 address selected by SlaveAddressIndex.\r
1131 EFI_DEVICE_ERROR will be returned if the\r
1132 controller cannot distinguish when the NACK\r
1133 occurred.\r
1134 @retval EFI_OUT_OF_RESOURCES Insufficient memory for I2C transaction\r
1135 @retval EFI_UNSUPPORTED The controller does not support the requested\r
1136 transaction.\r
1137\r
1138**/\r
1139EFI_STATUS\r
1140EFIAPI\r
1141I2cBusQueueRequest (\r
1142 IN CONST EFI_I2C_IO_PROTOCOL *This,\r
1143 IN UINTN SlaveAddressIndex,\r
1144 IN EFI_EVENT Event OPTIONAL,\r
1145 IN EFI_I2C_REQUEST_PACKET *RequestPacket,\r
1146 OUT EFI_STATUS *I2cStatus OPTIONAL\r
1147 )\r
1148{\r
1436aea4
MK
1149 CONST EFI_I2C_DEVICE *I2cDevice;\r
1150 I2C_BUS_CONTEXT *I2cBusContext;\r
1151 CONST EFI_I2C_HOST_PROTOCOL *I2cHost;\r
1152 I2C_DEVICE_CONTEXT *I2cDeviceContext;\r
1153 EFI_STATUS Status;\r
43e543bc
EL
1154\r
1155 if (RequestPacket == NULL) {\r
1156 return EFI_INVALID_PARAMETER;\r
1157 }\r
1158\r
1159 //\r
1160 // Validate the I2C slave index\r
1161 //\r
1162 I2cDeviceContext = I2C_DEVICE_CONTEXT_FROM_PROTOCOL (This);\r
1163 I2cDevice = I2cDeviceContext->I2cDevice;\r
1164 if ( SlaveAddressIndex >= I2cDevice->SlaveAddressCount ) {\r
1165 return EFI_INVALID_PARAMETER;\r
1166 }\r
1167\r
1168 //\r
1169 // Locate the I2c Host Protocol to queue request\r
1170 //\r
1171 I2cBusContext = I2cDeviceContext->I2cBusContext;\r
1172 I2cHost = I2cBusContext->I2cHost;\r
1173\r
1174 //\r
1175 // Start the I2C operation\r
1176 //\r
1177 Status = I2cHost->QueueRequest (\r
1178 I2cHost,\r
1179 I2cDevice->I2cBusConfiguration,\r
1436aea4 1180 I2cDevice->SlaveAddressArray[SlaveAddressIndex],\r
43e543bc
EL
1181 Event,\r
1182 RequestPacket,\r
1183 I2cStatus\r
1184 );\r
1185\r
1186 return Status;\r
1187}\r
1188\r
1189/**\r
1190 Release all the resources allocated for the I2C device.\r
1191\r
1192 This function releases all the resources allocated for the I2C device.\r
1193\r
1194 @param I2cDeviceContext The I2C child device involved for the operation.\r
1195\r
1196**/\r
1197VOID\r
1198ReleaseI2cDeviceContext (\r
1436aea4 1199 IN I2C_DEVICE_CONTEXT *I2cDeviceContext\r
43e543bc
EL
1200 )\r
1201{\r
1202 if (I2cDeviceContext == NULL) {\r
1203 return;\r
1204 }\r
d1102dba 1205\r
43e543bc
EL
1206 if (I2cDeviceContext->DevicePath != NULL) {\r
1207 FreePool (I2cDeviceContext->DevicePath);\r
1208 }\r
1209\r
1210 FreePool (I2cDeviceContext);\r
1211}\r
1212\r
1213/**\r
1214 Unregister an I2C device.\r
1215\r
1216 This function removes the protocols installed on the controller handle and\r
1217 frees the resources allocated for the I2C device.\r
1218\r
1219 @param This The pointer to EFI_DRIVER_BINDING_PROTOCOL instance.\r
1220 @param Controller The controller handle of the I2C device.\r
1221 @param Handle The child handle.\r
1222\r
1223 @retval EFI_SUCCESS The I2C device is successfully unregistered.\r
1224 @return Others Some error occurs when unregistering the I2C device.\r
1225\r
1226**/\r
1227EFI_STATUS\r
1228UnRegisterI2cDevice (\r
1436aea4
MK
1229 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1230 IN EFI_HANDLE Controller,\r
1231 IN EFI_HANDLE Handle\r
43e543bc
EL
1232 )\r
1233{\r
1436aea4
MK
1234 EFI_STATUS Status;\r
1235 I2C_DEVICE_CONTEXT *I2cDeviceContext;\r
1236 EFI_I2C_IO_PROTOCOL *I2cIo;\r
1237 EFI_I2C_HOST_PROTOCOL *I2cHost;\r
43e543bc
EL
1238\r
1239 I2cIo = NULL;\r
1240\r
1241 Status = gBS->OpenProtocol (\r
1242 Handle,\r
1243 &gEfiI2cIoProtocolGuid,\r
1436aea4 1244 (VOID **)&I2cIo,\r
43e543bc
EL
1245 This->DriverBindingHandle,\r
1246 Controller,\r
1247 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1248 );\r
1249 if (EFI_ERROR (Status)) {\r
1250 return Status;\r
1251 }\r
1252\r
1253 //\r
1254 // Get I2c device context data.\r
1255 //\r
1256 I2cDeviceContext = I2C_DEVICE_CONTEXT_FROM_PROTOCOL (I2cIo);\r
1257\r
1258 //\r
1259 // Close the child handle\r
1260 //\r
1261 gBS->CloseProtocol (\r
1262 Controller,\r
1263 &gEfiI2cHostProtocolGuid,\r
1264 This->DriverBindingHandle,\r
1265 Handle\r
1266 );\r
1267\r
1268 //\r
1269 // The I2C Bus driver installs the I2C Io and Device Path Protocol in the DriverBindingStart().\r
1270 // Here should uninstall them.\r
1271 //\r
1272 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1273 Handle,\r
1274 &gEfiDevicePathProtocolGuid,\r
1275 I2cDeviceContext->DevicePath,\r
1276 &gEfiI2cIoProtocolGuid,\r
1277 &I2cDeviceContext->I2cIo,\r
1278 NULL\r
1279 );\r
1280\r
1281 if (EFI_ERROR (Status)) {\r
1282 //\r
1283 // Keep parent and child relationship\r
1284 //\r
1285 gBS->OpenProtocol (\r
1436aea4
MK
1286 Controller,\r
1287 &gEfiI2cHostProtocolGuid,\r
1288 (VOID **)&I2cHost,\r
1289 This->DriverBindingHandle,\r
1290 Handle,\r
1291 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
1292 );\r
43e543bc
EL
1293 return Status;\r
1294 }\r
d1102dba 1295\r
43e543bc
EL
1296 //\r
1297 // Free resources for this I2C device\r
1298 //\r
1299 ReleaseI2cDeviceContext (I2cDeviceContext);\r
d1102dba 1300\r
43e543bc
EL
1301 return EFI_SUCCESS;\r
1302}\r
1303\r
1304/**\r
1305 Create a path for the I2C device\r
1306\r
1307 Append the I2C slave path to the I2C master controller path.\r
1308\r
1309 @param[in] I2cDeviceContext Address of an I2C_DEVICE_CONTEXT structure.\r
1310 @param[in] BuildControllerNode Flag to build controller node in device path.\r
1311\r
1312 @retval EFI_SUCCESS The I2C device path is built successfully.\r
1313 @return Others It is failed to built device path.\r
1314\r
1315**/\r
1316EFI_STATUS\r
1317I2cBusDevicePathAppend (\r
1436aea4
MK
1318 IN I2C_DEVICE_CONTEXT *I2cDeviceContext,\r
1319 IN BOOLEAN BuildControllerNode\r
43e543bc
EL
1320 )\r
1321{\r
1322 EFI_DEVICE_PATH_PROTOCOL *PreviousDevicePath;\r
d1102dba 1323\r
43e543bc
EL
1324 PreviousDevicePath = NULL;\r
1325\r
1326 //\r
1327 // Build vendor device path\r
d1102dba 1328 //\r
43e543bc 1329 CopyMem (&gVendorDevicePathTemplate.Guid, I2cDeviceContext->I2cDevice->DeviceGuid, sizeof (EFI_GUID));\r
1436aea4
MK
1330 I2cDeviceContext->DevicePath = AppendDevicePathNode (\r
1331 I2cDeviceContext->I2cBusContext->ParentDevicePath,\r
1332 (EFI_DEVICE_PATH_PROTOCOL *)&gVendorDevicePathTemplate\r
1333 );\r
43e543bc
EL
1334 ASSERT (I2cDeviceContext->DevicePath != NULL);\r
1335 if (I2cDeviceContext->DevicePath == NULL) {\r
1336 return EFI_OUT_OF_RESOURCES;\r
1337 }\r
d1102dba 1338\r
43e543bc
EL
1339 if ((BuildControllerNode) && (I2cDeviceContext->DevicePath != NULL)) {\r
1340 //\r
1341 // Build the final I2C device path with controller node\r
1342 //\r
1436aea4 1343 PreviousDevicePath = I2cDeviceContext->DevicePath;\r
d1102dba 1344 gControllerDevicePathTemplate.ControllerNumber = I2cDeviceContext->I2cDevice->DeviceIndex;\r
1436aea4
MK
1345 I2cDeviceContext->DevicePath = AppendDevicePathNode (\r
1346 I2cDeviceContext->DevicePath,\r
1347 (EFI_DEVICE_PATH_PROTOCOL *)&gControllerDevicePathTemplate\r
1348 );\r
43e543bc
EL
1349 gBS->FreePool (PreviousDevicePath);\r
1350 ASSERT (I2cDeviceContext->DevicePath != NULL);\r
1351 if (I2cDeviceContext->DevicePath == NULL) {\r
1352 return EFI_OUT_OF_RESOURCES;\r
1353 }\r
1354 }\r
1355\r
1356 return EFI_SUCCESS;\r
1357}\r
1358\r
1359/**\r
1360 The user entry point for the I2C bus module. The user code starts with\r
1361 this function.\r
1362\r
1363 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
1364 @param[in] SystemTable A pointer to the EFI System Table.\r
1365\r
1366 @retval EFI_SUCCESS The entry point is executed successfully.\r
1367 @retval other Some error occurs when executing this entry point.\r
1368\r
1369**/\r
1370EFI_STATUS\r
1371EFIAPI\r
1436aea4
MK
1372InitializeI2cBus (\r
1373 IN EFI_HANDLE ImageHandle,\r
1374 IN EFI_SYSTEM_TABLE *SystemTable\r
43e543bc
EL
1375 )\r
1376{\r
1436aea4 1377 EFI_STATUS Status;\r
43e543bc
EL
1378\r
1379 //\r
1380 // Install driver model protocol(s).\r
1381 //\r
1382 Status = EfiLibInstallDriverBindingComponentName2 (\r
1383 ImageHandle,\r
1384 SystemTable,\r
1385 &gI2cBusDriverBinding,\r
1386 NULL,\r
1387 &gI2cBusComponentName,\r
1388 &gI2cBusComponentName2\r
1389 );\r
1390 ASSERT_EFI_ERROR (Status);\r
1391\r
43e543bc
EL
1392 return Status;\r
1393}\r
1394\r
1395/**\r
1396 This is the unload handle for I2C bus module.\r
1397\r
1398 Disconnect the driver specified by ImageHandle from all the devices in the handle database.\r
1399 Uninstall all the protocols installed in the driver entry point.\r
1400\r
1401 @param[in] ImageHandle The drivers' driver image.\r
1402\r
1403 @retval EFI_SUCCESS The image is unloaded.\r
1404 @retval Others Failed to unload the image.\r
1405\r
1406**/\r
1407EFI_STATUS\r
1408EFIAPI\r
1409I2cBusUnload (\r
1436aea4 1410 IN EFI_HANDLE ImageHandle\r
43e543bc
EL
1411 )\r
1412{\r
1436aea4
MK
1413 EFI_STATUS Status;\r
1414 EFI_HANDLE *DeviceHandleBuffer;\r
1415 UINTN DeviceHandleCount;\r
1416 UINTN Index;\r
1417 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;\r
1418 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;\r
43e543bc
EL
1419\r
1420 //\r
1421 // Get the list of all I2C Controller handles in the handle database.\r
1422 // If there is an error getting the list, then the unload\r
1423 // operation fails.\r
1424 //\r
1425 Status = gBS->LocateHandleBuffer (\r
1426 ByProtocol,\r
1427 &gEfiI2cHostProtocolGuid,\r
1428 NULL,\r
1429 &DeviceHandleCount,\r
1430 &DeviceHandleBuffer\r
1431 );\r
1432\r
2fa77862
EL
1433 if (!EFI_ERROR (Status)) {\r
1434 //\r
1435 // Disconnect the driver specified by Driver BindingHandle from all\r
1436 // the devices in the handle database.\r
1437 //\r
1438 for (Index = 0; Index < DeviceHandleCount; Index++) {\r
1439 Status = gBS->DisconnectController (\r
1440 DeviceHandleBuffer[Index],\r
1441 gI2cBusDriverBinding.DriverBindingHandle,\r
1442 NULL\r
1443 );\r
1444 if (EFI_ERROR (Status)) {\r
1445 goto Done;\r
1446 }\r
43e543bc
EL
1447 }\r
1448 }\r
1449\r
1450 //\r
1451 // Uninstall all the protocols installed in the driver entry point\r
1452 //\r
1453 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1454 gI2cBusDriverBinding.DriverBindingHandle,\r
1455 &gEfiDriverBindingProtocolGuid,\r
1456 &gI2cBusDriverBinding,\r
43e543bc
EL
1457 NULL\r
1458 );\r
1459 ASSERT_EFI_ERROR (Status);\r
1460\r
6f497f8f
EL
1461 //\r
1462 // Note we have to one by one uninstall the following protocols.\r
1463 // It's because some of them are optionally installed based on\r
1464 // the following PCD settings.\r
1465 // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnosticsDisable\r
1466 // gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable\r
1467 // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnostics2Disable\r
1468 // gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable\r
1469 //\r
1470 Status = gBS->HandleProtocol (\r
1471 gI2cBusDriverBinding.DriverBindingHandle,\r
1472 &gEfiComponentNameProtocolGuid,\r
1436aea4 1473 (VOID **)&ComponentName\r
6f497f8f
EL
1474 );\r
1475 if (!EFI_ERROR (Status)) {\r
1476 gBS->UninstallProtocolInterface (\r
1477 gI2cBusDriverBinding.DriverBindingHandle,\r
1478 &gEfiComponentNameProtocolGuid,\r
1479 ComponentName\r
1480 );\r
1481 }\r
1482\r
1483 Status = gBS->HandleProtocol (\r
1484 gI2cBusDriverBinding.DriverBindingHandle,\r
1485 &gEfiComponentName2ProtocolGuid,\r
1436aea4 1486 (VOID **)&ComponentName2\r
6f497f8f
EL
1487 );\r
1488 if (!EFI_ERROR (Status)) {\r
1489 gBS->UninstallProtocolInterface (\r
1490 gI2cBusDriverBinding.DriverBindingHandle,\r
1491 &gEfiComponentName2ProtocolGuid,\r
1492 ComponentName2\r
1493 );\r
1494 }\r
1495\r
1496 Status = EFI_SUCCESS;\r
1497\r
43e543bc
EL
1498Done:\r
1499 //\r
1500 // Free the buffer containing the list of handles from the handle database\r
1501 //\r
1502 if (DeviceHandleBuffer != NULL) {\r
1503 gBS->FreePool (DeviceHandleBuffer);\r
1504 }\r
1505\r
1506 return Status;\r
1507}\r