]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c
Merge in some fix from R8 on USB Bus 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
661 //
662 // Wait at least 100 ms for the power on port to stable
663 //
664 gBS->Stall (100 * USB_STALL_1_MS);
665
666 //
667 // Hub resets the device for at least 10 milliseconds.
668 // Host learns device speed. If device is of low/full speed
669 // and the hub is a EHCI root hub, ResetPort will release
670 // the device to its companion UHCI and return an error.
671 //
672 Status = HubApi->ResetPort (HubIf, Port);
673
674 if (EFI_ERROR (Status)) {
675 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to reset port %d - %r\n", Port, Status));
676
677 return Status;
678 }
679
680 DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: hub port %d is reset\n", Port));
681
682 Child = UsbCreateDevice (HubIf, Port);
683
684 if (Child == NULL) {
685 return EFI_OUT_OF_RESOURCES;
686 }
687
688 //
689 // OK, now identify the device speed. After reset, hub
690 // fully knows the actual device speed.
691 //
692 Status = HubApi->GetPortStatus (HubIf, Port, &PortState);
693
694 if (EFI_ERROR (Status)) {
695 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to get speed of port %d\n", Port));
696 goto ON_ERROR;
697 }
698
699 if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
700 Child->Speed = EFI_USB_SPEED_LOW;
701
702 } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
703 Child->Speed = EFI_USB_SPEED_HIGH;
704
705 } else {
706 Child->Speed = EFI_USB_SPEED_FULL;
707 }
708
709 DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device is of %d speed\n", Child->Speed));
710
711 if (Child->Speed != EFI_USB_SPEED_HIGH) {
712 //
713 // If the child isn't a high speed device, it is necessary to
714 // set the transaction translator. This is quite simple:
715 // 1. if parent is of high speed, then parent is our translator
716 // 2. otherwise use parent's translator.
717 //
718 if (Parent->Speed == EFI_USB_SPEED_HIGH) {
719 Child->Translator.TranslatorHubAddress = Parent->Address;
720 Child->Translator.TranslatorPortNumber = Port;
721
722 } else {
723 Child->Translator = Parent->Translator;
724 }
725
726 DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device uses translator (%d, %d)\n",
727 Child->Translator.TranslatorHubAddress,
728 Child->Translator.TranslatorPortNumber));
729 }
730
731 //
732 // After port is reset, hub establishes a signal path between
733 // the device and host (DEFALUT state). Device¡¯s registers are
734 // reset, use default address 0 (host enumerates one device at
735 // a time) , and ready to respond to control transfer at EP 0.
736 //
737
738 //
739 // Host sends a Get_Descriptor request to learn the max packet
740 // size of default pipe (only part of the device¡¯s descriptor).
741 //
742 Status = UsbGetMaxPacketSize0 (Child);
743
744 if (EFI_ERROR (Status)) {
745 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to get max packet for EP 0 - %r\n", Status));
746 goto ON_ERROR;
747 }
748
749 DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: max packet size for EP 0 is %d\n", Child->MaxPacket0));
750
751 //
752 // Host assigns an address to the device. Device completes the
753 // status stage with default address, then switches to new address.
754 // ADDRESS state. Address zero is reserved for root hub.
755 //
756 for (Address = 1; Address < USB_MAX_DEVICES; Address++) {
757 if (Bus->Devices[Address] == NULL) {
758 break;
759 }
760 }
761
762 if (Address == USB_MAX_DEVICES) {
763 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: address pool is full for port %d\n", Port));
764
765 Status = EFI_ACCESS_DENIED;
766 goto ON_ERROR;
767 }
768
769 Bus->Devices[Address] = Child;
770 Status = UsbSetAddress (Child, Address);
771 Child->Address = Address;
772
773 if (EFI_ERROR (Status)) {
774 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to set device address - %r\n", Status));
775 goto ON_ERROR;
776 }
777
778 //
779 // Wait 20ms for set address to complete
780 //
781 gBS->Stall (20 * USB_STALL_1_MS);
782
783 DEBUG ((EFI_D_INFO, "UsbEnumerateNewDev: device is now ADDRESSED at %d\n", Address));
784
785 //
786 // Host learns about the device¡¯s abilities by requesting device's
787 // entire descriptions.
788 //
789 Status = UsbBuildDescTable (Child);
790
791 if (EFI_ERROR (Status)) {
792 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to build descriptor table - %r\n", Status));
793 goto ON_ERROR;
794 }
795
796 //
797 // Select a default configuration: UEFI must set the configuration
798 // before the driver can connect to the device.
799 //
800 Config = Child->DevDesc->Configs[0]->Desc.ConfigurationValue;
801 Status = UsbSetConfig (Child, Config);
802
803 if (EFI_ERROR (Status)) {
804 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to set configure %d - %r\n", Config, Status));
805 goto ON_ERROR;
806 }
807
808 DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device %d is now in CONFIGED state\n", Address));
809
810 //
811 // Host assigns and loads a device driver.
812 //
813 Status = UsbSelectConfig (Child, Config);
814
815 if (EFI_ERROR (Status)) {
816 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to create interfaces - %r\n", Status));
817 goto ON_ERROR;
818 }
819
820 return EFI_SUCCESS;
821
822 ON_ERROR:
823 if (Address != USB_MAX_DEVICES) {
824 Bus->Devices[Address] = NULL;
825 }
826
827 if (Child != NULL) {
828 UsbFreeDevice (Child);
829 }
830
831 return Status;
832 }
833
834
835
836 /**
837 Process the events on the port.
838
839 @param HubIf The HUB that has the device connected
840 @param Port The port index of the hub (started with zero)
841
842 @retval EFI_SUCCESS The device is enumerated (added or removed)
843 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the device
844 @retval Others Failed to enumerate the device
845
846 **/
847 STATIC
848 EFI_STATUS
849 UsbEnumeratePort (
850 IN USB_INTERFACE *HubIf,
851 IN UINT8 Port
852 )
853 {
854 USB_HUB_API *HubApi;
855 USB_DEVICE *Child;
856 EFI_USB_PORT_STATUS PortState;
857 EFI_STATUS Status;
858
859 Child = NULL;
860 HubApi = HubIf->HubApi;
861
862 //
863 // Host learns of the new device by polling the hub for port changes.
864 //
865 Status = HubApi->GetPortStatus (HubIf, Port, &PortState);
866
867 if (EFI_ERROR (Status)) {
868 DEBUG ((EFI_D_ERROR, "UsbEnumeratePort: failed to get state of port %d\n", Port));
869 return Status;
870 }
871
872 if (PortState.PortChangeStatus == 0) {
873 return EFI_SUCCESS;
874 }
875
876 DEBUG (( EFI_D_INFO, "UsbEnumeratePort: port %d state - %x, change - %x\n",
877 Port, PortState.PortStatus, PortState.PortChangeStatus));
878
879 //
880 // This driver only process two kinds of events now: over current and
881 // connect/disconnect. Other three events are: ENABLE, SUSPEND, RESET.
882 // ENABLE/RESET is used to reset port. SUSPEND isn't supported.
883 //
884
885 if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_OVERCURRENT)) {
886
887 if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_OVERCURRENT)) {
888 //
889 // Both OverCurrent and OverCurrentChange set, means over current occurs,
890 // which probably is caused by short circuit. It has to wait system hardware
891 // to perform recovery.
892 //
893 DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: Critical Over Current\n", Port));
894 return EFI_DEVICE_ERROR;
895
896 } else {
897 //
898 // Only OverCurrentChange set, means system has been recoveried from
899 // over current. As a result, all ports are nearly power-off, so
900 // it's necessary to detach and enumerate all ports again.
901 //
902 DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: 2.0 device Recovery Over Current\n", Port));
903 goto ON_ENUMERATE;
904
905 }
906 }
907
908 if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_ENABLE)) {
909 //
910 // 1.1 roothub port reg doesn't reflect over-current state, while its counterpart
911 // on 2.0 roothub does. When over-current has influence on 1.1 device, the port
912 // would be disabled, so it's also necessary to detach and enumerate again.
913 //
914 DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: 1.1 device Recovery Over Current\n", Port));
915 goto ON_ENUMERATE;
916 }
917
918 if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_CONNECTION)) {
919 //
920 // Device connected or disconnected normally.
921 //
922 goto ON_ENUMERATE;
923 }
924
925 ON_ENUMERATE:
926
927 //
928 // In case there is already a device on this port logically, it's safety to remove
929 // and enumerate again.
930 //
931 Child = UsbFindChild (HubIf, Port);
932
933 if (Child != NULL) {
934 DEBUG (( EFI_D_INFO, "UsbEnumeratePort: device at port %d removed from system\n", Port));
935 UsbRemoveDevice (Child);
936 }
937
938 if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {
939 //
940 // Now, new device connected, enumerate and configure the device
941 //
942 DEBUG (( EFI_D_INFO, "UsbEnumeratePort: new device connected at port %d\n", Port));
943 Status = UsbEnumerateNewDev (HubIf, Port);
944
945 } else {
946 DEBUG (( EFI_D_INFO, "UsbEnumeratePort: device disconnected event on port %d\n", Port));
947 }
948
949 HubApi->ClearPortChange (HubIf, Port);
950 return Status;
951 }
952
953
954 /**
955 Enumerate all the changed hub ports
956
957 @param Event The event that is triggered
958 @param Context The context to the event
959
960 @return None
961
962 **/
963 VOID
964 UsbHubEnumeration (
965 IN EFI_EVENT Event,
966 IN VOID *Context
967 )
968 {
969 USB_INTERFACE *HubIf;
970 UINT8 Byte;
971 UINT8 Bit;
972 UINT8 Index;
973
974 ASSERT (Context);
975
976 HubIf = (USB_INTERFACE *) Context;
977
978 if (HubIf->ChangeMap == NULL) {
979 return ;
980 }
981
982 //
983 // HUB starts its port index with 1.
984 //
985 Byte = 0;
986 Bit = 1;
987
988 for (Index = 0; Index < HubIf->NumOfPort; Index++) {
989 if (USB_BIT_IS_SET (HubIf->ChangeMap[Byte], USB_BIT (Bit))) {
990 UsbEnumeratePort (HubIf, Index);
991 }
992
993 USB_NEXT_BIT (Byte, Bit);
994 }
995
996 UsbHubAckHubStatus (HubIf->Device);
997
998 gBS->FreePool (HubIf->ChangeMap);
999 HubIf->ChangeMap = NULL;
1000 return ;
1001 }
1002
1003
1004 /**
1005 Enumerate all the changed hub ports
1006
1007 @param Event The event that is triggered
1008 @param Context The context to the event
1009
1010 @return None
1011
1012 **/
1013 VOID
1014 UsbRootHubEnumeration (
1015 IN EFI_EVENT Event,
1016 IN VOID *Context
1017 )
1018 {
1019 USB_INTERFACE *RootHub;
1020 UINT8 Index;
1021
1022 RootHub = (USB_INTERFACE *) Context;
1023
1024 for (Index = 0; Index < RootHub->NumOfPort; Index++) {
1025 UsbEnumeratePort (RootHub, Index);
1026 }
1027 }