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