]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c
Fixed unexpected timeout in Usb MassStorage Driver.
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusDxe / UsbEnumer.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 UsbEnumer.c
15
16 Abstract:
17
18 Usb bus enumeration support
19
20 Revision History
21
22
23 **/
24
25 #include "UsbBus.h"
26
27
28 /**
29 Return the endpoint descriptor in this interface
30
31 @param UsbIf The interface to search in
32 @param EpAddr The address of the endpoint to return
33
34 @return The endpoint descriptor or NULL
35
36 **/
37 USB_ENDPOINT_DESC *
38 UsbGetEndpointDesc (
39 IN USB_INTERFACE *UsbIf,
40 IN UINT8 EpAddr
41 )
42 {
43 USB_ENDPOINT_DESC *EpDesc;
44 UINTN Index;
45
46 for (Index = 0; Index < UsbIf->IfSetting->Desc.NumEndpoints; Index++) {
47 EpDesc = UsbIf->IfSetting->Endpoints[Index];
48
49 if (EpDesc->Desc.EndpointAddress == EpAddr) {
50 return EpDesc;
51 }
52 }
53
54 return NULL;
55 }
56
57
58 /**
59 Free the resource used by USB interface
60
61 @param UsbIf The USB interface to free
62
63 @return None
64
65 **/
66 STATIC
67 VOID
68 UsbFreeInterface (
69 IN USB_INTERFACE *UsbIf
70 )
71 {
72 UsbCloseHostProtoByChild (UsbIf->Device->Bus, UsbIf->Handle);
73
74 gBS->UninstallMultipleProtocolInterfaces (
75 UsbIf->Handle,
76 &gEfiDevicePathProtocolGuid,
77 UsbIf->DevicePath,
78 &gEfiUsbIoProtocolGuid,
79 &UsbIf->UsbIo,
80 NULL
81 );
82
83 if (UsbIf->DevicePath != NULL) {
84 gBS->FreePool (UsbIf->DevicePath);
85 }
86
87 gBS->FreePool (UsbIf);
88 }
89
90
91 /**
92 Create an interface for the descriptor IfDesc. Each
93 device's configuration can have several interfaces.
94
95 @param Device The device has the interface descriptor
96 @param IfDesc The interface descriptor
97
98 @return The created USB interface for the descriptor, or NULL.
99
100 **/
101 STATIC
102 USB_INTERFACE *
103 UsbCreateInterface (
104 IN USB_DEVICE *Device,
105 IN USB_INTERFACE_DESC *IfDesc
106 )
107 {
108 USB_DEVICE_PATH UsbNode;
109 USB_INTERFACE *UsbIf;
110 USB_INTERFACE *HubIf;
111 EFI_STATUS Status;
112
113 UsbIf = AllocateZeroPool (sizeof (USB_INTERFACE));
114
115 if (UsbIf == NULL) {
116 return NULL;
117 }
118
119 UsbIf->Signature = USB_INTERFACE_SIGNATURE;
120 UsbIf->Device = Device;
121 UsbIf->IfDesc = IfDesc;
122 UsbIf->IfSetting = IfDesc->Settings[IfDesc->ActiveIndex];
123
124 CopyMem (
125 &(UsbIf->UsbIo),
126 &mUsbIoProtocol,
127 sizeof (EFI_USB_IO_PROTOCOL)
128 );
129
130 //
131 // Install protocols for USBIO and device path
132 //
133 UsbNode.Header.Type = MESSAGING_DEVICE_PATH;
134 UsbNode.Header.SubType = MSG_USB_DP;
135 UsbNode.ParentPortNumber = Device->ParentPort;
136 UsbNode.InterfaceNumber = UsbIf->IfSetting->Desc.InterfaceNumber;
137
138 SetDevicePathNodeLength (&UsbNode.Header, sizeof (UsbNode));
139
140 HubIf = Device->ParentIf;
141 ASSERT (HubIf != NULL);
142
143 UsbIf->DevicePath = AppendDevicePathNode (HubIf->DevicePath, &UsbNode.Header);
144
145 if (UsbIf->DevicePath == NULL) {
146 DEBUG ((EFI_D_ERROR, "UsbCreateInterface: failed to create device path\n"));
147
148 Status = EFI_OUT_OF_RESOURCES;
149 goto ON_ERROR;
150 }
151
152 Status = gBS->InstallMultipleProtocolInterfaces (
153 &UsbIf->Handle,
154 &gEfiDevicePathProtocolGuid,
155 UsbIf->DevicePath,
156 &gEfiUsbIoProtocolGuid,
157 &UsbIf->UsbIo,
158 NULL
159 );
160
161 if (EFI_ERROR (Status)) {
162 DEBUG ((EFI_D_ERROR, "UsbCreateInterface: failed to install UsbIo - %r\n", Status));
163 goto ON_ERROR;
164 }
165
166 //
167 // Open USB Host Controller Protocol by Child
168 //
169 Status = UsbOpenHostProtoByChild (Device->Bus, UsbIf->Handle);
170
171 if (EFI_ERROR (Status)) {
172 gBS->UninstallMultipleProtocolInterfaces (
173 &UsbIf->Handle,
174 &gEfiDevicePathProtocolGuid,
175 UsbIf->DevicePath,
176 &gEfiUsbIoProtocolGuid,
177 &UsbIf->UsbIo,
178 NULL
179 );
180
181 DEBUG ((EFI_D_ERROR, "UsbCreateInterface: failed to open host for child - %r\n", Status));
182 goto ON_ERROR;
183 }
184
185 return UsbIf;
186
187 ON_ERROR:
188 if (UsbIf->DevicePath) {
189 gBS->FreePool (UsbIf->DevicePath);
190 }
191
192 gBS->FreePool (UsbIf);
193 return NULL;
194 }
195
196
197 /**
198 Free the resource used by this USB device
199
200 @param Device The USB device to free
201
202 @return None
203
204 **/
205 STATIC
206 VOID
207 UsbFreeDevice (
208 IN USB_DEVICE *Device
209 )
210 {
211 if (Device->DevDesc != NULL) {
212 UsbFreeDevDesc (Device->DevDesc);
213 }
214
215 gBS->FreePool (Device);
216 }
217
218
219 /**
220 Create a device which is on the parent's ParentPort port.
221
222 @param ParentIf The parent HUB interface
223 @param ParentPort The port on the HUB this device is connected to
224
225 @return Created USB device
226
227 **/
228 STATIC
229 USB_DEVICE *
230 UsbCreateDevice (
231 IN USB_INTERFACE *ParentIf,
232 IN UINT8 ParentPort
233 )
234 {
235 USB_DEVICE *Device;
236
237 ASSERT (ParentIf != NULL);
238
239 Device = AllocateZeroPool (sizeof (USB_DEVICE));
240
241 if (Device == NULL) {
242 return NULL;
243 }
244
245 Device->Bus = ParentIf->Device->Bus;
246 Device->MaxPacket0 = 8;
247 Device->ParentAddr = ParentIf->Device->Address;
248 Device->ParentIf = ParentIf;
249 Device->ParentPort = ParentPort;
250 return Device;
251 }
252
253
254 /**
255 Connect the USB interface with its driver. EFI USB bus will
256 create a USB interface for each seperate interface descriptor.
257
258 @param UsbIf The interface to connect driver to
259
260 @return EFI_SUCCESS : Interface is managed by some driver
261 @return Others : Failed to locate a driver for this interface
262
263 **/
264 STATIC
265 EFI_STATUS
266 UsbConnectDriver (
267 IN USB_INTERFACE *UsbIf
268 )
269 {
270 EFI_STATUS Status;
271 EFI_TPL OldTpl;
272
273 Status = EFI_SUCCESS;
274
275 //
276 // Hub is maintained by the USB bus driver. Otherwise try to
277 // connect drivers with this interface
278 //
279 if (UsbIsHubInterface (UsbIf)) {
280 DEBUG ((EFI_D_INFO, "UsbConnectDriver: found a hub device\n"));
281 Status = mUsbHubApi.Init (UsbIf);
282
283 } else {
284 //
285 // This function is called in both UsbIoControlTransfer and
286 // the timer callback in hub enumeration. So, at least it is
287 // called at TPL_CALLBACK. Some driver sitting on USB has
288 // twisted TPL used. It should be no problem for us to connect
289 // or disconnect at CALLBACK.
290 //
291 OldTpl = UsbGetCurrentTpl ();
292 DEBUG ((EFI_D_INFO, "UsbConnectDriver: TPL before connect is %d\n", OldTpl));
293
294 gBS->RestoreTPL (TPL_CALLBACK);
295
296 Status = gBS->ConnectController (UsbIf->Handle, NULL, NULL, TRUE);
297 UsbIf->IsManaged = (BOOLEAN)!EFI_ERROR (Status);
298
299 DEBUG ((EFI_D_INFO, "UsbConnectDriver: TPL after connect is %d\n", UsbGetCurrentTpl()));
300 ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);
301
302 gBS->RaiseTPL (OldTpl);
303 }
304
305 return Status;
306 }
307
308
309 /**
310 Select an alternate setting for the interface.
311 Each interface can have several mutually exclusive
312 settings. Only one setting is active. It will
313 also reset its endpoints' toggle to zero.
314
315 @param IfDesc The interface descriptor to set
316 @param Alternate The alternate setting number to locate
317
318 @retval EFI_NOT_FOUND There is no setting with this alternate index
319 @retval EFI_SUCCESS The interface is set to Alternate setting.
320
321 **/
322 EFI_STATUS
323 UsbSelectSetting (
324 IN USB_INTERFACE_DESC *IfDesc,
325 IN UINT8 Alternate
326 )
327 {
328 USB_INTERFACE_SETTING *Setting;
329 UINT8 Index;
330
331 //
332 // Locate the active alternate setting
333 //
334 Setting = NULL;
335
336 for (Index = 0; Index < IfDesc->NumOfSetting; Index++) {
337 Setting = IfDesc->Settings[Index];
338
339 if (Setting->Desc.AlternateSetting == Alternate) {
340 break;
341 }
342 }
343
344 if (Index == IfDesc->NumOfSetting) {
345 return EFI_NOT_FOUND;
346 }
347
348 IfDesc->ActiveIndex = Index;
349
350 DEBUG ((EFI_D_INFO, "UsbSelectSetting: setting %d selected for interface %d\n",
351 Alternate, Setting->Desc.InterfaceNumber));
352
353 //
354 // Reset the endpoint toggle to zero
355 //
356 for (Index = 0; Index < Setting->Desc.NumEndpoints; Index++) {
357 Setting->Endpoints[Index]->Toggle = 0;
358 }
359
360 return EFI_SUCCESS;
361 }
362
363
364 /**
365 Select a new configuration for the device. Each
366 device may support several configurations.
367
368 @param Device The device to select configuration
369 @param ConfigValue The index of the configuration ( != 0)
370
371 @retval EFI_NOT_FOUND There is no configuration with the index
372 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource
373 @retval EFI_SUCCESS The configuration is selected.
374
375 **/
376 EFI_STATUS
377 UsbSelectConfig (
378 IN USB_DEVICE *Device,
379 IN UINT8 ConfigValue
380 )
381 {
382 USB_DEVICE_DESC *DevDesc;
383 USB_CONFIG_DESC *ConfigDesc;
384 USB_INTERFACE_DESC *IfDesc;
385 USB_INTERFACE *UsbIf;
386 EFI_STATUS Status;
387 UINT8 Index;
388
389 //
390 // Locate the active config, then set the device's pointer
391 //
392 DevDesc = Device->DevDesc;
393 ConfigDesc = NULL;
394
395 for (Index = 0; Index < DevDesc->Desc.NumConfigurations; Index++) {
396 ConfigDesc = DevDesc->Configs[Index];
397
398 if (ConfigDesc->Desc.ConfigurationValue == ConfigValue) {
399 break;
400 }
401 }
402
403 if (Index == DevDesc->Desc.NumConfigurations) {
404 return EFI_NOT_FOUND;
405 }
406
407 Device->ActiveConfig = ConfigDesc;
408
409 DEBUG ((EFI_D_INFO, "UsbSelectConfig: config %d selected for device %d\n",
410 ConfigValue, Device->Address));
411
412 //
413 // Create interfaces for each USB interface descriptor.
414 //
415 for (Index = 0; Index < ConfigDesc->Desc.NumInterfaces; Index++) {
416 //
417 // First select the default interface setting, and reset
418 // the endpoint toggles to zero for its endpoints.
419 //
420 IfDesc = ConfigDesc->Interfaces[Index];
421 UsbSelectSetting (IfDesc, IfDesc->Settings[0]->Desc.AlternateSetting);
422
423 //
424 // Create a USB_INTERFACE and install USB_IO and other protocols
425 //
426 UsbIf = UsbCreateInterface (Device, ConfigDesc->Interfaces[Index]);
427
428 if (UsbIf == NULL) {
429 return EFI_OUT_OF_RESOURCES;
430 }
431
432 Device->Interfaces[Index] = UsbIf;
433
434 //
435 // Connect the device to drivers, if it failed, ignore
436 // the error. Don't let the unsupported interfaces to block
437 // the supported interfaces.
438 //
439 Status = UsbConnectDriver (UsbIf);
440
441 if (EFI_ERROR (Status)) {
442 DEBUG ((EFI_D_ERROR, "UsbSelectConfig: failed to connect driver %r, ignored\n", Status));
443 }
444 }
445
446 Device->NumOfInterface = Index;
447
448 return EFI_SUCCESS;
449 }
450
451
452
453 /**
454 Disconnect the USB interface with its driver.
455
456 @param UsbIf The interface to disconnect driver from
457
458 @return None
459
460 **/
461 STATIC
462 VOID
463 UsbDisconnectDriver (
464 IN USB_INTERFACE *UsbIf
465 )
466 {
467 EFI_TPL OldTpl;
468
469 //
470 // Release the hub if it's a hub controller, otherwise
471 // disconnect the driver if it is managed by other drivers.
472 //
473 if (UsbIf->IsHub) {
474 UsbIf->HubApi->Release (UsbIf);
475
476 } else if (UsbIf->IsManaged) {
477 //
478 // This function is called in both UsbIoControlTransfer and
479 // the timer callback in hub enumeration. So, at least it is
480 // called at TPL_CALLBACK. Some driver sitting on USB has
481 // twisted TPL used. It should be no problem for us to connect
482 // or disconnect at CALLBACK.
483 //
484 OldTpl = UsbGetCurrentTpl ();
485 DEBUG ((EFI_D_INFO, "UsbDisconnectDriver: old TPL is %d\n", OldTpl));
486
487 gBS->RestoreTPL (TPL_CALLBACK);
488
489 gBS->DisconnectController (UsbIf->Handle, NULL, NULL);
490 UsbIf->IsManaged = FALSE;
491
492 DEBUG (( EFI_D_INFO, "UsbDisconnectDriver: TPL after disconnect is %d\n", UsbGetCurrentTpl()));
493 ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);
494
495 gBS->RaiseTPL (OldTpl);
496 }
497 }
498
499
500
501 /**
502 Remove the current device configuration
503
504 @param Device The USB device to remove configuration from
505
506 @return None
507
508 **/
509 VOID
510 UsbRemoveConfig (
511 IN USB_DEVICE *Device
512 )
513 {
514 USB_INTERFACE *UsbIf;
515 UINTN Index;
516
517 //
518 // Remove each interface of the device
519 //
520 for (Index = 0; Index < Device->NumOfInterface; Index++) {
521 UsbIf = Device->Interfaces[Index];
522
523 if (UsbIf == NULL) {
524 continue;
525 }
526
527 UsbDisconnectDriver (UsbIf);
528 UsbFreeInterface (UsbIf);
529 Device->Interfaces[Index] = NULL;
530 }
531
532 Device->ActiveConfig = NULL;
533 Device->NumOfInterface = 0;
534 }
535
536
537
538 /**
539 Remove the device and all its children from the bus.
540
541 @param Device The device to remove
542
543 @retval EFI_SUCCESS The device is removed
544
545 **/
546 EFI_STATUS
547 UsbRemoveDevice (
548 IN USB_DEVICE *Device
549 )
550 {
551 USB_BUS *Bus;
552 USB_DEVICE *Child;
553 EFI_STATUS Status;
554 UINT8 Index;
555
556 Bus = Device->Bus;
557
558 //
559 // Remove all the devices on its downstream ports. Search from devices[1].
560 // Devices[0] is the root hub.
561 //
562 for (Index = 1; Index < USB_MAX_DEVICES; Index++) {
563 Child = Bus->Devices[Index];
564
565 if ((Child == NULL) || (Child->ParentAddr != Device->Address)) {
566 continue;
567 }
568
569 Status = UsbRemoveDevice (Child);
570
571 if (EFI_ERROR (Status)) {
572 DEBUG ((EFI_D_ERROR, "UsbRemoveDevice: failed to remove child, ignore error\n"));
573 Bus->Devices[Index] = NULL;
574 }
575 }
576
577 UsbRemoveConfig (Device);
578
579 DEBUG (( EFI_D_INFO, "UsbRemoveDevice: device %d removed\n", Device->Address));
580
581 Bus->Devices[Device->Address] = NULL;
582 UsbFreeDevice (Device);
583
584 return EFI_SUCCESS;
585 }
586
587
588 /**
589 Find the child device on the hub's port
590
591 @param HubIf The hub interface
592 @param Port The port of the hub this child is connected to
593
594 @return The device on the hub's port, or NULL if there is none
595
596 **/
597 STATIC
598 USB_DEVICE *
599 UsbFindChild (
600 IN USB_INTERFACE *HubIf,
601 IN UINT8 Port
602 )
603 {
604 USB_DEVICE *Device;
605 USB_BUS *Bus;
606 UINTN Index;
607
608 Bus = HubIf->Device->Bus;
609
610 //
611 // Start checking from device 1, device 0 is the root hub
612 //
613 for (Index = 1; Index < USB_MAX_DEVICES; Index++) {
614 Device = Bus->Devices[Index];
615
616 if ((Device != NULL) && (Device->ParentAddr == HubIf->Device->Address) &&
617 (Device->ParentPort == Port)) {
618
619 return Device;
620 }
621 }
622
623 return NULL;
624 }
625
626
627
628 /**
629 Enumerate and configure the new device on the port of this HUB interface.
630
631 @param HubIf The HUB that has the device connected
632 @param Port The port index of the hub (started with zero)
633
634 @retval EFI_SUCCESS The device is enumerated (added or removed)
635 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the device
636 @retval Others Failed to enumerate the device
637
638 **/
639 STATIC
640 EFI_STATUS
641 UsbEnumerateNewDev (
642 IN USB_INTERFACE *HubIf,
643 IN UINT8 Port
644 )
645 {
646 USB_BUS *Bus;
647 USB_HUB_API *HubApi;
648 USB_DEVICE *Child;
649 USB_DEVICE *Parent;
650 EFI_USB_PORT_STATUS PortState;
651 UINT8 Address;
652 UINT8 Config;
653 EFI_STATUS Status;
654
655 Address = USB_MAX_DEVICES;
656 Parent = HubIf->Device;
657 Bus = Parent->Bus;
658 HubApi = HubIf->HubApi;
659
660 gBS->Stall (USB_WAIT_PORT_STABLE_STALL);
661
662 //
663 // Hub resets the device for at least 10 milliseconds.
664 // Host learns device speed. If device is of low/full speed
665 // and the hub is a EHCI root hub, ResetPort will release
666 // the device to its companion UHCI and return an error.
667 //
668 Status = HubApi->ResetPort (HubIf, Port);
669
670 if (EFI_ERROR (Status)) {
671 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to reset port %d - %r\n", Port, Status));
672
673 return Status;
674 }
675
676 DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: hub port %d is reset\n", Port));
677
678 Child = UsbCreateDevice (HubIf, Port);
679
680 if (Child == NULL) {
681 return EFI_OUT_OF_RESOURCES;
682 }
683
684 //
685 // OK, now identify the device speed. After reset, hub
686 // fully knows the actual device speed.
687 //
688 Status = HubApi->GetPortStatus (HubIf, Port, &PortState);
689
690 if (EFI_ERROR (Status)) {
691 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to get speed of port %d\n", Port));
692 goto ON_ERROR;
693 }
694
695 if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
696 Child->Speed = EFI_USB_SPEED_LOW;
697
698 } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
699 Child->Speed = EFI_USB_SPEED_HIGH;
700
701 } else {
702 Child->Speed = EFI_USB_SPEED_FULL;
703 }
704
705 DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device is of %d speed\n", Child->Speed));
706
707 if (Child->Speed != EFI_USB_SPEED_HIGH) {
708 //
709 // If the child isn't a high speed device, it is necessary to
710 // set the transaction translator. This is quite simple:
711 // 1. if parent is of high speed, then parent is our translator
712 // 2. otherwise use parent's translator.
713 //
714 if (Parent->Speed == EFI_USB_SPEED_HIGH) {
715 Child->Translator.TranslatorHubAddress = Parent->Address;
716 Child->Translator.TranslatorPortNumber = Port;
717
718 } else {
719 Child->Translator = Parent->Translator;
720 }
721
722 DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device uses translator (%d, %d)\n",
723 Child->Translator.TranslatorHubAddress,
724 Child->Translator.TranslatorPortNumber));
725 }
726
727 //
728 // After port is reset, hub establishes a signal path between
729 // the device and host (DEFALUT state). Device¡¯s registers are
730 // reset, use default address 0 (host enumerates one device at
731 // a time) , and ready to respond to control transfer at EP 0.
732 //
733
734 //
735 // Host sends a Get_Descriptor request to learn the max packet
736 // size of default pipe (only part of the device¡¯s descriptor).
737 //
738 Status = UsbGetMaxPacketSize0 (Child);
739
740 if (EFI_ERROR (Status)) {
741 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to get max packet for EP 0 - %r\n", Status));
742 goto ON_ERROR;
743 }
744
745 DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: max packet size for EP 0 is %d\n", Child->MaxPacket0));
746
747 //
748 // Host assigns an address to the device. Device completes the
749 // status stage with default address, then switches to new address.
750 // ADDRESS state. Address zero is reserved for root hub.
751 //
752 for (Address = 1; Address < USB_MAX_DEVICES; Address++) {
753 if (Bus->Devices[Address] == NULL) {
754 break;
755 }
756 }
757
758 if (Address == USB_MAX_DEVICES) {
759 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: address pool is full for port %d\n", Port));
760
761 Status = EFI_ACCESS_DENIED;
762 goto ON_ERROR;
763 }
764
765 Bus->Devices[Address] = Child;
766 Status = UsbSetAddress (Child, Address);
767 Child->Address = Address;
768
769 if (EFI_ERROR (Status)) {
770 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to set device address - %r\n", Status));
771 goto ON_ERROR;
772 }
773
774 gBS->Stall (USB_SET_DEVICE_ADDRESS_STALL);
775
776 DEBUG ((EFI_D_INFO, "UsbEnumerateNewDev: device is now ADDRESSED at %d\n", Address));
777
778 //
779 // Host learns about the device¡¯s abilities by requesting device's
780 // entire descriptions.
781 //
782 Status = UsbBuildDescTable (Child);
783
784 if (EFI_ERROR (Status)) {
785 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to build descriptor table - %r\n", Status));
786 goto ON_ERROR;
787 }
788
789 //
790 // Select a default configuration: UEFI must set the configuration
791 // before the driver can connect to the device.
792 //
793 Config = Child->DevDesc->Configs[0]->Desc.ConfigurationValue;
794 Status = UsbSetConfig (Child, Config);
795
796 if (EFI_ERROR (Status)) {
797 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to set configure %d - %r\n", Config, Status));
798 goto ON_ERROR;
799 }
800
801 DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device %d is now in CONFIGED state\n", Address));
802
803 //
804 // Host assigns and loads a device driver.
805 //
806 Status = UsbSelectConfig (Child, Config);
807
808 if (EFI_ERROR (Status)) {
809 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to create interfaces - %r\n", Status));
810 goto ON_ERROR;
811 }
812
813 return EFI_SUCCESS;
814
815 ON_ERROR:
816 if (Address != USB_MAX_DEVICES) {
817 Bus->Devices[Address] = NULL;
818 }
819
820 if (Child != NULL) {
821 UsbFreeDevice (Child);
822 }
823
824 return Status;
825 }
826
827
828
829 /**
830 Process the events on the port.
831
832 @param HubIf The HUB that has the device connected
833 @param Port The port index of the hub (started with zero)
834
835 @retval EFI_SUCCESS The device is enumerated (added or removed)
836 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the device
837 @retval Others Failed to enumerate the device
838
839 **/
840 STATIC
841 EFI_STATUS
842 UsbEnumeratePort (
843 IN USB_INTERFACE *HubIf,
844 IN UINT8 Port
845 )
846 {
847 USB_HUB_API *HubApi;
848 USB_DEVICE *Child;
849 EFI_USB_PORT_STATUS PortState;
850 EFI_STATUS Status;
851
852 Child = NULL;
853 HubApi = HubIf->HubApi;
854
855 //
856 // Host learns of the new device by polling the hub for port changes.
857 //
858 Status = HubApi->GetPortStatus (HubIf, Port, &PortState);
859
860 if (EFI_ERROR (Status)) {
861 DEBUG ((EFI_D_ERROR, "UsbEnumeratePort: failed to get state of port %d\n", Port));
862 return Status;
863 }
864
865 if (PortState.PortChangeStatus == 0) {
866 return EFI_SUCCESS;
867 }
868
869 DEBUG (( EFI_D_INFO, "UsbEnumeratePort: port %d state - %x, change - %x\n",
870 Port, PortState.PortStatus, PortState.PortChangeStatus));
871
872 //
873 // This driver only process two kinds of events now: over current and
874 // connect/disconnect. Other three events are: ENABLE, SUSPEND, RESET.
875 // ENABLE/RESET is used to reset port. SUSPEND isn't supported.
876 //
877
878 if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_OVERCURRENT)) {
879
880 if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_OVERCURRENT)) {
881 //
882 // Case1:
883 // Both OverCurrent and OverCurrentChange set, means over current occurs,
884 // which probably is caused by short circuit. It has to wait system hardware
885 // to perform recovery.
886 //
887 DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: Critical Over Current\n", Port));
888 return EFI_DEVICE_ERROR;
889
890 }
891 //
892 // Case2:
893 // Only OverCurrentChange set, means system has been recoveried from
894 // over current. As a result, all ports are nearly power-off, so
895 // it's necessary to detach and enumerate all ports again.
896 //
897 DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: 2.0 device Recovery Over Current\n", Port));
898 }
899
900 if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_ENABLE)) {
901 //
902 // Case3:
903 // 1.1 roothub port reg doesn't reflect over-current state, while its counterpart
904 // on 2.0 roothub does. When over-current has influence on 1.1 device, the port
905 // would be disabled, so it's also necessary to detach and enumerate again.
906 //
907 DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: 1.1 device Recovery Over Current\n", Port));
908 }
909
910 if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_CONNECTION)) {
911 //
912 // Case4:
913 // Device connected or disconnected normally.
914 //
915 DEBUG ((EFI_D_ERROR, "UsbEnumeratePort: Device Connect/Discount Normally\n", Port));
916 }
917
918 //
919 // Following as the above cases, it's safety to remove and create again.
920 //
921 Child = UsbFindChild (HubIf, Port);
922
923 if (Child != NULL) {
924 DEBUG (( EFI_D_INFO, "UsbEnumeratePort: device at port %d removed from system\n", Port));
925 UsbRemoveDevice (Child);
926 }
927
928 if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {
929 //
930 // Now, new device connected, enumerate and configure the device
931 //
932 DEBUG (( EFI_D_INFO, "UsbEnumeratePort: new device connected at port %d\n", Port));
933 Status = UsbEnumerateNewDev (HubIf, Port);
934
935 } else {
936 DEBUG (( EFI_D_INFO, "UsbEnumeratePort: device disconnected event on port %d\n", Port));
937 }
938
939 HubApi->ClearPortChange (HubIf, Port);
940 return Status;
941 }
942
943
944 /**
945 Enumerate all the changed hub ports
946
947 @param Event The event that is triggered
948 @param Context The context to the event
949
950 @return None
951
952 **/
953 VOID
954 UsbHubEnumeration (
955 IN EFI_EVENT Event,
956 IN VOID *Context
957 )
958 {
959 USB_INTERFACE *HubIf;
960 UINT8 Byte;
961 UINT8 Bit;
962 UINT8 Index;
963
964 ASSERT (Context);
965
966 HubIf = (USB_INTERFACE *) Context;
967
968 if (HubIf->ChangeMap == NULL) {
969 return ;
970 }
971
972 //
973 // HUB starts its port index with 1.
974 //
975 Byte = 0;
976 Bit = 1;
977
978 for (Index = 0; Index < HubIf->NumOfPort; Index++) {
979 if (USB_BIT_IS_SET (HubIf->ChangeMap[Byte], USB_BIT (Bit))) {
980 UsbEnumeratePort (HubIf, Index);
981 }
982
983 USB_NEXT_BIT (Byte, Bit);
984 }
985
986 UsbHubAckHubStatus (HubIf->Device);
987
988 gBS->FreePool (HubIf->ChangeMap);
989 HubIf->ChangeMap = NULL;
990 return ;
991 }
992
993
994 /**
995 Enumerate all the changed hub ports
996
997 @param Event The event that is triggered
998 @param Context The context to the event
999
1000 @return None
1001
1002 **/
1003 VOID
1004 EFIAPI
1005 UsbRootHubEnumeration (
1006 IN EFI_EVENT Event,
1007 IN VOID *Context
1008 )
1009 {
1010 USB_INTERFACE *RootHub;
1011 UINT8 Index;
1012
1013 RootHub = (USB_INTERFACE *) Context;
1014
1015 for (Index = 0; Index < RootHub->NumOfPort; Index++) {
1016 UsbEnumeratePort (RootHub, Index);
1017 }
1018 }