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