]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.c
MdeModulePkg: Apply uncrustify changes
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusDxe / UsbBus.c
CommitLineData
e237e7ae 1/** @file\r
2\r
8616fc4c 3 Usb Bus Driver Binding and Bus IO Protocol.\r
4\r
d1102dba 5Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
e237e7ae 7\r
e237e7ae 8**/\r
9\r
10#include "UsbBus.h"\r
11\r
1436aea4 12EFI_USB_IO_PROTOCOL mUsbIoProtocol = {\r
aa79b0b3 13 UsbIoControlTransfer,\r
14 UsbIoBulkTransfer,\r
15 UsbIoAsyncInterruptTransfer,\r
16 UsbIoSyncInterruptTransfer,\r
17 UsbIoIsochronousTransfer,\r
18 UsbIoAsyncIsochronousTransfer,\r
19 UsbIoGetDeviceDescriptor,\r
20 UsbIoGetActiveConfigDescriptor,\r
21 UsbIoGetInterfaceDescriptor,\r
22 UsbIoGetEndpointDescriptor,\r
23 UsbIoGetStringDescriptor,\r
24 UsbIoGetSupportedLanguages,\r
25 UsbIoPortReset\r
26};\r
27\r
1436aea4 28EFI_DRIVER_BINDING_PROTOCOL mUsbBusDriverBinding = {\r
aa79b0b3 29 UsbBusControllerDriverSupported,\r
30 UsbBusControllerDriverStart,\r
31 UsbBusControllerDriverStop,\r
32 0xa,\r
33 NULL,\r
34 NULL\r
35};\r
36\r
e237e7ae 37/**\r
38 USB_IO function to execute a control transfer. This\r
39 function will execute the USB transfer. If transfer\r
40 successes, it will sync the internal state of USB bus\r
41 with device state.\r
42\r
43 @param This The USB_IO instance\r
44 @param Request The control transfer request\r
45 @param Direction Direction for data stage\r
46 @param Timeout The time to wait before timeout\r
47 @param Data The buffer holding the data\r
48 @param DataLength Then length of the data\r
49 @param UsbStatus USB result\r
50\r
51 @retval EFI_INVALID_PARAMETER The parameters are invalid\r
d17371e8 52 @retval EFI_SUCCESS The control transfer succeeded.\r
e237e7ae 53 @retval Others Failed to execute the transfer\r
54\r
55**/\r
e237e7ae 56EFI_STATUS\r
57EFIAPI\r
58UsbIoControlTransfer (\r
59 IN EFI_USB_IO_PROTOCOL *This,\r
60 IN EFI_USB_DEVICE_REQUEST *Request,\r
61 IN EFI_USB_DATA_DIRECTION Direction,\r
62 IN UINT32 Timeout,\r
e3917e22
MK
63 IN OUT VOID *Data OPTIONAL,\r
64 IN UINTN DataLength OPTIONAL,\r
e237e7ae 65 OUT UINT32 *UsbStatus\r
66 )\r
67{\r
1436aea4
MK
68 USB_DEVICE *Dev;\r
69 USB_INTERFACE *UsbIf;\r
70 USB_ENDPOINT_DESC *EpDesc;\r
71 EFI_TPL OldTpl;\r
72 EFI_STATUS Status;\r
73 UINTN RequestedDataLength;\r
e237e7ae 74\r
75 if (UsbStatus == NULL) {\r
76 return EFI_INVALID_PARAMETER;\r
77 }\r
78\r
79 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
80\r
1436aea4
MK
81 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
82 Dev = UsbIf->Device;\r
e237e7ae 83\r
b4e96b82 84 RequestedDataLength = DataLength;\r
1436aea4
MK
85 Status = UsbHcControlTransfer (\r
86 Dev->Bus,\r
87 Dev->Address,\r
88 Dev->Speed,\r
89 Dev->MaxPacket0,\r
90 Request,\r
91 Direction,\r
92 Data,\r
93 &DataLength,\r
94 (UINTN)Timeout,\r
95 &Dev->Translator,\r
96 UsbStatus\r
97 );\r
b4e96b82 98 //\r
13a623cf 99 // If the request completed successfully and the Direction of the request is\r
b4e96b82 100 // EfiUsbDataIn or EfiUsbDataOut, then make sure the actual number of bytes\r
13a623cf
AC
101 // transferred is the same as the number of bytes requested. If a different\r
102 // number of bytes were transferred, then return EFI_DEVICE_ERROR.\r
b4e96b82
MK
103 //\r
104 if (!EFI_ERROR (Status)) {\r
1436aea4 105 if ((Direction != EfiUsbNoData) && (DataLength != RequestedDataLength)) {\r
b4e96b82
MK
106 Status = EFI_DEVICE_ERROR;\r
107 goto ON_EXIT;\r
108 }\r
109 }\r
e237e7ae 110\r
111 if (EFI_ERROR (Status) || (*UsbStatus != EFI_USB_NOERROR)) {\r
112 //\r
113 // Clear TT buffer when CTRL/BULK split transaction failes\r
114 // Clear the TRANSLATOR TT buffer, not parent's buffer\r
115 //\r
a9292c13 116 ASSERT (Dev->Translator.TranslatorHubAddress < Dev->Bus->MaxDevices);\r
e237e7ae 117 if (Dev->Translator.TranslatorHubAddress != 0) {\r
118 UsbHubCtrlClearTTBuffer (\r
119 Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress],\r
120 Dev->Translator.TranslatorPortNumber,\r
121 Dev->Address,\r
122 0,\r
123 USB_ENDPOINT_CONTROL\r
124 );\r
125 }\r
126\r
127 goto ON_EXIT;\r
128 }\r
129\r
130 //\r
131 // Some control transfer will change the device's internal\r
132 // status, such as Set_Configuration and Set_Interface.\r
133 // We must synchronize the bus driver's status with that in\r
134 // device. We ignore the Set_Descriptor request because it's\r
135 // hardly used by any device, especially in pre-boot environment\r
136 //\r
137\r
138 //\r
139 // Reset the endpoint toggle when endpoint stall is cleared\r
140 //\r
141 if ((Request->Request == USB_REQ_CLEAR_FEATURE) &&\r
1436aea4
MK
142 (Request->RequestType == USB_REQUEST_TYPE (\r
143 EfiUsbNoData,\r
144 USB_REQ_TYPE_STANDARD,\r
145 USB_TARGET_ENDPOINT\r
146 )) &&\r
147 (Request->Value == USB_FEATURE_ENDPOINT_HALT))\r
148 {\r
149 EpDesc = UsbGetEndpointDesc (UsbIf, (UINT8)Request->Index);\r
e237e7ae 150\r
151 if (EpDesc != NULL) {\r
152 EpDesc->Toggle = 0;\r
153 }\r
154 }\r
155\r
156 //\r
157 // Select a new configuration. This is a dangerous action. Upper driver\r
158 // should stop use its current UsbIo after calling this driver. The old\r
159 // UsbIo will be uninstalled and new UsbIo be installed. We can't use\r
160 // ReinstallProtocol since interfaces in different configuration may be\r
d17371e8 161 // completely irrelevant.\r
e237e7ae 162 //\r
163 if ((Request->Request == USB_REQ_SET_CONFIG) &&\r
1436aea4
MK
164 (Request->RequestType == USB_REQUEST_TYPE (\r
165 EfiUsbNoData,\r
166 USB_REQ_TYPE_STANDARD,\r
167 USB_TARGET_DEVICE\r
168 )))\r
169 {\r
e237e7ae 170 //\r
171 // Don't re-create the USB interfaces if configuration isn't changed.\r
172 //\r
173 if ((Dev->ActiveConfig != NULL) &&\r
1436aea4
MK
174 (Request->Value == Dev->ActiveConfig->Desc.ConfigurationValue))\r
175 {\r
e237e7ae 176 goto ON_EXIT;\r
177 }\r
1436aea4 178\r
87000d77 179 DEBUG ((DEBUG_INFO, "UsbIoControlTransfer: configure changed!!! Do NOT use old UsbIo!!!\n"));\r
e237e7ae 180\r
181 if (Dev->ActiveConfig != NULL) {\r
182 UsbRemoveConfig (Dev);\r
183 }\r
184\r
185 if (Request->Value != 0) {\r
1436aea4 186 Status = UsbSelectConfig (Dev, (UINT8)Request->Value);\r
e237e7ae 187 }\r
188\r
189 //\r
190 // Exit now, Old USB_IO is invalid now\r
191 //\r
192 goto ON_EXIT;\r
193 }\r
194\r
195 //\r
196 // A new alternative setting is selected for the interface.\r
197 // No need to reinstall UsbIo in this case because only\r
198 // underlying communication endpoints are changed. Functionality\r
199 // should remains the same.\r
200 //\r
201 if ((Request->Request == USB_REQ_SET_INTERFACE) &&\r
1436aea4
MK
202 (Request->RequestType == USB_REQUEST_TYPE (\r
203 EfiUsbNoData,\r
204 USB_REQ_TYPE_STANDARD,\r
205 USB_TARGET_INTERFACE\r
206 )) &&\r
207 (Request->Index == UsbIf->IfSetting->Desc.InterfaceNumber))\r
208 {\r
209 Status = UsbSelectSetting (UsbIf->IfDesc, (UINT8)Request->Value);\r
e237e7ae 210\r
211 if (!EFI_ERROR (Status)) {\r
a1b749d0 212 ASSERT (UsbIf->IfDesc->ActiveIndex < USB_MAX_INTERFACE_SETTING);\r
e237e7ae 213 UsbIf->IfSetting = UsbIf->IfDesc->Settings[UsbIf->IfDesc->ActiveIndex];\r
214 }\r
215 }\r
216\r
217ON_EXIT:\r
218 gBS->RestoreTPL (OldTpl);\r
219 return Status;\r
220}\r
221\r
e237e7ae 222/**\r
8616fc4c 223 Execute a bulk transfer to the device endpoint.\r
e237e7ae 224\r
8616fc4c 225 @param This The USB IO instance.\r
226 @param Endpoint The device endpoint.\r
227 @param Data The data to transfer.\r
228 @param DataLength The length of the data to transfer.\r
229 @param Timeout Time to wait before timeout.\r
230 @param UsbStatus The result of USB transfer.\r
e237e7ae 231\r
8616fc4c 232 @retval EFI_SUCCESS The bulk transfer is OK.\r
233 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
e237e7ae 234 @retval Others Failed to execute transfer, reason returned in\r
8616fc4c 235 UsbStatus.\r
e237e7ae 236\r
237**/\r
e237e7ae 238EFI_STATUS\r
239EFIAPI\r
240UsbIoBulkTransfer (\r
1436aea4
MK
241 IN EFI_USB_IO_PROTOCOL *This,\r
242 IN UINT8 Endpoint,\r
243 IN OUT VOID *Data,\r
244 IN OUT UINTN *DataLength,\r
245 IN UINTN Timeout,\r
246 OUT UINT32 *UsbStatus\r
e237e7ae 247 )\r
248{\r
1436aea4
MK
249 USB_DEVICE *Dev;\r
250 USB_INTERFACE *UsbIf;\r
251 USB_ENDPOINT_DESC *EpDesc;\r
252 UINT8 BufNum;\r
253 UINT8 Toggle;\r
254 EFI_TPL OldTpl;\r
255 EFI_STATUS Status;\r
256\r
257 if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR (Endpoint) > 15) ||\r
258 (UsbStatus == NULL))\r
259 {\r
e237e7ae 260 return EFI_INVALID_PARAMETER;\r
261 }\r
262\r
1436aea4 263 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
e237e7ae 264\r
1436aea4
MK
265 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
266 Dev = UsbIf->Device;\r
e237e7ae 267\r
1436aea4 268 EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint);\r
e237e7ae 269\r
270 if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_BULK)) {\r
271 Status = EFI_INVALID_PARAMETER;\r
272 goto ON_EXIT;\r
273 }\r
274\r
1436aea4
MK
275 BufNum = 1;\r
276 Toggle = EpDesc->Toggle;\r
277 Status = UsbHcBulkTransfer (\r
278 Dev->Bus,\r
279 Dev->Address,\r
280 Endpoint,\r
281 Dev->Speed,\r
282 EpDesc->Desc.MaxPacketSize,\r
283 BufNum,\r
284 &Data,\r
285 DataLength,\r
286 &Toggle,\r
287 Timeout,\r
288 &Dev->Translator,\r
289 UsbStatus\r
290 );\r
e237e7ae 291\r
292 EpDesc->Toggle = Toggle;\r
293\r
294 if (EFI_ERROR (Status) || (*UsbStatus != EFI_USB_NOERROR)) {\r
295 //\r
296 // Clear TT buffer when CTRL/BULK split transaction failes.\r
297 // Clear the TRANSLATOR TT buffer, not parent's buffer\r
298 //\r
a9292c13 299 ASSERT (Dev->Translator.TranslatorHubAddress < Dev->Bus->MaxDevices);\r
e237e7ae 300 if (Dev->Translator.TranslatorHubAddress != 0) {\r
301 UsbHubCtrlClearTTBuffer (\r
302 Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress],\r
303 Dev->Translator.TranslatorPortNumber,\r
304 Dev->Address,\r
305 0,\r
306 USB_ENDPOINT_BULK\r
307 );\r
308 }\r
309 }\r
310\r
311ON_EXIT:\r
312 gBS->RestoreTPL (OldTpl);\r
313 return Status;\r
314}\r
315\r
e237e7ae 316/**\r
8616fc4c 317 Execute a synchronous interrupt transfer.\r
e237e7ae 318\r
8616fc4c 319 @param This The USB IO instance.\r
320 @param Endpoint The device endpoint.\r
321 @param Data The data to transfer.\r
322 @param DataLength The length of the data to transfer.\r
323 @param Timeout Time to wait before timeout.\r
324 @param UsbStatus The result of USB transfer.\r
e237e7ae 325\r
8616fc4c 326 @retval EFI_SUCCESS The synchronous interrupt transfer is OK.\r
327 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
e237e7ae 328 @retval Others Failed to execute transfer, reason returned in\r
8616fc4c 329 UsbStatus.\r
e237e7ae 330\r
331**/\r
e237e7ae 332EFI_STATUS\r
333EFIAPI\r
334UsbIoSyncInterruptTransfer (\r
1436aea4
MK
335 IN EFI_USB_IO_PROTOCOL *This,\r
336 IN UINT8 Endpoint,\r
337 IN OUT VOID *Data,\r
338 IN OUT UINTN *DataLength,\r
339 IN UINTN Timeout,\r
340 OUT UINT32 *UsbStatus\r
e237e7ae 341 )\r
342{\r
1436aea4
MK
343 USB_DEVICE *Dev;\r
344 USB_INTERFACE *UsbIf;\r
345 USB_ENDPOINT_DESC *EpDesc;\r
346 EFI_TPL OldTpl;\r
347 UINT8 Toggle;\r
348 EFI_STATUS Status;\r
349\r
350 if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR (Endpoint) > 15) ||\r
351 (UsbStatus == NULL))\r
352 {\r
e237e7ae 353 return EFI_INVALID_PARAMETER;\r
354 }\r
355\r
1436aea4 356 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
e237e7ae 357\r
1436aea4
MK
358 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
359 Dev = UsbIf->Device;\r
e237e7ae 360\r
1436aea4 361 EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint);\r
e237e7ae 362\r
363 if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_INTERRUPT)) {\r
364 Status = EFI_INVALID_PARAMETER;\r
365 goto ON_EXIT;\r
366 }\r
367\r
368 Toggle = EpDesc->Toggle;\r
369 Status = UsbHcSyncInterruptTransfer (\r
370 Dev->Bus,\r
371 Dev->Address,\r
372 Endpoint,\r
373 Dev->Speed,\r
374 EpDesc->Desc.MaxPacketSize,\r
375 Data,\r
376 DataLength,\r
377 &Toggle,\r
378 Timeout,\r
379 &Dev->Translator,\r
380 UsbStatus\r
381 );\r
382\r
383 EpDesc->Toggle = Toggle;\r
384\r
385ON_EXIT:\r
386 gBS->RestoreTPL (OldTpl);\r
387 return Status;\r
388}\r
389\r
e237e7ae 390/**\r
391 Queue a new asynchronous interrupt transfer, or remove the old\r
8616fc4c 392 request if (IsNewTransfer == FALSE).\r
e237e7ae 393\r
8616fc4c 394 @param This The USB_IO instance.\r
395 @param Endpoint The device endpoint.\r
e237e7ae 396 @param IsNewTransfer Whether this is a new request, if it's old, remove\r
8616fc4c 397 the request.\r
398 @param PollInterval The interval to poll the transfer result, (in ms).\r
399 @param DataLength The length of perodic data transfer.\r
13a623cf 400 @param Callback The function to call periodically when transfer is\r
8616fc4c 401 ready.\r
402 @param Context The context to the callback.\r
e237e7ae 403\r
8616fc4c 404 @retval EFI_SUCCESS New transfer is queued or old request is removed.\r
405 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
e237e7ae 406 @retval Others Failed to queue the new request or remove the old\r
8616fc4c 407 request.\r
e237e7ae 408\r
409**/\r
e237e7ae 410EFI_STATUS\r
411EFIAPI\r
412UsbIoAsyncInterruptTransfer (\r
413 IN EFI_USB_IO_PROTOCOL *This,\r
414 IN UINT8 Endpoint,\r
415 IN BOOLEAN IsNewTransfer,\r
e3917e22
MK
416 IN UINTN PollInterval OPTIONAL,\r
417 IN UINTN DataLength OPTIONAL,\r
418 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback OPTIONAL,\r
e237e7ae 419 IN VOID *Context OPTIONAL\r
420 )\r
421{\r
1436aea4
MK
422 USB_DEVICE *Dev;\r
423 USB_INTERFACE *UsbIf;\r
424 USB_ENDPOINT_DESC *EpDesc;\r
425 EFI_TPL OldTpl;\r
426 UINT8 Toggle;\r
427 EFI_STATUS Status;\r
e237e7ae 428\r
429 if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR (Endpoint) > 15)) {\r
430 return EFI_INVALID_PARAMETER;\r
431 }\r
432\r
1436aea4
MK
433 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
434 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
435 Dev = UsbIf->Device;\r
e237e7ae 436\r
1436aea4 437 EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint);\r
e237e7ae 438\r
439 if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_INTERRUPT)) {\r
440 Status = EFI_INVALID_PARAMETER;\r
441 goto ON_EXIT;\r
442 }\r
443\r
1436aea4
MK
444 Toggle = EpDesc->Toggle;\r
445 Status = UsbHcAsyncInterruptTransfer (\r
446 Dev->Bus,\r
447 Dev->Address,\r
448 Endpoint,\r
449 Dev->Speed,\r
450 EpDesc->Desc.MaxPacketSize,\r
451 IsNewTransfer,\r
452 &Toggle,\r
453 PollInterval,\r
454 DataLength,\r
455 &Dev->Translator,\r
456 Callback,\r
457 Context\r
458 );\r
e237e7ae 459\r
460 EpDesc->Toggle = Toggle;\r
461\r
462ON_EXIT:\r
463 gBS->RestoreTPL (OldTpl);\r
464 return Status;\r
465}\r
466\r
e237e7ae 467/**\r
8616fc4c 468 Execute a synchronous isochronous transfer.\r
e237e7ae 469\r
8616fc4c 470 @param This The USB IO instance.\r
471 @param DeviceEndpoint The device endpoint.\r
472 @param Data The data to transfer.\r
473 @param DataLength The length of the data to transfer.\r
474 @param UsbStatus The result of USB transfer.\r
e237e7ae 475\r
8616fc4c 476 @retval EFI_UNSUPPORTED Currently isochronous transfer isn't supported.\r
e237e7ae 477\r
478**/\r
e237e7ae 479EFI_STATUS\r
480EFIAPI\r
481UsbIoIsochronousTransfer (\r
1436aea4
MK
482 IN EFI_USB_IO_PROTOCOL *This,\r
483 IN UINT8 DeviceEndpoint,\r
484 IN OUT VOID *Data,\r
485 IN UINTN DataLength,\r
486 OUT UINT32 *Status\r
e237e7ae 487 )\r
488{\r
489 return EFI_UNSUPPORTED;\r
490}\r
491\r
e237e7ae 492/**\r
8616fc4c 493 Queue an asynchronous isochronous transfer.\r
e237e7ae 494\r
8616fc4c 495 @param This The USB_IO instance.\r
496 @param DeviceEndpoint The device endpoint.\r
497 @param Data The data to transfer.\r
498 @param DataLength The length of perodic data transfer.\r
13a623cf 499 @param IsochronousCallBack The function to call periodically when transfer is\r
8616fc4c 500 ready.\r
501 @param Context The context to the callback.\r
e237e7ae 502\r
8616fc4c 503 @retval EFI_UNSUPPORTED Currently isochronous transfer isn't supported.\r
e237e7ae 504\r
505**/\r
e237e7ae 506EFI_STATUS\r
507EFIAPI\r
508UsbIoAsyncIsochronousTransfer (\r
509 IN EFI_USB_IO_PROTOCOL *This,\r
510 IN UINT8 DeviceEndpoint,\r
511 IN OUT VOID *Data,\r
512 IN UINTN DataLength,\r
513 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,\r
514 IN VOID *Context OPTIONAL\r
515 )\r
516{\r
517 return EFI_UNSUPPORTED;\r
518}\r
519\r
e237e7ae 520/**\r
8616fc4c 521 Retrieve the device descriptor of the device.\r
e237e7ae 522\r
8616fc4c 523 @param This The USB IO instance.\r
524 @param Descriptor The variable to receive the device descriptor.\r
e237e7ae 525\r
8616fc4c 526 @retval EFI_SUCCESS The device descriptor is returned.\r
527 @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
e237e7ae 528\r
529**/\r
e237e7ae 530EFI_STATUS\r
531EFIAPI\r
532UsbIoGetDeviceDescriptor (\r
1436aea4
MK
533 IN EFI_USB_IO_PROTOCOL *This,\r
534 OUT EFI_USB_DEVICE_DESCRIPTOR *Descriptor\r
e237e7ae 535 )\r
536{\r
1436aea4
MK
537 USB_DEVICE *Dev;\r
538 USB_INTERFACE *UsbIf;\r
539 EFI_TPL OldTpl;\r
e237e7ae 540\r
541 if (Descriptor == NULL) {\r
542 return EFI_INVALID_PARAMETER;\r
543 }\r
544\r
545 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
546\r
1436aea4
MK
547 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
548 Dev = UsbIf->Device;\r
e237e7ae 549\r
550 CopyMem (Descriptor, &Dev->DevDesc->Desc, sizeof (EFI_USB_DEVICE_DESCRIPTOR));\r
551\r
552 gBS->RestoreTPL (OldTpl);\r
553 return EFI_SUCCESS;\r
554}\r
555\r
e237e7ae 556/**\r
8616fc4c 557 Return the configuration descriptor of the current active configuration.\r
e237e7ae 558\r
8616fc4c 559 @param This The USB IO instance.\r
560 @param Descriptor The USB configuration descriptor.\r
e237e7ae 561\r
8616fc4c 562 @retval EFI_SUCCESS The active configuration descriptor is returned.\r
563 @retval EFI_INVALID_PARAMETER Some parameter is invalid.\r
e237e7ae 564 @retval EFI_NOT_FOUND Currently no active configuration is selected.\r
565\r
566**/\r
e237e7ae 567EFI_STATUS\r
568EFIAPI\r
569UsbIoGetActiveConfigDescriptor (\r
1436aea4
MK
570 IN EFI_USB_IO_PROTOCOL *This,\r
571 OUT EFI_USB_CONFIG_DESCRIPTOR *Descriptor\r
e237e7ae 572 )\r
573{\r
1436aea4
MK
574 USB_DEVICE *Dev;\r
575 USB_INTERFACE *UsbIf;\r
576 EFI_STATUS Status;\r
577 EFI_TPL OldTpl;\r
e237e7ae 578\r
579 if (Descriptor == NULL) {\r
580 return EFI_INVALID_PARAMETER;\r
581 }\r
582\r
583 Status = EFI_SUCCESS;\r
584 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
585\r
1436aea4
MK
586 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
587 Dev = UsbIf->Device;\r
e237e7ae 588\r
589 if (Dev->ActiveConfig == NULL) {\r
590 Status = EFI_NOT_FOUND;\r
591 goto ON_EXIT;\r
592 }\r
593\r
594 CopyMem (Descriptor, &(Dev->ActiveConfig->Desc), sizeof (EFI_USB_CONFIG_DESCRIPTOR));\r
595\r
596ON_EXIT:\r
597 gBS->RestoreTPL (OldTpl);\r
598 return Status;\r
599}\r
600\r
e237e7ae 601/**\r
8616fc4c 602 Retrieve the active interface setting descriptor for this USB IO instance.\r
e237e7ae 603\r
8616fc4c 604 @param This The USB IO instance.\r
605 @param Descriptor The variable to receive active interface setting.\r
e237e7ae 606\r
8616fc4c 607 @retval EFI_SUCCESS The active interface setting is returned.\r
608 @retval EFI_INVALID_PARAMETER Some parameter is invalid.\r
e237e7ae 609\r
610**/\r
e237e7ae 611EFI_STATUS\r
612EFIAPI\r
613UsbIoGetInterfaceDescriptor (\r
614 IN EFI_USB_IO_PROTOCOL *This,\r
615 OUT EFI_USB_INTERFACE_DESCRIPTOR *Descriptor\r
616 )\r
617{\r
1436aea4
MK
618 USB_INTERFACE *UsbIf;\r
619 EFI_TPL OldTpl;\r
e237e7ae 620\r
621 if (Descriptor == NULL) {\r
622 return EFI_INVALID_PARAMETER;\r
623 }\r
624\r
625 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
626\r
1436aea4 627 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
e237e7ae 628 CopyMem (Descriptor, &(UsbIf->IfSetting->Desc), sizeof (EFI_USB_INTERFACE_DESCRIPTOR));\r
629\r
630 gBS->RestoreTPL (OldTpl);\r
631 return EFI_SUCCESS;\r
632}\r
633\r
e237e7ae 634/**\r
8616fc4c 635 Retrieve the endpoint descriptor from this interface setting.\r
e237e7ae 636\r
8616fc4c 637 @param This The USB IO instance.\r
e237e7ae 638 @param Index The index (start from zero) of the endpoint to\r
8616fc4c 639 retrieve.\r
640 @param Descriptor The variable to receive the descriptor.\r
e237e7ae 641\r
8616fc4c 642 @retval EFI_SUCCESS The endpoint descriptor is returned.\r
643 @retval EFI_INVALID_PARAMETER Some parameter is invalid.\r
e237e7ae 644\r
645**/\r
e237e7ae 646EFI_STATUS\r
647EFIAPI\r
648UsbIoGetEndpointDescriptor (\r
1436aea4
MK
649 IN EFI_USB_IO_PROTOCOL *This,\r
650 IN UINT8 Index,\r
651 OUT EFI_USB_ENDPOINT_DESCRIPTOR *Descriptor\r
e237e7ae 652 )\r
653{\r
1436aea4
MK
654 USB_INTERFACE *UsbIf;\r
655 EFI_TPL OldTpl;\r
e237e7ae 656\r
657 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
658\r
1436aea4 659 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
e237e7ae 660\r
50fa1b3a 661 if ((Descriptor == NULL) || (Index > 15)) {\r
e237e7ae 662 gBS->RestoreTPL (OldTpl);\r
663 return EFI_INVALID_PARAMETER;\r
664 }\r
665\r
50fa1b3a 666 if (Index >= UsbIf->IfSetting->Desc.NumEndpoints) {\r
667 gBS->RestoreTPL (OldTpl);\r
668 return EFI_NOT_FOUND;\r
669 }\r
670\r
e237e7ae 671 CopyMem (\r
672 Descriptor,\r
673 &(UsbIf->IfSetting->Endpoints[Index]->Desc),\r
674 sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)\r
675 );\r
676\r
677 gBS->RestoreTPL (OldTpl);\r
678 return EFI_SUCCESS;\r
679}\r
680\r
e237e7ae 681/**\r
8616fc4c 682 Retrieve the supported language ID table from the device.\r
e237e7ae 683\r
8616fc4c 684 @param This The USB IO instance.\r
685 @param LangIDTable The table to return the language IDs.\r
84909ad4 686 @param TableSize The size, in bytes, of the table LangIDTable.\r
e237e7ae 687\r
8616fc4c 688 @retval EFI_SUCCESS The language ID is return.\r
e237e7ae 689\r
690**/\r
e237e7ae 691EFI_STATUS\r
692EFIAPI\r
693UsbIoGetSupportedLanguages (\r
1436aea4
MK
694 IN EFI_USB_IO_PROTOCOL *This,\r
695 OUT UINT16 **LangIDTable,\r
696 OUT UINT16 *TableSize\r
e237e7ae 697 )\r
698{\r
1436aea4
MK
699 USB_DEVICE *Dev;\r
700 USB_INTERFACE *UsbIf;\r
701 EFI_TPL OldTpl;\r
e237e7ae 702\r
1436aea4 703 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
e237e7ae 704\r
1436aea4
MK
705 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
706 Dev = UsbIf->Device;\r
e237e7ae 707\r
1436aea4
MK
708 *LangIDTable = Dev->LangId;\r
709 *TableSize = (UINT16)(Dev->TotalLangId * sizeof (UINT16));\r
e237e7ae 710\r
711 gBS->RestoreTPL (OldTpl);\r
712 return EFI_SUCCESS;\r
713}\r
714\r
e237e7ae 715/**\r
8616fc4c 716 Retrieve an indexed string in the language of LangID.\r
e237e7ae 717\r
8616fc4c 718 @param This The USB IO instance.\r
719 @param LangID The language ID of the string to retrieve.\r
720 @param StringIndex The index of the string.\r
721 @param String The variable to receive the string.\r
e237e7ae 722\r
8616fc4c 723 @retval EFI_SUCCESS The string is returned.\r
724 @retval EFI_NOT_FOUND No such string existed.\r
e237e7ae 725\r
726**/\r
e237e7ae 727EFI_STATUS\r
728EFIAPI\r
729UsbIoGetStringDescriptor (\r
1436aea4
MK
730 IN EFI_USB_IO_PROTOCOL *This,\r
731 IN UINT16 LangID,\r
732 IN UINT8 StringIndex,\r
733 OUT CHAR16 **String\r
e237e7ae 734 )\r
735{\r
1436aea4
MK
736 USB_DEVICE *Dev;\r
737 USB_INTERFACE *UsbIf;\r
738 EFI_USB_STRING_DESCRIPTOR *StrDesc;\r
739 EFI_TPL OldTpl;\r
740 UINT8 *Buf;\r
741 UINT8 Index;\r
742 EFI_STATUS Status;\r
e237e7ae 743\r
744 if ((StringIndex == 0) || (LangID == 0)) {\r
745 return EFI_NOT_FOUND;\r
746 }\r
747\r
748 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
749\r
1436aea4
MK
750 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
751 Dev = UsbIf->Device;\r
e237e7ae 752\r
753 //\r
754 // Check whether language ID is supported\r
755 //\r
756 Status = EFI_NOT_FOUND;\r
757\r
758 for (Index = 0; Index < Dev->TotalLangId; Index++) {\r
a1b749d0 759 ASSERT (Index < USB_MAX_LANG_ID);\r
e237e7ae 760 if (Dev->LangId[Index] == LangID) {\r
761 break;\r
762 }\r
763 }\r
764\r
765 if (Index == Dev->TotalLangId) {\r
766 goto ON_EXIT;\r
767 }\r
768\r
769 //\r
770 // Retrieve the string descriptor then allocate a buffer\r
771 // to hold the string itself.\r
772 //\r
773 StrDesc = UsbGetOneString (Dev, StringIndex, LangID);\r
774\r
775 if (StrDesc == NULL) {\r
776 goto ON_EXIT;\r
777 }\r
778\r
779 if (StrDesc->Length <= 2) {\r
780 goto FREE_STR;\r
781 }\r
782\r
783 Buf = AllocateZeroPool (StrDesc->Length);\r
784\r
785 if (Buf == NULL) {\r
786 Status = EFI_OUT_OF_RESOURCES;\r
787 goto FREE_STR;\r
788 }\r
789\r
790 CopyMem (Buf, StrDesc->String, StrDesc->Length - 2);\r
1436aea4 791 *String = (CHAR16 *)Buf;\r
e237e7ae 792 Status = EFI_SUCCESS;\r
793\r
794FREE_STR:\r
795 gBS->FreePool (StrDesc);\r
796\r
797ON_EXIT:\r
798 gBS->RestoreTPL (OldTpl);\r
799 return Status;\r
800}\r
801\r
e237e7ae 802/**\r
803 Reset the device, then if that succeeds, reconfigure the\r
804 device with its address and current active configuration.\r
805\r
8616fc4c 806 @param This The USB IO instance.\r
e237e7ae 807\r
8616fc4c 808 @retval EFI_SUCCESS The device is reset and configured.\r
809 @retval Others Failed to reset the device.\r
e237e7ae 810\r
811**/\r
812EFI_STATUS\r
813EFIAPI\r
814UsbIoPortReset (\r
815 IN EFI_USB_IO_PROTOCOL *This\r
816 )\r
817{\r
1436aea4
MK
818 USB_INTERFACE *UsbIf;\r
819 USB_INTERFACE *HubIf;\r
820 USB_DEVICE *Dev;\r
821 EFI_TPL OldTpl;\r
822 EFI_STATUS Status;\r
823 UINT8 DevAddress;\r
e237e7ae 824\r
825 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
826\r
1436aea4
MK
827 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
828 Dev = UsbIf->Device;\r
e237e7ae 829\r
a92d4e8a 830 if (UsbIf->IsHub) {\r
50fa1b3a 831 Status = EFI_INVALID_PARAMETER;\r
832 goto ON_EXIT;\r
833 }\r
834\r
e237e7ae 835 HubIf = Dev->ParentIf;\r
836 Status = HubIf->HubApi->ResetPort (HubIf, Dev->ParentPort);\r
837\r
838 if (EFI_ERROR (Status)) {\r
1436aea4
MK
839 DEBUG ((\r
840 DEBUG_ERROR,\r
841 "UsbIoPortReset: failed to reset hub port %d@hub %d, %r \n",\r
842 Dev->ParentPort,\r
843 Dev->ParentAddr,\r
844 Status\r
845 ));\r
e237e7ae 846\r
847 goto ON_EXIT;\r
848 }\r
849\r
71619ac2 850 HubIf->HubApi->ClearPortChange (HubIf, Dev->ParentPort);\r
851\r
e237e7ae 852 //\r
c4b8c2d8 853 // Reset the device to its current address. The device now has an address\r
854 // of ZERO after port reset, so need to set Dev->Address to the device again for\r
855 // host to communicate with it.\r
e237e7ae 856 //\r
71619ac2 857 DevAddress = Dev->Address;\r
858 Dev->Address = 0;\r
1436aea4 859 Status = UsbSetAddress (Dev, DevAddress);\r
71619ac2 860 Dev->Address = DevAddress;\r
efe9186f 861\r
862 gBS->Stall (USB_SET_DEVICE_ADDRESS_STALL);\r
d1102dba 863\r
e237e7ae 864 if (EFI_ERROR (Status)) {\r
c4b8c2d8 865 //\r
866 // It may fail due to device disconnection or other reasons.\r
867 //\r
1436aea4
MK
868 DEBUG ((\r
869 DEBUG_ERROR,\r
870 "UsbIoPortReset: failed to set address for device %d - %r\n",\r
871 Dev->Address,\r
872 Status\r
873 ));\r
e237e7ae 874\r
875 goto ON_EXIT;\r
876 }\r
877\r
1436aea4 878 DEBUG ((DEBUG_INFO, "UsbIoPortReset: device is now ADDRESSED at %d\n", Dev->Address));\r
e237e7ae 879\r
880 //\r
881 // Reset the current active configure, after this device\r
882 // is in CONFIGURED state.\r
883 //\r
884 if (Dev->ActiveConfig != NULL) {\r
885 Status = UsbSetConfig (Dev, Dev->ActiveConfig->Desc.ConfigurationValue);\r
886\r
887 if (EFI_ERROR (Status)) {\r
1436aea4
MK
888 DEBUG ((\r
889 DEBUG_ERROR,\r
890 "UsbIoPortReset: failed to set configure for device %d - %r\n",\r
891 Dev->Address,\r
892 Status\r
893 ));\r
e237e7ae 894 }\r
895 }\r
896\r
897ON_EXIT:\r
898 gBS->RestoreTPL (OldTpl);\r
899 return Status;\r
900}\r
901\r
ecb575d9 902/**\r
8616fc4c 903 Install Usb Bus Protocol on host controller, and start the Usb bus.\r
ecb575d9 904\r
8616fc4c 905 @param This The USB bus driver binding instance.\r
906 @param Controller The controller to check.\r
907 @param RemainingDevicePath The remaining device patch.\r
ecb575d9 908\r
8616fc4c 909 @retval EFI_SUCCESS The controller is controlled by the usb bus.\r
910 @retval EFI_ALREADY_STARTED The controller is already controlled by the usb bus.\r
911 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
ecb575d9 912\r
913**/\r
914EFI_STATUS\r
915EFIAPI\r
916UsbBusBuildProtocol (\r
917 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
918 IN EFI_HANDLE Controller,\r
919 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
920 )\r
921{\r
1436aea4
MK
922 USB_BUS *UsbBus;\r
923 USB_DEVICE *RootHub;\r
924 USB_INTERFACE *RootIf;\r
925 EFI_STATUS Status;\r
926 EFI_STATUS Status2;\r
ecb575d9 927\r
928 UsbBus = AllocateZeroPool (sizeof (USB_BUS));\r
929\r
930 if (UsbBus == NULL) {\r
931 return EFI_OUT_OF_RESOURCES;\r
932 }\r
933\r
a9292c13 934 UsbBus->Signature = USB_BUS_SIGNATURE;\r
935 UsbBus->HostHandle = Controller;\r
936 UsbBus->MaxDevices = USB_MAX_DEVICES;\r
ecb575d9 937\r
938 Status = gBS->OpenProtocol (\r
939 Controller,\r
940 &gEfiDevicePathProtocolGuid,\r
1436aea4 941 (VOID **)&UsbBus->DevicePath,\r
ecb575d9 942 This->DriverBindingHandle,\r
943 Controller,\r
944 EFI_OPEN_PROTOCOL_BY_DRIVER\r
945 );\r
946\r
947 if (EFI_ERROR (Status)) {\r
87000d77 948 DEBUG ((DEBUG_ERROR, "UsbBusStart: Failed to open device path %r\n", Status));\r
ecb575d9 949\r
d17371e8 950 FreePool (UsbBus);\r
ecb575d9 951 return Status;\r
952 }\r
953\r
954 //\r
955 // Get USB_HC2/USB_HC host controller protocol (EHCI/UHCI).\r
d17371e8 956 // This is for backward compatibility with EFI 1.x. In UEFI\r
ecb575d9 957 // 2.x, USB_HC2 replaces USB_HC. We will open both USB_HC2\r
958 // and USB_HC because EHCI driver will install both protocols\r
959 // (for the same reason). If we don't consume both of them,\r
960 // the unconsumed one may be opened by others.\r
961 //\r
962 Status = gBS->OpenProtocol (\r
963 Controller,\r
964 &gEfiUsb2HcProtocolGuid,\r
1436aea4 965 (VOID **)&(UsbBus->Usb2Hc),\r
ecb575d9 966 This->DriverBindingHandle,\r
967 Controller,\r
968 EFI_OPEN_PROTOCOL_BY_DRIVER\r
969 );\r
970\r
971 Status2 = gBS->OpenProtocol (\r
972 Controller,\r
973 &gEfiUsbHcProtocolGuid,\r
1436aea4 974 (VOID **)&(UsbBus->UsbHc),\r
ecb575d9 975 This->DriverBindingHandle,\r
976 Controller,\r
977 EFI_OPEN_PROTOCOL_BY_DRIVER\r
978 );\r
979\r
980 if (EFI_ERROR (Status) && EFI_ERROR (Status2)) {\r
87000d77 981 DEBUG ((DEBUG_ERROR, "UsbBusStart: Failed to open USB_HC/USB2_HC %r\n", Status));\r
ecb575d9 982\r
983 Status = EFI_DEVICE_ERROR;\r
984 goto CLOSE_HC;\r
985 }\r
986\r
92870c98 987 if (!EFI_ERROR (Status)) {\r
a9292c13 988 //\r
989 // The EFI_USB2_HC_PROTOCOL is produced for XHCI support.\r
990 // Then its max supported devices are 256. Otherwise it's 128.\r
991 //\r
9bdcf582 992 ASSERT (UsbBus->Usb2Hc != NULL);\r
92870c98 993 if (UsbBus->Usb2Hc->MajorRevision == 0x3) {\r
a9292c13 994 UsbBus->MaxDevices = 256;\r
92870c98 995 }\r
996 }\r
997\r
ecb575d9 998 //\r
d17371e8 999 // Install an EFI_USB_BUS_PROTOCOL to host controller to identify it.\r
ecb575d9 1000 //\r
1001 Status = gBS->InstallProtocolInterface (\r
1002 &Controller,\r
c8ad2d7a 1003 &gEfiCallerIdGuid,\r
ecb575d9 1004 EFI_NATIVE_INTERFACE,\r
1005 &UsbBus->BusId\r
1006 );\r
1007\r
1008 if (EFI_ERROR (Status)) {\r
87000d77 1009 DEBUG ((DEBUG_ERROR, "UsbBusStart: Failed to install bus protocol %r\n", Status));\r
ecb575d9 1010 goto CLOSE_HC;\r
1011 }\r
1012\r
1013 //\r
1014 // Initial the wanted child device path list, and add first RemainingDevicePath\r
1015 //\r
1016 InitializeListHead (&UsbBus->WantedUsbIoDPList);\r
1017 Status = UsbBusAddWantedUsbIoDP (&UsbBus->BusId, RemainingDevicePath);\r
1018 ASSERT (!EFI_ERROR (Status));\r
1019 //\r
1020 // Create a fake usb device for root hub\r
1021 //\r
1022 RootHub = AllocateZeroPool (sizeof (USB_DEVICE));\r
1023\r
1024 if (RootHub == NULL) {\r
1025 Status = EFI_OUT_OF_RESOURCES;\r
1026 goto UNINSTALL_USBBUS;\r
1027 }\r
1028\r
1029 RootIf = AllocateZeroPool (sizeof (USB_INTERFACE));\r
1030\r
1031 if (RootIf == NULL) {\r
d17371e8 1032 FreePool (RootHub);\r
ecb575d9 1033 Status = EFI_OUT_OF_RESOURCES;\r
1034 goto FREE_ROOTHUB;\r
1035 }\r
1036\r
1037 RootHub->Bus = UsbBus;\r
1038 RootHub->NumOfInterface = 1;\r
1039 RootHub->Interfaces[0] = RootIf;\r
92870c98 1040 RootHub->Tier = 0;\r
ecb575d9 1041 RootIf->Signature = USB_INTERFACE_SIGNATURE;\r
1042 RootIf->Device = RootHub;\r
1043 RootIf->DevicePath = UsbBus->DevicePath;\r
d1102dba 1044\r
37623a5c 1045 //\r
1046 // Report Status Code here since we will enumerate the USB devices\r
1047 //\r
1048 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1049 EFI_PROGRESS_CODE,\r
1050 (EFI_IO_BUS_USB | EFI_IOB_PC_DETECT),\r
1051 UsbBus->DevicePath\r
1052 );\r
d1102dba 1053\r
1436aea4 1054 Status = mUsbRootHubApi.Init (RootIf);\r
ecb575d9 1055\r
1056 if (EFI_ERROR (Status)) {\r
87000d77 1057 DEBUG ((DEBUG_ERROR, "UsbBusStart: Failed to init root hub %r\n", Status));\r
ecb575d9 1058 goto FREE_ROOTHUB;\r
1059 }\r
1060\r
1061 UsbBus->Devices[0] = RootHub;\r
1062\r
87000d77 1063 DEBUG ((DEBUG_INFO, "UsbBusStart: usb bus started on %p, root hub %p\n", Controller, RootIf));\r
ecb575d9 1064 return EFI_SUCCESS;\r
1065\r
1066FREE_ROOTHUB:\r
1067 if (RootIf != NULL) {\r
d17371e8 1068 FreePool (RootIf);\r
ecb575d9 1069 }\r
1436aea4 1070\r
ecb575d9 1071 if (RootHub != NULL) {\r
d17371e8 1072 FreePool (RootHub);\r
ecb575d9 1073 }\r
1074\r
1075UNINSTALL_USBBUS:\r
c8ad2d7a 1076 gBS->UninstallProtocolInterface (Controller, &gEfiCallerIdGuid, &UsbBus->BusId);\r
ecb575d9 1077\r
1078CLOSE_HC:\r
1079 if (UsbBus->Usb2Hc != NULL) {\r
1080 gBS->CloseProtocol (\r
1436aea4
MK
1081 Controller,\r
1082 &gEfiUsb2HcProtocolGuid,\r
1083 This->DriverBindingHandle,\r
1084 Controller\r
1085 );\r
ecb575d9 1086 }\r
1436aea4 1087\r
ecb575d9 1088 if (UsbBus->UsbHc != NULL) {\r
1089 gBS->CloseProtocol (\r
1436aea4
MK
1090 Controller,\r
1091 &gEfiUsbHcProtocolGuid,\r
1092 This->DriverBindingHandle,\r
1093 Controller\r
1094 );\r
ecb575d9 1095 }\r
1436aea4 1096\r
ecb575d9 1097 gBS->CloseProtocol (\r
1098 Controller,\r
1099 &gEfiDevicePathProtocolGuid,\r
1100 This->DriverBindingHandle,\r
1101 Controller\r
1102 );\r
d17371e8 1103 FreePool (UsbBus);\r
ecb575d9 1104\r
87000d77 1105 DEBUG ((DEBUG_ERROR, "UsbBusStart: Failed to start bus driver %r\n", Status));\r
ecb575d9 1106 return Status;\r
1107}\r
1108\r
8616fc4c 1109/**\r
1110 The USB bus driver entry pointer.\r
1111\r
1112 @param ImageHandle The driver image handle.\r
1113 @param SystemTable The system table.\r
1114\r
1115 @return EFI_SUCCESS The component name protocol is installed.\r
1116 @return Others Failed to init the usb driver.\r
1117\r
1118**/\r
e237e7ae 1119EFI_STATUS\r
1120EFIAPI\r
1121UsbBusDriverEntryPoint (\r
1436aea4
MK
1122 IN EFI_HANDLE ImageHandle,\r
1123 IN EFI_SYSTEM_TABLE *SystemTable\r
e237e7ae 1124 )\r
e237e7ae 1125{\r
62b9bb55 1126 return EfiLibInstallDriverBindingComponentName2 (\r
e237e7ae 1127 ImageHandle,\r
1128 SystemTable,\r
1129 &mUsbBusDriverBinding,\r
1130 ImageHandle,\r
1131 &mUsbBusComponentName,\r
62b9bb55 1132 &mUsbBusComponentName2\r
e237e7ae 1133 );\r
1134}\r
1135\r
e237e7ae 1136/**\r
8616fc4c 1137 Check whether USB bus driver support this device.\r
e237e7ae 1138\r
8616fc4c 1139 @param This The USB bus driver binding protocol.\r
34a0bac4 1140 @param Controller The controller handle to check.\r
8616fc4c 1141 @param RemainingDevicePath The remaining device path.\r
e237e7ae 1142\r
1143 @retval EFI_SUCCESS The bus supports this controller.\r
8616fc4c 1144 @retval EFI_UNSUPPORTED This device isn't supported.\r
e237e7ae 1145\r
1146**/\r
1147EFI_STATUS\r
1148EFIAPI\r
1149UsbBusControllerDriverSupported (\r
1150 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1151 IN EFI_HANDLE Controller,\r
1152 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1153 )\r
1154{\r
1155 EFI_DEV_PATH_PTR DevicePathNode;\r
1156 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
1157 EFI_USB2_HC_PROTOCOL *Usb2Hc;\r
1158 EFI_USB_HC_PROTOCOL *UsbHc;\r
1159 EFI_STATUS Status;\r
1160\r
1161 //\r
1162 // Check whether device path is valid\r
1163 //\r
1164 if (RemainingDevicePath != NULL) {\r
af4a6385 1165 //\r
d1102dba 1166 // Check if RemainingDevicePath is the End of Device Path Node,\r
af4a6385 1167 // if yes, go on checking other conditions\r
1168 //\r
1169 if (!IsDevicePathEnd (RemainingDevicePath)) {\r
1170 //\r
1171 // If RemainingDevicePath isn't the End of Device Path Node,\r
1172 // check its validation\r
1173 //\r
1174 DevicePathNode.DevPath = RemainingDevicePath;\r
d1102dba 1175\r
af4a6385 1176 if ((DevicePathNode.DevPath->Type != MESSAGING_DEVICE_PATH) ||\r
1436aea4
MK
1177 ( (DevicePathNode.DevPath->SubType != MSG_USB_DP) &&\r
1178 (DevicePathNode.DevPath->SubType != MSG_USB_CLASS_DP)\r
1179 && (DevicePathNode.DevPath->SubType != MSG_USB_WWID_DP)\r
1180 ))\r
1181 {\r
af4a6385 1182 return EFI_UNSUPPORTED;\r
1183 }\r
e237e7ae 1184 }\r
1185 }\r
1186\r
e237e7ae 1187 //\r
1188 // Check whether USB_HC2 protocol is installed\r
1189 //\r
1190 Status = gBS->OpenProtocol (\r
1191 Controller,\r
1192 &gEfiUsb2HcProtocolGuid,\r
1436aea4 1193 (VOID **)&Usb2Hc,\r
e237e7ae 1194 This->DriverBindingHandle,\r
1195 Controller,\r
1196 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1197 );\r
e237e7ae 1198 if (Status == EFI_ALREADY_STARTED) {\r
1199 return EFI_SUCCESS;\r
1200 }\r
1201\r
af4a6385 1202 if (EFI_ERROR (Status)) {\r
1203 //\r
1204 // If failed to open USB_HC2, fall back to USB_HC\r
1205 //\r
1206 Status = gBS->OpenProtocol (\r
1207 Controller,\r
1208 &gEfiUsbHcProtocolGuid,\r
1436aea4 1209 (VOID **)&UsbHc,\r
af4a6385 1210 This->DriverBindingHandle,\r
1211 Controller,\r
1212 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1213 );\r
1214 if (Status == EFI_ALREADY_STARTED) {\r
1215 return EFI_SUCCESS;\r
1216 }\r
d1102dba 1217\r
af4a6385 1218 if (EFI_ERROR (Status)) {\r
1219 return Status;\r
1220 }\r
1221\r
1222 //\r
1223 // Close the USB_HC used to perform the supported test\r
1224 //\r
e237e7ae 1225 gBS->CloseProtocol (\r
1436aea4
MK
1226 Controller,\r
1227 &gEfiUsbHcProtocolGuid,\r
1228 This->DriverBindingHandle,\r
1229 Controller\r
1230 );\r
af4a6385 1231 } else {\r
af4a6385 1232 //\r
1233 // Close the USB_HC2 used to perform the supported test\r
1234 //\r
1235 gBS->CloseProtocol (\r
1236 Controller,\r
1237 &gEfiUsb2HcProtocolGuid,\r
1238 This->DriverBindingHandle,\r
1239 Controller\r
1240 );\r
1241 }\r
d1102dba 1242\r
e237e7ae 1243 //\r
af4a6385 1244 // Open the EFI Device Path protocol needed to perform the supported test\r
e237e7ae 1245 //\r
1246 Status = gBS->OpenProtocol (\r
1247 Controller,\r
af4a6385 1248 &gEfiDevicePathProtocolGuid,\r
1436aea4 1249 (VOID **)&ParentDevicePath,\r
e237e7ae 1250 This->DriverBindingHandle,\r
1251 Controller,\r
1252 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1253 );\r
e237e7ae 1254 if (Status == EFI_ALREADY_STARTED) {\r
1255 return EFI_SUCCESS;\r
1256 }\r
1257\r
1258 if (!EFI_ERROR (Status)) {\r
af4a6385 1259 //\r
1260 // Close protocol, don't use device path protocol in the Support() function\r
1261 //\r
e237e7ae 1262 gBS->CloseProtocol (\r
1436aea4
MK
1263 Controller,\r
1264 &gEfiDevicePathProtocolGuid,\r
1265 This->DriverBindingHandle,\r
1266 Controller\r
1267 );\r
af4a6385 1268\r
1269 return EFI_SUCCESS;\r
e237e7ae 1270 }\r
1271\r
1272 return Status;\r
1273}\r
1274\r
e237e7ae 1275/**\r
8616fc4c 1276 Start to process the controller.\r
e237e7ae 1277\r
8616fc4c 1278 @param This The USB bus driver binding instance.\r
1279 @param Controller The controller to check.\r
1280 @param RemainingDevicePath The remaining device patch.\r
e237e7ae 1281\r
8616fc4c 1282 @retval EFI_SUCCESS The controller is controlled by the usb bus.\r
e237e7ae 1283 @retval EFI_ALREADY_STARTED The controller is already controlled by the usb\r
8616fc4c 1284 bus.\r
1285 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
e237e7ae 1286\r
1287**/\r
1288EFI_STATUS\r
1289EFIAPI\r
1290UsbBusControllerDriverStart (\r
1291 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1292 IN EFI_HANDLE Controller,\r
1293 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1294 )\r
1295{\r
1436aea4
MK
1296 EFI_USB_BUS_PROTOCOL *UsbBusId;\r
1297 EFI_STATUS Status;\r
1298 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
37623a5c 1299\r
1300 Status = gBS->OpenProtocol (\r
1301 Controller,\r
1302 &gEfiDevicePathProtocolGuid,\r
1436aea4 1303 (VOID **)&ParentDevicePath,\r
37623a5c 1304 This->DriverBindingHandle,\r
1305 Controller,\r
1306 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1307 );\r
1308 ASSERT_EFI_ERROR (Status);\r
1309\r
1310 //\r
1311 // Report Status Code here since we will initialize the host controller\r
1312 //\r
1313 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1314 EFI_PROGRESS_CODE,\r
1315 (EFI_IO_BUS_USB | EFI_IOB_PC_INIT),\r
1316 ParentDevicePath\r
1317 );\r
e237e7ae 1318\r
1319 //\r
1320 // Locate the USB bus protocol, if it is found, USB bus\r
1321 // is already started on this controller.\r
1322 //\r
1323 Status = gBS->OpenProtocol (\r
1324 Controller,\r
c8ad2d7a 1325 &gEfiCallerIdGuid,\r
1436aea4 1326 (VOID **)&UsbBusId,\r
e237e7ae 1327 This->DriverBindingHandle,\r
1328 Controller,\r
1329 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1330 );\r
1331\r
e237e7ae 1332 if (EFI_ERROR (Status)) {\r
ecb575d9 1333 //\r
d17371e8 1334 // If first start, build the bus execute environment and install bus protocol\r
ecb575d9 1335 //\r
3d0a2385 1336 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_IO_BUS_USB | EFI_P_PC_ENABLE));\r
ecb575d9 1337 Status = UsbBusBuildProtocol (This, Controller, RemainingDevicePath);\r
1338 if (EFI_ERROR (Status)) {\r
1339 return Status;\r
1340 }\r
1436aea4 1341\r
ecb575d9 1342 //\r
1343 // Try get the Usb Bus protocol interface again\r
1344 //\r
1345 Status = gBS->OpenProtocol (\r
1346 Controller,\r
c8ad2d7a 1347 &gEfiCallerIdGuid,\r
1436aea4 1348 (VOID **)&UsbBusId,\r
ecb575d9 1349 This->DriverBindingHandle,\r
1350 Controller,\r
1351 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1352 );\r
1353 ASSERT (!EFI_ERROR (Status));\r
1354 } else {\r
1355 //\r
1356 // USB Bus driver need to control the recursive connect policy of the bus, only those wanted\r
1357 // usb child device will be recursively connected.\r
1358 // The RemainingDevicePath indicate the child usb device which user want to fully recursively connecte this time.\r
1359 // All wanted usb child devices will be remembered by the usb bus driver itself.\r
1360 // If RemainingDevicePath == NULL, all the usb child devices in the usb bus are wanted devices.\r
1361 //\r
1362 // Save the passed in RemainingDevicePath this time\r
1363 //\r
af4a6385 1364 if (RemainingDevicePath != NULL) {\r
1365 if (IsDevicePathEnd (RemainingDevicePath)) {\r
1366 //\r
1367 // If RemainingDevicePath is the End of Device Path Node,\r
13a623cf 1368 // skip enumerate any device and return EFI_SUCCESS\r
d1102dba 1369 //\r
af4a6385 1370 return EFI_SUCCESS;\r
1371 }\r
1372 }\r
1373\r
ecb575d9 1374 Status = UsbBusAddWantedUsbIoDP (UsbBusId, RemainingDevicePath);\r
1375 ASSERT (!EFI_ERROR (Status));\r
1376 //\r
1377 // Ensure all wanted child usb devices are fully recursively connected\r
1378 //\r
1379 Status = UsbBusRecursivelyConnectWantedUsbIo (UsbBusId);\r
1380 ASSERT (!EFI_ERROR (Status));\r
e237e7ae 1381 }\r
1382\r
e237e7ae 1383 return EFI_SUCCESS;\r
e237e7ae 1384}\r
1385\r
e237e7ae 1386/**\r
8616fc4c 1387 Stop handle the controller by this USB bus driver.\r
e237e7ae 1388\r
8616fc4c 1389 @param This The USB bus driver binding protocol.\r
1390 @param Controller The controller to release.\r
e237e7ae 1391 @param NumberOfChildren The child of USB bus that opened controller\r
8616fc4c 1392 BY_CHILD.\r
1393 @param ChildHandleBuffer The array of child handle.\r
e237e7ae 1394\r
8616fc4c 1395 @retval EFI_SUCCESS The controller or children are stopped.\r
1396 @retval EFI_DEVICE_ERROR Failed to stop the driver.\r
e237e7ae 1397\r
1398**/\r
1399EFI_STATUS\r
1400EFIAPI\r
1401UsbBusControllerDriverStop (\r
1402 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1403 IN EFI_HANDLE Controller,\r
1404 IN UINTN NumberOfChildren,\r
1405 IN EFI_HANDLE *ChildHandleBuffer\r
1406 )\r
1407{\r
1408 USB_BUS *Bus;\r
1409 USB_DEVICE *RootHub;\r
1410 USB_DEVICE *UsbDev;\r
1411 USB_INTERFACE *RootIf;\r
1412 USB_INTERFACE *UsbIf;\r
1413 EFI_USB_BUS_PROTOCOL *BusId;\r
1414 EFI_USB_IO_PROTOCOL *UsbIo;\r
1415 EFI_TPL OldTpl;\r
1416 UINTN Index;\r
1417 EFI_STATUS Status;\r
0f58371b 1418 EFI_STATUS ReturnStatus;\r
e237e7ae 1419\r
1436aea4 1420 Status = EFI_SUCCESS;\r
e237e7ae 1421\r
1422 if (NumberOfChildren > 0) {\r
ecb575d9 1423 //\r
1424 // BugBug: Raise TPL to callback level instead of USB_BUS_TPL to avoid TPL conflict\r
1425 //\r
1436aea4 1426 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
e237e7ae 1427\r
0f58371b 1428 ReturnStatus = EFI_SUCCESS;\r
e237e7ae 1429 for (Index = 0; Index < NumberOfChildren; Index++) {\r
1430 Status = gBS->OpenProtocol (\r
1431 ChildHandleBuffer[Index],\r
1432 &gEfiUsbIoProtocolGuid,\r
1436aea4 1433 (VOID **)&UsbIo,\r
e237e7ae 1434 This->DriverBindingHandle,\r
1435 Controller,\r
1436 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1437 );\r
1438\r
1439 if (EFI_ERROR (Status)) {\r
1440 //\r
1441 // It is possible that the child has already been released:\r
1442 // 1. For combo device, free one device will release others.\r
1443 // 2. If a hub is released, all devices on its down facing\r
1444 // ports are released also.\r
1445 //\r
1446 continue;\r
1447 }\r
1448\r
1436aea4
MK
1449 UsbIf = USB_INTERFACE_FROM_USBIO (UsbIo);\r
1450 UsbDev = UsbIf->Device;\r
e237e7ae 1451\r
0f58371b 1452 ReturnStatus = UsbRemoveDevice (UsbDev);\r
e237e7ae 1453 }\r
1454\r
1455 gBS->RestoreTPL (OldTpl);\r
0f58371b 1456 return ReturnStatus;\r
e237e7ae 1457 }\r
1458\r
1436aea4 1459 DEBUG ((DEBUG_INFO, "UsbBusStop: usb bus stopped on %p\n", Controller));\r
e237e7ae 1460\r
1461 //\r
1462 // Locate USB_BUS for the current host controller\r
1463 //\r
1464 Status = gBS->OpenProtocol (\r
1465 Controller,\r
c8ad2d7a 1466 &gEfiCallerIdGuid,\r
1436aea4 1467 (VOID **)&BusId,\r
e237e7ae 1468 This->DriverBindingHandle,\r
1469 Controller,\r
1470 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1471 );\r
1472\r
1473 if (EFI_ERROR (Status)) {\r
1474 return Status;\r
1475 }\r
1476\r
1477 Bus = USB_BUS_FROM_THIS (BusId);\r
1478\r
1479 //\r
1480 // Stop the root hub, then free all the devices\r
1481 //\r
ecb575d9 1482 // BugBug: Raise TPL to callback level instead of USB_BUS_TPL to avoid TPL conflict\r
1483 //\r
1436aea4 1484 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
e237e7ae 1485\r
1486 RootHub = Bus->Devices[0];\r
1487 RootIf = RootHub->Interfaces[0];\r
1488\r
a9292c13 1489 ASSERT (Bus->MaxDevices <= 256);\r
0f58371b 1490 ReturnStatus = EFI_SUCCESS;\r
a9292c13 1491 for (Index = 1; Index < Bus->MaxDevices; Index++) {\r
e237e7ae 1492 if (Bus->Devices[Index] != NULL) {\r
0f58371b
FT
1493 Status = UsbRemoveDevice (Bus->Devices[Index]);\r
1494 if (EFI_ERROR (Status)) {\r
1495 ReturnStatus = Status;\r
1496 }\r
e237e7ae 1497 }\r
1498 }\r
1499\r
1500 gBS->RestoreTPL (OldTpl);\r
1501\r
0f58371b
FT
1502 if (!EFI_ERROR (ReturnStatus)) {\r
1503 mUsbRootHubApi.Release (RootIf);\r
1436aea4
MK
1504 gBS->FreePool (RootIf);\r
1505 gBS->FreePool (RootHub);\r
e237e7ae 1506\r
0f58371b
FT
1507 Status = UsbBusFreeUsbDPList (&Bus->WantedUsbIoDPList);\r
1508 ASSERT (!EFI_ERROR (Status));\r
e237e7ae 1509\r
0f58371b
FT
1510 //\r
1511 // Uninstall the bus identifier and close USB_HC/USB2_HC protocols\r
1512 //\r
1513 gBS->UninstallProtocolInterface (Controller, &gEfiCallerIdGuid, &Bus->BusId);\r
e237e7ae 1514\r
0f58371b
FT
1515 if (Bus->Usb2Hc != NULL) {\r
1516 Status = gBS->CloseProtocol (\r
1517 Controller,\r
1518 &gEfiUsb2HcProtocolGuid,\r
1519 This->DriverBindingHandle,\r
1520 Controller\r
1521 );\r
1522 }\r
e237e7ae 1523\r
0f58371b
FT
1524 if (Bus->UsbHc != NULL) {\r
1525 Status = gBS->CloseProtocol (\r
1526 Controller,\r
1527 &gEfiUsbHcProtocolGuid,\r
1528 This->DriverBindingHandle,\r
1529 Controller\r
1530 );\r
1531 }\r
e237e7ae 1532\r
0f58371b
FT
1533 if (!EFI_ERROR (Status)) {\r
1534 gBS->CloseProtocol (\r
1535 Controller,\r
1536 &gEfiDevicePathProtocolGuid,\r
1537 This->DriverBindingHandle,\r
1538 Controller\r
1539 );\r
e237e7ae 1540\r
0f58371b
FT
1541 gBS->FreePool (Bus);\r
1542 }\r
1543 }\r
1436aea4 1544\r
e237e7ae 1545 return Status;\r
1546}\r