1 /** @file
2   IsaIo UEFI driver.
3 
4   Produce an instance of the ISA I/O Protocol for every SIO controller.
5 
6 Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution.  The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11 
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 #include "IsaDriver.h"
18 
19 //
20 // IsaIo Driver Global Variables
21 //
22 EFI_DRIVER_BINDING_PROTOCOL gIsaIoDriver = {
23   IsaIoDriverSupported,
24   IsaIoDriverStart,
25   IsaIoDriverStop,
26   0xa,
27   NULL,
28   NULL
29 };
30 
31 /**
32   The main entry point for the IsaIo driver.
33 
34   @param[in] ImageHandle        The firmware allocated handle for the EFI image.
35   @param[in] SystemTable        A pointer to the EFI System Table.
36 
37   @retval EFI_SUCCESS           The entry point is executed successfully.
38   @retval EFI_OUT_OF_RESOURCES  There was not enough memory in pool to install all the protocols.
39 **/
40 EFI_STATUS
41 EFIAPI
InitializeIsaIo(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)42 InitializeIsaIo (
43   IN EFI_HANDLE           ImageHandle,
44   IN EFI_SYSTEM_TABLE     *SystemTable
45   )
46 {
47   EFI_STATUS              Status;
48 
49   //
50   // Install driver model protocol(s).
51   //
52   Status = EfiLibInstallDriverBindingComponentName2 (
53              ImageHandle,
54              SystemTable,
55              &gIsaIoDriver,
56              ImageHandle,
57              &gIsaIoComponentName,
58              &gIsaIoComponentName2
59              );
60   ASSERT_EFI_ERROR (Status);
61 
62   return Status;
63 }
64 
65 /**
66   Tests to see if a controller can be managed by the IsaIo driver.
67 
68   @param[in] This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
69   @param[in] Controller           The handle of the controller to test.
70   @param[in] RemainingDevicePath  A pointer to the remaining portion of a device path.
71 
72   @retval EFI_SUCCESS             The device is supported by this driver.
73   @retval EFI_ALREADY_STARTED     The device is already being managed by this driver.
74   @retval EFI_ACCESS_DENIED       The device is already being managed by a different driver
75                                   or an application that requires exclusive access.
76   @retval EFI_UNSUPPORTED         The device is is not supported by this driver.
77 
78 **/
79 EFI_STATUS
80 EFIAPI
IsaIoDriverSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)81 IsaIoDriverSupported (
82   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
83   IN EFI_HANDLE                   Controller,
84   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
85   )
86 {
87   EFI_STATUS                Status;
88   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
89   EFI_SIO_PROTOCOL          *Sio;
90   EFI_HANDLE                PciHandle;
91 
92   //
93   // Try to open EFI DEVICE PATH protocol on the controller
94   //
95   Status = gBS->OpenProtocol (
96                   Controller,
97                   &gEfiDevicePathProtocolGuid,
98                   (VOID **) &DevicePath,
99                   This->DriverBindingHandle,
100                   Controller,
101                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
102                   );
103 
104   if (!EFI_ERROR (Status)) {
105     //
106     // Get the PciIo protocol from its parent controller.
107     //
108     Status = gBS->LocateDevicePath (&gEfiPciIoProtocolGuid, &DevicePath, &PciHandle);
109   }
110 
111   if (EFI_ERROR (Status)) {
112     return Status;
113   }
114 
115   //
116   // Try to open the Super IO protocol on the controller
117   //
118   Status = gBS->OpenProtocol (
119                   Controller,
120                   &gEfiSioProtocolGuid,
121                   (VOID **) &Sio,
122                   This->DriverBindingHandle,
123                   Controller,
124                   EFI_OPEN_PROTOCOL_BY_DRIVER
125                   );
126   if (!EFI_ERROR (Status)) {
127     gBS->CloseProtocol (
128            Controller,
129            &gEfiSioProtocolGuid,
130            This->DriverBindingHandle,
131            Controller
132            );
133   }
134 
135   return Status;
136 }
137 
138 /**
139   Start this driver on ControllerHandle.
140 
141   The Start() function is designed to be invoked from the EFI boot service ConnectController().
142   As a result, much of the error checking on the parameters to Start() has been moved into this
143   common boot service. It is legal to call Start() from other locations, but the following calling
144   restrictions must be followed or the system behavior will not be deterministic.
145   1. ControllerHandle must be a valid EFI_HANDLE.
146   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
147      EFI_DEVICE_PATH_PROTOCOL.
148   3. Prior to calling Start(), the Supported() function for the driver specified by This must
149      have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
150 
151   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
152   @param[in]  ControllerHandle     The handle of the controller to start. This handle
153                                    must support a protocol interface that supplies
154                                    an I/O abstraction to the driver.
155   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.
156                                    This parameter is ignored by device drivers, and is optional for bus drivers.
157 
158   @retval EFI_SUCCESS              The device was started.
159   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.
160                                    Currently not implemented.
161   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
162   @retval Others                   The driver failded to start the device.
163 **/
164 EFI_STATUS
165 EFIAPI
IsaIoDriverStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)166 IsaIoDriverStart (
167   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
168   IN EFI_HANDLE                   Controller,
169   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
170   )
171 {
172   EFI_STATUS                            Status;
173   EFI_PCI_IO_PROTOCOL                   *PciIo;
174   EFI_DEVICE_PATH_PROTOCOL              *DevicePath;
175   EFI_HANDLE                            PciHandle;
176   EFI_SIO_PROTOCOL                      *Sio;
177   ACPI_RESOURCE_HEADER_PTR              Resources;
178   EFI_DEVICE_PATH_PROTOCOL              *TempDevicePath;
179   ISA_IO_DEVICE                         *IsaIoDevice;
180 
181   PciIo = NULL;
182   Sio   = NULL;
183 
184   //
185   // Open Device Path Protocol
186   //
187   Status = gBS->OpenProtocol (
188                   Controller,
189                   &gEfiDevicePathProtocolGuid,
190                   (VOID **) &DevicePath,
191                   This->DriverBindingHandle,
192                   Controller,
193                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
194                   );
195   if (EFI_ERROR (Status)) {
196     return Status;
197   }
198 
199   //
200   // Get the PciIo protocol from its parent controller.
201   //
202   TempDevicePath = DevicePath;
203   Status = gBS->LocateDevicePath (&gEfiPciIoProtocolGuid, &TempDevicePath, &PciHandle);
204   if (!EFI_ERROR (Status)) {
205     Status = gBS->HandleProtocol (PciHandle, &gEfiPciIoProtocolGuid, (VOID **) &PciIo);
206     ASSERT_EFI_ERROR (Status);
207 
208     //
209     // Open Super IO Protocol
210     //
211     Status = gBS->OpenProtocol (
212                     Controller,
213                     &gEfiSioProtocolGuid,
214                     (VOID **) &Sio,
215                     This->DriverBindingHandle,
216                     Controller,
217                     EFI_OPEN_PROTOCOL_BY_DRIVER
218                     );
219   }
220 
221   if (EFI_ERROR (Status)) {
222     //
223     // Fail due to LocateDevicePath(...) or OpenProtocol(Sio, BY_DRIVER)
224     //
225     return Status;
226   }
227 
228   Status = Sio->GetResources (Sio, &Resources);
229   ASSERT_EFI_ERROR (Status);
230 
231   IsaIoDevice = AllocatePool (sizeof (ISA_IO_DEVICE));
232   ASSERT (IsaIoDevice != NULL);
233 
234   IsaIoDevice->Signature = ISA_IO_DEVICE_SIGNATURE;
235   IsaIoDevice->PciIo     = PciIo;
236 
237   //
238   // Initialize the ISA I/O instance structure
239   //
240   InitializeIsaIoInstance (IsaIoDevice, DevicePath, Resources);
241 
242   //
243   // Install the ISA I/O protocol on the Controller handle
244   //
245   Status = gBS->InstallMultipleProtocolInterfaces (
246                   &Controller,
247                   &gEfiIsaIoProtocolGuid,
248                   &IsaIoDevice->IsaIo,
249                   NULL
250                   );
251   ASSERT_EFI_ERROR (Status);
252 
253   return EFI_SUCCESS;
254 }
255 
256 /**
257   Stop this driver on ControllerHandle.
258 
259   The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
260   As a result, much of the error checking on the parameters to Stop() has been moved
261   into this common boot service. It is legal to call Stop() from other locations,
262   but the following calling restrictions must be followed or the system behavior will not be deterministic.
263   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
264      same driver's Start() function.
265   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
266      EFI_HANDLE. In addition, all of these handles must have been created in this driver's
267      Start() function, and the Start() function must have called OpenProtocol() on
268      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
269 
270   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
271   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
272                                 support a bus specific I/O protocol for the driver
273                                 to use to stop the device.
274   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
275   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
276                                 if NumberOfChildren is 0.
277 
278   @retval EFI_SUCCESS           The device was stopped.
279   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
280 **/
281 EFI_STATUS
282 EFIAPI
IsaIoDriverStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)283 IsaIoDriverStop (
284   IN  EFI_DRIVER_BINDING_PROTOCOL  * This,
285   IN  EFI_HANDLE                   Controller,
286   IN  UINTN                        NumberOfChildren,
287   IN  EFI_HANDLE                   * ChildHandleBuffer OPTIONAL
288   )
289 {
290   EFI_STATUS                          Status;
291   ISA_IO_DEVICE                       *IsaIoDevice;
292   EFI_ISA_IO_PROTOCOL                 *IsaIo;
293 
294   Status = gBS->OpenProtocol (
295                   Controller,
296                   &gEfiIsaIoProtocolGuid,
297                   (VOID **) &IsaIo,
298                   This->DriverBindingHandle,
299                   Controller,
300                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
301                   );
302   if (EFI_ERROR (Status)) {
303     return EFI_UNSUPPORTED;
304   }
305 
306   IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (IsaIo);
307 
308   Status = gBS->UninstallMultipleProtocolInterfaces (
309                   Controller,
310                   &gEfiIsaIoProtocolGuid,
311                   &IsaIoDevice->IsaIo,
312                   NULL
313                   );
314   if (!EFI_ERROR (Status)) {
315     Status = gBS->CloseProtocol (
316                     Controller,
317                     &gEfiSioProtocolGuid,
318                     This->DriverBindingHandle,
319                     Controller
320                     );
321     FreePool (IsaIoDevice->IsaIo.ResourceList);
322     FreePool (IsaIoDevice);
323   }
324 
325    return Status;
326 }
327