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