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