1/** @file
2
3  Copyright (C) 2016, Linaro Ltd. All rights reserved.<BR>
4
5  This program and the accompanying materials are licensed and made available
6  under the terms and conditions of the BSD License which accompanies this
7  distribution. The full text of the license may be found at
8  http://opensource.org/licenses/bsd-license.php
9
10  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
11  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include "NonDiscoverablePciDeviceIo.h"
16
17#include <Protocol/DriverBinding.h>
18
19EFI_CPU_ARCH_PROTOCOL      *mCpu;
20
21//
22// We only support the following device types
23//
24STATIC
25CONST EFI_GUID * CONST
26SupportedNonDiscoverableDevices[] = {
27  &gEdkiiNonDiscoverableAhciDeviceGuid,
28  &gEdkiiNonDiscoverableEhciDeviceGuid,
29  &gEdkiiNonDiscoverableNvmeDeviceGuid,
30  &gEdkiiNonDiscoverableOhciDeviceGuid,
31  &gEdkiiNonDiscoverableSdhciDeviceGuid,
32  &gEdkiiNonDiscoverableUfsDeviceGuid,
33  &gEdkiiNonDiscoverableUhciDeviceGuid,
34  &gEdkiiNonDiscoverableXhciDeviceGuid,
35};
36
37//
38// Probe, start and stop functions of this driver, called by the DXE core for
39// specific devices.
40//
41// The following specifications document these interfaces:
42// - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
43// - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
44//
45// The implementation follows:
46// - Driver Writer's Guide for UEFI 2.3.1 v1.01
47//   - 5.1.3.4 OpenProtocol() and CloseProtocol()
48// - UEFI Spec 2.3.1 + Errata C
49//   -  6.3 Protocol Handler Services
50//
51
52/**
53  Supported function of Driver Binding protocol for this driver.
54  Test to see if this driver supports ControllerHandle.
55
56  @param This                   Protocol instance pointer.
57  @param DeviceHandle           Handle of device to test.
58  @param RemainingDevicePath    A pointer to the device path.
59                                it should be ignored by device driver.
60
61  @retval EFI_SUCCESS           This driver supports this device.
62  @retval other                 This driver does not support this device.
63
64**/
65STATIC
66EFI_STATUS
67EFIAPI
68NonDiscoverablePciDeviceSupported (
69  IN EFI_DRIVER_BINDING_PROTOCOL *This,
70  IN EFI_HANDLE                  DeviceHandle,
71  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
72  )
73{
74  NON_DISCOVERABLE_DEVICE             *Device;
75  EFI_STATUS                          Status;
76  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;
77  INTN                                Idx;
78
79  Status = gBS->OpenProtocol (DeviceHandle,
80                  &gEdkiiNonDiscoverableDeviceProtocolGuid, (VOID **)&Device,
81                  This->DriverBindingHandle, DeviceHandle,
82                  EFI_OPEN_PROTOCOL_BY_DRIVER);
83  if (EFI_ERROR (Status)) {
84    return Status;
85  }
86
87  Status = EFI_UNSUPPORTED;
88  for (Idx = 0; Idx < ARRAY_SIZE (SupportedNonDiscoverableDevices); Idx++) {
89    if (CompareGuid (Device->Type, SupportedNonDiscoverableDevices [Idx])) {
90      Status = EFI_SUCCESS;
91      break;
92    }
93  }
94
95  if (EFI_ERROR (Status)) {
96    goto CloseProtocol;
97  }
98
99  //
100  // We only support MMIO devices, so iterate over the resources to ensure
101  // that they only describe things that we can handle
102  //
103  for (Desc = Device->Resources; Desc->Desc != ACPI_END_TAG_DESCRIPTOR;
104       Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {
105    if (Desc->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR ||
106        Desc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) {
107      Status = EFI_UNSUPPORTED;
108      break;
109    }
110  }
111
112CloseProtocol:
113  gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid,
114         This->DriverBindingHandle, DeviceHandle);
115
116  return Status;
117}
118
119/**
120  This routine is called right after the .Supported() called and
121  Start this driver on ControllerHandle.
122
123  @param This                   Protocol instance pointer.
124  @param DeviceHandle           Handle of device to bind driver to.
125  @param RemainingDevicePath    A pointer to the device path.
126                                it should be ignored by device driver.
127
128  @retval EFI_SUCCESS           This driver is added to this device.
129  @retval other                 Some error occurs when binding this driver to this device.
130
131**/
132STATIC
133EFI_STATUS
134EFIAPI
135NonDiscoverablePciDeviceStart (
136  IN EFI_DRIVER_BINDING_PROTOCOL *This,
137  IN EFI_HANDLE                  DeviceHandle,
138  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
139  )
140{
141  NON_DISCOVERABLE_PCI_DEVICE   *Dev;
142  EFI_STATUS                    Status;
143
144  Dev = AllocateZeroPool (sizeof *Dev);
145  if (Dev == NULL) {
146    return EFI_OUT_OF_RESOURCES;
147  }
148
149  Status = gBS->OpenProtocol (DeviceHandle,
150                  &gEdkiiNonDiscoverableDeviceProtocolGuid,
151                  (VOID **)&Dev->Device, This->DriverBindingHandle,
152                  DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
153  if (EFI_ERROR (Status)) {
154    goto FreeDev;
155  }
156
157  InitializePciIoProtocol (Dev);
158
159  //
160  // Setup complete, attempt to export the driver instance's
161  // EFI_PCI_IO_PROTOCOL interface.
162  //
163  Dev->Signature = NON_DISCOVERABLE_PCI_DEVICE_SIG;
164  Status = gBS->InstallProtocolInterface (&DeviceHandle, &gEfiPciIoProtocolGuid,
165                  EFI_NATIVE_INTERFACE, &Dev->PciIo);
166  if (EFI_ERROR (Status)) {
167    goto CloseProtocol;
168  }
169
170  return EFI_SUCCESS;
171
172CloseProtocol:
173  gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid,
174         This->DriverBindingHandle, DeviceHandle);
175
176FreeDev:
177  FreePool (Dev);
178
179  return Status;
180}
181
182/**
183  Stop this driver on ControllerHandle.
184
185  @param This               Protocol instance pointer.
186  @param DeviceHandle       Handle of device to stop driver on.
187  @param NumberOfChildren   Not used.
188  @param ChildHandleBuffer  Not used.
189
190  @retval EFI_SUCCESS   This driver is removed from this device.
191  @retval other         Some error occurs when removing this driver from this device.
192
193**/
194STATIC
195EFI_STATUS
196EFIAPI
197NonDiscoverablePciDeviceStop (
198  IN EFI_DRIVER_BINDING_PROTOCOL *This,
199  IN EFI_HANDLE                  DeviceHandle,
200  IN UINTN                       NumberOfChildren,
201  IN EFI_HANDLE                  *ChildHandleBuffer
202  )
203{
204  EFI_STATUS                      Status;
205  EFI_PCI_IO_PROTOCOL             *PciIo;
206  NON_DISCOVERABLE_PCI_DEVICE     *Dev;
207
208  Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
209                  (VOID **)&PciIo, This->DriverBindingHandle, DeviceHandle,
210                  EFI_OPEN_PROTOCOL_GET_PROTOCOL);
211  if (EFI_ERROR (Status)) {
212    return Status;
213  }
214
215  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO (PciIo);
216
217  //
218  // Handle Stop() requests for in-use driver instances gracefully.
219  //
220  Status = gBS->UninstallProtocolInterface (DeviceHandle,
221                  &gEfiPciIoProtocolGuid, &Dev->PciIo);
222  if (EFI_ERROR (Status)) {
223    return Status;
224  }
225
226  gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid,
227         This->DriverBindingHandle, DeviceHandle);
228
229  FreePool (Dev);
230
231  return EFI_SUCCESS;
232}
233
234
235//
236// The static object that groups the Supported() (ie. probe), Start() and
237// Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
238// C, 10.1 EFI Driver Binding Protocol.
239//
240STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
241  &NonDiscoverablePciDeviceSupported,
242  &NonDiscoverablePciDeviceStart,
243  &NonDiscoverablePciDeviceStop,
244  0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
245  NULL,
246  NULL
247};
248
249/**
250  Entry point of this driver.
251
252  @param  ImageHandle     Image handle this driver.
253  @param  SystemTable     Pointer to the System Table.
254
255  @retval EFI_SUCCESS     The entry point is executed successfully.
256  @retval other           Some error occurred when executing this entry point.
257
258**/
259EFI_STATUS
260EFIAPI
261NonDiscoverablePciDeviceDxeEntryPoint (
262  IN EFI_HANDLE       ImageHandle,
263  IN EFI_SYSTEM_TABLE *SystemTable
264  )
265{
266  EFI_STATUS      Status;
267
268  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&mCpu);
269  ASSERT_EFI_ERROR(Status);
270
271  return EfiLibInstallDriverBindingComponentName2 (
272           ImageHandle,
273           SystemTable,
274           &gDriverBinding,
275           ImageHandle,
276           &gComponentName,
277           &gComponentName2
278           );
279}
280