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