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