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