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