]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c
795f545b7712eb59865756eeb6b45abbdd2195d5
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusDxe / UsbHub.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 UsbHub.c
15
16 Abstract:
17
18 Unified interface for RootHub and Hub
19
20 Revision History
21
22
23 **/
24
25 #include "UsbBus.h"
26
27 //
28 // USB hub class specific requests. Although USB hub
29 // is related to an interface, these requests are sent
30 // to the control endpoint of the device.
31 //
32
33
34 /**
35 USB hub control transfer to clear the hub feature
36
37 @param HubDev The device of the hub
38 @param Feature The feature to clear
39
40 @retval EFI_SUCCESS Feature of the hub is cleared
41 @retval Others Failed to clear the feature
42
43 **/
44 STATIC
45 EFI_STATUS
46 UsbHubCtrlClearHubFeature (
47 IN USB_DEVICE *HubDev,
48 IN UINT16 Feature
49 )
50 {
51 EFI_STATUS Status;
52
53 Status = UsbCtrlRequest (
54 HubDev,
55 EfiUsbNoData,
56 USB_REQ_TYPE_CLASS,
57 USB_HUB_TARGET_HUB,
58 USB_HUB_REQ_CLEAR_FEATURE,
59 Feature,
60 0,
61 NULL,
62 0
63 );
64
65 return Status;
66 }
67
68
69 /**
70 Clear the feature of the device's port
71
72 @param HubDev The hub device
73 @param Port The port to clear feature
74 @param Feature The feature to clear
75
76 @retval EFI_SUCCESS The feature of the port is cleared.
77 @retval Others Failed to clear the feature.
78
79 **/
80 STATIC
81 EFI_STATUS
82 UsbHubCtrlClearPortFeature (
83 IN USB_DEVICE *HubDev,
84 IN UINT8 Port,
85 IN UINT16 Feature
86 )
87 {
88 EFI_STATUS Status;
89
90 //
91 // In USB bus, all the port index starts from 0. But HUB
92 // indexes its port from 1. So, port number is added one.
93 //
94 Status = UsbCtrlRequest (
95 HubDev,
96 EfiUsbNoData,
97 USB_REQ_TYPE_CLASS,
98 USB_HUB_TARGET_PORT,
99 USB_HUB_REQ_CLEAR_FEATURE,
100 Feature,
101 (UINT16) (Port + 1),
102 NULL,
103 0
104 );
105
106 return Status;
107 }
108
109
110
111 /**
112 Clear the transaction translate buffer if full/low
113 speed control/bulk transfer failed and the transfer
114 uses this hub as translator.Remember to clear the TT
115 buffer of transaction translator, not that of the
116 parent.
117
118 @param HubDev The hub device
119 @param Port The port of the hub
120 @param DevAddr Address of the failed transaction
121 @param EpNum The endpoint number of the failed transaction
122 @param EpType The type of failed transaction
123
124 @retval EFI_SUCCESS The TT buffer is cleared
125 @retval Others Failed to clear the TT buffer
126
127 **/
128 EFI_STATUS
129 UsbHubCtrlClearTTBuffer (
130 IN USB_DEVICE *HubDev,
131 IN UINT8 Port,
132 IN UINT16 DevAddr,
133 IN UINT16 EpNum,
134 IN UINT16 EpType
135 )
136 {
137 EFI_STATUS Status;
138 UINT16 Value;
139
140 //
141 // Check USB2.0 spec page 424 for wValue's encoding
142 //
143 Value = (UINT16) ((EpNum & 0x0F) | (DevAddr << 4) |
144 ((EpType & 0x03) << 11) | ((EpNum & 0x80) << 15));
145
146 Status = UsbCtrlRequest (
147 HubDev,
148 EfiUsbNoData,
149 USB_REQ_TYPE_CLASS,
150 USB_HUB_TARGET_PORT,
151 USB_HUB_REQ_CLEAR_TT,
152 Value,
153 (UINT16) (Port + 1),
154 NULL,
155 0
156 );
157
158 return Status;
159 }
160
161
162 /**
163 Usb hub control transfer to get the hub descriptor
164
165 @param HubDev The hub device
166 @param Buf The buffer to hold the descriptor
167 @param Len The length to retrieve
168
169 @retval EFI_SUCCESS The hub descriptor is retrieved
170 @retval Others Failed to retrieve the hub descriptor
171
172 **/
173 STATIC
174 EFI_STATUS
175 UsbHubCtrlGetHubDesc (
176 IN USB_DEVICE *HubDev,
177 OUT VOID *Buf,
178 IN UINTN Len
179 )
180 {
181 EFI_STATUS Status;
182
183 Status = UsbCtrlRequest (
184 HubDev,
185 EfiUsbDataIn,
186 USB_REQ_TYPE_CLASS,
187 USB_HUB_TARGET_HUB,
188 USB_HUB_REQ_GET_DESC,
189 (UINT16) (USB_DESC_TYPE_HUB << 8),
190 0,
191 Buf,
192 Len
193 );
194
195 return Status;
196 }
197
198
199 /**
200 Usb hub control transfer to get the hub status
201
202 @param HubDev The hub device
203 @param State The variable to return the status
204
205 @retval EFI_SUCCESS The hub status is returned in State
206 @retval Others Failed to get the hub status
207
208 **/
209 STATIC
210 EFI_STATUS
211 UsbHubCtrlGetHubStatus (
212 IN USB_DEVICE *HubDev,
213 OUT UINT32 *State
214 )
215 {
216 EFI_STATUS Status;
217
218 Status = UsbCtrlRequest (
219 HubDev,
220 EfiUsbDataIn,
221 USB_REQ_TYPE_CLASS,
222 USB_HUB_TARGET_HUB,
223 USB_HUB_REQ_GET_STATUS,
224 0,
225 0,
226 State,
227 4
228 );
229
230 return Status;
231 }
232
233
234 /**
235 Usb hub control transfer to get the port status
236
237 @param HubDev The hub device
238 @param Port The port of the hub
239 @param State Variable to return the hub port state
240
241 @retval EFI_SUCCESS The port state is returned in State
242 @retval Others Failed to retrive the port state
243
244 **/
245 STATIC
246 EFI_STATUS
247 UsbHubCtrlGetPortStatus (
248 IN USB_DEVICE *HubDev,
249 IN UINT8 Port,
250 OUT VOID *State
251 )
252 {
253 EFI_STATUS Status;
254
255 //
256 // In USB bus, all the port index starts from 0. But HUB
257 // indexes its port from 1. So, port number is added one.
258 // No need to convert the hub bit to UEFI definition, they
259 // are the same
260 //
261 Status = UsbCtrlRequest (
262 HubDev,
263 EfiUsbDataIn,
264 USB_REQ_TYPE_CLASS,
265 USB_HUB_TARGET_PORT,
266 USB_HUB_REQ_GET_STATUS,
267 0,
268 (UINT16) (Port + 1),
269 State,
270 4
271 );
272
273 return Status;
274 }
275
276
277 /**
278 Usb hub control transfer to reset the TT (Transaction Transaltor)
279
280 @param HubDev The hub device
281 @param Port The port of the hub
282
283 @retval EFI_SUCCESS The TT of the hub is reset
284 @retval Others Failed to reset the port
285
286 **/
287 EFI_STATUS
288 UsbHubCtrlResetTT (
289 IN USB_DEVICE *HubDev,
290 IN UINT8 Port
291 )
292 {
293 EFI_STATUS Status;
294
295 Status = UsbCtrlRequest (
296 HubDev,
297 EfiUsbNoData,
298 USB_REQ_TYPE_CLASS,
299 USB_HUB_TARGET_HUB,
300 USB_HUB_REQ_RESET_TT,
301 0,
302 (UINT16) (Port + 1),
303 NULL,
304 0
305 );
306
307 return Status;
308 }
309
310
311 /**
312 Usb hub control transfer to set the hub feature
313
314 @param HubDev The hub device
315 @param Feature The feature to set
316
317 @retval EFI_SUCESS The feature is set for the hub
318 @retval Others Failed to set the feature
319
320 **/
321 EFI_STATUS
322 UsbHubCtrlSetHubFeature (
323 IN USB_DEVICE *HubDev,
324 IN UINT8 Feature
325 )
326 {
327 EFI_STATUS Status;
328
329 Status = UsbCtrlRequest (
330 HubDev,
331 EfiUsbNoData,
332 USB_REQ_TYPE_CLASS,
333 USB_HUB_TARGET_HUB,
334 USB_HUB_REQ_SET_FEATURE,
335 Feature,
336 0,
337 NULL,
338 0
339 );
340
341 return Status;
342 }
343
344
345 /**
346 Usb hub control transfer to set the port feature
347
348 @param HubDev The Usb hub device
349 @param Port The Usb port to set feature for
350 @param Feature The feature to set
351
352 @retval EFI_SUCCESS The feature is set for the port
353 @retval Others Failed to set the feature
354
355 **/
356 STATIC
357 EFI_STATUS
358 UsbHubCtrlSetPortFeature (
359 IN USB_DEVICE *HubDev,
360 IN UINT8 Port,
361 IN UINT8 Feature
362 )
363 {
364 EFI_STATUS Status;
365
366 //
367 // In USB bus, all the port index starts from 0. But HUB
368 // indexes its port from 1. So, port number is added one.
369 //
370 Status = UsbCtrlRequest (
371 HubDev,
372 EfiUsbNoData,
373 USB_REQ_TYPE_CLASS,
374 USB_HUB_TARGET_PORT,
375 USB_HUB_REQ_SET_FEATURE,
376 Feature,
377 (UINT16) (Port + 1),
378 NULL,
379 0
380 );
381
382 return Status;
383 }
384
385
386 /**
387 Read the whole usb hub descriptor. It is necessary
388 to do it in two steps because hub descriptor is of
389 variable length
390
391 @param HubDev The hub device
392 @param HubDesc The variable to return the descriptor
393
394 @retval EFI_SUCCESS The hub descriptor is read
395 @retval Others Failed to read the hub descriptor
396
397 **/
398 STATIC
399 EFI_STATUS
400 UsbHubReadDesc (
401 IN USB_DEVICE *HubDev,
402 OUT EFI_USB_HUB_DESCRIPTOR *HubDesc
403 )
404 {
405 EFI_STATUS Status;
406
407 //
408 // First get the hub descriptor length
409 //
410 Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, 2);
411
412 if (EFI_ERROR (Status)) {
413 return Status;
414 }
415
416 //
417 // Get the whole hub descriptor
418 //
419 Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, HubDesc->Length);
420
421 return Status;
422 }
423
424
425
426 /**
427 Ack the hub change bits. If these bits are not ACKed, Hub will
428 always return changed bit map from its interrupt endpoint.
429
430 @param HubDev The hub device
431
432 @retval EFI_SUCCESS The hub change status is ACKed
433 @retval Others Failed to ACK the hub status
434
435 **/
436 EFI_STATUS
437 UsbHubAckHubStatus (
438 IN USB_DEVICE *HubDev
439 )
440 {
441 EFI_USB_PORT_STATUS HubState;
442 EFI_STATUS Status;
443
444 Status = UsbHubCtrlGetHubStatus (HubDev, (UINT32 *) &HubState);
445
446 if (EFI_ERROR (Status)) {
447 return Status;
448 }
449
450 if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_LOCAL_POWER)) {
451 UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_LOCAL_POWER);
452 }
453
454 if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_OVER_CURRENT)) {
455 UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_OVER_CURRENT);
456 }
457
458 return EFI_SUCCESS;
459 }
460
461
462 /**
463 Test whether the interface is a hub interface.
464
465 @param UsbIf The interface to test
466
467 @retval TRUE The interface is a hub interface
468 @retval FALSE The interface isn't a hub interface
469
470 **/
471 BOOLEAN
472 UsbIsHubInterface (
473 IN USB_INTERFACE *UsbIf
474 )
475 {
476 EFI_USB_INTERFACE_DESCRIPTOR *Setting;
477
478 //
479 // If the hub is a high-speed hub with multiple TT,
480 // the hub will has a default setting of single TT.
481 //
482 Setting = &UsbIf->IfSetting->Desc;
483
484 if ((Setting->InterfaceClass == USB_HUB_CLASS_CODE) &&
485 (Setting->InterfaceSubClass == USB_HUB_SUBCLASS_CODE)) {
486
487 return TRUE;
488 }
489
490 return FALSE;
491 }
492
493
494 /**
495 The callback function to the USB hub status change
496 interrupt endpoint. It is called periodically by
497 the underlying host controller.
498
499 @param Data The data read
500 @param DataLength The length of the data read
501 @param Context The context
502 @param Result The result of the last interrupt transfer
503
504 @retval EFI_SUCCESS The process is OK
505 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource
506
507 **/
508 STATIC
509 EFI_STATUS
510 UsbOnHubInterrupt (
511 IN VOID *Data,
512 IN UINTN DataLength,
513 IN VOID *Context,
514 IN UINT32 Result
515 )
516 {
517 USB_INTERFACE *HubIf;
518 EFI_USB_IO_PROTOCOL *UsbIo;
519 EFI_USB_ENDPOINT_DESCRIPTOR *EpDesc;
520 EFI_STATUS Status;
521
522 HubIf = (USB_INTERFACE *) Context;
523 UsbIo = &(HubIf->UsbIo);
524 EpDesc = &(HubIf->HubEp->Desc);
525
526 if (Result != EFI_USB_NOERROR) {
527 //
528 // If endpoint is stalled, clear the stall. Use UsbIo to access
529 // the control transfer so internal status are maintained.
530 //
531 if (USB_BIT_IS_SET (Result, EFI_USB_ERR_STALL)) {
532 UsbIoClearFeature (
533 UsbIo,
534 USB_TARGET_ENDPOINT,
535 USB_FEATURE_ENDPOINT_HALT,
536 EpDesc->EndpointAddress
537 );
538 }
539
540 //
541 // Delete and submit a new async interrupt
542 //
543 Status = UsbIo->UsbAsyncInterruptTransfer (
544 UsbIo,
545 EpDesc->EndpointAddress,
546 FALSE,
547 0,
548 0,
549 NULL,
550 NULL
551 );
552
553 if (EFI_ERROR (Status)) {
554 DEBUG (( EFI_D_ERROR, "UsbOnHubInterrupt: failed to remove async transfer - %r\n", Status));
555 return Status;
556 }
557
558 Status = UsbIo->UsbAsyncInterruptTransfer (
559 UsbIo,
560 EpDesc->EndpointAddress,
561 TRUE,
562 USB_HUB_POLL_INTERVAL,
563 HubIf->NumOfPort / 8 + 1,
564 UsbOnHubInterrupt,
565 HubIf
566 );
567
568 if (EFI_ERROR (Status)) {
569 DEBUG (( EFI_D_ERROR, "UsbOnHubInterrupt: failed to submit new async transfer - %r\n", Status));
570 }
571
572 return Status;
573 }
574
575 if ((DataLength == 0) || (Data == NULL)) {
576 return EFI_SUCCESS;
577 }
578
579 //
580 // OK, actually something is changed, save the change map
581 // then signal the HUB to do enumeration. This is a good
582 // practise since UsbOnHubInterrupt is called in the context
583 // of host contrller's AsyncInterrupt monitor.
584 //
585 HubIf->ChangeMap = AllocateZeroPool (DataLength);
586
587 if (HubIf->ChangeMap == NULL) {
588 return EFI_OUT_OF_RESOURCES;
589 }
590
591 CopyMem (HubIf->ChangeMap, Data, DataLength);
592 gBS->SignalEvent (HubIf->HubNotify);
593
594 return EFI_SUCCESS;
595 }
596
597 //
598 // Array that maps the change bit to feature value which is
599 // used to clear these change bit. USB HUB API will clear
600 // these change bit automatically. For non-root hub, these
601 // bits determine whether hub will report the port in changed
602 // bit maps.
603 //
604 #define USB_HUB_MAP_SIZE 5
605
606 USB_CHANGE_FEATURE_MAP mHubFeatureMap[USB_HUB_MAP_SIZE] = {
607 {USB_PORT_STAT_C_CONNECTION, USB_HUB_C_PORT_CONNECT},
608 {USB_PORT_STAT_C_ENABLE, USB_HUB_C_PORT_ENABLE},
609 {USB_PORT_STAT_C_SUSPEND, USB_HUB_C_PORT_SUSPEND},
610 {USB_PORT_STAT_C_OVERCURRENT, USB_HUB_C_PORT_OVER_CURRENT},
611 {USB_PORT_STAT_C_RESET, USB_HUB_C_PORT_RESET},
612 };
613
614 #define USB_ROOT_HUB_MAP_SIZE 5
615
616 USB_CHANGE_FEATURE_MAP mRootHubFeatureMap[USB_ROOT_HUB_MAP_SIZE] = {
617 {USB_PORT_STAT_C_CONNECTION, EfiUsbPortConnectChange},
618 {USB_PORT_STAT_C_ENABLE, EfiUsbPortEnableChange},
619 {USB_PORT_STAT_C_SUSPEND, EfiUsbPortSuspendChange},
620 {USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange},
621 {USB_PORT_STAT_C_RESET, EfiUsbPortResetChange},
622 };
623
624
625
626 /**
627 Initialize the device for a non-root hub
628
629 @param HubIf The USB hub interface
630
631 @retval EFI_SUCCESS The hub is initialized
632 @retval EFI_DEVICE_ERROR Failed to initialize the hub
633
634 **/
635 STATIC
636 EFI_STATUS
637 UsbHubInit (
638 IN USB_INTERFACE *HubIf
639 )
640 {
641 EFI_USB_HUB_DESCRIPTOR HubDesc;
642 USB_ENDPOINT_DESC *EpDesc;
643 USB_INTERFACE_SETTING *Setting;
644 EFI_USB_IO_PROTOCOL *UsbIo;
645 USB_DEVICE *HubDev;
646 EFI_STATUS Status;
647 UINT8 Index;
648
649 //
650 // Locate the interrupt endpoint for port change map
651 //
652 HubIf->IsHub = FALSE;
653 Setting = HubIf->IfSetting;
654 HubDev = HubIf->Device;
655 EpDesc = NULL;
656
657 for (Index = 0; Index < Setting->Desc.NumEndpoints; Index++) {
658 ASSERT ((Setting->Endpoints != NULL) && (Setting->Endpoints[Index] != NULL));
659
660 EpDesc = Setting->Endpoints[Index];
661
662 if (USB_BIT_IS_SET (EpDesc->Desc.EndpointAddress, USB_ENDPOINT_DIR_IN) &&
663 (USB_ENDPOINT_TYPE (&EpDesc->Desc) == USB_ENDPOINT_INTERRUPT)) {
664 break;
665 }
666 }
667
668 if (Index == Setting->Desc.NumEndpoints) {
669 DEBUG (( EFI_D_ERROR, "UsbHubInit: no interrupt endpoint found for hub %d\n", HubDev->Address));
670 return EFI_DEVICE_ERROR;
671 }
672
673 Status = UsbHubReadDesc (HubDev, &HubDesc);
674
675 if (EFI_ERROR (Status)) {
676 DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to read HUB descriptor %r\n", Status));
677 return Status;
678 }
679
680 HubIf->NumOfPort = HubDesc.NumPorts;
681
682 DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d has %d ports\n", HubDev->Address,HubIf->NumOfPort));
683
684 //
685 // Create an event to enumerate the hub's port. On
686 //
687 Status = gBS->CreateEvent (
688 EVT_NOTIFY_SIGNAL,
689 TPL_CALLBACK,
690 UsbHubEnumeration,
691 HubIf,
692 &HubIf->HubNotify
693 );
694
695 if (EFI_ERROR (Status)) {
696 DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to create signal for hub %d - %r\n",
697 HubDev->Address, Status));
698
699 return Status;
700 }
701
702 //
703 // Create AsyncInterrupt to query hub port change endpoint
704 // periodically. If the hub ports are changed, hub will return
705 // changed port map from the interrupt endpoint. The port map
706 // must be able to hold (HubIf->NumOfPort + 1) bits (one bit for
707 // host change status).
708 //
709 UsbIo = &HubIf->UsbIo;
710 Status = UsbIo->UsbAsyncInterruptTransfer (
711 UsbIo,
712 EpDesc->Desc.EndpointAddress,
713 TRUE,
714 USB_HUB_POLL_INTERVAL,
715 HubIf->NumOfPort / 8 + 1,
716 UsbOnHubInterrupt,
717 HubIf
718 );
719
720 if (EFI_ERROR (Status)) {
721 DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to queue interrupt transfer for hub %d - %r\n",
722 HubDev->Address, Status));
723
724 gBS->CloseEvent (HubIf->HubNotify);
725 HubIf->HubNotify = NULL;
726
727 return Status;
728 }
729
730 //
731 // OK, set IsHub to TRUE. Now usb bus can handle this device
732 // as a working HUB. If failed eariler, bus driver will not
733 // recognize it as a hub. Other parts of the bus should be able
734 // to work.
735 //
736 HubIf->IsHub = TRUE;
737 HubIf->HubApi = &mUsbHubApi;
738 HubIf->HubEp = EpDesc;
739
740 //
741 // Feed power to all the hub ports. It should be ok
742 // for both gang/individual powered hubs.
743 //
744 for (Index = 0; Index < HubDesc.NumPorts; Index++) {
745 UsbHubCtrlSetPortFeature (HubIf->Device, Index, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_POWER);
746 }
747
748 gBS->Stall (HubDesc.PwrOn2PwrGood * 2 * USB_STALL_1_MS);
749 UsbHubAckHubStatus (HubIf->Device);
750
751 DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d initialized\n", HubDev->Address));
752 return Status;
753 }
754
755
756
757 /**
758 Get the port status. This function is required to
759 ACK the port change bits although it will return
760 the port changes in PortState. Bus enumeration code
761 doesn't need to ACK the port change bits.
762
763 @param HubIf The hub interface
764 @param Port The port of the hub to get state
765 @param PortState Variable to return the port state
766
767 @retval EFI_SUCCESS The port status is successfully returned
768 @retval Others Failed to return the status
769
770 **/
771 STATIC
772 EFI_STATUS
773 UsbHubGetPortStatus (
774 IN USB_INTERFACE *HubIf,
775 IN UINT8 Port,
776 OUT EFI_USB_PORT_STATUS *PortState
777 )
778 {
779 EFI_STATUS Status;
780
781 Status = UsbHubCtrlGetPortStatus (HubIf->Device, Port, PortState);
782
783 return Status;
784 }
785
786
787
788 /**
789 Clear the port change status.
790
791 @param HubIf The hub interface
792 @param Port The hub port
793
794 @return None
795
796 **/
797 STATIC
798 VOID
799 UsbHubClearPortChange (
800 IN USB_INTERFACE *HubIf,
801 IN UINT8 Port
802 )
803 {
804 EFI_USB_PORT_STATUS PortState;
805 USB_CHANGE_FEATURE_MAP *Map;
806 UINTN Index;
807 EFI_STATUS Status;
808
809 Status = UsbHubGetPortStatus (HubIf, Port, &PortState);
810
811 if (EFI_ERROR (Status)) {
812 return;
813 }
814
815 //
816 // OK, get the usb port status, now ACK the change bits.
817 // Don't return error when failed to clear the change bits.
818 // It may lead to extra port state report. USB bus should
819 // be able to handle this.
820 //
821 for (Index = 0; Index < USB_HUB_MAP_SIZE; Index++) {
822 Map = &mHubFeatureMap[Index];
823
824 if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {
825 UsbHubCtrlClearPortFeature (HubIf->Device, Port, Map->Feature);
826 }
827 }
828 }
829
830
831
832 /**
833 Function to set the port feature for non-root hub
834
835 @param HubIf The hub interface
836 @param Port The port of the hub
837 @param Feature The feature of the port to set
838
839 @retval EFI_SUCCESS The hub port feature is set
840 @retval Others Failed to set the port feature
841
842 **/
843 STATIC
844 EFI_STATUS
845 UsbHubSetPortFeature (
846 IN USB_INTERFACE *HubIf,
847 IN UINT8 Port,
848 IN EFI_USB_PORT_FEATURE Feature
849 )
850 {
851 EFI_STATUS Status;
852
853 Status = UsbHubCtrlSetPortFeature (HubIf->Device, Port, (UINT8) Feature);
854
855 return Status;
856 }
857
858
859 /**
860 Interface function to clear the port feature for non-root hub
861
862 @param HubIf The hub interface
863 @param Port The port of the hub to clear feature for
864 @param Feature The feature to clear
865
866 @retval EFI_SUCCESS The port feature is cleared
867 @retval Others Failed to clear the port feature
868
869 **/
870 STATIC
871 EFI_STATUS
872 UsbHubClearPortFeature (
873 IN USB_INTERFACE *HubIf,
874 IN UINT8 Port,
875 IN EFI_USB_PORT_FEATURE Feature
876 )
877 {
878 EFI_STATUS Status;
879
880 Status = UsbHubCtrlClearPortFeature (HubIf->Device, Port, (UINT8) Feature);
881
882 return Status;
883 }
884
885
886 /**
887 Interface funtion to reset the port
888
889 @param HubIf The hub interface
890 @param Port The port to reset
891
892 @retval EFI_SUCCESS The hub port is reset
893 @retval EFI_TIMEOUT Failed to reset the port in time
894 @retval Others Failed to reset the port
895
896 **/
897 STATIC
898 EFI_STATUS
899 UsbHubResetPort (
900 IN USB_INTERFACE *HubIf,
901 IN UINT8 Port
902 )
903 {
904 EFI_USB_PORT_STATUS PortState;
905 UINTN Index;
906 EFI_STATUS Status;
907
908 Status = UsbHubSetPortFeature (HubIf, Port, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_RESET);
909
910 if (EFI_ERROR (Status)) {
911 return Status;
912 }
913
914 //
915 // Drive the reset signal for at least 10ms. Check USB 2.0 Spec
916 // section 7.1.7.5 for timing requirements.
917 //
918 gBS->Stall (20 * USB_STALL_1_MS);
919
920 //
921 // USB hub will clear RESET bit if reset is actually finished.
922 //
923 ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));
924
925 for (Index = 0; Index < 20; Index++) {
926 Status = UsbHubGetPortStatus (HubIf, Port, &PortState);
927
928 if (!EFI_ERROR (Status) &&
929 !USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {
930
931 return EFI_SUCCESS;
932 }
933
934 gBS->Stall (5 * USB_STALL_1_MS);
935 }
936
937 return EFI_TIMEOUT;
938 }
939
940
941 /**
942 Release the hub's control of the interface
943
944 @param HubIf The hub interface
945
946 @retval EFI_SUCCESS The interface is release of hub control
947
948 **/
949 STATIC
950 EFI_STATUS
951 UsbHubRelease (
952 IN USB_INTERFACE *HubIf
953 )
954 {
955 EFI_USB_IO_PROTOCOL *UsbIo;
956 EFI_STATUS Status;
957
958 UsbIo = &HubIf->UsbIo;
959 Status = UsbIo->UsbAsyncInterruptTransfer (
960 UsbIo,
961 HubIf->HubEp->Desc.EndpointAddress,
962 FALSE,
963 USB_HUB_POLL_INTERVAL,
964 0,
965 NULL,
966 0
967 );
968
969 if (EFI_ERROR (Status)) {
970 return Status;
971 }
972
973 gBS->CloseEvent (HubIf->HubNotify);
974
975 HubIf->IsHub = FALSE;
976 HubIf->HubApi = NULL;
977 HubIf->HubEp = NULL;
978 HubIf->HubNotify = NULL;
979
980 DEBUG (( EFI_D_INFO, "UsbHubRelease: hub device %d released\n", HubIf->Device->Address));
981 return EFI_SUCCESS;
982 }
983
984
985
986 /**
987 Initialize the interface for root hub
988
989 @param HubIf The root hub interface
990
991 @retval EFI_SUCCESS The interface is initialied for root hub
992 @retval Others Failed to initialize the hub
993
994 **/
995 STATIC
996 EFI_STATUS
997 UsbRootHubInit (
998 IN USB_INTERFACE *HubIf
999 )
1000 {
1001 EFI_STATUS Status;
1002 UINT8 MaxSpeed;
1003 UINT8 NumOfPort;
1004 UINT8 Support64;
1005
1006 Status = UsbHcGetCapability (HubIf->Device->Bus, &MaxSpeed, &NumOfPort, &Support64);
1007
1008 if (EFI_ERROR (Status)) {
1009 return Status;
1010 }
1011
1012 DEBUG (( EFI_D_INFO, "UsbRootHubInit: root hub %x - max speed %d, %d ports\n",
1013 HubIf, MaxSpeed, NumOfPort));
1014
1015 HubIf->IsHub = TRUE;
1016 HubIf->HubApi = &mUsbRootHubApi;
1017 HubIf->HubEp = NULL;
1018 HubIf->MaxSpeed = MaxSpeed;
1019 HubIf->NumOfPort = NumOfPort;
1020 HubIf->HubNotify = NULL;
1021
1022 //
1023 // Create a timer to poll root hub ports periodically
1024 //
1025 Status = gBS->CreateEvent (
1026 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1027 TPL_CALLBACK,
1028 UsbRootHubEnumeration,
1029 HubIf,
1030 &HubIf->HubNotify
1031 );
1032
1033 if (EFI_ERROR (Status)) {
1034 return Status;
1035 }
1036
1037 //
1038 // It should signal the event immediately here, or device detection
1039 // by bus enumeration might be delayed by the timer interval.
1040 //
1041 gBS->SignalEvent (HubIf->HubNotify);
1042
1043 Status = gBS->SetTimer (
1044 HubIf->HubNotify,
1045 TimerPeriodic,
1046 USB_ROOTHUB_POLL_INTERVAL
1047 );
1048
1049 if (EFI_ERROR (Status)) {
1050 gBS->CloseEvent (HubIf->HubNotify);
1051 }
1052
1053 return Status;
1054 }
1055
1056
1057
1058 /**
1059 Get the port status. This function is required to
1060 ACK the port change bits although it will return
1061 the port changes in PortState. Bus enumeration code
1062 doesn't need to ACK the port change bits.
1063
1064 @param HubIf The root hub interface
1065 @param Port The root hub port to get the state
1066 @param PortState Variable to return the port state
1067
1068 @retval EFI_SUCCESS The port state is returned
1069 @retval Others Failed to retrieve the port state
1070
1071 **/
1072 STATIC
1073 EFI_STATUS
1074 UsbRootHubGetPortStatus (
1075 IN USB_INTERFACE *HubIf,
1076 IN UINT8 Port,
1077 OUT EFI_USB_PORT_STATUS *PortState
1078 )
1079 {
1080 USB_BUS *Bus;
1081 EFI_STATUS Status;
1082
1083 Bus = HubIf->Device->Bus;
1084 Status = UsbHcGetRootHubPortStatus (Bus, Port, PortState);
1085
1086 return Status;
1087 }
1088
1089
1090 /**
1091 Clear the port change status.
1092
1093 @param HubIf The root hub interface
1094 @param Port The root hub port
1095
1096 @retval EFI_SUCCESS The port state is returned
1097 @retval Others Failed to retrieve the port state
1098
1099 **/
1100 STATIC
1101 VOID
1102 UsbRootHubClearPortChange (
1103 IN USB_INTERFACE *HubIf,
1104 IN UINT8 Port
1105 )
1106 {
1107 EFI_USB_PORT_STATUS PortState;
1108 USB_CHANGE_FEATURE_MAP *Map;
1109 UINTN Index;
1110 EFI_STATUS Status;
1111
1112 Status = UsbRootHubGetPortStatus (HubIf, Port, &PortState);
1113
1114 if (EFI_ERROR (Status)) {
1115 return;
1116 }
1117
1118 //
1119 // OK, get the usb port status, now ACK the change bits.
1120 // Don't return error when failed to clear the change bits.
1121 // It may lead to extra port state report. USB bus should
1122 // be able to handle this.
1123 //
1124 for (Index = 0; Index < USB_ROOT_HUB_MAP_SIZE; Index++) {
1125 Map = &mRootHubFeatureMap[Index];
1126
1127 if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {
1128 UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, (EFI_USB_PORT_FEATURE) Map->Feature);
1129 }
1130 }
1131 }
1132
1133
1134
1135 /**
1136 Set the root hub port feature
1137
1138 @param HubIf The Usb hub interface
1139 @param Port The hub port
1140 @param Feature The feature to set
1141
1142 @retval EFI_SUCCESS The root hub port is set with the feature
1143 @retval Others Failed to set the feature
1144
1145 **/
1146 STATIC
1147 EFI_STATUS
1148 UsbRootHubSetPortFeature (
1149 IN USB_INTERFACE *HubIf,
1150 IN UINT8 Port,
1151 IN EFI_USB_PORT_FEATURE Feature
1152 )
1153 {
1154 EFI_STATUS Status;
1155
1156 Status = UsbHcSetRootHubPortFeature (HubIf->Device->Bus, Port, Feature);
1157
1158 return Status;
1159 }
1160
1161
1162 /**
1163 Clear the root hub port feature
1164
1165 @param HubIf The root hub interface
1166 @param Port The root hub port
1167 @param Feature The feature to clear
1168
1169 @retval EFI_SUCCESS The root hub port is cleared of the feature
1170 @retval Others Failed to clear the feature
1171
1172 **/
1173 STATIC
1174 EFI_STATUS
1175 UsbRootHubClearPortFeature (
1176 IN USB_INTERFACE *HubIf,
1177 IN UINT8 Port,
1178 IN EFI_USB_PORT_FEATURE Feature
1179 )
1180 {
1181 EFI_STATUS Status;
1182
1183 Status = UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, Feature);
1184
1185 return Status;
1186 }
1187
1188
1189 /**
1190 Interface funtion to reset the root hub port
1191
1192 @param RootIf The root hub interface
1193 @param Port The port to reset
1194
1195 @retval EFI_SUCCESS The hub port is reset
1196 @retval EFI_TIMEOUT Failed to reset the port in time
1197 @retval EFI_NOT_FOUND The low/full speed device connected to high speed
1198 root hub is released to the companion UHCI
1199 @retval Others Failed to reset the port
1200
1201 **/
1202 STATIC
1203 EFI_STATUS
1204 UsbRootHubResetPort (
1205 IN USB_INTERFACE *RootIf,
1206 IN UINT8 Port
1207 )
1208 {
1209 USB_BUS *Bus;
1210 EFI_STATUS Status;
1211 EFI_USB_PORT_STATUS PortState;
1212 UINTN Index;
1213
1214 //
1215 // Notice: although EHCI requires that ENABLED bit be cleared
1216 // when reset the port, we don't need to care that here. It
1217 // should be handled in the EHCI driver.
1218 //
1219 Bus = RootIf->Device->Bus;
1220 Status = UsbHcSetRootHubPortFeature (Bus, Port, EfiUsbPortReset);
1221
1222 if (EFI_ERROR (Status)) {
1223 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to start reset on port %d\n", Port));
1224 return Status;
1225 }
1226
1227 //
1228 // Drive the reset signal for at least 50ms. Check USB 2.0 Spec
1229 // section 7.1.7.5 for timing requirements.
1230 //
1231 gBS->Stall (50 * USB_STALL_1_MS);
1232
1233 Status = UsbHcClearRootHubPortFeature (Bus, Port, EfiUsbPortReset);
1234
1235 if (EFI_ERROR (Status)) {
1236 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to clear reset on port %d\n", Port));
1237 return Status;
1238 }
1239
1240 gBS->Stall (USB_STALL_1_MS);
1241
1242 //
1243 // USB host controller won't clear the RESET bit until
1244 // reset is actually finished.
1245 //
1246 ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));
1247
1248 for (Index = 0; Index < USB_HUB_LOOP; Index++) {
1249 Status = UsbHcGetRootHubPortStatus (Bus, Port, &PortState);
1250
1251 if (EFI_ERROR (Status)) {
1252 return Status;
1253 }
1254
1255 if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {
1256 break;
1257 }
1258
1259 gBS->Stall (10 * USB_STALL_1_MS);
1260 }
1261
1262 if (Index == USB_HUB_LOOP) {
1263 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: reset not finished in time on port %d\n", Port));
1264 return EFI_TIMEOUT;
1265 }
1266
1267 if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_ENABLE)) {
1268 //
1269 // OK, the port is reset. If root hub is of high speed and
1270 // the device is of low/full speed, release the ownership to
1271 // companion UHCI. If root hub is of full speed, it won't
1272 // automatically enable the port, we need to enable it manually.
1273 //
1274 if (RootIf->MaxSpeed == EFI_USB_SPEED_HIGH) {
1275 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: release low/full speed device (%d) to UHCI\n", Port));
1276
1277 UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortOwner);
1278 return EFI_NOT_FOUND;
1279
1280 } else {
1281
1282 Status = UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortEnable);
1283
1284 if (EFI_ERROR (Status)) {
1285 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to enable port %d for UHCI\n", Port));
1286 return Status;
1287 }
1288
1289 gBS->Stall (20 * USB_STALL_1_MS);
1290 }
1291 }
1292
1293 return EFI_SUCCESS;
1294 }
1295
1296
1297 /**
1298 Release the root hub's control of the interface
1299
1300 @param HubIf The root hub interface
1301
1302 @retval EFI_SUCCESS The root hub's control of the interface is
1303 released.
1304
1305 **/
1306 STATIC
1307 EFI_STATUS
1308 UsbRootHubRelease (
1309 IN USB_INTERFACE *HubIf
1310 )
1311 {
1312 DEBUG (( EFI_D_INFO, "UsbRootHubRelease: root hub released for hub %x\n", HubIf));
1313
1314 gBS->SetTimer (HubIf->HubNotify, TimerCancel, USB_ROOTHUB_POLL_INTERVAL);
1315 gBS->CloseEvent (HubIf->HubNotify);
1316
1317 return EFI_SUCCESS;
1318 }
1319
1320 USB_HUB_API mUsbHubApi = {
1321 UsbHubInit,
1322 UsbHubGetPortStatus,
1323 UsbHubClearPortChange,
1324 UsbHubSetPortFeature,
1325 UsbHubClearPortFeature,
1326 UsbHubResetPort,
1327 UsbHubRelease
1328 };
1329
1330 USB_HUB_API mUsbRootHubApi = {
1331 UsbRootHubInit,
1332 UsbRootHubGetPortStatus,
1333 UsbRootHubClearPortChange,
1334 UsbRootHubSetPortFeature,
1335 UsbRootHubClearPortFeature,
1336 UsbRootHubResetPort,
1337 UsbRootHubRelease
1338 };