1 /** @file
2   This file consumes the ISA Host Controller protocol produced by the ISA Host
3   Controller and installs the ISA Host Controller Service Binding protocol
4   on the ISA Host Controller's handle.
5 
6   Copyright (c) 2015, 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 
18 #include "IsaBusDxe.h"
19 #include "ComponentName.h"
20 
21 /**
22   Tests to see if this driver supports a given controller. If a child device is provided,
23   it further tests to see if this driver supports creating a handle for the specified child device.
24 
25   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
26   @param[in]  ControllerHandle     The handle of the controller to test. This handle
27                                    must support a protocol interface that supplies
28                                    an I/O abstraction to the driver.
29   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
30                                    parameter is ignored by device drivers, and is optional for bus
31                                    drivers. For bus drivers, if this parameter is not NULL, then
32                                    the bus driver must determine if the bus controller specified
33                                    by ControllerHandle and the child controller specified
34                                    by RemainingDevicePath are both supported by this
35                                    bus driver.
36 
37   @retval EFI_SUCCESS              The device specified by ControllerHandle and
38                                    RemainingDevicePath is supported by the driver specified by This.
39   @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
40                                    RemainingDevicePath is already being managed by the driver
41                                    specified by This.
42   @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
43                                    RemainingDevicePath is already being managed by a different
44                                    driver or an application that requires exclusive access.
45                                    Currently not implemented.
46   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
47                                    RemainingDevicePath is not supported by the driver specified by This.
48 **/
49 EFI_STATUS
50 EFIAPI
IsaBusDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)51 IsaBusDriverBindingSupported (
52   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
53   IN EFI_HANDLE                     Controller,
54   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
55   )
56 {
57   EFI_STATUS                        Status;
58   VOID                              *Instance;
59 
60   Status = gBS->OpenProtocol (
61                   Controller,
62                   &gEfiIsaHcProtocolGuid,
63                   &Instance,
64                   This->DriverBindingHandle,
65                   Controller,
66                   EFI_OPEN_PROTOCOL_BY_DRIVER
67                   );
68   if (!EFI_ERROR (Status)) {
69     gBS->CloseProtocol (
70       Controller,
71       &gEfiIsaHcProtocolGuid,
72       This->DriverBindingHandle,
73       Controller
74       );
75   }
76 
77   if (EFI_ERROR (Status)) {
78     return Status;
79   }
80 
81   Status = gBS->OpenProtocol (
82                   Controller,
83                   &gEfiDevicePathProtocolGuid,
84                   &Instance,
85                   This->DriverBindingHandle,
86                   Controller,
87                   EFI_OPEN_PROTOCOL_BY_DRIVER
88                   );
89   if (!EFI_ERROR (Status)) {
90     gBS->CloseProtocol (
91       Controller,
92       &gEfiDevicePathProtocolGuid,
93       This->DriverBindingHandle,
94       Controller
95       );
96   }
97 
98   return Status;
99 }
100 
101 ISA_BUS_CHILD_PRIVATE_DATA mIsaBusChildPrivateTemplate = {
102   ISA_BUS_CHILD_PRIVATE_DATA_SIGNATURE,
103   FALSE
104 };
105 
106 /**
107   Creates a child handle and installs a protocol.
108 
109   The CreateChild() function installs a protocol on ChildHandle.
110   If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
111   If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
112 
113   @param  This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
114   @param  ChildHandle Pointer to the handle of the child to create. If it is NULL,
115                       then a new handle is created. If it is a pointer to an existing UEFI handle,
116                       then the protocol is added to the existing UEFI handle.
117 
118   @retval EFI_SUCCES            The protocol was added to ChildHandle.
119   @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
120   @retval EFI_OUT_OF_RESOURCES  There are not enough resources availabe to create
121                                 the child
122   @retval other                 The child handle was not created
123 
124 **/
125 EFI_STATUS
126 EFIAPI
IsaBusCreateChild(IN EFI_SERVICE_BINDING_PROTOCOL * This,IN OUT EFI_HANDLE * ChildHandle)127 IsaBusCreateChild (
128   IN     EFI_SERVICE_BINDING_PROTOCOL  *This,
129   IN OUT EFI_HANDLE                    *ChildHandle
130   )
131 {
132   EFI_STATUS                           Status;
133   ISA_BUS_PRIVATE_DATA                 *Private;
134   EFI_ISA_HC_PROTOCOL                  *IsaHc;
135   ISA_BUS_CHILD_PRIVATE_DATA           *Child;
136 
137   Private = ISA_BUS_PRIVATE_DATA_FROM_THIS (This);
138 
139   Child = AllocateCopyPool (sizeof (mIsaBusChildPrivateTemplate), &mIsaBusChildPrivateTemplate);
140   if (Child == NULL) {
141     return EFI_OUT_OF_RESOURCES;
142   }
143 
144   Status = gBS->InstallMultipleProtocolInterfaces (
145                   ChildHandle,
146                   &gEfiIsaHcProtocolGuid, Private->IsaHc,
147                   &gEfiCallerIdGuid,      Child,
148                   NULL
149                   );
150   if (EFI_ERROR (Status)) {
151     FreePool (Child);
152     return Status;
153   }
154 
155   return gBS->OpenProtocol (
156                 Private->IsaHcHandle,
157                 &gEfiIsaHcProtocolGuid,
158                 (VOID **) &IsaHc,
159                 gIsaBusDriverBinding.DriverBindingHandle,
160                 *ChildHandle,
161                 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
162                 );
163 }
164 
165 /**
166   Destroys a child handle with a protocol installed on it.
167 
168   The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
169   that was installed by CreateChild() from ChildHandle. If the removed protocol is the
170   last protocol on ChildHandle, then ChildHandle is destroyed.
171 
172   @param  This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
173   @param  ChildHandle Handle of the child to destroy
174 
175   @retval EFI_SUCCES            The protocol was removed from ChildHandle.
176   @retval EFI_UNSUPPORTED       ChildHandle does not support the protocol that is being removed.
177   @retval EFI_INVALID_PARAMETER Child handle is NULL.
178   @retval EFI_ACCESS_DENIED     The protocol could not be removed from the ChildHandle
179                                 because its services are being used.
180   @retval other                 The child handle was not destroyed
181 
182 **/
183 EFI_STATUS
184 EFIAPI
IsaBusDestroyChild(IN EFI_SERVICE_BINDING_PROTOCOL * This,IN EFI_HANDLE ChildHandle)185 IsaBusDestroyChild (
186   IN EFI_SERVICE_BINDING_PROTOCOL     *This,
187   IN EFI_HANDLE                       ChildHandle
188   )
189 {
190   EFI_STATUS                           Status;
191   ISA_BUS_PRIVATE_DATA                 *Private;
192   EFI_ISA_HC_PROTOCOL                  *IsaHc;
193   ISA_BUS_CHILD_PRIVATE_DATA           *Child;
194 
195   Private = ISA_BUS_PRIVATE_DATA_FROM_THIS (This);
196 
197   Status = gBS->OpenProtocol (
198                   ChildHandle,
199                   &gEfiCallerIdGuid,
200                   (VOID **) &Child,
201                   gIsaBusDriverBinding.DriverBindingHandle,
202                   ChildHandle,
203                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
204                   );
205   if (EFI_ERROR (Status)) {
206     return Status;
207   }
208 
209   ASSERT (Child->Signature == ISA_BUS_CHILD_PRIVATE_DATA_SIGNATURE);
210 
211   if (Child->InDestroying) {
212     return EFI_SUCCESS;
213   }
214 
215   Child->InDestroying = TRUE;
216   Status = gBS->CloseProtocol (
217                   Private->IsaHcHandle,
218                   &gEfiIsaHcProtocolGuid,
219                   gIsaBusDriverBinding.DriverBindingHandle,
220                   ChildHandle
221                   );
222   ASSERT_EFI_ERROR (Status);
223   if (!EFI_ERROR (Status)) {
224     Status = gBS->UninstallMultipleProtocolInterfaces (
225                     ChildHandle,
226                     &gEfiIsaHcProtocolGuid, Private->IsaHc,
227                     &gEfiCallerIdGuid,      Child,
228                     NULL
229                     );
230     if (EFI_ERROR (Status)) {
231       gBS->OpenProtocol (
232              Private->IsaHcHandle,
233              &gEfiIsaHcProtocolGuid,
234              (VOID **) &IsaHc,
235              gIsaBusDriverBinding.DriverBindingHandle,
236              ChildHandle,
237              EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
238              );
239     }
240   }
241 
242   if (EFI_ERROR (Status)) {
243     Child->InDestroying = FALSE;
244   } else {
245     FreePool (Child);
246   }
247 
248   return Status;
249 }
250 
251 ISA_BUS_PRIVATE_DATA   mIsaBusPrivateTemplate = {
252   ISA_BUS_PRIVATE_DATA_SIGNATURE,
253   {
254     IsaBusCreateChild,
255     IsaBusDestroyChild
256   }
257 };
258 
259 /**
260   Starts a device controller or a bus controller.
261 
262   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
263   @param[in]  ControllerHandle     The handle of the controller to start. This handle
264                                    must support a protocol interface that supplies
265                                    an I/O abstraction to the driver.
266   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
267                                    parameter is ignored by device drivers, and is optional for bus
268                                    drivers. For a bus driver, if this parameter is NULL, then handles
269                                    for all the children of Controller are created by this driver.
270                                    If this parameter is not NULL and the first Device Path Node is
271                                    not the End of Device Path Node, then only the handle for the
272                                    child device specified by the first Device Path Node of
273                                    RemainingDevicePath is created by this driver.
274                                    If the first Device Path Node of RemainingDevicePath is
275                                    the End of Device Path Node, no child handle is created by this
276                                    driver.
277 
278   @retval EFI_SUCCESS              The device was started.
279   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.
280   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
281   @retval Others                   The driver failded to start the device.
282 
283 **/
284 EFI_STATUS
285 EFIAPI
IsaBusDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)286 IsaBusDriverBindingStart (
287   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
288   IN EFI_HANDLE                     Controller,
289   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
290   )
291 {
292   EFI_STATUS                        Status;
293   EFI_DEVICE_PATH_PROTOCOL          *DevicePath;
294   ISA_BUS_PRIVATE_DATA              *Private;
295 
296   Status = gBS->OpenProtocol (
297                   Controller,
298                   &gEfiIsaHcProtocolGuid,
299                   (VOID **) &mIsaBusPrivateTemplate.IsaHc,
300                   This->DriverBindingHandle,
301                   Controller,
302                   EFI_OPEN_PROTOCOL_BY_DRIVER
303                   );
304   if (EFI_ERROR (Status)) {
305     return Status;
306   }
307 
308   Status = gBS->OpenProtocol (
309                   Controller,
310                   &gEfiDevicePathProtocolGuid,
311                   (VOID **) &DevicePath,
312                   This->DriverBindingHandle,
313                   Controller,
314                   EFI_OPEN_PROTOCOL_BY_DRIVER
315                   );
316   if (EFI_ERROR (Status)) {
317     gBS->CloseProtocol (
318            Controller,
319            &gEfiIsaHcProtocolGuid,
320            This->DriverBindingHandle,
321            Controller
322            );
323     return Status;
324   }
325 
326   Private = AllocateCopyPool (sizeof (mIsaBusPrivateTemplate), &mIsaBusPrivateTemplate);
327   ASSERT (Private != NULL);
328 
329   Private->IsaHcHandle = Controller;
330 
331   Status = gBS->InstallMultipleProtocolInterfaces (
332                   &Controller,
333                   &gEfiIsaHcServiceBindingProtocolGuid, &Private->ServiceBinding,
334                   NULL
335                   );
336   ASSERT_EFI_ERROR (Status);
337 
338   return Status;
339 }
340 
341 /**
342   Stops a device controller or a bus controller.
343 
344   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
345   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
346                                 support a bus specific I/O protocol for the driver
347                                 to use to stop the device.
348   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
349   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
350                                 if NumberOfChildren is 0.
351 
352   @retval EFI_SUCCESS           The device was stopped.
353   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
354 
355 **/
356 EFI_STATUS
357 EFIAPI
IsaBusDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)358 IsaBusDriverBindingStop (
359   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
360   IN  EFI_HANDLE                     Controller,
361   IN  UINTN                          NumberOfChildren,
362   IN  EFI_HANDLE                     *ChildHandleBuffer
363   )
364 {
365   EFI_STATUS                         Status;
366   EFI_SERVICE_BINDING_PROTOCOL       *ServiceBinding;
367   ISA_BUS_PRIVATE_DATA               *Private;
368   UINTN                              Index;
369   BOOLEAN                            AllChildrenStopped;
370 
371   Status = gBS->OpenProtocol (
372                   Controller,
373                   &gEfiIsaHcServiceBindingProtocolGuid,
374                   (VOID **) &ServiceBinding,
375                   This->DriverBindingHandle,
376                   Controller,
377                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
378                   );
379   if (EFI_ERROR (Status)) {
380     return Status;
381   }
382 
383   Private = ISA_BUS_PRIVATE_DATA_FROM_THIS (ServiceBinding);
384 
385   if (NumberOfChildren == 0) {
386     Status = gBS->UninstallMultipleProtocolInterfaces (
387                     Controller,
388                     &gEfiIsaHcServiceBindingProtocolGuid, &Private->ServiceBinding,
389                     NULL
390                     );
391     if (!EFI_ERROR (Status)) {
392       gBS->CloseProtocol (
393              Controller,
394              &gEfiDevicePathProtocolGuid,
395              This->DriverBindingHandle,
396              Controller
397              );
398       gBS->CloseProtocol (
399              Controller,
400              &gEfiIsaHcProtocolGuid,
401              This->DriverBindingHandle,
402              Controller
403              );
404       FreePool (Private);
405     }
406 
407     return Status;
408   }
409 
410   AllChildrenStopped = TRUE;
411   for (Index = 0; Index < NumberOfChildren; Index++) {
412     Status = ServiceBinding->DestroyChild (ServiceBinding, ChildHandleBuffer[Index]);
413     if (EFI_ERROR (Status)) {
414       AllChildrenStopped = FALSE;
415     }
416   }
417 
418   return AllChildrenStopped ? EFI_SUCCESS : EFI_DEVICE_ERROR;
419 }
420 
421 //
422 // ISA Bus Driver Binding Protocol Instance
423 //
424 EFI_DRIVER_BINDING_PROTOCOL gIsaBusDriverBinding = {
425   IsaBusDriverBindingSupported,
426   IsaBusDriverBindingStart,
427   IsaBusDriverBindingStop,
428   0x10,
429   NULL,
430   NULL
431 };
432 
433 /**
434   Entry point of the IsaBusDxe driver.
435 
436   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
437   @param[in] SystemTable    A pointer to the EFI System Table.
438 
439   @retval EFI_SUCCESS       The entry point is executed successfully.
440   @retval other             Some error occurs when executing this entry point.
441 **/
442 EFI_STATUS
443 EFIAPI
InitializeIsaBus(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)444 InitializeIsaBus (
445   IN EFI_HANDLE        ImageHandle,
446   IN EFI_SYSTEM_TABLE  *SystemTable
447   )
448 {
449   EFI_STATUS           Status;
450 
451   Status = EfiLibInstallDriverBindingComponentName2 (
452              ImageHandle,
453              SystemTable,
454              &gIsaBusDriverBinding,
455              ImageHandle,
456              &gIsaBusComponentName,
457              &gIsaBusComponentName2
458              );
459   ASSERT_EFI_ERROR (Status);
460   return Status;
461 }
462