]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c
Enhance the Usb bus driver to support Star with Remaining device path.
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusDxe / UsbEnumer.c
1 /** @file
2
3 Copyright (c) 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 UsbEnumer.c
15
16 Abstract:
17
18 Usb bus enumeration support
19
20 Revision History
21
22
23 **/
24
25 #include "UsbBus.h"
26
27
28 /**
29 Return the endpoint descriptor in this interface
30
31 @param UsbIf The interface to search in
32 @param EpAddr The address of the endpoint to return
33
34 @return The endpoint descriptor or NULL
35
36 **/
37 USB_ENDPOINT_DESC *
38 UsbGetEndpointDesc (
39 IN USB_INTERFACE *UsbIf,
40 IN UINT8 EpAddr
41 )
42 {
43 USB_ENDPOINT_DESC *EpDesc;
44 UINTN Index;
45
46 for (Index = 0; Index < UsbIf->IfSetting->Desc.NumEndpoints; Index++) {
47 EpDesc = UsbIf->IfSetting->Endpoints[Index];
48
49 if (EpDesc->Desc.EndpointAddress == EpAddr) {
50 return EpDesc;
51 }
52 }
53
54 return NULL;
55 }
56
57
58 /**
59 Free the resource used by USB interface
60
61 @param UsbIf The USB interface to free
62
63 @return None
64
65 **/
66 STATIC
67 VOID
68 UsbFreeInterface (
69 IN USB_INTERFACE *UsbIf
70 )
71 {
72 UsbCloseHostProtoByChild (UsbIf->Device->Bus, UsbIf->Handle);
73
74 gBS->UninstallMultipleProtocolInterfaces (
75 UsbIf->Handle,
76 &gEfiDevicePathProtocolGuid,
77 UsbIf->DevicePath,
78 &gEfiUsbIoProtocolGuid,
79 &UsbIf->UsbIo,
80 NULL
81 );
82
83 if (UsbIf->DevicePath != NULL) {
84 gBS->FreePool (UsbIf->DevicePath);
85 }
86
87 gBS->FreePool (UsbIf);
88 }
89
90
91 /**
92 Create an interface for the descriptor IfDesc. Each
93 device's configuration can have several interfaces.
94
95 @param Device The device has the interface descriptor
96 @param IfDesc The interface descriptor
97
98 @return The created USB interface for the descriptor, or NULL.
99
100 **/
101 STATIC
102 USB_INTERFACE *
103 UsbCreateInterface (
104 IN USB_DEVICE *Device,
105 IN USB_INTERFACE_DESC *IfDesc
106 )
107 {
108 USB_DEVICE_PATH UsbNode;
109 USB_INTERFACE *UsbIf;
110 USB_INTERFACE *HubIf;
111 EFI_STATUS Status;
112
113 UsbIf = AllocateZeroPool (sizeof (USB_INTERFACE));
114
115 if (UsbIf == NULL) {
116 return NULL;
117 }
118
119 UsbIf->Signature = USB_INTERFACE_SIGNATURE;
120 UsbIf->Device = Device;
121 UsbIf->IfDesc = IfDesc;
122 UsbIf->IfSetting = IfDesc->Settings[IfDesc->ActiveIndex];
123
124 CopyMem (
125 &(UsbIf->UsbIo),
126 &mUsbIoProtocol,
127 sizeof (EFI_USB_IO_PROTOCOL)
128 );
129
130 //
131 // Install protocols for USBIO and device path
132 //
133 UsbNode.Header.Type = MESSAGING_DEVICE_PATH;
134 UsbNode.Header.SubType = MSG_USB_DP;
135 UsbNode.ParentPortNumber = Device->ParentPort;
136 UsbNode.InterfaceNumber = UsbIf->IfSetting->Desc.InterfaceNumber;
137
138 SetDevicePathNodeLength (&UsbNode.Header, sizeof (UsbNode));
139
140 HubIf = Device->ParentIf;
141 ASSERT (HubIf != NULL);
142
143 UsbIf->DevicePath = AppendDevicePathNode (HubIf->DevicePath, &UsbNode.Header);
144
145 if (UsbIf->DevicePath == NULL) {
146 DEBUG ((EFI_D_ERROR, "UsbCreateInterface: failed to create device path\n"));
147
148 Status = EFI_OUT_OF_RESOURCES;
149 goto ON_ERROR;
150 }
151
152 Status = gBS->InstallMultipleProtocolInterfaces (
153 &UsbIf->Handle,
154 &gEfiDevicePathProtocolGuid,
155 UsbIf->DevicePath,
156 &gEfiUsbIoProtocolGuid,
157 &UsbIf->UsbIo,
158 NULL
159 );
160
161 if (EFI_ERROR (Status)) {
162 DEBUG ((EFI_D_ERROR, "UsbCreateInterface: failed to install UsbIo - %r\n", Status));
163 goto ON_ERROR;
164 }
165
166 //
167 // Open USB Host Controller Protocol by Child
168 //
169 Status = UsbOpenHostProtoByChild (Device->Bus, UsbIf->Handle);
170
171 if (EFI_ERROR (Status)) {
172 gBS->UninstallMultipleProtocolInterfaces (
173 &UsbIf->Handle,
174 &gEfiDevicePathProtocolGuid,
175 UsbIf->DevicePath,
176 &gEfiUsbIoProtocolGuid,
177 &UsbIf->UsbIo,
178 NULL
179 );
180
181 DEBUG ((EFI_D_ERROR, "UsbCreateInterface: failed to open host for child - %r\n", Status));
182 goto ON_ERROR;
183 }
184
185 return UsbIf;
186
187 ON_ERROR:
188 if (UsbIf->DevicePath) {
189 gBS->FreePool (UsbIf->DevicePath);
190 }
191
192 gBS->FreePool (UsbIf);
193 return NULL;
194 }
195
196
197 /**
198 Free the resource used by this USB device
199
200 @param Device The USB device to free
201
202 @return None
203
204 **/
205 STATIC
206 VOID
207 UsbFreeDevice (
208 IN USB_DEVICE *Device
209 )
210 {
211 if (Device->DevDesc != NULL) {
212 UsbFreeDevDesc (Device->DevDesc);
213 }
214
215 gBS->FreePool (Device);
216 }
217
218
219 /**
220 Create a device which is on the parent's ParentPort port.
221
222 @param ParentIf The parent HUB interface
223 @param ParentPort The port on the HUB this device is connected to
224
225 @return Created USB device
226
227 **/
228 STATIC
229 USB_DEVICE *
230 UsbCreateDevice (
231 IN USB_INTERFACE *ParentIf,
232 IN UINT8 ParentPort
233 )
234 {
235 USB_DEVICE *Device;
236
237 ASSERT (ParentIf != NULL);
238
239 Device = AllocateZeroPool (sizeof (USB_DEVICE));
240
241 if (Device == NULL) {
242 return NULL;
243 }
244
245 Device->Bus = ParentIf->Device->Bus;
246 Device->MaxPacket0 = 8;
247 Device->ParentAddr = ParentIf->Device->Address;
248 Device->ParentIf = ParentIf;
249 Device->ParentPort = ParentPort;
250 return Device;
251 }
252
253
254 /**
255 Connect the USB interface with its driver. EFI USB bus will
256 create a USB interface for each seperate interface descriptor.
257
258 @param UsbIf The interface to connect driver to
259
260 @return EFI_SUCCESS : Interface is managed by some driver
261 @return Others : Failed to locate a driver for this interface
262
263 **/
264 STATIC
265 EFI_STATUS
266 UsbConnectDriver (
267 IN USB_INTERFACE *UsbIf
268 )
269 {
270 EFI_STATUS Status;
271 EFI_TPL OldTpl;
272
273 Status = EFI_SUCCESS;
274
275 //
276 // Hub is maintained by the USB bus driver. Otherwise try to
277 // connect drivers with this interface
278 //
279 if (UsbIsHubInterface (UsbIf)) {
280 DEBUG ((EFI_D_INFO, "UsbConnectDriver: found a hub device\n"));
281 Status = mUsbHubApi.Init (UsbIf);
282
283 } else {
284 //
285 // This function is called in both UsbIoControlTransfer and
286 // the timer callback in hub enumeration. So, at least it is
287 // called at TPL_CALLBACK. Some driver sitting on USB has
288 // twisted TPL used. It should be no problem for us to connect
289 // or disconnect at CALLBACK.
290 //
291
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. This is quite simple:
717 // 1. if parent is of high speed, then parent is our translator
718 // 2. otherwise use parent's translator.
719 //
720 if (Parent->Speed == EFI_USB_SPEED_HIGH) {
721 Child->Translator.TranslatorHubAddress = Parent->Address;
722 Child->Translator.TranslatorPortNumber = Port;
723
724 } else {
725 Child->Translator = Parent->Translator;
726 }
727
728 DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device uses translator (%d, %d)\n",
729 Child->Translator.TranslatorHubAddress,
730 Child->Translator.TranslatorPortNumber));
731 }
732
733 //
734 // After port is reset, hub establishes a signal path between
735 // the device and host (DEFALUT state). Device¡¯s registers are
736 // reset, use default address 0 (host enumerates one device at
737 // a time) , and ready to respond to control transfer at EP 0.
738 //
739
740 //
741 // Host sends a Get_Descriptor request to learn the max packet
742 // size of default pipe (only part of the device¡¯s descriptor).
743 //
744 Status = UsbGetMaxPacketSize0 (Child);
745
746 if (EFI_ERROR (Status)) {
747 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to get max packet for EP 0 - %r\n", Status));
748 goto ON_ERROR;
749 }
750
751 DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: max packet size for EP 0 is %d\n", Child->MaxPacket0));
752
753 //
754 // Host assigns an address to the device. Device completes the
755 // status stage with default address, then switches to new address.
756 // ADDRESS state. Address zero is reserved for root hub.
757 //
758 for (Address = 1; Address < USB_MAX_DEVICES; Address++) {
759 if (Bus->Devices[Address] == NULL) {
760 break;
761 }
762 }
763
764 if (Address == USB_MAX_DEVICES) {
765 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: address pool is full for port %d\n", Port));
766
767 Status = EFI_ACCESS_DENIED;
768 goto ON_ERROR;
769 }
770
771 Bus->Devices[Address] = Child;
772 Status = UsbSetAddress (Child, Address);
773 Child->Address = Address;
774
775 if (EFI_ERROR (Status)) {
776 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to set device address - %r\n", Status));
777 goto ON_ERROR;
778 }
779
780 gBS->Stall (USB_SET_DEVICE_ADDRESS_STALL);
781
782 DEBUG ((EFI_D_INFO, "UsbEnumerateNewDev: device is now ADDRESSED at %d\n", Address));
783
784 //
785 // Host learns about the device¡¯s abilities by requesting device's
786 // entire descriptions.
787 //
788 Status = UsbBuildDescTable (Child);
789
790 if (EFI_ERROR (Status)) {
791 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to build descriptor table - %r\n", Status));
792 goto ON_ERROR;
793 }
794
795 //
796 // Select a default configuration: UEFI must set the configuration
797 // before the driver can connect to the device.
798 //
799 Config = Child->DevDesc->Configs[0]->Desc.ConfigurationValue;
800 Status = UsbSetConfig (Child, Config);
801
802 if (EFI_ERROR (Status)) {
803 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to set configure %d - %r\n", Config, Status));
804 goto ON_ERROR;
805 }
806
807 DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device %d is now in CONFIGED state\n", Address));
808
809 //
810 // Host assigns and loads a device driver.
811 //
812 Status = UsbSelectConfig (Child, Config);
813
814 if (EFI_ERROR (Status)) {
815 DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to create interfaces - %r\n", Status));
816 goto ON_ERROR;
817 }
818
819 return EFI_SUCCESS;
820
821 ON_ERROR:
822 if (Address != USB_MAX_DEVICES) {
823 Bus->Devices[Address] = NULL;
824 }
825
826 if (Child != NULL) {
827 UsbFreeDevice (Child);
828 }
829
830 return Status;
831 }
832
833
834
835 /**
836 Process the events on the port.
837
838 @param HubIf The HUB that has the device connected
839 @param Port The port index of the hub (started with zero)
840
841 @retval EFI_SUCCESS The device is enumerated (added or removed)
842 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the device
843 @retval Others Failed to enumerate the device
844
845 **/
846 STATIC
847 EFI_STATUS
848 UsbEnumeratePort (
849 IN USB_INTERFACE *HubIf,
850 IN UINT8 Port
851 )
852 {
853 USB_HUB_API *HubApi;
854 USB_DEVICE *Child;
855 EFI_USB_PORT_STATUS PortState;
856 EFI_STATUS Status;
857
858 Child = NULL;
859 HubApi = HubIf->HubApi;
860
861 //
862 // Host learns of the new device by polling the hub for port changes.
863 //
864 Status = HubApi->GetPortStatus (HubIf, Port, &PortState);
865
866 if (EFI_ERROR (Status)) {
867 DEBUG ((EFI_D_ERROR, "UsbEnumeratePort: failed to get state of port %d\n", Port));
868 return Status;
869 }
870
871 if (PortState.PortChangeStatus == 0) {
872 return EFI_SUCCESS;
873 }
874
875 DEBUG (( EFI_D_INFO, "UsbEnumeratePort: port %d state - %x, change - %x\n",
876 Port, PortState.PortStatus, PortState.PortChangeStatus));
877
878 //
879 // This driver only process two kinds of events now: over current and
880 // connect/disconnect. Other three events are: ENABLE, SUSPEND, RESET.
881 // ENABLE/RESET is used to reset port. SUSPEND isn't supported.
882 //
883
884 if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_OVERCURRENT)) {
885
886 if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_OVERCURRENT)) {
887 //
888 // Case1:
889 // Both OverCurrent and OverCurrentChange set, means over current occurs,
890 // which probably is caused by short circuit. It has to wait system hardware
891 // to perform recovery.
892 //
893 DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: Critical Over Current\n", Port));
894 return EFI_DEVICE_ERROR;
895
896 }
897 //
898 // Case2:
899 // Only OverCurrentChange set, means system has been recoveried from
900 // over current. As a result, all ports are nearly power-off, so
901 // it's necessary to detach and enumerate all ports again.
902 //
903 DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: 2.0 device Recovery Over Current\n", Port));
904 }
905
906 if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_ENABLE)) {
907 //
908 // Case3:
909 // 1.1 roothub port reg doesn't reflect over-current state, while its counterpart
910 // on 2.0 roothub does. When over-current has influence on 1.1 device, the port
911 // would be disabled, so it's also necessary to detach and enumerate again.
912 //
913 DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: 1.1 device Recovery Over Current\n", Port));
914 }
915
916 if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_CONNECTION)) {
917 //
918 // Case4:
919 // Device connected or disconnected normally.
920 //
921 DEBUG ((EFI_D_ERROR, "UsbEnumeratePort: Device Connect/Discount Normally\n", Port));
922 }
923
924 //
925 // Following as the above cases, it's safety to remove and create again.
926 //
927 Child = UsbFindChild (HubIf, Port);
928
929 if (Child != NULL) {
930 DEBUG (( EFI_D_INFO, "UsbEnumeratePort: device at port %d removed from system\n", Port));
931 UsbRemoveDevice (Child);
932 }
933
934 if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {
935 //
936 // Now, new device connected, enumerate and configure the device
937 //
938 DEBUG (( EFI_D_INFO, "UsbEnumeratePort: new device connected at port %d\n", Port));
939 Status = UsbEnumerateNewDev (HubIf, Port);
940
941 } else {
942 DEBUG (( EFI_D_INFO, "UsbEnumeratePort: device disconnected event on port %d\n", Port));
943 }
944
945 HubApi->ClearPortChange (HubIf, Port);
946 return Status;
947 }
948
949
950 /**
951 Enumerate all the changed hub ports
952
953 @param Event The event that is triggered
954 @param Context The context to the event
955
956 @return None
957
958 **/
959 VOID
960 UsbHubEnumeration (
961 IN EFI_EVENT Event,
962 IN VOID *Context
963 )
964 {
965 USB_INTERFACE *HubIf;
966 UINT8 Byte;
967 UINT8 Bit;
968 UINT8 Index;
969
970 ASSERT (Context);
971
972 HubIf = (USB_INTERFACE *) Context;
973
974 if (HubIf->ChangeMap == NULL) {
975 return ;
976 }
977
978 //
979 // HUB starts its port index with 1.
980 //
981 Byte = 0;
982 Bit = 1;
983
984 for (Index = 0; Index < HubIf->NumOfPort; Index++) {
985 if (USB_BIT_IS_SET (HubIf->ChangeMap[Byte], USB_BIT (Bit))) {
986 UsbEnumeratePort (HubIf, Index);
987 }
988
989 USB_NEXT_BIT (Byte, Bit);
990 }
991
992 UsbHubAckHubStatus (HubIf->Device);
993
994 gBS->FreePool (HubIf->ChangeMap);
995 HubIf->ChangeMap = NULL;
996 return ;
997 }
998
999
1000 /**
1001 Enumerate all the changed hub ports
1002
1003 @param Event The event that is triggered
1004 @param Context The context to the event
1005
1006 @return None
1007
1008 **/
1009 VOID
1010 EFIAPI
1011 UsbRootHubEnumeration (
1012 IN EFI_EVENT Event,
1013 IN VOID *Context
1014 )
1015 {
1016 USB_INTERFACE *RootHub;
1017 UINT8 Index;
1018
1019 RootHub = (USB_INTERFACE *) Context;
1020
1021 for (Index = 0; Index < RootHub->NumOfPort; Index++) {
1022 UsbEnumeratePort (RootHub, Index);
1023 }
1024 }