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