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