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