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