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