Home | History | Annotate | Download | only in EmuBusDriverDxe
      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
     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
    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
    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 *
    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
    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