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