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
19 EFI_CPU_ARCH_PROTOCOL *mCpu;
20
21 //
22 // We only support the following device types
23 //
24 STATIC
25 CONST EFI_GUID * CONST
26 SupportedNonDiscoverableDevices[] = {
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 **/
65 STATIC
66 EFI_STATUS
67 EFIAPI
NonDiscoverablePciDeviceSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)68 NonDiscoverablePciDeviceSupported (
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
112 CloseProtocol:
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 **/
132 STATIC
133 EFI_STATUS
134 EFIAPI
NonDiscoverablePciDeviceStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)135 NonDiscoverablePciDeviceStart (
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
172 CloseProtocol:
173 gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid,
174 This->DriverBindingHandle, DeviceHandle);
175
176 FreeDev:
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 **/
194 STATIC
195 EFI_STATUS
196 EFIAPI
NonDiscoverablePciDeviceStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)197 NonDiscoverablePciDeviceStop (
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 //
240 STATIC 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 **/
259 EFI_STATUS
260 EFIAPI
NonDiscoverablePciDeviceDxeEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)261 NonDiscoverablePciDeviceDxeEntryPoint (
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