1 /** @file
2 Emu Bus driver
3
4 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
5 Portions copyright (c) 2011, Apple Inc. All rights reserved.
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14
15 **/
16
17 #include "EmuBusDriverDxe.h"
18
19
20
21 //
22 // DriverBinding protocol global
23 //
24 EFI_DRIVER_BINDING_PROTOCOL gEmuBusDriverBinding = {
25 EmuBusDriverBindingSupported,
26 EmuBusDriverBindingStart,
27 EmuBusDriverBindingStop,
28 0xa,
29 NULL,
30 NULL
31 };
32
33
34
35 EFI_STATUS
36 EFIAPI
EmuBusDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)37 EmuBusDriverBindingSupported (
38 IN EFI_DRIVER_BINDING_PROTOCOL *This,
39 IN EFI_HANDLE ControllerHandle,
40 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
41 )
42 {
43 EFI_STATUS Status;
44 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
45 EMU_THUNK_PROTOCOL *EmuThunk;
46
47 //
48 // Check the contents of the first Device Path Node of RemainingDevicePath to make sure
49 // it is a legal Device Path Node for this bus driver's children.
50 //
51 if (RemainingDevicePath != NULL) {
52 //
53 // Check if RemainingDevicePath is the End of Device Path Node,
54 // if yes, go on checking other conditions
55 //
56 if (!IsDevicePathEnd (RemainingDevicePath)) {
57 //
58 // If RemainingDevicePath isn't the End of Device Path Node,
59 // check its validation
60 //
61 if (RemainingDevicePath->Type != HARDWARE_DEVICE_PATH ||
62 RemainingDevicePath->SubType != HW_VENDOR_DP ||
63 DevicePathNodeLength(RemainingDevicePath) != sizeof(EMU_VENDOR_DEVICE_PATH_NODE)) {
64 return EFI_UNSUPPORTED;
65 }
66 }
67 }
68
69 //
70 // Open the IO Abstraction(s) needed to perform the supported test
71 //
72 Status = gBS->OpenProtocol (
73 ControllerHandle,
74 &gEmuThunkProtocolGuid,
75 (VOID **)&EmuThunk ,
76 This->DriverBindingHandle,
77 ControllerHandle,
78 EFI_OPEN_PROTOCOL_BY_DRIVER
79 );
80 if (Status == EFI_ALREADY_STARTED) {
81 return EFI_SUCCESS;
82 }
83
84 if (EFI_ERROR (Status)) {
85 return Status;
86 }
87
88 //
89 // Close the I/O Abstraction(s) used to perform the supported test
90 //
91 gBS->CloseProtocol (
92 ControllerHandle,
93 &gEmuThunkProtocolGuid,
94 This->DriverBindingHandle,
95 ControllerHandle
96 );
97
98 //
99 // Open the EFI Device Path protocol needed to perform the supported test
100 //
101 Status = gBS->OpenProtocol (
102 ControllerHandle,
103 &gEfiDevicePathProtocolGuid,
104 (VOID **)&ParentDevicePath,
105 This->DriverBindingHandle,
106 ControllerHandle,
107 EFI_OPEN_PROTOCOL_BY_DRIVER
108 );
109 if (Status == EFI_ALREADY_STARTED) {
110 return EFI_SUCCESS;
111 }
112
113 if (EFI_ERROR (Status)) {
114 return Status;
115 }
116
117
118 //
119 // Close protocol, don't use device path protocol in the Support() function
120 //
121 gBS->CloseProtocol (
122 ControllerHandle,
123 &gEfiDevicePathProtocolGuid,
124 This->DriverBindingHandle,
125 ControllerHandle
126 );
127
128 return Status;
129 }
130
131
132 EFI_STATUS
133 EFIAPI
EmuBusDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)134 EmuBusDriverBindingStart (
135 IN EFI_DRIVER_BINDING_PROTOCOL *This,
136 IN EFI_HANDLE ControllerHandle,
137 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
138 )
139 {
140 EFI_STATUS Status;
141 EFI_STATUS InstallStatus;
142 EMU_THUNK_PROTOCOL *EmuThunk;
143 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
144 EMU_IO_DEVICE *EmuDevice;
145 EMU_BUS_DEVICE *EmuBusDevice;
146 EMU_IO_THUNK_PROTOCOL *EmuIoThunk;
147 UINT16 ComponentName[512];
148 EMU_VENDOR_DEVICE_PATH_NODE *Node;
149 BOOLEAN CreateDevice;
150
151 InstallStatus = EFI_UNSUPPORTED;
152 Status = EFI_UNSUPPORTED;
153
154 //
155 // Grab the protocols we need
156 //
157 Status = gBS->OpenProtocol (
158 ControllerHandle,
159 &gEfiDevicePathProtocolGuid,
160 (VOID **)&ParentDevicePath,
161 This->DriverBindingHandle,
162 ControllerHandle,
163 EFI_OPEN_PROTOCOL_BY_DRIVER
164 );
165 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
166 return Status;
167 }
168
169 Status = gBS->OpenProtocol (
170 ControllerHandle,
171 &gEmuThunkProtocolGuid,
172 (VOID **)&EmuThunk,
173 This->DriverBindingHandle,
174 ControllerHandle,
175 EFI_OPEN_PROTOCOL_BY_DRIVER
176 );
177 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
178 return Status;
179 }
180
181 if (Status != EFI_ALREADY_STARTED) {
182 EmuBusDevice = AllocatePool (sizeof (EMU_BUS_DEVICE));
183 if (EmuBusDevice == NULL) {
184 return EFI_OUT_OF_RESOURCES;
185 }
186
187 EmuBusDevice->Signature = EMU_BUS_DEVICE_SIGNATURE;
188 EmuBusDevice->ControllerNameTable = NULL;
189
190 AddUnicodeString2 (
191 "eng",
192 gEmuBusDriverComponentName.SupportedLanguages,
193 &EmuBusDevice->ControllerNameTable,
194 L"Emulator Bus Controller",
195 TRUE
196 );
197 AddUnicodeString2 (
198 "en",
199 gEmuBusDriverComponentName2.SupportedLanguages,
200 &EmuBusDevice->ControllerNameTable,
201 L"Emulator Bus Controller",
202 FALSE
203 );
204
205
206 Status = gBS->InstallMultipleProtocolInterfaces (
207 &ControllerHandle,
208 &gEfiCallerIdGuid, EmuBusDevice,
209 NULL
210 );
211 if (EFI_ERROR (Status)) {
212 FreeUnicodeStringTable (EmuBusDevice->ControllerNameTable);
213 gBS->FreePool (EmuBusDevice);
214 return Status;
215 }
216 }
217
218
219 for (Status = EFI_SUCCESS, EmuIoThunk = NULL; !EFI_ERROR (Status); ) {
220 Status = EmuThunk->GetNextProtocol (TRUE, &EmuIoThunk);
221 if (EFI_ERROR (Status)) {
222 break;
223 }
224
225 CreateDevice = TRUE;
226 if (RemainingDevicePath != NULL) {
227 CreateDevice = FALSE;
228 //
229 // Check if RemainingDevicePath is the End of Device Path Node,
230 // if yes, don't create any child device
231 //
232 if (!IsDevicePathEnd (RemainingDevicePath)) {
233 //
234 // If RemainingDevicePath isn't the End of Device Path Node,
235 // check its validation
236 //
237 Node = (EMU_VENDOR_DEVICE_PATH_NODE *) RemainingDevicePath;
238 if (Node->VendorDevicePath.Header.Type == HARDWARE_DEVICE_PATH &&
239 Node->VendorDevicePath.Header.SubType == HW_VENDOR_DP &&
240 DevicePathNodeLength (&Node->VendorDevicePath.Header) == sizeof (EMU_VENDOR_DEVICE_PATH_NODE)
241 ) {
242 if (CompareGuid (&Node->VendorDevicePath.Guid, EmuIoThunk->Protocol) && Node->Instance == EmuIoThunk->Instance) {
243 CreateDevice = TRUE;
244 }
245 }
246 }
247 }
248
249 if (CreateDevice) {
250 //
251 // Allocate instance structure, and fill in parent information.
252 //
253 EmuDevice = AllocatePool (sizeof (EMU_IO_DEVICE));
254 if (EmuDevice == NULL) {
255 return EFI_OUT_OF_RESOURCES;
256 }
257
258 EmuDevice->Handle = NULL;
259 EmuDevice->ControllerHandle = ControllerHandle;
260 EmuDevice->ParentDevicePath = ParentDevicePath;
261 CopyMem (&EmuDevice->EmuIoThunk, EmuIoThunk, sizeof (EMU_IO_THUNK_PROTOCOL));
262
263 EmuDevice->ControllerNameTable = NULL;
264
265 StrnCpy (ComponentName, EmuIoThunk->ConfigString, sizeof (ComponentName)/sizeof (CHAR16));
266
267 EmuDevice->DevicePath = EmuBusCreateDevicePath (
268 ParentDevicePath,
269 EmuIoThunk->Protocol,
270 EmuIoThunk->Instance
271 );
272 if (EmuDevice->DevicePath == NULL) {
273 gBS->FreePool (EmuDevice);
274 return EFI_OUT_OF_RESOURCES;
275 }
276
277 AddUnicodeString (
278 "eng",
279 gEmuBusDriverComponentName.SupportedLanguages,
280 &EmuDevice->ControllerNameTable,
281 ComponentName
282 );
283
284 EmuDevice->Signature = EMU_IO_DEVICE_SIGNATURE;
285
286 InstallStatus = gBS->InstallMultipleProtocolInterfaces (
287 &EmuDevice->Handle,
288 &gEfiDevicePathProtocolGuid, EmuDevice->DevicePath,
289 &gEmuIoThunkProtocolGuid, &EmuDevice->EmuIoThunk,
290 NULL
291 );
292 if (EFI_ERROR (InstallStatus)) {
293 FreeUnicodeStringTable (EmuDevice->ControllerNameTable);
294 gBS->FreePool (EmuDevice);
295 } else {
296 //
297 // Open For Child Device
298 //
299 Status = gBS->OpenProtocol (
300 ControllerHandle,
301 &gEmuThunkProtocolGuid,
302 (VOID **)&EmuThunk ,
303 This->DriverBindingHandle,
304 EmuDevice->Handle,
305 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
306 );
307 if (!EFI_ERROR (Status)) {
308 InstallStatus = EFI_SUCCESS;
309 }
310 }
311 }
312 }
313
314 return InstallStatus;
315 }
316
317
318 EFI_STATUS
319 EFIAPI
EmuBusDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)320 EmuBusDriverBindingStop (
321 IN EFI_DRIVER_BINDING_PROTOCOL *This,
322 IN EFI_HANDLE ControllerHandle,
323 IN UINTN NumberOfChildren,
324 IN EFI_HANDLE *ChildHandleBuffer
325 )
326 {
327 EFI_STATUS Status;
328 UINTN Index;
329 BOOLEAN AllChildrenStopped;
330 EMU_IO_THUNK_PROTOCOL *EmuIoThunk;
331 EMU_BUS_DEVICE *EmuBusDevice;
332 EMU_IO_DEVICE *EmuDevice;
333 EMU_THUNK_PROTOCOL *EmuThunk;
334
335 //
336 // Complete all outstanding transactions to Controller.
337 // Don't allow any new transaction to Controller to be started.
338 //
339
340 if (NumberOfChildren == 0) {
341 //
342 // Close the bus driver
343 //
344 Status = gBS->OpenProtocol (
345 ControllerHandle,
346 &gEfiCallerIdGuid,
347 (VOID **)&EmuBusDevice,
348 This->DriverBindingHandle,
349 ControllerHandle,
350 EFI_OPEN_PROTOCOL_GET_PROTOCOL
351 );
352 if (EFI_ERROR (Status)) {
353 return Status;
354 }
355
356 gBS->UninstallMultipleProtocolInterfaces (
357 ControllerHandle,
358 &gEfiCallerIdGuid, EmuBusDevice,
359 NULL
360 );
361
362 FreeUnicodeStringTable (EmuBusDevice->ControllerNameTable);
363
364 gBS->FreePool (EmuBusDevice);
365
366 gBS->CloseProtocol (
367 ControllerHandle,
368 &gEmuThunkProtocolGuid,
369 This->DriverBindingHandle,
370 ControllerHandle
371 );
372
373 gBS->CloseProtocol (
374 ControllerHandle,
375 &gEfiDevicePathProtocolGuid,
376 This->DriverBindingHandle,
377 ControllerHandle
378 );
379 return EFI_SUCCESS;
380 }
381
382 AllChildrenStopped = TRUE;
383
384 for (Index = 0; Index < NumberOfChildren; Index++) {
385
386 Status = gBS->OpenProtocol (
387 ChildHandleBuffer[Index],
388 &gEmuIoThunkProtocolGuid,
389 (VOID **)&EmuIoThunk,
390 This->DriverBindingHandle,
391 ControllerHandle,
392 EFI_OPEN_PROTOCOL_GET_PROTOCOL
393 );
394 if (!EFI_ERROR (Status)) {
395 EmuDevice = EMU_IO_DEVICE_FROM_THIS (EmuIoThunk);
396
397 Status = gBS->CloseProtocol (
398 ControllerHandle,
399 &gEmuThunkProtocolGuid,
400 This->DriverBindingHandle,
401 EmuDevice->Handle
402 );
403
404 Status = gBS->UninstallMultipleProtocolInterfaces (
405 EmuDevice->Handle,
406 &gEfiDevicePathProtocolGuid, EmuDevice->DevicePath,
407 &gEmuIoThunkProtocolGuid, &EmuDevice->EmuIoThunk,
408 NULL
409 );
410
411 if (EFI_ERROR (Status)) {
412 gBS->OpenProtocol (
413 ControllerHandle,
414 &gEmuThunkProtocolGuid,
415 (VOID **) &EmuThunk ,
416 This->DriverBindingHandle,
417 EmuDevice->Handle,
418 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
419 );
420 } else {
421 //
422 // Close the child handle
423 //
424 FreeUnicodeStringTable (EmuDevice->ControllerNameTable);
425 FreePool (EmuDevice);
426 }
427 }
428
429 if (EFI_ERROR (Status)) {
430 AllChildrenStopped = FALSE;
431 }
432 }
433
434 if (!AllChildrenStopped) {
435 return EFI_DEVICE_ERROR;
436 }
437
438 return EFI_SUCCESS;
439 }
440
441
442 /*++
443
444 Routine Description:
445 Create a device path node using Guid and InstanceNumber and append it to
446 the passed in RootDevicePath
447
448 Arguments:
449 RootDevicePath - Root of the device path to return.
450
451 Guid - GUID to use in vendor device path node.
452
453 InstanceNumber - Instance number to use in the vendor device path. This
454 argument is needed to make sure each device path is unique.
455
456 Returns:
457
458 EFI_DEVICE_PATH_PROTOCOL
459
460 **/
461 EFI_DEVICE_PATH_PROTOCOL *
EmuBusCreateDevicePath(IN EFI_DEVICE_PATH_PROTOCOL * RootDevicePath,IN EFI_GUID * Guid,IN UINT16 InstanceNumber)462 EmuBusCreateDevicePath (
463 IN EFI_DEVICE_PATH_PROTOCOL *RootDevicePath,
464 IN EFI_GUID *Guid,
465 IN UINT16 InstanceNumber
466 )
467 {
468 EMU_VENDOR_DEVICE_PATH_NODE DevicePath;
469
470 DevicePath.VendorDevicePath.Header.Type = HARDWARE_DEVICE_PATH;
471 DevicePath.VendorDevicePath.Header.SubType = HW_VENDOR_DP;
472 SetDevicePathNodeLength (&DevicePath.VendorDevicePath.Header, sizeof (EMU_VENDOR_DEVICE_PATH_NODE));
473
474 //
475 // The GUID defines the Class
476 //
477 CopyMem (&DevicePath.VendorDevicePath.Guid, Guid, sizeof (EFI_GUID));
478
479 //
480 // Add an instance number so we can make sure there are no Device Path
481 // duplication.
482 //
483 DevicePath.Instance = InstanceNumber;
484
485 return AppendDevicePathNode (
486 RootDevicePath,
487 (EFI_DEVICE_PATH_PROTOCOL *) &DevicePath
488 );
489 }
490
491
492
493 /**
494 The user Entry Point for module EmuBusDriver. The user code starts with this function.
495
496 @param[in] ImageHandle The firmware allocated handle for the EFI image.
497 @param[in] SystemTable A pointer to the EFI System Table.
498
499 @retval EFI_SUCCESS The entry point is executed successfully.
500 @retval other Some error occurs when executing this entry point.
501
502 **/
503 EFI_STATUS
504 EFIAPI
InitializeEmuBusDriver(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)505 InitializeEmuBusDriver (
506 IN EFI_HANDLE ImageHandle,
507 IN EFI_SYSTEM_TABLE *SystemTable
508 )
509 {
510 EFI_STATUS Status;
511
512 Status = EfiLibInstallAllDriverProtocols (
513 ImageHandle,
514 SystemTable,
515 &gEmuBusDriverBinding,
516 ImageHandle,
517 &gEmuBusDriverComponentName,
518 NULL,
519 NULL
520 );
521 ASSERT_EFI_ERROR (Status);
522
523
524 return Status;
525 }
526
527
528
529
530