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