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