1 /** @file
2   EFI PCAT ISA ACPI Driver for a Generic PC Platform
3 
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "PcatIsaAcpi.h"
10 
11 //
12 //  PcatIsaAcpi Driver Binding Protocol
13 //
14 EFI_DRIVER_BINDING_PROTOCOL gPcatIsaAcpiDriverBinding = {
15   PcatIsaAcpiDriverBindingSupported,
16   PcatIsaAcpiDriverBindingStart,
17   PcatIsaAcpiDriverBindingStop,
18   0xa,
19   NULL,
20   NULL
21 };
22 
23 /**
24   the entry point of the PcatIsaAcpi driver.
25 
26   @param ImageHandle     Handle for driver image
27   @param SystemTable     Point to EFI_SYSTEM_TABLE
28 
29   @return Success or not for installing driver binding protocol
30 **/
31 EFI_STATUS
32 EFIAPI
PcatIsaAcpiDriverEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)33 PcatIsaAcpiDriverEntryPoint (
34   IN EFI_HANDLE        ImageHandle,
35   IN EFI_SYSTEM_TABLE  *SystemTable
36   )
37 {
38   return EfiLibInstallDriverBindingComponentName2 (
39            ImageHandle,
40            SystemTable,
41            &gPcatIsaAcpiDriverBinding,
42            ImageHandle,
43            &gPcatIsaAcpiComponentName,
44            &gPcatIsaAcpiComponentName2
45            );
46 }
47 
48 /**
49   ControllerDriver Protocol Method
50 
51   @param This                 Driver Binding protocol instance pointer.
52   @param Controller           Handle of device to test.
53   @param RemainingDevicePath  Optional parameter use to pick a specific child
54                               device to start.
55   @retval EFI_SUCCESS         This driver supports this device.
56   @retval other               This driver does not support this device.
57 
58 **/
59 EFI_STATUS
60 EFIAPI
PcatIsaAcpiDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)61 PcatIsaAcpiDriverBindingSupported (
62   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
63   IN EFI_HANDLE                   Controller,
64   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
65   )
66 {
67   EFI_STATUS           Status;
68   EFI_PCI_IO_PROTOCOL  *PciIo;
69   PCI_TYPE00           Pci;
70   UINTN                SegmentNumber;
71   UINTN                BusNumber;
72   UINTN                DeviceNumber;
73   UINTN                FunctionNumber;
74 
75   //
76   // Get PciIo protocol instance
77   //
78   Status = gBS->OpenProtocol (
79                   Controller,
80                   &gEfiPciIoProtocolGuid,
81                   (VOID**)&PciIo,
82                   This->DriverBindingHandle,
83                   Controller,
84                   EFI_OPEN_PROTOCOL_BY_DRIVER
85                   );
86   if (EFI_ERROR(Status)) {
87     return Status;
88   }
89 
90   Status = PciIo->Pci.Read (
91                     PciIo,
92                     EfiPciIoWidthUint32,
93                     0,
94                     sizeof(Pci) / sizeof(UINT32),
95                     &Pci);
96 
97   if (!EFI_ERROR (Status)) {
98     Status = EFI_UNSUPPORTED;
99     if ((Pci.Hdr.Command & 0x03) == 0x03) {
100       if (Pci.Hdr.ClassCode[2] == PCI_CLASS_BRIDGE) {
101         //
102         // See if this is a standard PCI to ISA Bridge from the Base Code and Class Code
103         //
104         if (Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA) {
105           Status = EFI_SUCCESS;
106         }
107 
108         //
109         // See if this is an Intel PCI to ISA bridge in Positive Decode Mode
110         //
111         if (Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA_PDECODE &&
112             Pci.Hdr.VendorId     == 0x8086                          ) {
113           //
114           // See if this is on Function #0 to avoid false positives on
115           // PCI_CLASS_BRIDGE_OTHER that has the same value as
116           // PCI_CLASS_BRIDGE_ISA_PDECODE
117           //
118           Status = PciIo->GetLocation (
119                             PciIo,
120                             &SegmentNumber,
121                             &BusNumber,
122                             &DeviceNumber,
123                             &FunctionNumber
124                             );
125           if (!EFI_ERROR (Status) && FunctionNumber == 0) {
126             Status = EFI_SUCCESS;
127           } else {
128             Status = EFI_UNSUPPORTED;
129           }
130         }
131       }
132     }
133   }
134 
135   gBS->CloseProtocol (
136          Controller,
137          &gEfiPciIoProtocolGuid,
138          This->DriverBindingHandle,
139          Controller
140          );
141 
142   return Status;
143 }
144 
145 /**
146   Install EFI_ISA_ACPI_PROTOCOL.
147 
148   @param  This                 Driver Binding protocol instance pointer.
149   @param  ControllerHandle     Handle of device to bind driver to.
150   @param  RemainingDevicePath  Optional parameter use to pick a specific child
151                                device to start.
152 
153   @retval EFI_SUCCESS          This driver is added to ControllerHandle
154   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
155   @retval other                This driver does not support this device
156 **/
157 EFI_STATUS
158 EFIAPI
PcatIsaAcpiDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)159 PcatIsaAcpiDriverBindingStart (
160   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
161   IN EFI_HANDLE                   Controller,
162   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
163   )
164 {
165   EFI_STATUS           Status;
166   EFI_PCI_IO_PROTOCOL  *PciIo;
167   PCAT_ISA_ACPI_DEV    *PcatIsaAcpiDev;
168   UINT64               Supports;
169   UINT64               OriginalAttributes;
170   BOOLEAN              Enabled;
171 
172   Enabled = FALSE;
173   Supports = 0;
174   PcatIsaAcpiDev = NULL;
175   OriginalAttributes = 0;
176   //
177   // Open the PCI I/O Protocol Interface
178   //
179   PciIo = NULL;
180   Status = gBS->OpenProtocol (
181                   Controller,
182                   &gEfiPciIoProtocolGuid,
183                   (VOID**)&PciIo,
184                   This->DriverBindingHandle,
185                   Controller,
186                   EFI_OPEN_PROTOCOL_BY_DRIVER
187                   );
188   if (EFI_ERROR (Status)) {
189     goto Done;
190   }
191 
192   //
193   // Get supported PCI attributes
194   //
195   Status = PciIo->Attributes (
196                     PciIo,
197                     EfiPciIoAttributeOperationSupported,
198                     0,
199                     &Supports
200                     );
201   if (EFI_ERROR (Status)) {
202     goto Done;
203   }
204 
205   Supports &= (UINT64) (EFI_PCI_IO_ATTRIBUTE_ISA_IO | EFI_PCI_IO_ATTRIBUTE_ISA_IO_16);
206   if (Supports == 0 || Supports == (EFI_PCI_IO_ATTRIBUTE_ISA_IO | EFI_PCI_IO_ATTRIBUTE_ISA_IO_16)) {
207     Status = EFI_UNSUPPORTED;
208     goto Done;
209   }
210 
211   Status = PciIo->Attributes (
212                     PciIo,
213                     EfiPciIoAttributeOperationGet,
214                     0,
215                     &OriginalAttributes
216                     );
217   if (EFI_ERROR (Status)) {
218     goto Done;
219   }
220 
221   Status = PciIo->Attributes (
222                     PciIo,
223                     EfiPciIoAttributeOperationEnable,
224                     EFI_PCI_DEVICE_ENABLE | Supports | EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO,
225                     NULL
226                     );
227   if (EFI_ERROR (Status)) {
228     goto Done;
229   }
230 
231   Enabled = TRUE;
232   //
233   // Allocate memory for the PCAT ISA ACPI Device structure
234   //
235   PcatIsaAcpiDev = NULL;
236   Status = gBS->AllocatePool (
237                   EfiBootServicesData,
238                   sizeof(PCAT_ISA_ACPI_DEV),
239                   (VOID**)&PcatIsaAcpiDev
240                   );
241   if (EFI_ERROR (Status)) {
242     goto Done;
243   }
244 
245   //
246   // Initialize the PCAT ISA ACPI Device structure
247   //
248   PcatIsaAcpiDev->Signature          = PCAT_ISA_ACPI_DEV_SIGNATURE;
249   PcatIsaAcpiDev->Handle             = Controller;
250   PcatIsaAcpiDev->PciIo              = PciIo;
251   PcatIsaAcpiDev->OriginalAttributes = OriginalAttributes;
252 
253   //
254   // Initialize PcatIsaAcpiDeviceList
255   //
256   InitializePcatIsaAcpiDeviceList ();
257 
258   //
259   // IsaAcpi interface
260   //
261   (PcatIsaAcpiDev->IsaAcpi).DeviceEnumerate  = IsaDeviceEnumerate;
262   (PcatIsaAcpiDev->IsaAcpi).SetPower         = IsaDeviceSetPower;
263   (PcatIsaAcpiDev->IsaAcpi).GetCurResource   = IsaGetCurrentResource;
264   (PcatIsaAcpiDev->IsaAcpi).GetPosResource   = IsaGetPossibleResource;
265   (PcatIsaAcpiDev->IsaAcpi).SetResource      = IsaSetResource;
266   (PcatIsaAcpiDev->IsaAcpi).EnableDevice     = IsaEnableDevice;
267   (PcatIsaAcpiDev->IsaAcpi).InitDevice       = IsaInitDevice;
268   (PcatIsaAcpiDev->IsaAcpi).InterfaceInit    = IsaInterfaceInit;
269 
270   //
271   // Install the ISA ACPI Protocol interface
272   //
273   Status = gBS->InstallMultipleProtocolInterfaces (
274                   &Controller,
275                   &gEfiIsaAcpiProtocolGuid, &PcatIsaAcpiDev->IsaAcpi,
276                   NULL
277                   );
278 
279 Done:
280   if (EFI_ERROR (Status)) {
281     if (PciIo != NULL && Enabled) {
282       PciIo->Attributes (
283                PciIo,
284                EfiPciIoAttributeOperationSet,
285                OriginalAttributes,
286                NULL
287                );
288     }
289     gBS->CloseProtocol (
290            Controller,
291            &gEfiPciIoProtocolGuid,
292            This->DriverBindingHandle,
293            Controller
294            );
295     if (PcatIsaAcpiDev != NULL) {
296       gBS->FreePool (PcatIsaAcpiDev);
297     }
298     return Status;
299   }
300 
301   return EFI_SUCCESS;
302 }
303 
304 
305 /**
306   Stop this driver on ControllerHandle. Support stopping any child handles
307   created by this driver.
308 
309   @param  This              Protocol instance pointer.
310   @param  ControllerHandle  Handle of device to stop driver on
311   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
312                             children is zero stop the entire bus driver.
313   @param  ChildHandleBuffer List of Child Handles to Stop.
314 
315   @retval EFI_SUCCESS       This driver is removed ControllerHandle
316   @retval other             This driver was not removed from this device
317 
318 **/
319 EFI_STATUS
320 EFIAPI
PcatIsaAcpiDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)321 PcatIsaAcpiDriverBindingStop (
322   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
323   IN EFI_HANDLE                   Controller,
324   IN UINTN                        NumberOfChildren,
325   IN EFI_HANDLE                   *ChildHandleBuffer
326   )
327 {
328   EFI_STATUS             Status;
329   EFI_ISA_ACPI_PROTOCOL  *IsaAcpi;
330   PCAT_ISA_ACPI_DEV      *PcatIsaAcpiDev;
331 
332   //
333   // Get the ISA ACPI Protocol Interface
334   //
335   Status = gBS->OpenProtocol (
336                   Controller,
337                   &gEfiIsaAcpiProtocolGuid,
338                   (VOID**)&IsaAcpi,
339                   This->DriverBindingHandle,
340                   Controller,
341                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
342                   );
343   if (EFI_ERROR (Status)) {
344     return Status;
345   }
346 
347   //
348   // Get the PCAT ISA ACPI Device structure from the ISA ACPI Protocol
349   //
350   PcatIsaAcpiDev = PCAT_ISA_ACPI_DEV_FROM_THIS (IsaAcpi);
351 
352   //
353   // Restore PCI attributes
354   //
355   Status = PcatIsaAcpiDev->PciIo->Attributes (
356                                     PcatIsaAcpiDev->PciIo,
357                                     EfiPciIoAttributeOperationSet,
358                                     PcatIsaAcpiDev->OriginalAttributes,
359                                     NULL
360                                     );
361   if (EFI_ERROR (Status)) {
362     return Status;
363   }
364 
365   //
366   // Uninstall protocol interface: EFI_ISA_ACPI_PROTOCOL
367   //
368   Status = gBS->UninstallProtocolInterface (
369                   Controller,
370                   &gEfiIsaAcpiProtocolGuid, &PcatIsaAcpiDev->IsaAcpi
371                   );
372   if (EFI_ERROR (Status)) {
373     return Status;
374   }
375 
376   gBS->CloseProtocol (
377          Controller,
378          &gEfiPciIoProtocolGuid,
379          This->DriverBindingHandle,
380          Controller
381          );
382 
383   gBS->FreePool (PcatIsaAcpiDev);
384 
385   return EFI_SUCCESS;
386 }
387