]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c
Coding style refinement.
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusDxe / UsbHub.c
CommitLineData
e237e7ae 1/** @file\r
2\r
8616fc4c 3 Unified interface for RootHub and Hub.\r
4\r
cd5ebaa0
HT
5Copyright (c) 2007 - 2009, Intel Corporation. All rights reserved.<BR> \r
6This program and the accompanying materials\r
e237e7ae 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
aa79b0b3 18//\r
19// Array that maps the change bit to feature value which is\r
20// used to clear these change bit. USB HUB API will clear\r
21// these change bit automatically. For non-root hub, these\r
22// bits determine whether hub will report the port in changed\r
23// bit maps.\r
24//\r
92870c98 25USB_CHANGE_FEATURE_MAP mHubFeatureMap[] = {\r
aa79b0b3 26 {USB_PORT_STAT_C_CONNECTION, EfiUsbPortConnectChange},\r
27 {USB_PORT_STAT_C_ENABLE, EfiUsbPortEnableChange},\r
28 {USB_PORT_STAT_C_SUSPEND, EfiUsbPortSuspendChange},\r
29 {USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange},\r
92870c98 30 {USB_PORT_STAT_C_RESET, EfiUsbPortResetChange}\r
aa79b0b3 31};\r
32\r
92870c98 33USB_CHANGE_FEATURE_MAP mRootHubFeatureMap[] = {\r
aa79b0b3 34 {USB_PORT_STAT_C_CONNECTION, EfiUsbPortConnectChange},\r
35 {USB_PORT_STAT_C_ENABLE, EfiUsbPortEnableChange},\r
36 {USB_PORT_STAT_C_SUSPEND, EfiUsbPortSuspendChange},\r
37 {USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange},\r
38 {USB_PORT_STAT_C_RESET, EfiUsbPortResetChange},\r
39};\r
40\r
e237e7ae 41//\r
42// USB hub class specific requests. Although USB hub\r
43// is related to an interface, these requests are sent\r
44// to the control endpoint of the device.\r
45//\r
92870c98 46/**\r
47 USB hub control transfer to set the hub depth.\r
48\r
49 @param HubDev The device of the hub.\r
50 @param Depth The depth to set.\r
51\r
52 @retval EFI_SUCCESS Depth of the hub is set.\r
53 @retval Others Failed to set the depth.\r
54\r
55**/\r
56EFI_STATUS\r
57UsbHubCtrlSetHubDepth (\r
58 IN USB_DEVICE *HubDev,\r
59 IN UINT16 Depth\r
60 )\r
61{\r
62 EFI_STATUS Status;\r
e237e7ae 63\r
92870c98 64 Status = UsbCtrlRequest (\r
65 HubDev,\r
66 EfiUsbNoData,\r
67 USB_REQ_TYPE_CLASS,\r
68 USB_HUB_TARGET_HUB,\r
69 USB_HUB_REQ_SET_DEPTH,\r
70 Depth,\r
71 0,\r
72 NULL,\r
73 0\r
74 );\r
75\r
76 return Status;\r
77}\r
e237e7ae 78\r
79/**\r
8616fc4c 80 USB hub control transfer to clear the hub feature.\r
e237e7ae 81\r
8616fc4c 82 @param HubDev The device of the hub.\r
83 @param Feature The feature to clear.\r
e237e7ae 84\r
8616fc4c 85 @retval EFI_SUCCESS Feature of the hub is cleared.\r
86 @retval Others Failed to clear the feature.\r
e237e7ae 87\r
88**/\r
e237e7ae 89EFI_STATUS\r
90UsbHubCtrlClearHubFeature (\r
91 IN USB_DEVICE *HubDev,\r
92 IN UINT16 Feature\r
93 )\r
94{\r
95 EFI_STATUS Status;\r
96\r
97 Status = UsbCtrlRequest (\r
98 HubDev,\r
99 EfiUsbNoData,\r
100 USB_REQ_TYPE_CLASS,\r
101 USB_HUB_TARGET_HUB,\r
102 USB_HUB_REQ_CLEAR_FEATURE,\r
103 Feature,\r
104 0,\r
105 NULL,\r
106 0\r
107 );\r
108\r
109 return Status;\r
110}\r
111\r
112\r
113/**\r
8616fc4c 114 Clear the feature of the device's port.\r
e237e7ae 115\r
8616fc4c 116 @param HubDev The hub device.\r
117 @param Port The port to clear feature.\r
118 @param Feature The feature to clear.\r
e237e7ae 119\r
120 @retval EFI_SUCCESS The feature of the port is cleared.\r
121 @retval Others Failed to clear the feature.\r
122\r
123**/\r
e237e7ae 124EFI_STATUS\r
125UsbHubCtrlClearPortFeature (\r
126 IN USB_DEVICE *HubDev,\r
127 IN UINT8 Port,\r
128 IN UINT16 Feature\r
129 )\r
130{\r
131 EFI_STATUS Status;\r
132\r
133 //\r
134 // In USB bus, all the port index starts from 0. But HUB\r
135 // indexes its port from 1. So, port number is added one.\r
136 //\r
137 Status = UsbCtrlRequest (\r
138 HubDev,\r
139 EfiUsbNoData,\r
140 USB_REQ_TYPE_CLASS,\r
141 USB_HUB_TARGET_PORT,\r
142 USB_HUB_REQ_CLEAR_FEATURE,\r
143 Feature,\r
c52fa98c 144 (UINT16) (Port + 1),\r
e237e7ae 145 NULL,\r
146 0\r
147 );\r
148\r
149 return Status;\r
150}\r
151\r
152\r
e237e7ae 153/**\r
154 Clear the transaction translate buffer if full/low\r
155 speed control/bulk transfer failed and the transfer\r
156 uses this hub as translator.Remember to clear the TT\r
157 buffer of transaction translator, not that of the\r
158 parent.\r
159\r
8616fc4c 160 @param HubDev The hub device.\r
161 @param Port The port of the hub.\r
162 @param DevAddr Address of the failed transaction.\r
163 @param EpNum The endpoint number of the failed transaction.\r
164 @param EpType The type of failed transaction.\r
e237e7ae 165\r
8616fc4c 166 @retval EFI_SUCCESS The TT buffer is cleared.\r
167 @retval Others Failed to clear the TT buffer.\r
e237e7ae 168\r
169**/\r
170EFI_STATUS\r
171UsbHubCtrlClearTTBuffer (\r
172 IN USB_DEVICE *HubDev,\r
173 IN UINT8 Port,\r
174 IN UINT16 DevAddr,\r
175 IN UINT16 EpNum,\r
176 IN UINT16 EpType\r
177 )\r
178{\r
179 EFI_STATUS Status;\r
180 UINT16 Value;\r
181\r
182 //\r
183 // Check USB2.0 spec page 424 for wValue's encoding\r
184 //\r
c52fa98c 185 Value = (UINT16) ((EpNum & 0x0F) | (DevAddr << 4) |\r
186 ((EpType & 0x03) << 11) | ((EpNum & 0x80) << 15));\r
e237e7ae 187\r
188 Status = UsbCtrlRequest (\r
189 HubDev,\r
190 EfiUsbNoData,\r
191 USB_REQ_TYPE_CLASS,\r
192 USB_HUB_TARGET_PORT,\r
193 USB_HUB_REQ_CLEAR_TT,\r
194 Value,\r
c52fa98c 195 (UINT16) (Port + 1),\r
e237e7ae 196 NULL,\r
197 0\r
198 );\r
199\r
200 return Status;\r
201}\r
202\r
92870c98 203/**\r
204 Usb hub control transfer to get the super speed hub descriptor.\r
205\r
206 @param HubDev The hub device.\r
207 @param Buf The buffer to hold the descriptor.\r
92870c98 208\r
209 @retval EFI_SUCCESS The hub descriptor is retrieved.\r
210 @retval Others Failed to retrieve the hub descriptor.\r
211\r
212**/\r
213EFI_STATUS\r
214UsbHubCtrlGetSuperSpeedHubDesc (\r
215 IN USB_DEVICE *HubDev,\r
216 OUT VOID *Buf\r
217 )\r
218{\r
219 EFI_STATUS Status;\r
220 \r
221 Status = EFI_INVALID_PARAMETER;\r
222 \r
223 Status = UsbCtrlRequest (\r
224 HubDev,\r
225 EfiUsbDataIn,\r
226 USB_REQ_TYPE_CLASS,\r
227 USB_HUB_TARGET_HUB,\r
228 USB_HUB_REQ_GET_DESC,\r
229 (UINT16) (USB_DESC_TYPE_HUB_SUPER_SPEED << 8),\r
230 0,\r
231 Buf,\r
232 32\r
233 );\r
234\r
235 return Status;\r
236}\r
e237e7ae 237\r
238/**\r
8616fc4c 239 Usb hub control transfer to get the hub descriptor.\r
e237e7ae 240\r
8616fc4c 241 @param HubDev The hub device.\r
242 @param Buf The buffer to hold the descriptor.\r
243 @param Len The length to retrieve.\r
e237e7ae 244\r
8616fc4c 245 @retval EFI_SUCCESS The hub descriptor is retrieved.\r
246 @retval Others Failed to retrieve the hub descriptor.\r
e237e7ae 247\r
248**/\r
e237e7ae 249EFI_STATUS\r
250UsbHubCtrlGetHubDesc (\r
251 IN USB_DEVICE *HubDev,\r
252 OUT VOID *Buf,\r
253 IN UINTN Len\r
254 )\r
255{\r
256 EFI_STATUS Status;\r
257\r
258 Status = UsbCtrlRequest (\r
259 HubDev,\r
260 EfiUsbDataIn,\r
261 USB_REQ_TYPE_CLASS,\r
262 USB_HUB_TARGET_HUB,\r
263 USB_HUB_REQ_GET_DESC,\r
264 (UINT16) (USB_DESC_TYPE_HUB << 8),\r
265 0,\r
266 Buf,\r
267 Len\r
268 );\r
269\r
270 return Status;\r
271}\r
272\r
273\r
274/**\r
8616fc4c 275 Usb hub control transfer to get the hub status.\r
e237e7ae 276\r
8616fc4c 277 @param HubDev The hub device.\r
278 @param State The variable to return the status.\r
e237e7ae 279\r
8616fc4c 280 @retval EFI_SUCCESS The hub status is returned in State.\r
281 @retval Others Failed to get the hub status.\r
e237e7ae 282\r
283**/\r
e237e7ae 284EFI_STATUS\r
285UsbHubCtrlGetHubStatus (\r
286 IN USB_DEVICE *HubDev,\r
287 OUT UINT32 *State\r
288 )\r
289{\r
290 EFI_STATUS Status;\r
291\r
292 Status = UsbCtrlRequest (\r
293 HubDev,\r
294 EfiUsbDataIn,\r
295 USB_REQ_TYPE_CLASS,\r
296 USB_HUB_TARGET_HUB,\r
297 USB_HUB_REQ_GET_STATUS,\r
298 0,\r
299 0,\r
300 State,\r
301 4\r
302 );\r
303\r
304 return Status;\r
305}\r
306\r
307\r
308/**\r
8616fc4c 309 Usb hub control transfer to get the port status.\r
e237e7ae 310\r
8616fc4c 311 @param HubDev The hub device.\r
312 @param Port The port of the hub.\r
313 @param State Variable to return the hub port state.\r
e237e7ae 314\r
8616fc4c 315 @retval EFI_SUCCESS The port state is returned in State.\r
d17371e8 316 @retval Others Failed to retrieve the port state.\r
e237e7ae 317\r
318**/\r
e237e7ae 319EFI_STATUS\r
320UsbHubCtrlGetPortStatus (\r
321 IN USB_DEVICE *HubDev,\r
322 IN UINT8 Port,\r
323 OUT VOID *State\r
324 )\r
325{\r
326 EFI_STATUS Status;\r
327\r
328 //\r
329 // In USB bus, all the port index starts from 0. But HUB\r
330 // indexes its port from 1. So, port number is added one.\r
331 // No need to convert the hub bit to UEFI definition, they\r
332 // are the same\r
333 //\r
334 Status = UsbCtrlRequest (\r
335 HubDev,\r
336 EfiUsbDataIn,\r
337 USB_REQ_TYPE_CLASS,\r
338 USB_HUB_TARGET_PORT,\r
339 USB_HUB_REQ_GET_STATUS,\r
340 0,\r
c52fa98c 341 (UINT16) (Port + 1),\r
e237e7ae 342 State,\r
343 4\r
344 );\r
345\r
346 return Status;\r
347}\r
348\r
349\r
350/**\r
8616fc4c 351 Usb hub control transfer to reset the TT (Transaction Transaltor).\r
e237e7ae 352\r
8616fc4c 353 @param HubDev The hub device.\r
354 @param Port The port of the hub.\r
e237e7ae 355\r
8616fc4c 356 @retval EFI_SUCCESS The TT of the hub is reset.\r
357 @retval Others Failed to reset the port.\r
e237e7ae 358\r
359**/\r
e237e7ae 360EFI_STATUS\r
361UsbHubCtrlResetTT (\r
362 IN USB_DEVICE *HubDev,\r
363 IN UINT8 Port\r
364 )\r
365{\r
366 EFI_STATUS Status;\r
367\r
368 Status = UsbCtrlRequest (\r
369 HubDev,\r
370 EfiUsbNoData,\r
371 USB_REQ_TYPE_CLASS,\r
372 USB_HUB_TARGET_HUB,\r
373 USB_HUB_REQ_RESET_TT,\r
374 0,\r
c52fa98c 375 (UINT16) (Port + 1),\r
e237e7ae 376 NULL,\r
377 0\r
378 );\r
379\r
380 return Status;\r
381}\r
382\r
383\r
384/**\r
8616fc4c 385 Usb hub control transfer to set the hub feature.\r
e237e7ae 386\r
8616fc4c 387 @param HubDev The hub device.\r
388 @param Feature The feature to set.\r
e237e7ae 389\r
8616fc4c 390 @retval EFI_SUCESS The feature is set for the hub.\r
391 @retval Others Failed to set the feature.\r
e237e7ae 392\r
393**/\r
e237e7ae 394EFI_STATUS\r
395UsbHubCtrlSetHubFeature (\r
396 IN USB_DEVICE *HubDev,\r
397 IN UINT8 Feature\r
398 )\r
399{\r
400 EFI_STATUS Status;\r
401\r
402 Status = UsbCtrlRequest (\r
403 HubDev,\r
404 EfiUsbNoData,\r
405 USB_REQ_TYPE_CLASS,\r
406 USB_HUB_TARGET_HUB,\r
407 USB_HUB_REQ_SET_FEATURE,\r
408 Feature,\r
409 0,\r
410 NULL,\r
411 0\r
412 );\r
413\r
414 return Status;\r
415}\r
416\r
417\r
418/**\r
8616fc4c 419 Usb hub control transfer to set the port feature.\r
e237e7ae 420\r
8616fc4c 421 @param HubDev The Usb hub device.\r
422 @param Port The Usb port to set feature for.\r
423 @param Feature The feature to set.\r
e237e7ae 424\r
8616fc4c 425 @retval EFI_SUCCESS The feature is set for the port.\r
426 @retval Others Failed to set the feature.\r
e237e7ae 427\r
428**/\r
e237e7ae 429EFI_STATUS\r
430UsbHubCtrlSetPortFeature (\r
431 IN USB_DEVICE *HubDev,\r
432 IN UINT8 Port,\r
433 IN UINT8 Feature\r
434 )\r
435{\r
436 EFI_STATUS Status;\r
437\r
438 //\r
439 // In USB bus, all the port index starts from 0. But HUB\r
440 // indexes its port from 1. So, port number is added one.\r
441 //\r
442 Status = UsbCtrlRequest (\r
443 HubDev,\r
444 EfiUsbNoData,\r
445 USB_REQ_TYPE_CLASS,\r
446 USB_HUB_TARGET_PORT,\r
447 USB_HUB_REQ_SET_FEATURE,\r
448 Feature,\r
c52fa98c 449 (UINT16) (Port + 1),\r
e237e7ae 450 NULL,\r
451 0\r
452 );\r
453\r
454 return Status;\r
455}\r
456\r
457\r
458/**\r
459 Read the whole usb hub descriptor. It is necessary\r
460 to do it in two steps because hub descriptor is of\r
8616fc4c 461 variable length.\r
e237e7ae 462\r
8616fc4c 463 @param HubDev The hub device.\r
464 @param HubDesc The variable to return the descriptor.\r
e237e7ae 465\r
8616fc4c 466 @retval EFI_SUCCESS The hub descriptor is read.\r
467 @retval Others Failed to read the hub descriptor.\r
e237e7ae 468\r
469**/\r
e237e7ae 470EFI_STATUS\r
471UsbHubReadDesc (\r
472 IN USB_DEVICE *HubDev,\r
473 OUT EFI_USB_HUB_DESCRIPTOR *HubDesc\r
474 )\r
475{\r
476 EFI_STATUS Status;\r
477\r
92870c98 478 if (HubDev->Speed == EFI_USB_SPEED_SUPER) {\r
479 //\r
480 // Get the super speed hub descriptor\r
481 //\r
482 Status = UsbHubCtrlGetSuperSpeedHubDesc (HubDev, HubDesc);\r
483 } else {\r
e237e7ae 484\r
92870c98 485 //\r
486 // First get the hub descriptor length\r
487 //\r
488 Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, 2);\r
e237e7ae 489\r
92870c98 490 if (EFI_ERROR (Status)) {\r
491 return Status;\r
492 }\r
493\r
494 //\r
495 // Get the whole hub descriptor\r
496 //\r
497 Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, HubDesc->Length);\r
498 }\r
e237e7ae 499\r
500 return Status;\r
501}\r
502\r
503\r
504\r
505/**\r
506 Ack the hub change bits. If these bits are not ACKed, Hub will\r
507 always return changed bit map from its interrupt endpoint.\r
508\r
8616fc4c 509 @param HubDev The hub device.\r
e237e7ae 510\r
8616fc4c 511 @retval EFI_SUCCESS The hub change status is ACKed.\r
512 @retval Others Failed to ACK the hub status.\r
e237e7ae 513\r
514**/\r
515EFI_STATUS\r
516UsbHubAckHubStatus (\r
517 IN USB_DEVICE *HubDev\r
518 )\r
519{\r
520 EFI_USB_PORT_STATUS HubState;\r
521 EFI_STATUS Status;\r
522\r
523 Status = UsbHubCtrlGetHubStatus (HubDev, (UINT32 *) &HubState);\r
524\r
525 if (EFI_ERROR (Status)) {\r
526 return Status;\r
527 }\r
528\r
529 if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_LOCAL_POWER)) {\r
530 UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_LOCAL_POWER);\r
531 }\r
532\r
533 if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_OVER_CURRENT)) {\r
534 UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_OVER_CURRENT);\r
535 }\r
536\r
537 return EFI_SUCCESS;\r
538}\r
539\r
540\r
541/**\r
542 Test whether the interface is a hub interface.\r
543\r
8616fc4c 544 @param UsbIf The interface to test.\r
e237e7ae 545\r
8616fc4c 546 @retval TRUE The interface is a hub interface.\r
547 @retval FALSE The interface isn't a hub interface.\r
e237e7ae 548\r
549**/\r
550BOOLEAN\r
551UsbIsHubInterface (\r
552 IN USB_INTERFACE *UsbIf\r
553 )\r
554{\r
555 EFI_USB_INTERFACE_DESCRIPTOR *Setting;\r
556\r
557 //\r
558 // If the hub is a high-speed hub with multiple TT,\r
559 // the hub will has a default setting of single TT.\r
560 //\r
561 Setting = &UsbIf->IfSetting->Desc;\r
562\r
563 if ((Setting->InterfaceClass == USB_HUB_CLASS_CODE) &&\r
564 (Setting->InterfaceSubClass == USB_HUB_SUBCLASS_CODE)) {\r
565\r
566 return TRUE;\r
567 }\r
568\r
569 return FALSE;\r
570}\r
571\r
572\r
573/**\r
574 The callback function to the USB hub status change\r
575 interrupt endpoint. It is called periodically by\r
576 the underlying host controller.\r
577\r
8616fc4c 578 @param Data The data read.\r
579 @param DataLength The length of the data read.\r
580 @param Context The context.\r
581 @param Result The result of the last interrupt transfer.\r
e237e7ae 582\r
8616fc4c 583 @retval EFI_SUCCESS The process is OK.\r
584 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.\r
e237e7ae 585\r
586**/\r
e237e7ae 587EFI_STATUS\r
6d3ea23f 588EFIAPI\r
e237e7ae 589UsbOnHubInterrupt (\r
590 IN VOID *Data,\r
591 IN UINTN DataLength,\r
592 IN VOID *Context,\r
593 IN UINT32 Result\r
594 )\r
595{\r
596 USB_INTERFACE *HubIf;\r
597 EFI_USB_IO_PROTOCOL *UsbIo;\r
598 EFI_USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
599 EFI_STATUS Status;\r
600\r
601 HubIf = (USB_INTERFACE *) Context;\r
602 UsbIo = &(HubIf->UsbIo);\r
603 EpDesc = &(HubIf->HubEp->Desc);\r
604\r
605 if (Result != EFI_USB_NOERROR) {\r
606 //\r
607 // If endpoint is stalled, clear the stall. Use UsbIo to access\r
608 // the control transfer so internal status are maintained.\r
609 //\r
610 if (USB_BIT_IS_SET (Result, EFI_USB_ERR_STALL)) {\r
611 UsbIoClearFeature (\r
612 UsbIo,\r
613 USB_TARGET_ENDPOINT,\r
614 USB_FEATURE_ENDPOINT_HALT,\r
615 EpDesc->EndpointAddress\r
616 );\r
617 }\r
618\r
619 //\r
620 // Delete and submit a new async interrupt\r
621 //\r
622 Status = UsbIo->UsbAsyncInterruptTransfer (\r
623 UsbIo,\r
624 EpDesc->EndpointAddress,\r
625 FALSE,\r
626 0,\r
627 0,\r
628 NULL,\r
629 NULL\r
630 );\r
631\r
632 if (EFI_ERROR (Status)) {\r
d2577026 633 DEBUG (( EFI_D_ERROR, "UsbOnHubInterrupt: failed to remove async transfer - %r\n", Status));\r
e237e7ae 634 return Status;\r
635 }\r
636\r
637 Status = UsbIo->UsbAsyncInterruptTransfer (\r
638 UsbIo,\r
639 EpDesc->EndpointAddress,\r
640 TRUE,\r
641 USB_HUB_POLL_INTERVAL,\r
642 HubIf->NumOfPort / 8 + 1,\r
643 UsbOnHubInterrupt,\r
644 HubIf\r
645 );\r
646\r
647 if (EFI_ERROR (Status)) {\r
d2577026 648 DEBUG (( EFI_D_ERROR, "UsbOnHubInterrupt: failed to submit new async transfer - %r\n", Status));\r
e237e7ae 649 }\r
650\r
651 return Status;\r
652 }\r
653\r
654 if ((DataLength == 0) || (Data == NULL)) {\r
655 return EFI_SUCCESS;\r
656 }\r
657\r
658 //\r
659 // OK, actually something is changed, save the change map\r
660 // then signal the HUB to do enumeration. This is a good\r
661 // practise since UsbOnHubInterrupt is called in the context\r
662 // of host contrller's AsyncInterrupt monitor.\r
663 //\r
664 HubIf->ChangeMap = AllocateZeroPool (DataLength);\r
665\r
666 if (HubIf->ChangeMap == NULL) {\r
667 return EFI_OUT_OF_RESOURCES;\r
668 }\r
669\r
670 CopyMem (HubIf->ChangeMap, Data, DataLength);\r
671 gBS->SignalEvent (HubIf->HubNotify);\r
672\r
673 return EFI_SUCCESS;\r
674}\r
675\r
e237e7ae 676\r
677\r
678\r
679/**\r
8616fc4c 680 Initialize the device for a non-root hub.\r
e237e7ae 681\r
8616fc4c 682 @param HubIf The USB hub interface.\r
e237e7ae 683\r
8616fc4c 684 @retval EFI_SUCCESS The hub is initialized.\r
685 @retval EFI_DEVICE_ERROR Failed to initialize the hub.\r
e237e7ae 686\r
687**/\r
e237e7ae 688EFI_STATUS\r
689UsbHubInit (\r
690 IN USB_INTERFACE *HubIf\r
691 )\r
692{\r
693 EFI_USB_HUB_DESCRIPTOR HubDesc;\r
694 USB_ENDPOINT_DESC *EpDesc;\r
695 USB_INTERFACE_SETTING *Setting;\r
696 EFI_USB_IO_PROTOCOL *UsbIo;\r
697 USB_DEVICE *HubDev;\r
698 EFI_STATUS Status;\r
699 UINT8 Index;\r
d17371e8 700 UINT8 NumEndpoints;\r
92870c98 701 UINT16 Depth;\r
e237e7ae 702\r
703 //\r
704 // Locate the interrupt endpoint for port change map\r
705 //\r
706 HubIf->IsHub = FALSE;\r
707 Setting = HubIf->IfSetting;\r
708 HubDev = HubIf->Device;\r
709 EpDesc = NULL;\r
d17371e8 710 NumEndpoints = Setting->Desc.NumEndpoints;\r
e237e7ae 711\r
d17371e8 712 for (Index = 0; Index < NumEndpoints; Index++) {\r
e237e7ae 713 ASSERT ((Setting->Endpoints != NULL) && (Setting->Endpoints[Index] != NULL));\r
714\r
715 EpDesc = Setting->Endpoints[Index];\r
716\r
717 if (USB_BIT_IS_SET (EpDesc->Desc.EndpointAddress, USB_ENDPOINT_DIR_IN) &&\r
718 (USB_ENDPOINT_TYPE (&EpDesc->Desc) == USB_ENDPOINT_INTERRUPT)) {\r
719 break;\r
720 }\r
721 }\r
722\r
d17371e8 723 if (Index == NumEndpoints) {\r
d2577026 724 DEBUG (( EFI_D_ERROR, "UsbHubInit: no interrupt endpoint found for hub %d\n", HubDev->Address));\r
e237e7ae 725 return EFI_DEVICE_ERROR;\r
726 }\r
727\r
728 Status = UsbHubReadDesc (HubDev, &HubDesc);\r
729\r
730 if (EFI_ERROR (Status)) {\r
d2577026 731 DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to read HUB descriptor %r\n", Status));\r
e237e7ae 732 return Status;\r
733 }\r
734\r
735 HubIf->NumOfPort = HubDesc.NumPorts;\r
736\r
d2577026 737 DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d has %d ports\n", HubDev->Address,HubIf->NumOfPort));\r
e237e7ae 738\r
92870c98 739 //\r
740 // OK, set IsHub to TRUE. Now usb bus can handle this device\r
741 // as a working HUB. If failed eariler, bus driver will not\r
742 // recognize it as a hub. Other parts of the bus should be able\r
743 // to work.\r
744 //\r
745 HubIf->IsHub = TRUE;\r
746 HubIf->HubApi = &mUsbHubApi;\r
747 HubIf->HubEp = EpDesc;\r
748\r
749 if (HubIf->Device->Speed == EFI_USB_SPEED_SUPER) {\r
750 Depth = (UINT16)(HubIf->Device->Tier - 1);\r
751 DEBUG ((EFI_D_INFO, "UsbHubInit: Set Hub Depth as 0x%x\n", Depth));\r
752 UsbHubCtrlSetHubDepth (HubIf->Device, Depth);\r
753 \r
754 for (Index = 0; Index < HubDesc.NumPorts; Index++) {\r
755 UsbHubCtrlSetPortFeature (HubIf->Device, Index, USB_HUB_PORT_REMOTE_WAKE_MASK);\r
756 } \r
757 } else {\r
758 //\r
759 // Feed power to all the hub ports. It should be ok\r
760 // for both gang/individual powered hubs.\r
761 //\r
762 for (Index = 0; Index < HubDesc.NumPorts; Index++) {\r
763 UsbHubCtrlSetPortFeature (HubIf->Device, Index, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_POWER);\r
764 }\r
765\r
766 gBS->Stall (HubDesc.PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);\r
767 UsbHubAckHubStatus (HubIf->Device);\r
768 }\r
769\r
e237e7ae 770 //\r
771 // Create an event to enumerate the hub's port. On\r
772 //\r
773 Status = gBS->CreateEvent (\r
774 EVT_NOTIFY_SIGNAL,\r
775 TPL_CALLBACK,\r
776 UsbHubEnumeration,\r
777 HubIf,\r
778 &HubIf->HubNotify\r
779 );\r
780\r
781 if (EFI_ERROR (Status)) {\r
d2577026 782 DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to create signal for hub %d - %r\n",\r
e237e7ae 783 HubDev->Address, Status));\r
784\r
785 return Status;\r
786 }\r
787\r
788 //\r
789 // Create AsyncInterrupt to query hub port change endpoint\r
790 // periodically. If the hub ports are changed, hub will return\r
791 // changed port map from the interrupt endpoint. The port map\r
792 // must be able to hold (HubIf->NumOfPort + 1) bits (one bit for\r
793 // host change status).\r
794 //\r
795 UsbIo = &HubIf->UsbIo;\r
796 Status = UsbIo->UsbAsyncInterruptTransfer (\r
797 UsbIo,\r
798 EpDesc->Desc.EndpointAddress,\r
799 TRUE,\r
800 USB_HUB_POLL_INTERVAL,\r
801 HubIf->NumOfPort / 8 + 1,\r
802 UsbOnHubInterrupt,\r
803 HubIf\r
804 );\r
805\r
806 if (EFI_ERROR (Status)) {\r
d2577026 807 DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to queue interrupt transfer for hub %d - %r\n",\r
e237e7ae 808 HubDev->Address, Status));\r
809\r
810 gBS->CloseEvent (HubIf->HubNotify);\r
811 HubIf->HubNotify = NULL;\r
812\r
813 return Status;\r
814 }\r
815\r
d2577026 816 DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d initialized\n", HubDev->Address));\r
e237e7ae 817 return Status;\r
818}\r
819\r
820\r
821\r
822/**\r
823 Get the port status. This function is required to\r
824 ACK the port change bits although it will return\r
825 the port changes in PortState. Bus enumeration code\r
826 doesn't need to ACK the port change bits.\r
827\r
8616fc4c 828 @param HubIf The hub interface.\r
829 @param Port The port of the hub to get state.\r
830 @param PortState Variable to return the port state.\r
e237e7ae 831\r
8616fc4c 832 @retval EFI_SUCCESS The port status is successfully returned.\r
833 @retval Others Failed to return the status.\r
e237e7ae 834\r
835**/\r
e237e7ae 836EFI_STATUS\r
837UsbHubGetPortStatus (\r
838 IN USB_INTERFACE *HubIf,\r
839 IN UINT8 Port,\r
840 OUT EFI_USB_PORT_STATUS *PortState\r
841 )\r
842{\r
843 EFI_STATUS Status;\r
844\r
845 Status = UsbHubCtrlGetPortStatus (HubIf->Device, Port, PortState);\r
846\r
92870c98 847 //\r
848 // Mark the USB_PORT_STAT_SUPER_SPEED bit if SuperSpeed\r
849 //\r
850 if (HubIf->Device->Speed == EFI_USB_SPEED_SUPER) {\r
851 PortState->PortStatus |= USB_PORT_STAT_SUPER_SPEED;\r
852 } \r
e237e7ae 853 return Status;\r
854}\r
855\r
856\r
857\r
858/**\r
859 Clear the port change status.\r
860\r
8616fc4c 861 @param HubIf The hub interface.\r
862 @param Port The hub port.\r
e237e7ae 863\r
e237e7ae 864**/\r
e237e7ae 865VOID\r
866UsbHubClearPortChange (\r
867 IN USB_INTERFACE *HubIf,\r
868 IN UINT8 Port\r
869 )\r
870{\r
871 EFI_USB_PORT_STATUS PortState;\r
872 USB_CHANGE_FEATURE_MAP *Map;\r
873 UINTN Index;\r
874 EFI_STATUS Status;\r
875\r
876 Status = UsbHubGetPortStatus (HubIf, Port, &PortState);\r
877\r
878 if (EFI_ERROR (Status)) {\r
879 return;\r
880 }\r
881\r
882 //\r
883 // OK, get the usb port status, now ACK the change bits.\r
884 // Don't return error when failed to clear the change bits.\r
885 // It may lead to extra port state report. USB bus should\r
886 // be able to handle this.\r
887 //\r
92870c98 888 for (Index = 0; Index < sizeof (mHubFeatureMap) / sizeof (mHubFeatureMap[0]); Index++) {\r
e237e7ae 889 Map = &mHubFeatureMap[Index];\r
890\r
891 if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {\r
23c326c2 892 UsbHubCtrlClearPortFeature (HubIf->Device, Port, (UINT16) Map->Feature);\r
e237e7ae 893 }\r
894 }\r
895}\r
896\r
897\r
898\r
899/**\r
8616fc4c 900 Function to set the port feature for non-root hub.\r
e237e7ae 901\r
8616fc4c 902 @param HubIf The hub interface.\r
903 @param Port The port of the hub.\r
904 @param Feature The feature of the port to set.\r
e237e7ae 905\r
8616fc4c 906 @retval EFI_SUCCESS The hub port feature is set.\r
907 @retval Others Failed to set the port feature.\r
e237e7ae 908\r
909**/\r
e237e7ae 910EFI_STATUS\r
911UsbHubSetPortFeature (\r
912 IN USB_INTERFACE *HubIf,\r
913 IN UINT8 Port,\r
914 IN EFI_USB_PORT_FEATURE Feature\r
915 )\r
916{\r
917 EFI_STATUS Status;\r
918\r
c52fa98c 919 Status = UsbHubCtrlSetPortFeature (HubIf->Device, Port, (UINT8) Feature);\r
e237e7ae 920\r
921 return Status;\r
922}\r
923\r
924\r
925/**\r
8616fc4c 926 Interface function to clear the port feature for non-root hub.\r
e237e7ae 927\r
8616fc4c 928 @param HubIf The hub interface.\r
929 @param Port The port of the hub to clear feature for.\r
930 @param Feature The feature to clear.\r
e237e7ae 931\r
8616fc4c 932 @retval EFI_SUCCESS The port feature is cleared.\r
933 @retval Others Failed to clear the port feature.\r
e237e7ae 934\r
935**/\r
e237e7ae 936EFI_STATUS\r
937UsbHubClearPortFeature (\r
938 IN USB_INTERFACE *HubIf,\r
939 IN UINT8 Port,\r
940 IN EFI_USB_PORT_FEATURE Feature\r
941 )\r
942{\r
943 EFI_STATUS Status;\r
944\r
c52fa98c 945 Status = UsbHubCtrlClearPortFeature (HubIf->Device, Port, (UINT8) Feature);\r
e237e7ae 946\r
947 return Status;\r
948}\r
949\r
950\r
951/**\r
d17371e8 952 Interface function to reset the port.\r
e237e7ae 953\r
8616fc4c 954 @param HubIf The hub interface.\r
955 @param Port The port to reset.\r
e237e7ae 956\r
8616fc4c 957 @retval EFI_SUCCESS The hub port is reset.\r
958 @retval EFI_TIMEOUT Failed to reset the port in time.\r
959 @retval Others Failed to reset the port.\r
e237e7ae 960\r
961**/\r
e237e7ae 962EFI_STATUS\r
963UsbHubResetPort (\r
964 IN USB_INTERFACE *HubIf,\r
965 IN UINT8 Port\r
966 )\r
967{\r
968 EFI_USB_PORT_STATUS PortState;\r
969 UINTN Index;\r
970 EFI_STATUS Status;\r
971\r
c52fa98c 972 Status = UsbHubSetPortFeature (HubIf, Port, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_RESET);\r
e237e7ae 973\r
974 if (EFI_ERROR (Status)) {\r
975 return Status;\r
976 }\r
977\r
978 //\r
979 // Drive the reset signal for at least 10ms. Check USB 2.0 Spec\r
980 // section 7.1.7.5 for timing requirements.\r
981 //\r
41e8ff27 982 gBS->Stall (USB_SET_PORT_RESET_STALL);\r
e237e7ae 983\r
984 //\r
985 // USB hub will clear RESET bit if reset is actually finished.\r
986 //\r
987 ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));\r
988\r
41e8ff27 989 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {\r
e237e7ae 990 Status = UsbHubGetPortStatus (HubIf, Port, &PortState);\r
991\r
992 if (!EFI_ERROR (Status) &&\r
993 !USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {\r
994\r
995 return EFI_SUCCESS;\r
996 }\r
997\r
41e8ff27 998 gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);\r
e237e7ae 999 }\r
1000\r
1001 return EFI_TIMEOUT;\r
1002}\r
1003\r
1004\r
1005/**\r
8616fc4c 1006 Release the hub's control of the interface.\r
e237e7ae 1007\r
8616fc4c 1008 @param HubIf The hub interface.\r
e237e7ae 1009\r
8616fc4c 1010 @retval EFI_SUCCESS The interface is release of hub control.\r
e237e7ae 1011\r
1012**/\r
e237e7ae 1013EFI_STATUS\r
1014UsbHubRelease (\r
1015 IN USB_INTERFACE *HubIf\r
1016 )\r
1017{\r
1018 EFI_USB_IO_PROTOCOL *UsbIo;\r
1019 EFI_STATUS Status;\r
1020\r
1021 UsbIo = &HubIf->UsbIo;\r
1022 Status = UsbIo->UsbAsyncInterruptTransfer (\r
1023 UsbIo,\r
1024 HubIf->HubEp->Desc.EndpointAddress,\r
1025 FALSE,\r
1026 USB_HUB_POLL_INTERVAL,\r
1027 0,\r
1028 NULL,\r
1029 0\r
1030 );\r
1031\r
1032 if (EFI_ERROR (Status)) {\r
1033 return Status;\r
1034 }\r
1035\r
1036 gBS->CloseEvent (HubIf->HubNotify);\r
1037\r
1038 HubIf->IsHub = FALSE;\r
1039 HubIf->HubApi = NULL;\r
1040 HubIf->HubEp = NULL;\r
1041 HubIf->HubNotify = NULL;\r
1042\r
d2577026 1043 DEBUG (( EFI_D_INFO, "UsbHubRelease: hub device %d released\n", HubIf->Device->Address));\r
e237e7ae 1044 return EFI_SUCCESS;\r
1045}\r
1046\r
1047\r
1048\r
1049/**\r
8616fc4c 1050 Initialize the interface for root hub.\r
e237e7ae 1051\r
8616fc4c 1052 @param HubIf The root hub interface.\r
e237e7ae 1053\r
d17371e8 1054 @retval EFI_SUCCESS The interface is initialized for root hub.\r
8616fc4c 1055 @retval Others Failed to initialize the hub.\r
e237e7ae 1056\r
1057**/\r
e237e7ae 1058EFI_STATUS\r
1059UsbRootHubInit (\r
1060 IN USB_INTERFACE *HubIf\r
1061 )\r
1062{\r
1063 EFI_STATUS Status;\r
1064 UINT8 MaxSpeed;\r
1065 UINT8 NumOfPort;\r
1066 UINT8 Support64;\r
1067\r
1068 Status = UsbHcGetCapability (HubIf->Device->Bus, &MaxSpeed, &NumOfPort, &Support64);\r
1069\r
1070 if (EFI_ERROR (Status)) {\r
1071 return Status;\r
1072 }\r
1073\r
0e549d5b 1074 DEBUG (( EFI_D_INFO, "UsbRootHubInit: root hub %p - max speed %d, %d ports\n",\r
e237e7ae 1075 HubIf, MaxSpeed, NumOfPort));\r
1076\r
1077 HubIf->IsHub = TRUE;\r
1078 HubIf->HubApi = &mUsbRootHubApi;\r
1079 HubIf->HubEp = NULL;\r
1080 HubIf->MaxSpeed = MaxSpeed;\r
1081 HubIf->NumOfPort = NumOfPort;\r
1082 HubIf->HubNotify = NULL;\r
1083\r
1084 //\r
1085 // Create a timer to poll root hub ports periodically\r
1086 //\r
1087 Status = gBS->CreateEvent (\r
1088 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
1089 TPL_CALLBACK,\r
1090 UsbRootHubEnumeration,\r
1091 HubIf,\r
1092 &HubIf->HubNotify\r
1093 );\r
1094\r
1095 if (EFI_ERROR (Status)) {\r
1096 return Status;\r
1097 }\r
1098\r
d2577026 1099 //\r
1100 // It should signal the event immediately here, or device detection\r
1101 // by bus enumeration might be delayed by the timer interval.\r
1102 //\r
1103 gBS->SignalEvent (HubIf->HubNotify);\r
1104\r
e237e7ae 1105 Status = gBS->SetTimer (\r
1106 HubIf->HubNotify,\r
1107 TimerPeriodic,\r
1108 USB_ROOTHUB_POLL_INTERVAL\r
1109 );\r
1110\r
1111 if (EFI_ERROR (Status)) {\r
1112 gBS->CloseEvent (HubIf->HubNotify);\r
1113 }\r
1114\r
1115 return Status;\r
1116}\r
1117\r
1118\r
e237e7ae 1119/**\r
1120 Get the port status. This function is required to\r
1121 ACK the port change bits although it will return\r
1122 the port changes in PortState. Bus enumeration code\r
1123 doesn't need to ACK the port change bits.\r
1124\r
8616fc4c 1125 @param HubIf The root hub interface.\r
1126 @param Port The root hub port to get the state.\r
1127 @param PortState Variable to return the port state.\r
e237e7ae 1128\r
8616fc4c 1129 @retval EFI_SUCCESS The port state is returned.\r
1130 @retval Others Failed to retrieve the port state.\r
e237e7ae 1131\r
1132**/\r
e237e7ae 1133EFI_STATUS\r
1134UsbRootHubGetPortStatus (\r
1135 IN USB_INTERFACE *HubIf,\r
1136 IN UINT8 Port,\r
1137 OUT EFI_USB_PORT_STATUS *PortState\r
1138 )\r
1139{\r
1140 USB_BUS *Bus;\r
1141 EFI_STATUS Status;\r
1142\r
1143 Bus = HubIf->Device->Bus;\r
1144 Status = UsbHcGetRootHubPortStatus (Bus, Port, PortState);\r
1145\r
1146 return Status;\r
1147}\r
1148\r
1149\r
1150/**\r
1151 Clear the port change status.\r
1152\r
8616fc4c 1153 @param HubIf The root hub interface.\r
1154 @param Port The root hub port.\r
e237e7ae 1155\r
e237e7ae 1156**/\r
e237e7ae 1157VOID\r
1158UsbRootHubClearPortChange (\r
1159 IN USB_INTERFACE *HubIf,\r
1160 IN UINT8 Port\r
1161 )\r
1162{\r
1163 EFI_USB_PORT_STATUS PortState;\r
1164 USB_CHANGE_FEATURE_MAP *Map;\r
1165 UINTN Index;\r
1166 EFI_STATUS Status;\r
1167\r
1168 Status = UsbRootHubGetPortStatus (HubIf, Port, &PortState);\r
1169\r
1170 if (EFI_ERROR (Status)) {\r
1171 return;\r
1172 }\r
1173\r
1174 //\r
1175 // OK, get the usb port status, now ACK the change bits.\r
1176 // Don't return error when failed to clear the change bits.\r
1177 // It may lead to extra port state report. USB bus should\r
1178 // be able to handle this.\r
1179 //\r
92870c98 1180 for (Index = 0; Index < sizeof (mRootHubFeatureMap) / sizeof (mRootHubFeatureMap[0]); Index++) {\r
e237e7ae 1181 Map = &mRootHubFeatureMap[Index];\r
1182\r
1183 if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {\r
c52fa98c 1184 UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, (EFI_USB_PORT_FEATURE) Map->Feature);\r
e237e7ae 1185 }\r
1186 }\r
1187}\r
1188\r
1189\r
e237e7ae 1190/**\r
8616fc4c 1191 Set the root hub port feature.\r
e237e7ae 1192\r
8616fc4c 1193 @param HubIf The Usb hub interface.\r
1194 @param Port The hub port.\r
1195 @param Feature The feature to set.\r
e237e7ae 1196\r
8616fc4c 1197 @retval EFI_SUCCESS The root hub port is set with the feature.\r
1198 @retval Others Failed to set the feature.\r
e237e7ae 1199\r
1200**/\r
e237e7ae 1201EFI_STATUS\r
1202UsbRootHubSetPortFeature (\r
1203 IN USB_INTERFACE *HubIf,\r
1204 IN UINT8 Port,\r
1205 IN EFI_USB_PORT_FEATURE Feature\r
1206 )\r
1207{\r
1208 EFI_STATUS Status;\r
1209\r
1210 Status = UsbHcSetRootHubPortFeature (HubIf->Device->Bus, Port, Feature);\r
1211\r
1212 return Status;\r
1213}\r
1214\r
1215\r
1216/**\r
8616fc4c 1217 Clear the root hub port feature.\r
e237e7ae 1218\r
8616fc4c 1219 @param HubIf The root hub interface.\r
1220 @param Port The root hub port.\r
1221 @param Feature The feature to clear.\r
e237e7ae 1222\r
8616fc4c 1223 @retval EFI_SUCCESS The root hub port is cleared of the feature.\r
1224 @retval Others Failed to clear the feature.\r
e237e7ae 1225\r
1226**/\r
e237e7ae 1227EFI_STATUS\r
1228UsbRootHubClearPortFeature (\r
1229 IN USB_INTERFACE *HubIf,\r
1230 IN UINT8 Port,\r
1231 IN EFI_USB_PORT_FEATURE Feature\r
1232 )\r
1233{\r
1234 EFI_STATUS Status;\r
1235\r
1236 Status = UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, Feature);\r
1237\r
1238 return Status;\r
1239}\r
1240\r
1241\r
1242/**\r
d17371e8 1243 Interface function to reset the root hub port.\r
e237e7ae 1244\r
8616fc4c 1245 @param RootIf The root hub interface.\r
1246 @param Port The port to reset.\r
e237e7ae 1247\r
8616fc4c 1248 @retval EFI_SUCCESS The hub port is reset.\r
1249 @retval EFI_TIMEOUT Failed to reset the port in time.\r
1250 @retval EFI_NOT_FOUND The low/full speed device connected to high speed.\r
1251 root hub is released to the companion UHCI.\r
1252 @retval Others Failed to reset the port.\r
e237e7ae 1253\r
1254**/\r
e237e7ae 1255EFI_STATUS\r
1256UsbRootHubResetPort (\r
1257 IN USB_INTERFACE *RootIf,\r
1258 IN UINT8 Port\r
1259 )\r
1260{\r
1261 USB_BUS *Bus;\r
1262 EFI_STATUS Status;\r
1263 EFI_USB_PORT_STATUS PortState;\r
1264 UINTN Index;\r
1265\r
1266 //\r
1267 // Notice: although EHCI requires that ENABLED bit be cleared\r
1268 // when reset the port, we don't need to care that here. It\r
1269 // should be handled in the EHCI driver.\r
1270 //\r
1271 Bus = RootIf->Device->Bus;\r
1272 Status = UsbHcSetRootHubPortFeature (Bus, Port, EfiUsbPortReset);\r
1273\r
1274 if (EFI_ERROR (Status)) {\r
d2577026 1275 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to start reset on port %d\n", Port));\r
e237e7ae 1276 return Status;\r
1277 }\r
1278\r
1279 //\r
1280 // Drive the reset signal for at least 50ms. Check USB 2.0 Spec\r
1281 // section 7.1.7.5 for timing requirements.\r
1282 //\r
41e8ff27 1283 gBS->Stall (USB_SET_ROOT_PORT_RESET_STALL);\r
e237e7ae 1284\r
1285 Status = UsbHcClearRootHubPortFeature (Bus, Port, EfiUsbPortReset);\r
1286\r
1287 if (EFI_ERROR (Status)) {\r
d2577026 1288 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to clear reset on port %d\n", Port));\r
e237e7ae 1289 return Status;\r
1290 }\r
1291\r
41e8ff27 1292 gBS->Stall (USB_CLR_ROOT_PORT_RESET_STALL);\r
e237e7ae 1293\r
1294 //\r
1295 // USB host controller won't clear the RESET bit until\r
1296 // reset is actually finished.\r
1297 //\r
1298 ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));\r
1299\r
41e8ff27 1300 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {\r
e237e7ae 1301 Status = UsbHcGetRootHubPortStatus (Bus, Port, &PortState);\r
1302\r
1303 if (EFI_ERROR (Status)) {\r
1304 return Status;\r
1305 }\r
1306\r
1307 if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {\r
1308 break;\r
1309 }\r
1310\r
41e8ff27 1311 gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);\r
e237e7ae 1312 }\r
1313\r
41e8ff27 1314 if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {\r
1315 DEBUG ((EFI_D_ERROR, "UsbRootHubResetPort: reset not finished in time on port %d\n", Port));\r
e237e7ae 1316 return EFI_TIMEOUT;\r
1317 }\r
1318\r
1319 if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_ENABLE)) {\r
1320 //\r
1321 // OK, the port is reset. If root hub is of high speed and\r
1322 // the device is of low/full speed, release the ownership to\r
1323 // companion UHCI. If root hub is of full speed, it won't\r
1324 // automatically enable the port, we need to enable it manually.\r
1325 //\r
1326 if (RootIf->MaxSpeed == EFI_USB_SPEED_HIGH) {\r
d2577026 1327 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: release low/full speed device (%d) to UHCI\n", Port));\r
e237e7ae 1328\r
1329 UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortOwner);\r
1330 return EFI_NOT_FOUND;\r
1331\r
1332 } else {\r
1333\r
1334 Status = UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortEnable);\r
1335\r
1336 if (EFI_ERROR (Status)) {\r
d2577026 1337 DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to enable port %d for UHCI\n", Port));\r
e237e7ae 1338 return Status;\r
1339 }\r
1340\r
41e8ff27 1341 gBS->Stall (USB_SET_ROOT_PORT_ENABLE_STALL);\r
e237e7ae 1342 }\r
1343 }\r
1344\r
1345 return EFI_SUCCESS;\r
1346}\r
1347\r
1348\r
1349/**\r
8616fc4c 1350 Release the root hub's control of the interface.\r
e237e7ae 1351\r
8616fc4c 1352 @param HubIf The root hub interface.\r
e237e7ae 1353\r
1354 @retval EFI_SUCCESS The root hub's control of the interface is\r
1355 released.\r
1356\r
1357**/\r
e237e7ae 1358EFI_STATUS\r
1359UsbRootHubRelease (\r
1360 IN USB_INTERFACE *HubIf\r
1361 )\r
1362{\r
0e549d5b 1363 DEBUG (( EFI_D_INFO, "UsbRootHubRelease: root hub released for hub %p\n", HubIf));\r
e237e7ae 1364\r
1365 gBS->SetTimer (HubIf->HubNotify, TimerCancel, USB_ROOTHUB_POLL_INTERVAL);\r
1366 gBS->CloseEvent (HubIf->HubNotify);\r
1367\r
1368 return EFI_SUCCESS;\r
1369}\r
1370\r
1371USB_HUB_API mUsbHubApi = {\r
1372 UsbHubInit,\r
1373 UsbHubGetPortStatus,\r
1374 UsbHubClearPortChange,\r
1375 UsbHubSetPortFeature,\r
1376 UsbHubClearPortFeature,\r
1377 UsbHubResetPort,\r
1378 UsbHubRelease\r
1379};\r
1380\r
1381USB_HUB_API mUsbRootHubApi = {\r
1382 UsbRootHubInit,\r
1383 UsbRootHubGetPortStatus,\r
1384 UsbRootHubClearPortChange,\r
1385 UsbRootHubSetPortFeature,\r
1386 UsbRootHubClearPortFeature,\r
1387 UsbRootHubResetPort,\r
1388 UsbRootHubRelease\r
1389};\r