MdeModulePkg/UsbBusDxe: Add UsbControlTransfer() error check
[mirror_edk2.git] / MdeModulePkg / Bus / Isa / IsaBusDxe / IsaBusDxe.c
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 - 2016, 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
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 available to create
121 the child
122 @retval other The child handle was not created
123
124 **/
125 EFI_STATUS
126 EFIAPI
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
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
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
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
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 }