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