]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - 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
1/** @file\r
2\r
3 Usb Bus Driver Binding and Bus IO Protocol.\r
4\r
5Copyright (c) 2004 - 2011, 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
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
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
48UINT16 mMaxUsbDeviceNum = USB_MAX_DEVICES;\r
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
65 @retval EFI_SUCCESS The control transfer succeeded.\r
66 @retval Others Failed to execute the transfer\r
67\r
68**/\r
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
115 ASSERT (Dev->Translator.TranslatorHubAddress < mMaxUsbDeviceNum);\r
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
157 // completely irrelevant.\r
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
170 DEBUG ((EFI_D_INFO, "UsbIoControlTransfer: configure changed!!! Do NOT use old UsbIo!!!\n"));\r
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
200 ASSERT (UsbIf->IfDesc->ActiveIndex < USB_MAX_INTERFACE_SETTING);\r
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
212 Execute a bulk transfer to the device endpoint.\r
213\r
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
220\r
221 @retval EFI_SUCCESS The bulk transfer is OK.\r
222 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
223 @retval Others Failed to execute transfer, reason returned in\r
224 UsbStatus.\r
225\r
226**/\r
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
288 ASSERT (Dev->Translator.TranslatorHubAddress < mMaxUsbDeviceNum);\r
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
307 Execute a synchronous interrupt transfer.\r
308\r
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
315\r
316 @retval EFI_SUCCESS The synchronous interrupt transfer is OK.\r
317 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
318 @retval Others Failed to execute transfer, reason returned in\r
319 UsbStatus.\r
320\r
321**/\r
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
383 request if (IsNewTransfer == FALSE).\r
384\r
385 @param This The USB_IO instance.\r
386 @param Endpoint The device endpoint.\r
387 @param IsNewTransfer Whether this is a new request, if it's old, remove\r
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
391 @param Callback The function to call periodicaly when transfer is\r
392 ready.\r
393 @param Context The context to the callback.\r
394\r
395 @retval EFI_SUCCESS New transfer is queued or old request is removed.\r
396 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
397 @retval Others Failed to queue the new request or remove the old\r
398 request.\r
399\r
400**/\r
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
460 Execute a synchronous isochronous transfer.\r
461\r
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
467\r
468 @retval EFI_UNSUPPORTED Currently isochronous transfer isn't supported.\r
469\r
470**/\r
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
486 Queue an asynchronous isochronous transfer.\r
487\r
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
492 @param IsochronousCallBack The function to call periodicaly when transfer is\r
493 ready.\r
494 @param Context The context to the callback.\r
495\r
496 @retval EFI_UNSUPPORTED Currently isochronous transfer isn't supported.\r
497\r
498**/\r
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
515 Retrieve the device descriptor of the device.\r
516\r
517 @param This The USB IO instance.\r
518 @param Descriptor The variable to receive the device descriptor.\r
519\r
520 @retval EFI_SUCCESS The device descriptor is returned.\r
521 @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
522\r
523**/\r
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
552 Return the configuration descriptor of the current active configuration.\r
553\r
554 @param This The USB IO instance.\r
555 @param Descriptor The USB configuration descriptor.\r
556\r
557 @retval EFI_SUCCESS The active configuration descriptor is returned.\r
558 @retval EFI_INVALID_PARAMETER Some parameter is invalid.\r
559 @retval EFI_NOT_FOUND Currently no active configuration is selected.\r
560\r
561**/\r
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
598 Retrieve the active interface setting descriptor for this USB IO instance.\r
599\r
600 @param This The USB IO instance.\r
601 @param Descriptor The variable to receive active interface setting.\r
602\r
603 @retval EFI_SUCCESS The active interface setting is returned.\r
604 @retval EFI_INVALID_PARAMETER Some parameter is invalid.\r
605\r
606**/\r
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
632 Retrieve the endpoint descriptor from this interface setting.\r
633\r
634 @param This The USB IO instance.\r
635 @param Index The index (start from zero) of the endpoint to\r
636 retrieve.\r
637 @param Descriptor The variable to receive the descriptor.\r
638\r
639 @retval EFI_SUCCESS The endpoint descriptor is returned.\r
640 @retval EFI_INVALID_PARAMETER Some parameter is invalid.\r
641\r
642**/\r
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
658 if ((Descriptor == NULL) || (Index > 15)) {\r
659 gBS->RestoreTPL (OldTpl);\r
660 return EFI_INVALID_PARAMETER;\r
661 }\r
662\r
663 if (Index >= UsbIf->IfSetting->Desc.NumEndpoints) {\r
664 gBS->RestoreTPL (OldTpl);\r
665 return EFI_NOT_FOUND;\r
666 }\r
667\r
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
680 Retrieve the supported language ID table from the device.\r
681\r
682 @param This The USB IO instance.\r
683 @param LangIDTable The table to return the language IDs.\r
684 @param TableSize The size, in bytes, of the table LangIDTable.\r
685\r
686 @retval EFI_SUCCESS The language ID is return.\r
687\r
688**/\r
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
707 *TableSize = (UINT16) (Dev->TotalLangId * sizeof (UINT16));\r
708\r
709 gBS->RestoreTPL (OldTpl);\r
710 return EFI_SUCCESS;\r
711}\r
712\r
713\r
714/**\r
715 Retrieve an indexed string in the language of LangID.\r
716\r
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
721\r
722 @retval EFI_SUCCESS The string is returned.\r
723 @retval EFI_NOT_FOUND No such string existed.\r
724\r
725**/\r
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
758 ASSERT (Index < USB_MAX_LANG_ID);\r
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
806 @param This The USB IO instance.\r
807\r
808 @retval EFI_SUCCESS The device is reset and configured.\r
809 @retval Others Failed to reset the device.\r
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
830 if (UsbIf->IsHub) {\r
831 Status = EFI_INVALID_PARAMETER;\r
832 goto ON_EXIT;\r
833 }\r
834\r
835 HubIf = Dev->ParentIf;\r
836 Status = HubIf->HubApi->ResetPort (HubIf, Dev->ParentPort);\r
837\r
838 if (EFI_ERROR (Status)) {\r
839 DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to reset hub port %d@hub %d, %r \n",\r
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
853\r
854 gBS->Stall (USB_SET_DEVICE_ADDRESS_STALL);\r
855 \r
856 if (EFI_ERROR (Status)) {\r
857 DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to set address for device %d - %r\n",\r
858 Address, Status));\r
859\r
860 goto ON_EXIT;\r
861 }\r
862\r
863 Dev->Address = Address;\r
864\r
865 DEBUG (( EFI_D_INFO, "UsbIoPortReset: device is now ADDRESSED at %d\n", Address));\r
866 \r
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
875 DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to set configure for device %d - %r\n",\r
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
885\r
886/**\r
887 Install Usb Bus Protocol on host controller, and start the Usb bus.\r
888\r
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
892\r
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
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
933 FreePool (UsbBus);\r
934 return Status;\r
935 }\r
936\r
937 //\r
938 // Get USB_HC2/USB_HC host controller protocol (EHCI/UHCI).\r
939 // This is for backward compatibility with EFI 1.x. In UEFI\r
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
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
980 UsbHcReset (UsbBus, EFI_USB_HC_RESET_GLOBAL);\r
981 UsbHcSetState (UsbBus, EfiUsbHcStateOperational);\r
982\r
983 //\r
984 // Install an EFI_USB_BUS_PROTOCOL to host controller to identify it.\r
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
1017 FreePool (RootHub);\r
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
1025 RootHub->Tier = 0;\r
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
1039 DEBUG ((EFI_D_INFO, "UsbBusStart: usb bus started on %p, root hub %p\n", Controller, RootIf));\r
1040 return EFI_SUCCESS;\r
1041\r
1042FREE_ROOTHUB:\r
1043 if (RootIf != NULL) {\r
1044 FreePool (RootIf);\r
1045 }\r
1046 if (RootHub != NULL) {\r
1047 FreePool (RootHub);\r
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
1076 FreePool (UsbBus);\r
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
1082\r
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
1093EFI_STATUS\r
1094EFIAPI\r
1095UsbBusDriverEntryPoint (\r
1096 IN EFI_HANDLE ImageHandle,\r
1097 IN EFI_SYSTEM_TABLE *SystemTable\r
1098 )\r
1099{\r
1100 return EfiLibInstallDriverBindingComponentName2 (\r
1101 ImageHandle,\r
1102 SystemTable,\r
1103 &mUsbBusDriverBinding,\r
1104 ImageHandle,\r
1105 &mUsbBusComponentName,\r
1106 &mUsbBusComponentName2\r
1107 );\r
1108}\r
1109\r
1110\r
1111/**\r
1112 Check whether USB bus driver support this device.\r
1113\r
1114 @param This The USB bus driver binding protocol.\r
1115 @param Controller The controller handle to check.\r
1116 @param RemainingDevicePath The remaining device path.\r
1117\r
1118 @retval EFI_SUCCESS The bus supports this controller.\r
1119 @retval EFI_UNSUPPORTED This device isn't supported.\r
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
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
1159 }\r
1160 }\r
1161\r
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
1173 if (Status == EFI_ALREADY_STARTED) {\r
1174 return EFI_SUCCESS;\r
1175 }\r
1176\r
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
1200 gBS->CloseProtocol (\r
1201 Controller,\r
1202 &gEfiUsbHcProtocolGuid,\r
1203 This->DriverBindingHandle,\r
1204 Controller\r
1205 );\r
1206\r
1207 } else {\r
1208\r
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
1220 //\r
1221 // Open the EFI Device Path protocol needed to perform the supported test\r
1222 //\r
1223 Status = gBS->OpenProtocol (\r
1224 Controller,\r
1225 &gEfiDevicePathProtocolGuid,\r
1226 (VOID **) &ParentDevicePath,\r
1227 This->DriverBindingHandle,\r
1228 Controller,\r
1229 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1230 );\r
1231 if (Status == EFI_ALREADY_STARTED) {\r
1232 return EFI_SUCCESS;\r
1233 }\r
1234\r
1235 if (!EFI_ERROR (Status)) {\r
1236 //\r
1237 // Close protocol, don't use device path protocol in the Support() function\r
1238 //\r
1239 gBS->CloseProtocol (\r
1240 Controller,\r
1241 &gEfiDevicePathProtocolGuid,\r
1242 This->DriverBindingHandle,\r
1243 Controller\r
1244 );\r
1245\r
1246 return EFI_SUCCESS;\r
1247 }\r
1248\r
1249 return Status;\r
1250}\r
1251\r
1252\r
1253/**\r
1254 Start to process the controller.\r
1255\r
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
1259\r
1260 @retval EFI_SUCCESS The controller is controlled by the usb bus.\r
1261 @retval EFI_ALREADY_STARTED The controller is already controlled by the usb\r
1262 bus.\r
1263 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
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
1274 EFI_USB_BUS_PROTOCOL *UsbBusId;\r
1275 EFI_STATUS Status;\r
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
1290 if (EFI_ERROR (Status)) {\r
1291 //\r
1292 // If first start, build the bus execute environment and install bus protocol\r
1293 //\r
1294 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_IO_BUS_USB | EFI_P_PC_ENABLE));\r
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
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
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
1338 }\r
1339\r
1340\r
1341 return EFI_SUCCESS;\r
1342}\r
1343\r
1344\r
1345/**\r
1346 Stop handle the controller by this USB bus driver.\r
1347\r
1348 @param This The USB bus driver binding protocol.\r
1349 @param Controller The controller to release.\r
1350 @param NumberOfChildren The child of USB bus that opened controller\r
1351 BY_CHILD.\r
1352 @param ChildHandleBuffer The array of child handle.\r
1353\r
1354 @retval EFI_SUCCESS The controller or children are stopped.\r
1355 @retval EFI_DEVICE_ERROR Failed to stop the driver.\r
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
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
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
1416 DEBUG (( EFI_D_INFO, "UsbBusStop: usb bus stopped on %p\n", Controller));\r
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
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
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
1449 for (Index = 1; Index < mMaxUsbDeviceNum; Index++) {\r
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
1459 Status = UsbBusFreeUsbDPList (&Bus->WantedUsbIoDPList);\r
1460 ASSERT (!EFI_ERROR (Status));\r
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