]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusDxe / UsbUtility.c
1 /** @file
2
3 Wrapper function for usb host controller interface.
4
5 Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "UsbBus.h"
11
12 //
13 // if RemainingDevicePath== NULL, then all Usb child devices in this bus are wanted.
14 // Use a shor form Usb class Device Path, which could match any usb device, in WantedUsbIoDPList to indicate all Usb devices
15 // are wanted Usb devices
16 //
17 USB_CLASS_FORMAT_DEVICE_PATH mAllUsbClassDevicePath = {
18 {
19 {
20 MESSAGING_DEVICE_PATH,
21 MSG_USB_CLASS_DP,
22 {
23 (UINT8)(sizeof (USB_CLASS_DEVICE_PATH)),
24 (UINT8)((sizeof (USB_CLASS_DEVICE_PATH)) >> 8)
25 }
26 },
27 0xffff, // VendorId
28 0xffff, // ProductId
29 0xff, // DeviceClass
30 0xff, // DeviceSubClass
31 0xff // DeviceProtocol
32 },
33
34 {
35 END_DEVICE_PATH_TYPE,
36 END_ENTIRE_DEVICE_PATH_SUBTYPE,
37 {
38 END_DEVICE_PATH_LENGTH,
39 0
40 }
41 }
42 };
43
44 /**
45 Get the capability of the host controller.
46
47 @param UsbBus The usb driver.
48 @param MaxSpeed The maximum speed this host controller supports.
49 @param NumOfPort The number of the root hub port.
50 @param Is64BitCapable Whether this controller support 64 bit addressing.
51
52 @retval EFI_SUCCESS The host controller capability is returned.
53 @retval Others Failed to retrieve the host controller capability.
54
55 **/
56 EFI_STATUS
57 UsbHcGetCapability (
58 IN USB_BUS *UsbBus,
59 OUT UINT8 *MaxSpeed,
60 OUT UINT8 *NumOfPort,
61 OUT UINT8 *Is64BitCapable
62 )
63 {
64 EFI_STATUS Status;
65
66 if (UsbBus->Usb2Hc != NULL) {
67 Status = UsbBus->Usb2Hc->GetCapability (
68 UsbBus->Usb2Hc,
69 MaxSpeed,
70 NumOfPort,
71 Is64BitCapable
72 );
73 } else {
74 Status = UsbBus->UsbHc->GetRootHubPortNumber (UsbBus->UsbHc, NumOfPort);
75
76 *MaxSpeed = EFI_USB_SPEED_FULL;
77 *Is64BitCapable = (UINT8)FALSE;
78 }
79
80 return Status;
81 }
82
83 /**
84 Get the root hub port state.
85
86 @param UsbBus The USB bus driver.
87 @param PortIndex The index of port.
88 @param PortStatus The variable to save port state.
89
90 @retval EFI_SUCCESS The root port state is returned in.
91 @retval Others Failed to get the root hub port state.
92
93 **/
94 EFI_STATUS
95 UsbHcGetRootHubPortStatus (
96 IN USB_BUS *UsbBus,
97 IN UINT8 PortIndex,
98 OUT EFI_USB_PORT_STATUS *PortStatus
99 )
100 {
101 EFI_STATUS Status;
102
103 if (UsbBus->Usb2Hc != NULL) {
104 Status = UsbBus->Usb2Hc->GetRootHubPortStatus (UsbBus->Usb2Hc, PortIndex, PortStatus);
105 } else {
106 Status = UsbBus->UsbHc->GetRootHubPortStatus (UsbBus->UsbHc, PortIndex, PortStatus);
107 }
108
109 return Status;
110 }
111
112 /**
113 Set the root hub port feature.
114
115 @param UsbBus The USB bus driver.
116 @param PortIndex The port index.
117 @param Feature The port feature to set.
118
119 @retval EFI_SUCCESS The port feature is set.
120 @retval Others Failed to set port feature.
121
122 **/
123 EFI_STATUS
124 UsbHcSetRootHubPortFeature (
125 IN USB_BUS *UsbBus,
126 IN UINT8 PortIndex,
127 IN EFI_USB_PORT_FEATURE Feature
128 )
129 {
130 EFI_STATUS Status;
131
132 if (UsbBus->Usb2Hc != NULL) {
133 Status = UsbBus->Usb2Hc->SetRootHubPortFeature (UsbBus->Usb2Hc, PortIndex, Feature);
134 } else {
135 Status = UsbBus->UsbHc->SetRootHubPortFeature (UsbBus->UsbHc, PortIndex, Feature);
136 }
137
138 return Status;
139 }
140
141 /**
142 Clear the root hub port feature.
143
144 @param UsbBus The USB bus driver.
145 @param PortIndex The port index.
146 @param Feature The port feature to clear.
147
148 @retval EFI_SUCCESS The port feature is clear.
149 @retval Others Failed to clear port feature.
150
151 **/
152 EFI_STATUS
153 UsbHcClearRootHubPortFeature (
154 IN USB_BUS *UsbBus,
155 IN UINT8 PortIndex,
156 IN EFI_USB_PORT_FEATURE Feature
157 )
158 {
159 EFI_STATUS Status;
160
161 if (UsbBus->Usb2Hc != NULL) {
162 Status = UsbBus->Usb2Hc->ClearRootHubPortFeature (UsbBus->Usb2Hc, PortIndex, Feature);
163 } else {
164 Status = UsbBus->UsbHc->ClearRootHubPortFeature (UsbBus->UsbHc, PortIndex, Feature);
165 }
166
167 return Status;
168 }
169
170 /**
171 Execute a control transfer to the device.
172
173 @param UsbBus The USB bus driver.
174 @param DevAddr The device address.
175 @param DevSpeed The device speed.
176 @param MaxPacket Maximum packet size of endpoint 0.
177 @param Request The control transfer request.
178 @param Direction The direction of data stage.
179 @param Data The buffer holding data.
180 @param DataLength The length of the data.
181 @param TimeOut Timeout (in ms) to wait until timeout.
182 @param Translator The transaction translator for low/full speed device.
183 @param UsbResult The result of transfer.
184
185 @retval EFI_SUCCESS The control transfer finished without error.
186 @retval Others The control transfer failed, reason returned in UsbReslt.
187
188 **/
189 EFI_STATUS
190 UsbHcControlTransfer (
191 IN USB_BUS *UsbBus,
192 IN UINT8 DevAddr,
193 IN UINT8 DevSpeed,
194 IN UINTN MaxPacket,
195 IN EFI_USB_DEVICE_REQUEST *Request,
196 IN EFI_USB_DATA_DIRECTION Direction,
197 IN OUT VOID *Data,
198 IN OUT UINTN *DataLength,
199 IN UINTN TimeOut,
200 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
201 OUT UINT32 *UsbResult
202 )
203 {
204 EFI_STATUS Status;
205 BOOLEAN IsSlowDevice;
206
207 if (UsbBus->Usb2Hc != NULL) {
208 Status = UsbBus->Usb2Hc->ControlTransfer (
209 UsbBus->Usb2Hc,
210 DevAddr,
211 DevSpeed,
212 MaxPacket,
213 Request,
214 Direction,
215 Data,
216 DataLength,
217 TimeOut,
218 Translator,
219 UsbResult
220 );
221 } else {
222 IsSlowDevice = (BOOLEAN)(EFI_USB_SPEED_LOW == DevSpeed);
223 Status = UsbBus->UsbHc->ControlTransfer (
224 UsbBus->UsbHc,
225 DevAddr,
226 IsSlowDevice,
227 (UINT8)MaxPacket,
228 Request,
229 Direction,
230 Data,
231 DataLength,
232 TimeOut,
233 UsbResult
234 );
235 }
236
237 return Status;
238 }
239
240 /**
241 Execute a bulk transfer to the device's endpoint.
242
243 @param UsbBus The USB bus driver.
244 @param DevAddr The target device address.
245 @param EpAddr The target endpoint address, with direction encoded in
246 bit 7.
247 @param DevSpeed The device's speed.
248 @param MaxPacket The endpoint's max packet size.
249 @param BufferNum The number of data buffer.
250 @param Data Array of pointers to data buffer.
251 @param DataLength The length of data buffer.
252 @param DataToggle On input, the initial data toggle to use, also return
253 the next toggle on output.
254 @param TimeOut The time to wait until timeout.
255 @param Translator The transaction translator for low/full speed device.
256 @param UsbResult The result of USB execution.
257
258 @retval EFI_SUCCESS The bulk transfer is finished without error.
259 @retval Others Failed to execute bulk transfer, result in UsbResult.
260
261 **/
262 EFI_STATUS
263 UsbHcBulkTransfer (
264 IN USB_BUS *UsbBus,
265 IN UINT8 DevAddr,
266 IN UINT8 EpAddr,
267 IN UINT8 DevSpeed,
268 IN UINTN MaxPacket,
269 IN UINT8 BufferNum,
270 IN OUT VOID *Data[],
271 IN OUT UINTN *DataLength,
272 IN OUT UINT8 *DataToggle,
273 IN UINTN TimeOut,
274 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
275 OUT UINT32 *UsbResult
276 )
277 {
278 EFI_STATUS Status;
279
280 if (UsbBus->Usb2Hc != NULL) {
281 Status = UsbBus->Usb2Hc->BulkTransfer (
282 UsbBus->Usb2Hc,
283 DevAddr,
284 EpAddr,
285 DevSpeed,
286 MaxPacket,
287 BufferNum,
288 Data,
289 DataLength,
290 DataToggle,
291 TimeOut,
292 Translator,
293 UsbResult
294 );
295 } else {
296 Status = UsbBus->UsbHc->BulkTransfer (
297 UsbBus->UsbHc,
298 DevAddr,
299 EpAddr,
300 (UINT8)MaxPacket,
301 *Data,
302 DataLength,
303 DataToggle,
304 TimeOut,
305 UsbResult
306 );
307 }
308
309 return Status;
310 }
311
312 /**
313 Queue or cancel an asynchronous interrupt transfer.
314
315 @param UsbBus The USB bus driver.
316 @param DevAddr The target device address.
317 @param EpAddr The target endpoint address, with direction encoded in
318 bit 7.
319 @param DevSpeed The device's speed.
320 @param MaxPacket The endpoint's max packet size.
321 @param IsNewTransfer Whether this is a new request. If not, cancel the old
322 request.
323 @param DataToggle Data toggle to use on input, next toggle on output.
324 @param PollingInterval The interval to poll the interrupt transfer (in ms).
325 @param DataLength The length of periodical data receive.
326 @param Translator The transaction translator for low/full speed device.
327 @param Callback Function to call when data is received.
328 @param Context The context to the callback.
329
330 @retval EFI_SUCCESS The asynchronous transfer is queued.
331 @retval Others Failed to queue the transfer.
332
333 **/
334 EFI_STATUS
335 UsbHcAsyncInterruptTransfer (
336 IN USB_BUS *UsbBus,
337 IN UINT8 DevAddr,
338 IN UINT8 EpAddr,
339 IN UINT8 DevSpeed,
340 IN UINTN MaxPacket,
341 IN BOOLEAN IsNewTransfer,
342 IN OUT UINT8 *DataToggle,
343 IN UINTN PollingInterval,
344 IN UINTN DataLength,
345 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
346 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
347 IN VOID *Context OPTIONAL
348 )
349 {
350 EFI_STATUS Status;
351 BOOLEAN IsSlowDevice;
352
353 if (UsbBus->Usb2Hc != NULL) {
354 Status = UsbBus->Usb2Hc->AsyncInterruptTransfer (
355 UsbBus->Usb2Hc,
356 DevAddr,
357 EpAddr,
358 DevSpeed,
359 MaxPacket,
360 IsNewTransfer,
361 DataToggle,
362 PollingInterval,
363 DataLength,
364 Translator,
365 Callback,
366 Context
367 );
368 } else {
369 IsSlowDevice = (BOOLEAN)(EFI_USB_SPEED_LOW == DevSpeed);
370
371 Status = UsbBus->UsbHc->AsyncInterruptTransfer (
372 UsbBus->UsbHc,
373 DevAddr,
374 EpAddr,
375 IsSlowDevice,
376 (UINT8)MaxPacket,
377 IsNewTransfer,
378 DataToggle,
379 PollingInterval,
380 DataLength,
381 Callback,
382 Context
383 );
384 }
385
386 return Status;
387 }
388
389 /**
390 Execute a synchronous interrupt transfer to the target endpoint.
391
392 @param UsbBus The USB bus driver.
393 @param DevAddr The target device address.
394 @param EpAddr The target endpoint address, with direction encoded in
395 bit 7.
396 @param DevSpeed The device's speed.
397 @param MaxPacket The endpoint's max packet size.
398 @param Data Pointer to data buffer.
399 @param DataLength The length of data buffer.
400 @param DataToggle On input, the initial data toggle to use, also return
401 the next toggle on output.
402 @param TimeOut The time to wait until timeout.
403 @param Translator The transaction translator for low/full speed device.
404 @param UsbResult The result of USB execution.
405
406 @retval EFI_SUCCESS The synchronous interrupt transfer is OK.
407 @retval Others Failed to execute the synchronous interrupt transfer.
408
409 **/
410 EFI_STATUS
411 UsbHcSyncInterruptTransfer (
412 IN USB_BUS *UsbBus,
413 IN UINT8 DevAddr,
414 IN UINT8 EpAddr,
415 IN UINT8 DevSpeed,
416 IN UINTN MaxPacket,
417 IN OUT VOID *Data,
418 IN OUT UINTN *DataLength,
419 IN OUT UINT8 *DataToggle,
420 IN UINTN TimeOut,
421 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
422 OUT UINT32 *UsbResult
423 )
424 {
425 EFI_STATUS Status;
426 BOOLEAN IsSlowDevice;
427
428 if (UsbBus->Usb2Hc != NULL) {
429 Status = UsbBus->Usb2Hc->SyncInterruptTransfer (
430 UsbBus->Usb2Hc,
431 DevAddr,
432 EpAddr,
433 DevSpeed,
434 MaxPacket,
435 Data,
436 DataLength,
437 DataToggle,
438 TimeOut,
439 Translator,
440 UsbResult
441 );
442 } else {
443 IsSlowDevice = (BOOLEAN)((EFI_USB_SPEED_LOW == DevSpeed) ? TRUE : FALSE);
444 Status = UsbBus->UsbHc->SyncInterruptTransfer (
445 UsbBus->UsbHc,
446 DevAddr,
447 EpAddr,
448 IsSlowDevice,
449 (UINT8)MaxPacket,
450 Data,
451 DataLength,
452 DataToggle,
453 TimeOut,
454 UsbResult
455 );
456 }
457
458 return Status;
459 }
460
461 /**
462 Open the USB host controller protocol BY_CHILD.
463
464 @param Bus The USB bus driver.
465 @param Child The child handle.
466
467 @return The open protocol return.
468
469 **/
470 EFI_STATUS
471 UsbOpenHostProtoByChild (
472 IN USB_BUS *Bus,
473 IN EFI_HANDLE Child
474 )
475 {
476 EFI_USB_HC_PROTOCOL *UsbHc;
477 EFI_USB2_HC_PROTOCOL *Usb2Hc;
478 EFI_STATUS Status;
479
480 if (Bus->Usb2Hc != NULL) {
481 Status = gBS->OpenProtocol (
482 Bus->HostHandle,
483 &gEfiUsb2HcProtocolGuid,
484 (VOID **)&Usb2Hc,
485 mUsbBusDriverBinding.DriverBindingHandle,
486 Child,
487 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
488 );
489 } else {
490 Status = gBS->OpenProtocol (
491 Bus->HostHandle,
492 &gEfiUsbHcProtocolGuid,
493 (VOID **)&UsbHc,
494 mUsbBusDriverBinding.DriverBindingHandle,
495 Child,
496 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
497 );
498 }
499
500 return Status;
501 }
502
503 /**
504 Close the USB host controller protocol BY_CHILD.
505
506 @param Bus The USB bus driver.
507 @param Child The child handle.
508
509 **/
510 VOID
511 UsbCloseHostProtoByChild (
512 IN USB_BUS *Bus,
513 IN EFI_HANDLE Child
514 )
515 {
516 if (Bus->Usb2Hc != NULL) {
517 gBS->CloseProtocol (
518 Bus->HostHandle,
519 &gEfiUsb2HcProtocolGuid,
520 mUsbBusDriverBinding.DriverBindingHandle,
521 Child
522 );
523 } else {
524 gBS->CloseProtocol (
525 Bus->HostHandle,
526 &gEfiUsbHcProtocolGuid,
527 mUsbBusDriverBinding.DriverBindingHandle,
528 Child
529 );
530 }
531 }
532
533 /**
534 return the current TPL, copied from the EDKII glue lib.
535
536 @param VOID.
537
538 @return Current TPL.
539
540 **/
541 EFI_TPL
542 UsbGetCurrentTpl (
543 VOID
544 )
545 {
546 EFI_TPL Tpl;
547
548 Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
549 gBS->RestoreTPL (Tpl);
550
551 return Tpl;
552 }
553
554 /**
555 Create a new device path which only contain the first Usb part of the DevicePath.
556
557 @param DevicePath A full device path which contain the usb nodes.
558
559 @return A new device path which only contain the Usb part of the DevicePath.
560
561 **/
562 EFI_DEVICE_PATH_PROTOCOL *
563 EFIAPI
564 GetUsbDPFromFullDP (
565 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
566 )
567 {
568 EFI_DEVICE_PATH_PROTOCOL *UsbDevicePathPtr;
569 EFI_DEVICE_PATH_PROTOCOL *UsbDevicePathBeginPtr;
570 EFI_DEVICE_PATH_PROTOCOL *UsbDevicePathEndPtr;
571 UINTN Size;
572
573 //
574 // Get the Usb part first Begin node in full device path
575 //
576 UsbDevicePathBeginPtr = DevicePath;
577 while ((!IsDevicePathEnd (UsbDevicePathBeginPtr)) &&
578 ((UsbDevicePathBeginPtr->Type != MESSAGING_DEVICE_PATH) ||
579 ( UsbDevicePathBeginPtr->SubType != MSG_USB_DP &&
580 UsbDevicePathBeginPtr->SubType != MSG_USB_CLASS_DP
581 && UsbDevicePathBeginPtr->SubType != MSG_USB_WWID_DP
582 )))
583 {
584 UsbDevicePathBeginPtr = NextDevicePathNode (UsbDevicePathBeginPtr);
585 }
586
587 //
588 // Get the Usb part first End node in full device path
589 //
590 UsbDevicePathEndPtr = UsbDevicePathBeginPtr;
591 while ((!IsDevicePathEnd (UsbDevicePathEndPtr)) &&
592 (UsbDevicePathEndPtr->Type == MESSAGING_DEVICE_PATH) &&
593 ( UsbDevicePathEndPtr->SubType == MSG_USB_DP ||
594 UsbDevicePathEndPtr->SubType == MSG_USB_CLASS_DP
595 || UsbDevicePathEndPtr->SubType == MSG_USB_WWID_DP
596 ))
597 {
598 UsbDevicePathEndPtr = NextDevicePathNode (UsbDevicePathEndPtr);
599 }
600
601 Size = GetDevicePathSize (UsbDevicePathBeginPtr);
602 Size -= GetDevicePathSize (UsbDevicePathEndPtr);
603 if (Size == 0) {
604 //
605 // The passed in DevicePath does not contain the usb nodes
606 //
607 return NULL;
608 }
609
610 //
611 // Create a new device path which only contain the above Usb part
612 //
613 UsbDevicePathPtr = AllocateZeroPool (Size + sizeof (EFI_DEVICE_PATH_PROTOCOL));
614 ASSERT (UsbDevicePathPtr != NULL);
615 CopyMem (UsbDevicePathPtr, UsbDevicePathBeginPtr, Size);
616 //
617 // Append end device path node
618 //
619 UsbDevicePathEndPtr = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN)UsbDevicePathPtr + Size);
620 SetDevicePathEndNode (UsbDevicePathEndPtr);
621 return UsbDevicePathPtr;
622 }
623
624 /**
625 Check whether a usb device path is in a DEVICE_PATH_LIST_ITEM list.
626
627 @param UsbDP a usb device path of DEVICE_PATH_LIST_ITEM.
628 @param UsbIoDPList a DEVICE_PATH_LIST_ITEM list.
629
630 @retval TRUE there is a DEVICE_PATH_LIST_ITEM in UsbIoDPList which contains the passed in UsbDP.
631 @retval FALSE there is no DEVICE_PATH_LIST_ITEM in UsbIoDPList which contains the passed in UsbDP.
632
633 **/
634 BOOLEAN
635 EFIAPI
636 SearchUsbDPInList (
637 IN EFI_DEVICE_PATH_PROTOCOL *UsbDP,
638 IN LIST_ENTRY *UsbIoDPList
639 )
640 {
641 LIST_ENTRY *ListIndex;
642 DEVICE_PATH_LIST_ITEM *ListItem;
643 BOOLEAN Found;
644 UINTN UsbDpDevicePathSize;
645
646 //
647 // Check that UsbDP and UsbIoDPList are valid
648 //
649 if ((UsbIoDPList == NULL) || (UsbDP == NULL)) {
650 return FALSE;
651 }
652
653 Found = FALSE;
654 ListIndex = UsbIoDPList->ForwardLink;
655 while (ListIndex != UsbIoDPList) {
656 ListItem = CR (ListIndex, DEVICE_PATH_LIST_ITEM, Link, DEVICE_PATH_LIST_ITEM_SIGNATURE);
657 //
658 // Compare DEVICE_PATH_LIST_ITEM.DevicePath[]
659 //
660 ASSERT (ListItem->DevicePath != NULL);
661
662 UsbDpDevicePathSize = GetDevicePathSize (UsbDP);
663 if (UsbDpDevicePathSize == GetDevicePathSize (ListItem->DevicePath)) {
664 if ((CompareMem (UsbDP, ListItem->DevicePath, UsbDpDevicePathSize)) == 0) {
665 Found = TRUE;
666 break;
667 }
668 }
669
670 ListIndex = ListIndex->ForwardLink;
671 }
672
673 return Found;
674 }
675
676 /**
677 Add a usb device path into the DEVICE_PATH_LIST_ITEM list.
678
679 @param UsbDP a usb device path of DEVICE_PATH_LIST_ITEM.
680 @param UsbIoDPList a DEVICE_PATH_LIST_ITEM list.
681
682 @retval EFI_INVALID_PARAMETER If parameters are invalid, return this value.
683 @retval EFI_SUCCESS If Add operation is successful, return this value.
684
685 **/
686 EFI_STATUS
687 EFIAPI
688 AddUsbDPToList (
689 IN EFI_DEVICE_PATH_PROTOCOL *UsbDP,
690 IN LIST_ENTRY *UsbIoDPList
691 )
692 {
693 DEVICE_PATH_LIST_ITEM *ListItem;
694
695 //
696 // Check that UsbDP and UsbIoDPList are valid
697 //
698 if ((UsbIoDPList == NULL) || (UsbDP == NULL)) {
699 return EFI_INVALID_PARAMETER;
700 }
701
702 if (SearchUsbDPInList (UsbDP, UsbIoDPList)) {
703 return EFI_SUCCESS;
704 }
705
706 //
707 // Prepare the usbio device path DEVICE_PATH_LIST_ITEM structure.
708 //
709 ListItem = AllocateZeroPool (sizeof (DEVICE_PATH_LIST_ITEM));
710 ASSERT (ListItem != NULL);
711 ListItem->Signature = DEVICE_PATH_LIST_ITEM_SIGNATURE;
712 ListItem->DevicePath = DuplicateDevicePath (UsbDP);
713
714 InsertTailList (UsbIoDPList, &ListItem->Link);
715
716 return EFI_SUCCESS;
717 }
718
719 /**
720 Check whether usb device, whose interface is UsbIf, matches the usb class which indicated by
721 UsbClassDevicePathPtr whose is a short form usb class device path.
722
723 @param UsbClassDevicePathPtr a short form usb class device path.
724 @param UsbIf a usb device interface.
725
726 @retval TRUE the usb device match the usb class.
727 @retval FALSE the usb device does not match the usb class.
728
729 **/
730 BOOLEAN
731 EFIAPI
732 MatchUsbClass (
733 IN USB_CLASS_DEVICE_PATH *UsbClassDevicePathPtr,
734 IN USB_INTERFACE *UsbIf
735 )
736 {
737 USB_INTERFACE_DESC *IfDesc;
738 EFI_USB_INTERFACE_DESCRIPTOR *ActIfDesc;
739 EFI_USB_DEVICE_DESCRIPTOR *DevDesc;
740
741 if ((UsbClassDevicePathPtr->Header.Type != MESSAGING_DEVICE_PATH) ||
742 (UsbClassDevicePathPtr->Header.SubType != MSG_USB_CLASS_DP))
743 {
744 ASSERT (0);
745 return FALSE;
746 }
747
748 IfDesc = UsbIf->IfDesc;
749 ASSERT (IfDesc->ActiveIndex < USB_MAX_INTERFACE_SETTING);
750 ActIfDesc = &(IfDesc->Settings[IfDesc->ActiveIndex]->Desc);
751 DevDesc = &(UsbIf->Device->DevDesc->Desc);
752
753 //
754 // If connect class policy, determine whether to create device handle by the five fields
755 // in class device path node.
756 //
757 // In addition, hub interface is always matched for this policy.
758 //
759 if ((ActIfDesc->InterfaceClass == USB_HUB_CLASS_CODE) &&
760 (ActIfDesc->InterfaceSubClass == USB_HUB_SUBCLASS_CODE))
761 {
762 return TRUE;
763 }
764
765 //
766 // If vendor id or product id is 0xffff, they will be ignored.
767 //
768 if (((UsbClassDevicePathPtr->VendorId == 0xffff) || (UsbClassDevicePathPtr->VendorId == DevDesc->IdVendor)) &&
769 ((UsbClassDevicePathPtr->ProductId == 0xffff) || (UsbClassDevicePathPtr->ProductId == DevDesc->IdProduct)))
770 {
771 //
772 // If Class in Device Descriptor is set to 0, the counterparts in interface should be checked.
773 //
774 if (DevDesc->DeviceClass == 0) {
775 if (((UsbClassDevicePathPtr->DeviceClass == ActIfDesc->InterfaceClass) ||
776 (UsbClassDevicePathPtr->DeviceClass == 0xff)) &&
777 ((UsbClassDevicePathPtr->DeviceSubClass == ActIfDesc->InterfaceSubClass) ||
778 (UsbClassDevicePathPtr->DeviceSubClass == 0xff)) &&
779 ((UsbClassDevicePathPtr->DeviceProtocol == ActIfDesc->InterfaceProtocol) ||
780 (UsbClassDevicePathPtr->DeviceProtocol == 0xff)))
781 {
782 return TRUE;
783 }
784 } else if (((UsbClassDevicePathPtr->DeviceClass == DevDesc->DeviceClass) ||
785 (UsbClassDevicePathPtr->DeviceClass == 0xff)) &&
786 ((UsbClassDevicePathPtr->DeviceSubClass == DevDesc->DeviceSubClass) ||
787 (UsbClassDevicePathPtr->DeviceSubClass == 0xff)) &&
788 ((UsbClassDevicePathPtr->DeviceProtocol == DevDesc->DeviceProtocol) ||
789 (UsbClassDevicePathPtr->DeviceProtocol == 0xff)))
790 {
791 return TRUE;
792 }
793 }
794
795 return FALSE;
796 }
797
798 /**
799 Check whether usb device, whose interface is UsbIf, matches the usb WWID requirement which indicated by
800 UsbWWIDDevicePathPtr whose is a short form usb WWID device path.
801
802 @param UsbWWIDDevicePathPtr a short form usb WWID device path.
803 @param UsbIf a usb device interface.
804
805 @retval TRUE the usb device match the usb WWID requirement.
806 @retval FALSE the usb device does not match the usb WWID requirement.
807
808 **/
809 BOOLEAN
810 MatchUsbWwid (
811 IN USB_WWID_DEVICE_PATH *UsbWWIDDevicePathPtr,
812 IN USB_INTERFACE *UsbIf
813 )
814 {
815 USB_INTERFACE_DESC *IfDesc;
816 EFI_USB_INTERFACE_DESCRIPTOR *ActIfDesc;
817 EFI_USB_DEVICE_DESCRIPTOR *DevDesc;
818 EFI_USB_STRING_DESCRIPTOR *StrDesc;
819 UINT16 Index;
820 CHAR16 *CompareStr;
821 UINTN CompareLen;
822 UINTN Length;
823
824 if ((UsbWWIDDevicePathPtr->Header.Type != MESSAGING_DEVICE_PATH) ||
825 (UsbWWIDDevicePathPtr->Header.SubType != MSG_USB_WWID_DP))
826 {
827 ASSERT (0);
828 return FALSE;
829 }
830
831 IfDesc = UsbIf->IfDesc;
832 ASSERT (IfDesc->ActiveIndex < USB_MAX_INTERFACE_SETTING);
833 ActIfDesc = &(IfDesc->Settings[IfDesc->ActiveIndex]->Desc);
834 DevDesc = &(UsbIf->Device->DevDesc->Desc);
835
836 //
837 // In addition, Hub interface is always matched for this policy.
838 //
839 if ((ActIfDesc->InterfaceClass == USB_HUB_CLASS_CODE) &&
840 (ActIfDesc->InterfaceSubClass == USB_HUB_SUBCLASS_CODE))
841 {
842 return TRUE;
843 }
844
845 //
846 // Check Vendor Id, Product Id and Interface Number.
847 //
848 if ((DevDesc->IdVendor != UsbWWIDDevicePathPtr->VendorId) ||
849 (DevDesc->IdProduct != UsbWWIDDevicePathPtr->ProductId) ||
850 (ActIfDesc->InterfaceNumber != UsbWWIDDevicePathPtr->InterfaceNumber))
851 {
852 return FALSE;
853 }
854
855 //
856 // Check SerialNumber.
857 //
858 if (DevDesc->StrSerialNumber == 0) {
859 return FALSE;
860 }
861
862 //
863 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
864 //
865 CompareStr = (CHAR16 *)(UINTN)(UsbWWIDDevicePathPtr + 1);
866 CompareLen = (DevicePathNodeLength (UsbWWIDDevicePathPtr) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);
867 if (CompareStr[CompareLen - 1] == L'\0') {
868 CompareLen--;
869 }
870
871 //
872 // Compare serial number in each supported language.
873 //
874 for (Index = 0; Index < UsbIf->Device->TotalLangId; Index++) {
875 StrDesc = UsbGetOneString (UsbIf->Device, DevDesc->StrSerialNumber, UsbIf->Device->LangId[Index]);
876 if (StrDesc == NULL) {
877 continue;
878 }
879
880 Length = (StrDesc->Length - 2) / sizeof (CHAR16);
881 if ((Length >= CompareLen) &&
882 (CompareMem (StrDesc->String + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0))
883 {
884 return TRUE;
885 }
886 }
887
888 return FALSE;
889 }
890
891 /**
892 Free a DEVICE_PATH_LIST_ITEM list.
893
894 @param UsbIoDPList a DEVICE_PATH_LIST_ITEM list pointer.
895
896 @retval EFI_INVALID_PARAMETER If parameters are invalid, return this value.
897 @retval EFI_SUCCESS If free operation is successful, return this value.
898
899 **/
900 EFI_STATUS
901 EFIAPI
902 UsbBusFreeUsbDPList (
903 IN LIST_ENTRY *UsbIoDPList
904 )
905 {
906 LIST_ENTRY *ListIndex;
907 DEVICE_PATH_LIST_ITEM *ListItem;
908
909 //
910 // Check that ControllerHandle is a valid handle
911 //
912 if (UsbIoDPList == NULL) {
913 return EFI_INVALID_PARAMETER;
914 }
915
916 ListIndex = UsbIoDPList->ForwardLink;
917 while (ListIndex != UsbIoDPList) {
918 ListItem = CR (ListIndex, DEVICE_PATH_LIST_ITEM, Link, DEVICE_PATH_LIST_ITEM_SIGNATURE);
919 //
920 // Free DEVICE_PATH_LIST_ITEM.DevicePath[]
921 //
922 if (ListItem->DevicePath != NULL) {
923 FreePool (ListItem->DevicePath);
924 }
925
926 //
927 // Free DEVICE_PATH_LIST_ITEM itself
928 //
929 ListIndex = ListIndex->ForwardLink;
930 RemoveEntryList (&ListItem->Link);
931 FreePool (ListItem);
932 }
933
934 InitializeListHead (UsbIoDPList);
935 return EFI_SUCCESS;
936 }
937
938 /**
939 Store a wanted usb child device info (its Usb part of device path) which is indicated by
940 RemainingDevicePath in a Usb bus which is indicated by UsbBusId.
941
942 @param UsbBusId Point to EFI_USB_BUS_PROTOCOL interface.
943 @param RemainingDevicePath The remaining device patch.
944
945 @retval EFI_SUCCESS Add operation is successful.
946 @retval EFI_INVALID_PARAMETER The parameters are invalid.
947
948 **/
949 EFI_STATUS
950 EFIAPI
951 UsbBusAddWantedUsbIoDP (
952 IN EFI_USB_BUS_PROTOCOL *UsbBusId,
953 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
954 )
955 {
956 USB_BUS *Bus;
957 EFI_STATUS Status;
958 EFI_DEVICE_PATH_PROTOCOL *DevicePathPtr;
959
960 //
961 // Check whether remaining device path is valid
962 //
963 if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {
964 if ((RemainingDevicePath->Type != MESSAGING_DEVICE_PATH) ||
965 ( (RemainingDevicePath->SubType != MSG_USB_DP) &&
966 (RemainingDevicePath->SubType != MSG_USB_CLASS_DP)
967 && (RemainingDevicePath->SubType != MSG_USB_WWID_DP)
968 ))
969 {
970 return EFI_INVALID_PARAMETER;
971 }
972 }
973
974 if (UsbBusId == NULL) {
975 return EFI_INVALID_PARAMETER;
976 }
977
978 Bus = USB_BUS_FROM_THIS (UsbBusId);
979
980 if (RemainingDevicePath == NULL) {
981 //
982 // RemainingDevicePath == NULL means all Usb devices in this bus are wanted.
983 // Here use a Usb class Device Path in WantedUsbIoDPList to indicate all Usb devices
984 // are wanted Usb devices
985 //
986 Status = UsbBusFreeUsbDPList (&Bus->WantedUsbIoDPList);
987 ASSERT (!EFI_ERROR (Status));
988 DevicePathPtr = DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL *)&mAllUsbClassDevicePath);
989 } else if (!IsDevicePathEnd (RemainingDevicePath)) {
990 //
991 // If RemainingDevicePath isn't the End of Device Path Node,
992 // Create new Usb device path according to the usb part in remaining device path
993 //
994 DevicePathPtr = GetUsbDPFromFullDP (RemainingDevicePath);
995 } else {
996 //
997 // If RemainingDevicePath is the End of Device Path Node,
998 // skip enumerate any device and return EFI_SUCCESS
999 //
1000 return EFI_SUCCESS;
1001 }
1002
1003 ASSERT (DevicePathPtr != NULL);
1004 Status = AddUsbDPToList (DevicePathPtr, &Bus->WantedUsbIoDPList);
1005 ASSERT (!EFI_ERROR (Status));
1006 FreePool (DevicePathPtr);
1007 return EFI_SUCCESS;
1008 }
1009
1010 /**
1011 Check whether a usb child device is the wanted device in a bus.
1012
1013 @param Bus The Usb bus's private data pointer.
1014 @param UsbIf The usb child device interface.
1015
1016 @retval True If a usb child device is the wanted device in a bus.
1017 @retval False If a usb child device is *NOT* the wanted device in a bus.
1018
1019 **/
1020 BOOLEAN
1021 EFIAPI
1022 UsbBusIsWantedUsbIO (
1023 IN USB_BUS *Bus,
1024 IN USB_INTERFACE *UsbIf
1025 )
1026 {
1027 EFI_DEVICE_PATH_PROTOCOL *DevicePathPtr;
1028 LIST_ENTRY *WantedUsbIoDPListPtr;
1029 LIST_ENTRY *WantedListIndex;
1030 DEVICE_PATH_LIST_ITEM *WantedListItem;
1031 BOOLEAN DoConvert;
1032 UINTN FirstDevicePathSize;
1033
1034 //
1035 // Check whether passed in parameters are valid
1036 //
1037 if ((UsbIf == NULL) || (Bus == NULL)) {
1038 return FALSE;
1039 }
1040
1041 //
1042 // Check whether UsbIf is Hub
1043 //
1044 if (UsbIf->IsHub) {
1045 return TRUE;
1046 }
1047
1048 //
1049 // Check whether all Usb devices in this bus are wanted
1050 //
1051 if (SearchUsbDPInList ((EFI_DEVICE_PATH_PROTOCOL *)&mAllUsbClassDevicePath, &Bus->WantedUsbIoDPList)) {
1052 return TRUE;
1053 }
1054
1055 //
1056 // Check whether the Usb device match any item in WantedUsbIoDPList
1057 //
1058 WantedUsbIoDPListPtr = &Bus->WantedUsbIoDPList;
1059 //
1060 // Create new Usb device path according to the usb part in UsbIo full device path
1061 //
1062 DevicePathPtr = GetUsbDPFromFullDP (UsbIf->DevicePath);
1063 ASSERT (DevicePathPtr != NULL);
1064
1065 DoConvert = FALSE;
1066 WantedListIndex = WantedUsbIoDPListPtr->ForwardLink;
1067 while (WantedListIndex != WantedUsbIoDPListPtr) {
1068 WantedListItem = CR (WantedListIndex, DEVICE_PATH_LIST_ITEM, Link, DEVICE_PATH_LIST_ITEM_SIGNATURE);
1069 ASSERT (WantedListItem->DevicePath->Type == MESSAGING_DEVICE_PATH);
1070 switch (WantedListItem->DevicePath->SubType) {
1071 case MSG_USB_DP:
1072 FirstDevicePathSize = GetDevicePathSize (WantedListItem->DevicePath);
1073 if (FirstDevicePathSize == GetDevicePathSize (DevicePathPtr)) {
1074 if (CompareMem (
1075 WantedListItem->DevicePath,
1076 DevicePathPtr,
1077 GetDevicePathSize (DevicePathPtr)
1078 ) == 0
1079 )
1080 {
1081 DoConvert = TRUE;
1082 }
1083 }
1084
1085 break;
1086 case MSG_USB_CLASS_DP:
1087 if (MatchUsbClass ((USB_CLASS_DEVICE_PATH *)WantedListItem->DevicePath, UsbIf)) {
1088 DoConvert = TRUE;
1089 }
1090
1091 break;
1092 case MSG_USB_WWID_DP:
1093 if (MatchUsbWwid ((USB_WWID_DEVICE_PATH *)WantedListItem->DevicePath, UsbIf)) {
1094 DoConvert = TRUE;
1095 }
1096
1097 break;
1098 default:
1099 ASSERT (0);
1100 break;
1101 }
1102
1103 if (DoConvert) {
1104 break;
1105 }
1106
1107 WantedListIndex = WantedListIndex->ForwardLink;
1108 }
1109
1110 gBS->FreePool (DevicePathPtr);
1111
1112 //
1113 // Check whether the new Usb device path is wanted
1114 //
1115 if (DoConvert) {
1116 return TRUE;
1117 } else {
1118 return FALSE;
1119 }
1120 }
1121
1122 /**
1123 Recursively connect every wanted usb child device to ensure they all fully connected.
1124 Check all the child Usb IO handles in this bus, recursively connecte if it is wanted usb child device.
1125
1126 @param UsbBusId Point to EFI_USB_BUS_PROTOCOL interface.
1127
1128 @retval EFI_SUCCESS Connect is done successfully.
1129 @retval EFI_INVALID_PARAMETER The parameter is invalid.
1130
1131 **/
1132 EFI_STATUS
1133 EFIAPI
1134 UsbBusRecursivelyConnectWantedUsbIo (
1135 IN EFI_USB_BUS_PROTOCOL *UsbBusId
1136 )
1137 {
1138 USB_BUS *Bus;
1139 EFI_STATUS Status;
1140 UINTN Index;
1141 EFI_USB_IO_PROTOCOL *UsbIo;
1142 USB_INTERFACE *UsbIf;
1143 UINTN UsbIoHandleCount;
1144 EFI_HANDLE *UsbIoBuffer;
1145 EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;
1146
1147 if (UsbBusId == NULL) {
1148 return EFI_INVALID_PARAMETER;
1149 }
1150
1151 Bus = USB_BUS_FROM_THIS (UsbBusId);
1152
1153 //
1154 // Get all Usb IO handles in system
1155 //
1156 UsbIoHandleCount = 0;
1157 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiUsbIoProtocolGuid, NULL, &UsbIoHandleCount, &UsbIoBuffer);
1158 if ((Status == EFI_NOT_FOUND) || (UsbIoHandleCount == 0)) {
1159 return EFI_SUCCESS;
1160 }
1161
1162 ASSERT (!EFI_ERROR (Status));
1163
1164 for (Index = 0; Index < UsbIoHandleCount; Index++) {
1165 //
1166 // Check whether the USB IO handle is a child of this bus
1167 // Note: The usb child handle maybe invalid because of hot plugged out during the loop
1168 //
1169 UsbIoDevicePath = NULL;
1170 Status = gBS->HandleProtocol (UsbIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *)&UsbIoDevicePath);
1171 if (EFI_ERROR (Status) || (UsbIoDevicePath == NULL)) {
1172 continue;
1173 }
1174
1175 if (CompareMem (
1176 UsbIoDevicePath,
1177 Bus->DevicePath,
1178 (GetDevicePathSize (Bus->DevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL))
1179 ) != 0)
1180 {
1181 continue;
1182 }
1183
1184 //
1185 // Get the child Usb IO interface
1186 //
1187 Status = gBS->HandleProtocol (
1188 UsbIoBuffer[Index],
1189 &gEfiUsbIoProtocolGuid,
1190 (VOID **)&UsbIo
1191 );
1192 if (EFI_ERROR (Status)) {
1193 continue;
1194 }
1195
1196 UsbIf = USB_INTERFACE_FROM_USBIO (UsbIo);
1197
1198 if (UsbBusIsWantedUsbIO (Bus, UsbIf)) {
1199 if (!UsbIf->IsManaged) {
1200 //
1201 // Recursively connect the wanted Usb Io handle
1202 //
1203 DEBUG ((DEBUG_INFO, "UsbBusRecursivelyConnectWantedUsbIo: TPL before connect is %d\n", (UINT32)UsbGetCurrentTpl ()));
1204 Status = gBS->ConnectController (UsbIf->Handle, NULL, NULL, TRUE);
1205 UsbIf->IsManaged = (BOOLEAN) !EFI_ERROR (Status);
1206 DEBUG ((DEBUG_INFO, "UsbBusRecursivelyConnectWantedUsbIo: TPL after connect is %d\n", (UINT32)UsbGetCurrentTpl ()));
1207 }
1208 }
1209 }
1210
1211 FreePool (UsbIoBuffer);
1212
1213 return EFI_SUCCESS;
1214 }