]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c
Clean up for GCC and Intel ICC build.
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusDxe / UsbEnumer.c
1 /** @file
2
3 Copyright (c) 2007 - 2008, 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
292 //
293 // Only recursively wanted usb child device
294 //
295 if (UsbBusIsWantedUsbIO (UsbIf->Device->Bus, UsbIf)) {
296 OldTpl = UsbGetCurrentTpl ();
297 DEBUG ((EFI_D_INFO, "UsbConnectDriver: TPL before connect is %d\n", OldTpl));
298
299 gBS->RestoreTPL (TPL_CALLBACK);
300
301 Status = gBS->ConnectController (UsbIf->Handle, NULL, NULL, TRUE);
302 UsbIf->IsManaged = (BOOLEAN)!EFI_ERROR (Status);
303
304 DEBUG ((EFI_D_INFO, "UsbConnectDriver: TPL after connect is %d\n", UsbGetCurrentTpl()));
305 ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);
306
307 gBS->RaiseTPL (OldTpl);
308 }
309 }
310
311 return Status;
312 }
313
314
315 /**
316 Select an alternate setting for the interface.
317 Each interface can have several mutually exclusive
318 settings. Only one setting is active. It will
319 also reset its endpoints' toggle to zero.
320
321 @param IfDesc The interface descriptor to set
322 @param Alternate The alternate setting number to locate
323
324 @retval EFI_NOT_FOUND There is no setting with this alternate index
325 @retval EFI_SUCCESS The interface is set to Alternate setting.
326
327 **/
328 EFI_STATUS
329 UsbSelectSetting (
330 IN USB_INTERFACE_DESC *IfDesc,
331 IN UINT8 Alternate
332 )
333 {
334 USB_INTERFACE_SETTING *Setting;
335 UINT8 Index;
336
337 //
338 // Locate the active alternate setting
339 //
340 Setting = NULL;
341
342 for (Index = 0; Index < IfDesc->NumOfSetting; Index++) {
343 Setting = IfDesc->Settings[Index];
344
345 if (Setting->Desc.AlternateSetting == Alternate) {
346 break;
347 }
348 }
349
350 if (Index == IfDesc->NumOfSetting) {
351 return EFI_NOT_FOUND;
352 }
353
354 IfDesc->ActiveIndex = Index;
355
356 DEBUG ((EFI_D_INFO, "UsbSelectSetting: setting %d selected for interface %d\n",
357 Alternate, Setting->Desc.InterfaceNumber));
358
359 //
360 // Reset the endpoint toggle to zero
361 //
362 for (Index = 0; Index < Setting->Desc.NumEndpoints; Index++) {
363 Setting->Endpoints[Index]->Toggle = 0;
364 }
365
366 return EFI_SUCCESS;
367 }
368
369
370 /**
371 Select a new configuration for the device. Each
372 device may support several configurations.
373
374 @param Device The device to select configuration
375 @param ConfigValue The index of the configuration ( != 0)
376
377 @retval EFI_NOT_FOUND There is no configuration with the index
378 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource
379 @retval EFI_SUCCESS The configuration is selected.
380
381 **/
382 EFI_STATUS
383 UsbSelectConfig (
384 IN USB_DEVICE *Device,
385 IN UINT8 ConfigValue
386 )
387 {
388 USB_DEVICE_DESC *DevDesc;
389 USB_CONFIG_DESC *ConfigDesc;
390 USB_INTERFACE_DESC *IfDesc;
391 USB_INTERFACE *UsbIf;
392 EFI_STATUS Status;
393 UINT8 Index;
394
395 //
396 // Locate the active config, then set the device's pointer
397 //
398 DevDesc = Device->DevDesc;
399 ConfigDesc = NULL;
400
401 for (Index = 0; Index < DevDesc->Desc.NumConfigurations; Index++) {
402 ConfigDesc = DevDesc->Configs[Index];
403
404 if (ConfigDesc->Desc.ConfigurationValue == ConfigValue) {
405 break;
406 }
407 }
408
409 if (Index == DevDesc->Desc.NumConfigurations) {
410 return EFI_NOT_FOUND;
411 }
412
413 Device->ActiveConfig = ConfigDesc;
414
415 DEBUG ((EFI_D_INFO, "UsbSelectConfig: config %d selected for device %d\n",
416 ConfigValue, Device->Address));
417
418 //
419 // Create interfaces for each USB interface descriptor.
420 //
421 for (Index = 0; Index < ConfigDesc->Desc.NumInterfaces; Index++) {
422 //
423 // First select the default interface setting, and reset
424 // the endpoint toggles to zero for its endpoints.
425 //
426 IfDesc = ConfigDesc->Interfaces[Index];
427 UsbSelectSetting (IfDesc, IfDesc->Settings[0]->Desc.AlternateSetting);
428
429 //
430 // Create a USB_INTERFACE and install USB_IO and other protocols
431 //
432 UsbIf = UsbCreateInterface (Device, ConfigDesc->Interfaces[Index]);
433
434 if (UsbIf == NULL) {
435 return EFI_OUT_OF_RESOURCES;
436 }
437
438 Device->Interfaces[Index] = UsbIf;
439
440 //
441 // Connect the device to drivers, if it failed, ignore
442 // the error. Don't let the unsupported interfaces to block
443 // the supported interfaces.
444 //
445 Status = UsbConnectDriver (UsbIf);
446
447 if (EFI_ERROR (Status)) {
448 DEBUG ((EFI_D_ERROR, "UsbSelectConfig: failed to connect driver %r, ignored\n", Status));
449 }
450 }
451
452 Device->NumOfInterface = Index;
453
454 return EFI_SUCCESS;
455 }
456
457
458
459 /**
460 Disconnect the USB interface with its driver.
461
462 @param UsbIf The interface to disconnect driver from
463
464 @return None
465
466 **/
467 STATIC
468 VOID
469 UsbDisconnectDriver (
470 IN USB_INTERFACE *UsbIf
471 )
472 {
473 EFI_TPL OldTpl;
474
475 //
476 // Release the hub if it's a hub controller, otherwise
477 // disconnect the driver if it is managed by other drivers.
478 //
479 if (UsbIf->IsHub) {
480 UsbIf->HubApi->Release (UsbIf);
481
482 } else if (UsbIf->IsManaged) {
483 //
484 // This function is called in both UsbIoControlTransfer and
485 // the timer callback in hub enumeration. So, at least it is
486 // called at TPL_CALLBACK. Some driver sitting on USB has
487 // twisted TPL used. It should be no problem for us to connect
488 // or disconnect at CALLBACK.
489 //
490 OldTpl = UsbGetCurrentTpl ();
491 DEBUG ((EFI_D_INFO, "UsbDisconnectDriver: old TPL is %d\n", OldTpl));
492
493 gBS->RestoreTPL (TPL_CALLBACK);
494
495 gBS->DisconnectController (UsbIf->Handle, NULL, NULL);
496 UsbIf->IsManaged = FALSE;
497
498 DEBUG (( EFI_D_INFO, "UsbDisconnectDriver: TPL after disconnect is %d\n", UsbGetCurrentTpl()));
499 ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);
500
501 gBS->RaiseTPL (OldTpl);
502 }
503 }
504
505
506
507 /**
508 Remove the current device configuration
509
510 @param Device The USB device to remove configuration from
511
512 @return None
513
514 **/
515 VOID
516 UsbRemoveConfig (
517 IN USB_DEVICE *Device
518 )
519 {
520 USB_INTERFACE *UsbIf;
521 UINTN Index;
522
523 //
524 // Remove each interface of the device
525 //
526 for (Index = 0; Index < Device->NumOfInterface; Index++) {
527 UsbIf = Device->Interfaces[Index];
528
529 if (UsbIf == NULL) {
530 continue;
531 }
532
533 UsbDisconnectDriver (UsbIf);
534 UsbFreeInterface (UsbIf);
535 Device->Interfaces[Index] = NULL;
536 }
537
538 Device->ActiveConfig = NULL;
539 Device->NumOfInterface = 0;
540 }
541
542
543
544 /**
545 Remove the device and all its children from the bus.
546
547 @param Device The device to remove
548
549 @retval EFI_SUCCESS The device is removed
550
551 **/
552 EFI_STATUS
553 UsbRemoveDevice (
554 IN USB_DEVICE *Device
555 )
556 {
557 USB_BUS *Bus;
558 USB_DEVICE *Child;
559 EFI_STATUS Status;
560 UINT8 Index;
561
562 Bus = Device->Bus;
563
564 //
565 // Remove all the devices on its downstream ports. Search from devices[1].
566 // Devices[0] is the root hub.
567 //
568 for (Index = 1; Index < USB_MAX_DEVICES; Index++) {
569 Child = Bus->Devices[Index];
570
571 if ((Child == NULL) || (Child->ParentAddr != Device->Address)) {
572 continue;
573 }
574
575 Status = UsbRemoveDevice (Child);
576
577 if (EFI_ERROR (Status)) {
578 DEBUG ((EFI_D_ERROR, "UsbRemoveDevice: failed to remove child, ignore error\n"));
579 Bus->Devices[Index] = NULL;
580 }
581 }
582
583 UsbRemoveConfig (Device);
584
585 DEBUG (( EFI_D_INFO, "UsbRemoveDevice: device %d removed\n", Device->Address));
586
587 Bus->Devices[Device->Address] = NULL;
588 UsbFreeDevice (Device);
589
590 return EFI_SUCCESS;
591 }
592
593
594 /**
595 Find the child device on the hub's port
596
597 @param HubIf The hub interface
598 @param Port The port of the hub this child is connected to
599
600 @return The device on the hub's port, or NULL if there is none
601
602 **/
603 STATIC
604 USB_DEVICE *
605 UsbFindChild (
606 IN USB_INTERFACE *HubIf,
607 IN UINT8 Port
608 )
609 {
610 USB_DEVICE *Device;
611 USB_BUS *Bus;
612 UINTN Index;
613
614 Bus = HubIf->Device->Bus;
615
616 //
617 // Start checking from device 1, device 0 is the root hub
618 //
619 for (Index = 1; Index < USB_MAX_DEVICES; Index++) {
620 Device = Bus->Devices[Index];
621
622 if ((Device != NULL) && (Device->ParentAddr == HubIf->Device->Address) &&
623 (Device->ParentPort == Port)) {
624
625 return Device;
626 }
627 }
628
629 return NULL;
630 }
631
632
633
634 /**
635 Enumerate and configure the new device on the port of this HUB interface.
636
637 @param HubIf The HUB that has the device connected
638 @param Port The port index of the hub (started with zero)
639
640 @retval EFI_SUCCESS The device is enumerated (added or removed)
641 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the device
642 @retval Others Failed to enumerate the device
643
644 **/
645 STATIC
646 EFI_STATUS
647 UsbEnumerateNewDev (
648 IN USB_INTERFACE *HubIf,
649 IN UINT8 Port
650 )
651 {
652 USB_BUS *Bus;
653 USB_HUB_API *HubApi;
654 USB_DEVICE *Child;
655 USB_DEVICE *Parent;
656 EFI_USB_PORT_STATUS PortState;
657 UINT8 Address;
658 UINT8 Config;
659 EFI_STATUS Status;
660
661 Address = USB_MAX_DEVICES;
662 Parent = HubIf->Device;
663 Bus = Parent->Bus;
664 HubApi = HubIf->HubApi;
665
666 gBS->Stall (USB_WAIT_PORT_STABLE_STALL);
667
668 //
669 // Hub resets the device for at least 10 milliseconds.
670 // Host learns device speed. If device is of low/full speed
671 // and the hub is a EHCI root hub, ResetPort will release
672 // the device to its companion UHCI and return an error.
673 //
674 Status = HubApi->ResetPort (HubIf, Port);
675
676 if (EFI_ERROR (Status)) {
677 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to reset port %d - %r\n", Port, Status));
678
679 return Status;
680 }
681
682 DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: hub port %d is reset\n", Port));
683
684 Child = UsbCreateDevice (HubIf, Port);
685
686 if (Child == NULL) {
687 return EFI_OUT_OF_RESOURCES;
688 }
689
690 //
691 // OK, now identify the device speed. After reset, hub
692 // fully knows the actual device speed.
693 //
694 Status = HubApi->GetPortStatus (HubIf, Port, &PortState);
695
696 if (EFI_ERROR (Status)) {
697 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to get speed of port %d\n", Port));
698 goto ON_ERROR;
699 }
700
701 if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
702 Child->Speed = EFI_USB_SPEED_LOW;
703
704 } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
705 Child->Speed = EFI_USB_SPEED_HIGH;
706
707 } else {
708 Child->Speed = EFI_USB_SPEED_FULL;
709 }
710
711 DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device is of %d speed\n", Child->Speed));
712
713 if (Child->Speed != EFI_USB_SPEED_HIGH) {
714 //
715 // If the child isn't a high speed device, it is necessary to
716 // set the transaction translator. Port TT is 1-based.
717 // This is quite simple:
718 // 1. if parent is of high speed, then parent is our translator
719 // 2. otherwise use parent's translator.
720 //
721 if (Parent->Speed == EFI_USB_SPEED_HIGH) {
722 Child->Translator.TranslatorHubAddress = Parent->Address;
723 Child->Translator.TranslatorPortNumber = (UINT8) (Port + 1);
724
725 } else {
726 Child->Translator = Parent->Translator;
727 }
728
729 DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device uses translator (%d, %d)\n",
730 Child->Translator.TranslatorHubAddress,
731 Child->Translator.TranslatorPortNumber));
732 }
733
734 //
735 // After port is reset, hub establishes a signal path between
736 // the device and host (DEFALUT state). Device's registers are
737 // reset, use default address 0 (host enumerates one device at
738 // a time) , and ready to respond to control transfer at EP 0.
739 //
740
741 //
742 // Host sends a Get_Descriptor request to learn the max packet
743 // size of default pipe (only part of the device's descriptor).
744 //
745 Status = UsbGetMaxPacketSize0 (Child);
746
747 if (EFI_ERROR (Status)) {
748 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to get max packet for EP 0 - %r\n", Status));
749 goto ON_ERROR;
750 }
751
752 DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: max packet size for EP 0 is %d\n", Child->MaxPacket0));
753
754 //
755 // Host assigns an address to the device. Device completes the
756 // status stage with default address, then switches to new address.
757 // ADDRESS state. Address zero is reserved for root hub.
758 //
759 for (Address = 1; Address < USB_MAX_DEVICES; Address++) {
760 if (Bus->Devices[Address] == NULL) {
761 break;
762 }
763 }
764
765 if (Address == USB_MAX_DEVICES) {
766 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: address pool is full for port %d\n", Port));
767
768 Status = EFI_ACCESS_DENIED;
769 goto ON_ERROR;
770 }
771
772 Bus->Devices[Address] = Child;
773 Status = UsbSetAddress (Child, Address);
774 Child->Address = Address;
775
776 if (EFI_ERROR (Status)) {
777 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to set device address - %r\n", Status));
778 goto ON_ERROR;
779 }
780
781 gBS->Stall (USB_SET_DEVICE_ADDRESS_STALL);
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 // Case1:
890 // Both OverCurrent and OverCurrentChange set, means over current occurs,
891 // which probably is caused by short circuit. It has to wait system hardware
892 // to perform recovery.
893 //
894 DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: Critical Over Current\n", Port));
895 return EFI_DEVICE_ERROR;
896
897 }
898 //
899 // Case2:
900 // Only OverCurrentChange set, means system has been recoveried from
901 // over current. As a result, all ports are nearly power-off, so
902 // it's necessary to detach and enumerate all ports again.
903 //
904 DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: 2.0 device Recovery Over Current\n", Port));
905 }
906
907 if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_ENABLE)) {
908 //
909 // Case3:
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 }
916
917 if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_CONNECTION)) {
918 //
919 // Case4:
920 // Device connected or disconnected normally.
921 //
922 DEBUG ((EFI_D_ERROR, "UsbEnumeratePort: Device Connect/Discount Normally\n", Port));
923 }
924
925 //
926 // Following as the above cases, it's safety to remove and create again.
927 //
928 Child = UsbFindChild (HubIf, Port);
929
930 if (Child != NULL) {
931 DEBUG (( EFI_D_INFO, "UsbEnumeratePort: device at port %d removed from system\n", Port));
932 UsbRemoveDevice (Child);
933 }
934
935 if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {
936 //
937 // Now, new device connected, enumerate and configure the device
938 //
939 DEBUG (( EFI_D_INFO, "UsbEnumeratePort: new device connected at port %d\n", Port));
940 Status = UsbEnumerateNewDev (HubIf, Port);
941
942 } else {
943 DEBUG (( EFI_D_INFO, "UsbEnumeratePort: device disconnected event on port %d\n", Port));
944 }
945
946 HubApi->ClearPortChange (HubIf, Port);
947 return Status;
948 }
949
950
951 /**
952 Enumerate all the changed hub ports
953
954 @param Event The event that is triggered
955 @param Context The context to the event
956
957 @return None
958
959 **/
960 VOID
961 UsbHubEnumeration (
962 IN EFI_EVENT Event,
963 IN VOID *Context
964 )
965 {
966 USB_INTERFACE *HubIf;
967 UINT8 Byte;
968 UINT8 Bit;
969 UINT8 Index;
970
971 ASSERT (Context);
972
973 HubIf = (USB_INTERFACE *) Context;
974
975 if (HubIf->ChangeMap == NULL) {
976 return ;
977 }
978
979 //
980 // HUB starts its port index with 1.
981 //
982 Byte = 0;
983 Bit = 1;
984
985 for (Index = 0; Index < HubIf->NumOfPort; Index++) {
986 if (USB_BIT_IS_SET (HubIf->ChangeMap[Byte], USB_BIT (Bit))) {
987 UsbEnumeratePort (HubIf, Index);
988 }
989
990 USB_NEXT_BIT (Byte, Bit);
991 }
992
993 UsbHubAckHubStatus (HubIf->Device);
994
995 gBS->FreePool (HubIf->ChangeMap);
996 HubIf->ChangeMap = NULL;
997 return ;
998 }
999
1000
1001 /**
1002 Enumerate all the changed hub ports
1003
1004 @param Event The event that is triggered
1005 @param Context The context to the event
1006
1007 @return None
1008
1009 **/
1010 VOID
1011 EFIAPI
1012 UsbRootHubEnumeration (
1013 IN EFI_EVENT Event,
1014 IN VOID *Context
1015 )
1016 {
1017 USB_INTERFACE *RootHub;
1018 UINT8 Index;
1019
1020 RootHub = (USB_INTERFACE *) Context;
1021
1022 for (Index = 0; Index < RootHub->NumOfPort; Index++) {
1023 UsbEnumeratePort (RootHub, Index);
1024 }
1025 }