]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.c
Raise TPL to prevent the BlockIo instance for USB device is removed during the locati...
[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
821 UINT8 Address;\r
822 EFI_TPL OldTpl;\r
823 EFI_STATUS Status;\r
824\r
825 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
826\r
827 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
828 Dev = UsbIf->Device;\r
829\r
a92d4e8a 830 if (UsbIf->IsHub) {\r
50fa1b3a 831 Status = EFI_INVALID_PARAMETER;\r
832 goto ON_EXIT;\r
833 }\r
834\r
e237e7ae 835 HubIf = Dev->ParentIf;\r
836 Status = HubIf->HubApi->ResetPort (HubIf, Dev->ParentPort);\r
837\r
838 if (EFI_ERROR (Status)) {\r
d2577026 839 DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to reset hub port %d@hub %d, %r \n",\r
e237e7ae 840 Dev->ParentPort, Dev->ParentAddr, Status));\r
841\r
842 goto ON_EXIT;\r
843 }\r
844\r
845 //\r
846 // Reset the device to its current address. The device now has a\r
847 // address of ZERO, so need to set Dev->Address to zero first for\r
848 // host to communicate with the device\r
849 //\r
850 Address = Dev->Address;\r
851 Dev->Address = 0;\r
852 Status = UsbSetAddress (Dev, Address);\r
efe9186f 853\r
854 gBS->Stall (USB_SET_DEVICE_ADDRESS_STALL);\r
7e388f85 855 \r
e237e7ae 856 if (EFI_ERROR (Status)) {\r
d2577026 857 DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to set address for device %d - %r\n",\r
e237e7ae 858 Address, Status));\r
859\r
860 goto ON_EXIT;\r
861 }\r
862\r
efe9186f 863 Dev->Address = Address;\r
e237e7ae 864\r
7e388f85 865 DEBUG (( EFI_D_INFO, "UsbIoPortReset: device is now ADDRESSED at %d\n", Address));\r
866 \r
e237e7ae 867 //\r
868 // Reset the current active configure, after this device\r
869 // is in CONFIGURED state.\r
870 //\r
871 if (Dev->ActiveConfig != NULL) {\r
872 Status = UsbSetConfig (Dev, Dev->ActiveConfig->Desc.ConfigurationValue);\r
873\r
874 if (EFI_ERROR (Status)) {\r
d2577026 875 DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to set configure for device %d - %r\n",\r
e237e7ae 876 Address, Status));\r
877 }\r
878 }\r
879\r
880ON_EXIT:\r
881 gBS->RestoreTPL (OldTpl);\r
882 return Status;\r
883}\r
884\r
ecb575d9 885\r
886/**\r
8616fc4c 887 Install Usb Bus Protocol on host controller, and start the Usb bus.\r
ecb575d9 888\r
8616fc4c 889 @param This The USB bus driver binding instance.\r
890 @param Controller The controller to check.\r
891 @param RemainingDevicePath The remaining device patch.\r
ecb575d9 892\r
8616fc4c 893 @retval EFI_SUCCESS The controller is controlled by the usb bus.\r
894 @retval EFI_ALREADY_STARTED The controller is already controlled by the usb bus.\r
895 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
ecb575d9 896\r
897**/\r
898EFI_STATUS\r
899EFIAPI\r
900UsbBusBuildProtocol (\r
901 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
902 IN EFI_HANDLE Controller,\r
903 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
904 )\r
905{\r
906 USB_BUS *UsbBus;\r
907 USB_DEVICE *RootHub;\r
908 USB_INTERFACE *RootIf;\r
909 EFI_STATUS Status;\r
910 EFI_STATUS Status2;\r
911\r
912 UsbBus = AllocateZeroPool (sizeof (USB_BUS));\r
913\r
914 if (UsbBus == NULL) {\r
915 return EFI_OUT_OF_RESOURCES;\r
916 }\r
917\r
918 UsbBus->Signature = USB_BUS_SIGNATURE;\r
919 UsbBus->HostHandle = Controller;\r
920\r
921 Status = gBS->OpenProtocol (\r
922 Controller,\r
923 &gEfiDevicePathProtocolGuid,\r
924 (VOID **) &UsbBus->DevicePath,\r
925 This->DriverBindingHandle,\r
926 Controller,\r
927 EFI_OPEN_PROTOCOL_BY_DRIVER\r
928 );\r
929\r
930 if (EFI_ERROR (Status)) {\r
931 DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to open device path %r\n", Status));\r
932\r
d17371e8 933 FreePool (UsbBus);\r
ecb575d9 934 return Status;\r
935 }\r
936\r
937 //\r
938 // Get USB_HC2/USB_HC host controller protocol (EHCI/UHCI).\r
d17371e8 939 // This is for backward compatibility with EFI 1.x. In UEFI\r
ecb575d9 940 // 2.x, USB_HC2 replaces USB_HC. We will open both USB_HC2\r
941 // and USB_HC because EHCI driver will install both protocols\r
942 // (for the same reason). If we don't consume both of them,\r
943 // the unconsumed one may be opened by others.\r
944 //\r
945 Status = gBS->OpenProtocol (\r
946 Controller,\r
947 &gEfiUsb2HcProtocolGuid,\r
948 (VOID **) &(UsbBus->Usb2Hc),\r
949 This->DriverBindingHandle,\r
950 Controller,\r
951 EFI_OPEN_PROTOCOL_BY_DRIVER\r
952 );\r
953\r
954 Status2 = gBS->OpenProtocol (\r
955 Controller,\r
956 &gEfiUsbHcProtocolGuid,\r
957 (VOID **) &(UsbBus->UsbHc),\r
958 This->DriverBindingHandle,\r
959 Controller,\r
960 EFI_OPEN_PROTOCOL_BY_DRIVER\r
961 );\r
962\r
963 if (EFI_ERROR (Status) && EFI_ERROR (Status2)) {\r
964 DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to open USB_HC/USB2_HC %r\n", Status));\r
965\r
966 Status = EFI_DEVICE_ERROR;\r
967 goto CLOSE_HC;\r
968 }\r
969\r
92870c98 970 if (!EFI_ERROR (Status)) {\r
971 if (UsbBus->Usb2Hc->MajorRevision == 0x3) {\r
972 //\r
973 // The EFI_USB2_HC_PROTOCOL is produced for XHCI support.\r
974 // Then its max supported devices are 256.\r
975 //\r
976 mMaxUsbDeviceNum = 256;\r
977 }\r
978 }\r
979\r
ecb575d9 980 UsbHcReset (UsbBus, EFI_USB_HC_RESET_GLOBAL);\r
981 UsbHcSetState (UsbBus, EfiUsbHcStateOperational);\r
982\r
983 //\r
d17371e8 984 // Install an EFI_USB_BUS_PROTOCOL to host controller to identify it.\r
ecb575d9 985 //\r
986 Status = gBS->InstallProtocolInterface (\r
987 &Controller,\r
988 &mUsbBusProtocolGuid,\r
989 EFI_NATIVE_INTERFACE,\r
990 &UsbBus->BusId\r
991 );\r
992\r
993 if (EFI_ERROR (Status)) {\r
994 DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to install bus protocol %r\n", Status));\r
995 goto CLOSE_HC;\r
996 }\r
997\r
998 //\r
999 // Initial the wanted child device path list, and add first RemainingDevicePath\r
1000 //\r
1001 InitializeListHead (&UsbBus->WantedUsbIoDPList);\r
1002 Status = UsbBusAddWantedUsbIoDP (&UsbBus->BusId, RemainingDevicePath);\r
1003 ASSERT (!EFI_ERROR (Status));\r
1004 //\r
1005 // Create a fake usb device for root hub\r
1006 //\r
1007 RootHub = AllocateZeroPool (sizeof (USB_DEVICE));\r
1008\r
1009 if (RootHub == NULL) {\r
1010 Status = EFI_OUT_OF_RESOURCES;\r
1011 goto UNINSTALL_USBBUS;\r
1012 }\r
1013\r
1014 RootIf = AllocateZeroPool (sizeof (USB_INTERFACE));\r
1015\r
1016 if (RootIf == NULL) {\r
d17371e8 1017 FreePool (RootHub);\r
ecb575d9 1018 Status = EFI_OUT_OF_RESOURCES;\r
1019 goto FREE_ROOTHUB;\r
1020 }\r
1021\r
1022 RootHub->Bus = UsbBus;\r
1023 RootHub->NumOfInterface = 1;\r
1024 RootHub->Interfaces[0] = RootIf;\r
92870c98 1025 RootHub->Tier = 0;\r
ecb575d9 1026 RootIf->Signature = USB_INTERFACE_SIGNATURE;\r
1027 RootIf->Device = RootHub;\r
1028 RootIf->DevicePath = UsbBus->DevicePath;\r
1029\r
1030 Status = mUsbRootHubApi.Init (RootIf);\r
1031\r
1032 if (EFI_ERROR (Status)) {\r
1033 DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to init root hub %r\n", Status));\r
1034 goto FREE_ROOTHUB;\r
1035 }\r
1036\r
1037 UsbBus->Devices[0] = RootHub;\r
1038\r
0e549d5b 1039 DEBUG ((EFI_D_INFO, "UsbBusStart: usb bus started on %p, root hub %p\n", Controller, RootIf));\r
ecb575d9 1040 return EFI_SUCCESS;\r
1041\r
1042FREE_ROOTHUB:\r
1043 if (RootIf != NULL) {\r
d17371e8 1044 FreePool (RootIf);\r
ecb575d9 1045 }\r
1046 if (RootHub != NULL) {\r
d17371e8 1047 FreePool (RootHub);\r
ecb575d9 1048 }\r
1049\r
1050UNINSTALL_USBBUS:\r
1051 gBS->UninstallProtocolInterface (Controller, &mUsbBusProtocolGuid, &UsbBus->BusId);\r
1052\r
1053CLOSE_HC:\r
1054 if (UsbBus->Usb2Hc != NULL) {\r
1055 gBS->CloseProtocol (\r
1056 Controller,\r
1057 &gEfiUsb2HcProtocolGuid,\r
1058 This->DriverBindingHandle,\r
1059 Controller\r
1060 );\r
1061 }\r
1062 if (UsbBus->UsbHc != NULL) {\r
1063 gBS->CloseProtocol (\r
1064 Controller,\r
1065 &gEfiUsbHcProtocolGuid,\r
1066 This->DriverBindingHandle,\r
1067 Controller\r
1068 );\r
1069 }\r
1070 gBS->CloseProtocol (\r
1071 Controller,\r
1072 &gEfiDevicePathProtocolGuid,\r
1073 This->DriverBindingHandle,\r
1074 Controller\r
1075 );\r
d17371e8 1076 FreePool (UsbBus);\r
ecb575d9 1077\r
1078 DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to start bus driver %r\n", Status));\r
1079 return Status;\r
1080}\r
1081\r
e237e7ae 1082\r
8616fc4c 1083/**\r
1084 The USB bus driver entry pointer.\r
1085\r
1086 @param ImageHandle The driver image handle.\r
1087 @param SystemTable The system table.\r
1088\r
1089 @return EFI_SUCCESS The component name protocol is installed.\r
1090 @return Others Failed to init the usb driver.\r
1091\r
1092**/\r
e237e7ae 1093EFI_STATUS\r
1094EFIAPI\r
1095UsbBusDriverEntryPoint (\r
1096 IN EFI_HANDLE ImageHandle,\r
1097 IN EFI_SYSTEM_TABLE *SystemTable\r
1098 )\r
e237e7ae 1099{\r
62b9bb55 1100 return EfiLibInstallDriverBindingComponentName2 (\r
e237e7ae 1101 ImageHandle,\r
1102 SystemTable,\r
1103 &mUsbBusDriverBinding,\r
1104 ImageHandle,\r
1105 &mUsbBusComponentName,\r
62b9bb55 1106 &mUsbBusComponentName2\r
e237e7ae 1107 );\r
1108}\r
1109\r
1110\r
1111/**\r
8616fc4c 1112 Check whether USB bus driver support this device.\r
e237e7ae 1113\r
8616fc4c 1114 @param This The USB bus driver binding protocol.\r
34a0bac4 1115 @param Controller The controller handle to check.\r
8616fc4c 1116 @param RemainingDevicePath The remaining device path.\r
e237e7ae 1117\r
1118 @retval EFI_SUCCESS The bus supports this controller.\r
8616fc4c 1119 @retval EFI_UNSUPPORTED This device isn't supported.\r
e237e7ae 1120\r
1121**/\r
1122EFI_STATUS\r
1123EFIAPI\r
1124UsbBusControllerDriverSupported (\r
1125 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1126 IN EFI_HANDLE Controller,\r
1127 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1128 )\r
1129{\r
1130 EFI_DEV_PATH_PTR DevicePathNode;\r
1131 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
1132 EFI_USB2_HC_PROTOCOL *Usb2Hc;\r
1133 EFI_USB_HC_PROTOCOL *UsbHc;\r
1134 EFI_STATUS Status;\r
1135\r
1136 //\r
1137 // Check whether device path is valid\r
1138 //\r
1139 if (RemainingDevicePath != NULL) {\r
af4a6385 1140 //\r
1141 // Check if RemainingDevicePath is the End of Device Path Node, \r
1142 // if yes, go on checking other conditions\r
1143 //\r
1144 if (!IsDevicePathEnd (RemainingDevicePath)) {\r
1145 //\r
1146 // If RemainingDevicePath isn't the End of Device Path Node,\r
1147 // check its validation\r
1148 //\r
1149 DevicePathNode.DevPath = RemainingDevicePath;\r
1150 \r
1151 if ((DevicePathNode.DevPath->Type != MESSAGING_DEVICE_PATH) ||\r
1152 (DevicePathNode.DevPath->SubType != MSG_USB_DP &&\r
1153 DevicePathNode.DevPath->SubType != MSG_USB_CLASS_DP\r
1154 && DevicePathNode.DevPath->SubType != MSG_USB_WWID_DP\r
1155 )) {\r
1156 \r
1157 return EFI_UNSUPPORTED;\r
1158 }\r
e237e7ae 1159 }\r
1160 }\r
1161\r
e237e7ae 1162 //\r
1163 // Check whether USB_HC2 protocol is installed\r
1164 //\r
1165 Status = gBS->OpenProtocol (\r
1166 Controller,\r
1167 &gEfiUsb2HcProtocolGuid,\r
1168 (VOID **) &Usb2Hc,\r
1169 This->DriverBindingHandle,\r
1170 Controller,\r
1171 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1172 );\r
e237e7ae 1173 if (Status == EFI_ALREADY_STARTED) {\r
1174 return EFI_SUCCESS;\r
1175 }\r
1176\r
af4a6385 1177 if (EFI_ERROR (Status)) {\r
1178 //\r
1179 // If failed to open USB_HC2, fall back to USB_HC\r
1180 //\r
1181 Status = gBS->OpenProtocol (\r
1182 Controller,\r
1183 &gEfiUsbHcProtocolGuid,\r
1184 (VOID **) &UsbHc,\r
1185 This->DriverBindingHandle,\r
1186 Controller,\r
1187 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1188 );\r
1189 if (Status == EFI_ALREADY_STARTED) {\r
1190 return EFI_SUCCESS;\r
1191 }\r
1192 \r
1193 if (EFI_ERROR (Status)) {\r
1194 return Status;\r
1195 }\r
1196\r
1197 //\r
1198 // Close the USB_HC used to perform the supported test\r
1199 //\r
e237e7ae 1200 gBS->CloseProtocol (\r
1201 Controller,\r
af4a6385 1202 &gEfiUsbHcProtocolGuid,\r
e237e7ae 1203 This->DriverBindingHandle,\r
1204 Controller\r
1205 );\r
1206\r
af4a6385 1207 } else {\r
e237e7ae 1208\r
af4a6385 1209 //\r
1210 // Close the USB_HC2 used to perform the supported test\r
1211 //\r
1212 gBS->CloseProtocol (\r
1213 Controller,\r
1214 &gEfiUsb2HcProtocolGuid,\r
1215 This->DriverBindingHandle,\r
1216 Controller\r
1217 );\r
1218 }\r
1219 \r
e237e7ae 1220 //\r
af4a6385 1221 // Open the EFI Device Path protocol needed to perform the supported test\r
e237e7ae 1222 //\r
1223 Status = gBS->OpenProtocol (\r
1224 Controller,\r
af4a6385 1225 &gEfiDevicePathProtocolGuid,\r
1226 (VOID **) &ParentDevicePath,\r
e237e7ae 1227 This->DriverBindingHandle,\r
1228 Controller,\r
1229 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1230 );\r
e237e7ae 1231 if (Status == EFI_ALREADY_STARTED) {\r
1232 return EFI_SUCCESS;\r
1233 }\r
1234\r
1235 if (!EFI_ERROR (Status)) {\r
af4a6385 1236 //\r
1237 // Close protocol, don't use device path protocol in the Support() function\r
1238 //\r
e237e7ae 1239 gBS->CloseProtocol (\r
1240 Controller,\r
af4a6385 1241 &gEfiDevicePathProtocolGuid,\r
e237e7ae 1242 This->DriverBindingHandle,\r
1243 Controller\r
1244 );\r
af4a6385 1245\r
1246 return EFI_SUCCESS;\r
e237e7ae 1247 }\r
1248\r
1249 return Status;\r
1250}\r
1251\r
1252\r
1253/**\r
8616fc4c 1254 Start to process the controller.\r
e237e7ae 1255\r
8616fc4c 1256 @param This The USB bus driver binding instance.\r
1257 @param Controller The controller to check.\r
1258 @param RemainingDevicePath The remaining device patch.\r
e237e7ae 1259\r
8616fc4c 1260 @retval EFI_SUCCESS The controller is controlled by the usb bus.\r
e237e7ae 1261 @retval EFI_ALREADY_STARTED The controller is already controlled by the usb\r
8616fc4c 1262 bus.\r
1263 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
e237e7ae 1264\r
1265**/\r
1266EFI_STATUS\r
1267EFIAPI\r
1268UsbBusControllerDriverStart (\r
1269 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1270 IN EFI_HANDLE Controller,\r
1271 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1272 )\r
1273{\r
ecb575d9 1274 EFI_USB_BUS_PROTOCOL *UsbBusId;\r
1275 EFI_STATUS Status;\r
e237e7ae 1276\r
1277 //\r
1278 // Locate the USB bus protocol, if it is found, USB bus\r
1279 // is already started on this controller.\r
1280 //\r
1281 Status = gBS->OpenProtocol (\r
1282 Controller,\r
1283 &mUsbBusProtocolGuid,\r
1284 (VOID **) &UsbBusId,\r
1285 This->DriverBindingHandle,\r
1286 Controller,\r
1287 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1288 );\r
1289\r
e237e7ae 1290 if (EFI_ERROR (Status)) {\r
ecb575d9 1291 //\r
d17371e8 1292 // If first start, build the bus execute environment and install bus protocol\r
ecb575d9 1293 //\r
3d0a2385 1294 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_IO_BUS_USB | EFI_P_PC_ENABLE));\r
ecb575d9 1295 Status = UsbBusBuildProtocol (This, Controller, RemainingDevicePath);\r
1296 if (EFI_ERROR (Status)) {\r
1297 return Status;\r
1298 }\r
1299 //\r
1300 // Try get the Usb Bus protocol interface again\r
1301 //\r
1302 Status = gBS->OpenProtocol (\r
1303 Controller,\r
1304 &mUsbBusProtocolGuid,\r
1305 (VOID **) &UsbBusId,\r
1306 This->DriverBindingHandle,\r
1307 Controller,\r
1308 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1309 );\r
1310 ASSERT (!EFI_ERROR (Status));\r
1311 } else {\r
1312 //\r
1313 // USB Bus driver need to control the recursive connect policy of the bus, only those wanted\r
1314 // usb child device will be recursively connected.\r
1315 // The RemainingDevicePath indicate the child usb device which user want to fully recursively connecte this time.\r
1316 // All wanted usb child devices will be remembered by the usb bus driver itself.\r
1317 // If RemainingDevicePath == NULL, all the usb child devices in the usb bus are wanted devices.\r
1318 //\r
1319 // Save the passed in RemainingDevicePath this time\r
1320 //\r
af4a6385 1321 if (RemainingDevicePath != NULL) {\r
1322 if (IsDevicePathEnd (RemainingDevicePath)) {\r
1323 //\r
1324 // If RemainingDevicePath is the End of Device Path Node,\r
1325 // skip enumerate any device and return EFI_SUCESSS\r
1326 // \r
1327 return EFI_SUCCESS;\r
1328 }\r
1329 }\r
1330\r
ecb575d9 1331 Status = UsbBusAddWantedUsbIoDP (UsbBusId, RemainingDevicePath);\r
1332 ASSERT (!EFI_ERROR (Status));\r
1333 //\r
1334 // Ensure all wanted child usb devices are fully recursively connected\r
1335 //\r
1336 Status = UsbBusRecursivelyConnectWantedUsbIo (UsbBusId);\r
1337 ASSERT (!EFI_ERROR (Status));\r
e237e7ae 1338 }\r
1339\r
e237e7ae 1340\r
e237e7ae 1341 return EFI_SUCCESS;\r
e237e7ae 1342}\r
1343\r
1344\r
1345/**\r
8616fc4c 1346 Stop handle the controller by this USB bus driver.\r
e237e7ae 1347\r
8616fc4c 1348 @param This The USB bus driver binding protocol.\r
1349 @param Controller The controller to release.\r
e237e7ae 1350 @param NumberOfChildren The child of USB bus that opened controller\r
8616fc4c 1351 BY_CHILD.\r
1352 @param ChildHandleBuffer The array of child handle.\r
e237e7ae 1353\r
8616fc4c 1354 @retval EFI_SUCCESS The controller or children are stopped.\r
1355 @retval EFI_DEVICE_ERROR Failed to stop the driver.\r
e237e7ae 1356\r
1357**/\r
1358EFI_STATUS\r
1359EFIAPI\r
1360UsbBusControllerDriverStop (\r
1361 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1362 IN EFI_HANDLE Controller,\r
1363 IN UINTN NumberOfChildren,\r
1364 IN EFI_HANDLE *ChildHandleBuffer\r
1365 )\r
1366{\r
1367 USB_BUS *Bus;\r
1368 USB_DEVICE *RootHub;\r
1369 USB_DEVICE *UsbDev;\r
1370 USB_INTERFACE *RootIf;\r
1371 USB_INTERFACE *UsbIf;\r
1372 EFI_USB_BUS_PROTOCOL *BusId;\r
1373 EFI_USB_IO_PROTOCOL *UsbIo;\r
1374 EFI_TPL OldTpl;\r
1375 UINTN Index;\r
1376 EFI_STATUS Status;\r
1377\r
1378 Status = EFI_SUCCESS;\r
1379\r
1380 if (NumberOfChildren > 0) {\r
ecb575d9 1381 //\r
1382 // BugBug: Raise TPL to callback level instead of USB_BUS_TPL to avoid TPL conflict\r
1383 //\r
1384 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
e237e7ae 1385\r
1386 for (Index = 0; Index < NumberOfChildren; Index++) {\r
1387 Status = gBS->OpenProtocol (\r
1388 ChildHandleBuffer[Index],\r
1389 &gEfiUsbIoProtocolGuid,\r
1390 (VOID **) &UsbIo,\r
1391 This->DriverBindingHandle,\r
1392 Controller,\r
1393 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1394 );\r
1395\r
1396 if (EFI_ERROR (Status)) {\r
1397 //\r
1398 // It is possible that the child has already been released:\r
1399 // 1. For combo device, free one device will release others.\r
1400 // 2. If a hub is released, all devices on its down facing\r
1401 // ports are released also.\r
1402 //\r
1403 continue;\r
1404 }\r
1405\r
1406 UsbIf = USB_INTERFACE_FROM_USBIO (UsbIo);\r
1407 UsbDev = UsbIf->Device;\r
1408\r
1409 UsbRemoveDevice (UsbDev);\r
1410 }\r
1411\r
1412 gBS->RestoreTPL (OldTpl);\r
1413 return EFI_SUCCESS;\r
1414 }\r
1415\r
0e549d5b 1416 DEBUG (( EFI_D_INFO, "UsbBusStop: usb bus stopped on %p\n", Controller));\r
e237e7ae 1417\r
1418 //\r
1419 // Locate USB_BUS for the current host controller\r
1420 //\r
1421 Status = gBS->OpenProtocol (\r
1422 Controller,\r
1423 &mUsbBusProtocolGuid,\r
1424 (VOID **) &BusId,\r
1425 This->DriverBindingHandle,\r
1426 Controller,\r
1427 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1428 );\r
1429\r
1430 if (EFI_ERROR (Status)) {\r
1431 return Status;\r
1432 }\r
1433\r
1434 Bus = USB_BUS_FROM_THIS (BusId);\r
1435\r
1436 //\r
1437 // Stop the root hub, then free all the devices\r
1438 //\r
ecb575d9 1439 // BugBug: Raise TPL to callback level instead of USB_BUS_TPL to avoid TPL conflict\r
1440 //\r
1441 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
e237e7ae 1442 UsbHcSetState (Bus, EfiUsbHcStateHalt);\r
1443\r
1444 RootHub = Bus->Devices[0];\r
1445 RootIf = RootHub->Interfaces[0];\r
1446\r
1447 mUsbRootHubApi.Release (RootIf);\r
1448\r
92870c98 1449 for (Index = 1; Index < mMaxUsbDeviceNum; Index++) {\r
e237e7ae 1450 if (Bus->Devices[Index] != NULL) {\r
1451 UsbRemoveDevice (Bus->Devices[Index]);\r
1452 }\r
1453 }\r
1454\r
1455 gBS->RestoreTPL (OldTpl);\r
1456\r
1457 gBS->FreePool (RootIf);\r
1458 gBS->FreePool (RootHub);\r
ecb575d9 1459 Status = UsbBusFreeUsbDPList (&Bus->WantedUsbIoDPList);\r
1460 ASSERT (!EFI_ERROR (Status));\r
e237e7ae 1461\r
1462 //\r
1463 // Uninstall the bus identifier and close USB_HC/USB2_HC protocols\r
1464 //\r
1465 gBS->UninstallProtocolInterface (Controller, &mUsbBusProtocolGuid, &Bus->BusId);\r
1466\r
1467 if (Bus->Usb2Hc != NULL) {\r
1468 gBS->CloseProtocol (\r
1469 Controller,\r
1470 &gEfiUsb2HcProtocolGuid,\r
1471 This->DriverBindingHandle,\r
1472 Controller\r
1473 );\r
1474 }\r
1475\r
1476 if (Bus->UsbHc != NULL) {\r
1477 gBS->CloseProtocol (\r
1478 Controller,\r
1479 &gEfiUsbHcProtocolGuid,\r
1480 This->DriverBindingHandle,\r
1481 Controller\r
1482 );\r
1483 }\r
1484\r
1485 gBS->CloseProtocol (\r
1486 Controller,\r
1487 &gEfiDevicePathProtocolGuid,\r
1488 This->DriverBindingHandle,\r
1489 Controller\r
1490 );\r
1491\r
1492 gBS->FreePool (Bus);\r
1493\r
1494 return Status;\r
1495}\r