b63173d18184d677ece1163bff627d607450d5e9
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusPei / UsbPeim.c
1 /** @file
2 The module to produce Usb Bus PPI.
3
4 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions
8 of the BSD License which accompanies this distribution. The
9 full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "UsbPeim.h"
18 #include "HubPeim.h"
19 #include "PeiUsbLib.h"
20
21 //
22 // UsbIo PPI interface function
23 //
24 PEI_USB_IO_PPI mUsbIoPpi = {
25 PeiUsbControlTransfer,
26 PeiUsbBulkTransfer,
27 PeiUsbGetInterfaceDescriptor,
28 PeiUsbGetEndpointDescriptor,
29 PeiUsbPortReset
30 };
31
32 EFI_PEI_PPI_DESCRIPTOR mUsbIoPpiList = {
33 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
34 &gPeiUsbIoPpiGuid,
35 NULL
36 };
37
38 /**
39 The enumeration routine to detect device change.
40
41 @param PeiServices Describes the list of possible PEI Services.
42 @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.
43 @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.
44
45 @retval EFI_SUCCESS The usb is enumerated successfully.
46 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
47 @retval Others Other failure occurs.
48
49 **/
50 EFI_STATUS
51 PeiUsbEnumeration (
52 IN EFI_PEI_SERVICES **PeiServices,
53 IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,
54 IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi
55 );
56
57 /**
58 Configure new detected usb device.
59
60 @param PeiServices Describes the list of possible PEI Services.
61 @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.
62 @param Port The port to be configured.
63 @param DeviceAddress The device address to be configured.
64
65 @retval EFI_SUCCESS The new detected usb device is configured successfully.
66 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
67 @retval Others Other failure occurs.
68
69 **/
70 EFI_STATUS
71 PeiConfigureUsbDevice (
72 IN EFI_PEI_SERVICES **PeiServices,
73 IN PEI_USB_DEVICE *PeiUsbDevice,
74 IN UINT8 Port,
75 IN OUT UINT8 *DeviceAddress
76 );
77
78 /**
79 Get all configurations from a detected usb device.
80
81 @param PeiServices Describes the list of possible PEI Services.
82 @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.
83
84 @retval EFI_SUCCESS The new detected usb device is configured successfully.
85 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
86 @retval Others Other failure occurs.
87
88 **/
89 EFI_STATUS
90 PeiUsbGetAllConfiguration (
91 IN EFI_PEI_SERVICES **PeiServices,
92 IN PEI_USB_DEVICE *PeiUsbDevice
93 );
94
95 /**
96 Get the start position of next wanted descriptor.
97
98 @param Buffer Buffer containing data to parse.
99 @param Length Buffer length.
100 @param DescType Descriptor type.
101 @param DescLength Descriptor length.
102 @param ParsedBytes Bytes has been parsed.
103
104 @retval EFI_SUCCESS Get wanted descriptor successfully.
105 @retval EFI_DEVICE_ERROR Error occurred.
106
107 **/
108 EFI_STATUS
109 GetExpectedDescriptor (
110 IN UINT8 *Buffer,
111 IN UINTN Length,
112 IN UINT8 DescType,
113 IN UINT8 DescLength,
114 OUT UINTN *ParsedBytes
115 );
116
117 /**
118 The entrypoint of the module, it will enumerate all HCs.
119
120 @param FileHandle Handle of the file being invoked.
121 @param PeiServices Describes the list of possible PEI Services.
122
123 @retval EFI_SUCCESS Usb initialization is done successfully.
124 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
125 @retval EFI_UNSUPPORTED Can't find required PPI.
126
127 **/
128 EFI_STATUS
129 EFIAPI
130 PeimInitializeUsb (
131 IN EFI_PEI_FILE_HANDLE FileHandle,
132 IN CONST EFI_PEI_SERVICES **PeiServices
133 )
134 {
135 EFI_STATUS Status;
136 UINTN Index;
137 PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi;
138 PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi;
139
140 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
141 return EFI_SUCCESS;
142 }
143
144 //
145 // gPeiUsbHostControllerPpiGuid and gPeiUsb2HostControllerPpiGuid should not
146 // be produced at the same time
147 //
148 Index = 0;
149 while (TRUE) {
150 //
151 // Get UsbHcPpi at first.
152 //
153 Status = PeiServicesLocatePpi (
154 &gPeiUsbHostControllerPpiGuid,
155 Index,
156 NULL,
157 (VOID **) &UsbHcPpi
158 );
159 if (EFI_ERROR (Status)) {
160 //
161 // No more host controller, break out
162 //
163 break;
164 }
165 PeiUsbEnumeration ((EFI_PEI_SERVICES **) PeiServices, UsbHcPpi, NULL);
166 Index++;
167 }
168
169 if (Index == 0) {
170 //
171 // Then try to get Usb2HcPpi.
172 //
173 while (TRUE) {
174 Status = PeiServicesLocatePpi (
175 &gPeiUsb2HostControllerPpiGuid,
176 Index,
177 NULL,
178 (VOID **) &Usb2HcPpi
179 );
180 if (EFI_ERROR (Status)) {
181 //
182 // No more host controller, break out
183 //
184 break;
185 }
186 PeiUsbEnumeration ((EFI_PEI_SERVICES **) PeiServices, NULL, Usb2HcPpi);
187 Index++;
188 }
189 }
190
191 if (Index == 0) {
192 return EFI_UNSUPPORTED;
193 }
194
195 return EFI_SUCCESS;
196 }
197
198 /**
199 The Hub Enumeration just scans the hub ports one time. It also
200 doesn't support hot-plug.
201
202 @param PeiServices Describes the list of possible PEI Services.
203 @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.
204 @param CurrentAddress The DeviceAddress of usb device.
205
206 @retval EFI_SUCCESS The usb hub is enumerated successfully.
207 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
208 @retval Others Other failure occurs.
209
210 **/
211 EFI_STATUS
212 PeiHubEnumeration (
213 IN EFI_PEI_SERVICES **PeiServices,
214 IN PEI_USB_DEVICE *PeiUsbDevice,
215 IN UINT8 *CurrentAddress
216 )
217 {
218 UINTN Index;
219 EFI_STATUS Status;
220 PEI_USB_IO_PPI *UsbIoPpi;
221 EFI_USB_PORT_STATUS PortStatus;
222 UINTN MemPages;
223 EFI_PHYSICAL_ADDRESS AllocateAddress;
224 PEI_USB_DEVICE *NewPeiUsbDevice;
225
226
227 UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
228
229 for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {
230
231 Status = PeiHubGetPortStatus (
232 PeiServices,
233 UsbIoPpi,
234 (UINT8) (Index + 1),
235 (UINT32 *) &PortStatus
236 );
237
238 if (EFI_ERROR (Status)) {
239 continue;
240 }
241
242 if (IsPortConnectChange (PortStatus.PortChangeStatus)) {
243 PeiHubClearPortFeature (
244 PeiServices,
245 UsbIoPpi,
246 (UINT8) (Index + 1),
247 EfiUsbPortConnectChange
248 );
249
250 MicroSecondDelay (100 * 1000);
251
252 if (IsPortConnect (PortStatus.PortStatus)) {
253
254 PeiHubGetPortStatus (
255 PeiServices,
256 UsbIoPpi,
257 (UINT8) (Index + 1),
258 (UINT32 *) &PortStatus
259 );
260
261 //
262 // Begin to deal with the new device
263 //
264 MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
265 Status = PeiServicesAllocatePages (
266 EfiBootServicesCode,
267 MemPages,
268 &AllocateAddress
269 );
270 if (EFI_ERROR (Status)) {
271 return EFI_OUT_OF_RESOURCES;
272 }
273
274 NewPeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress);
275 ZeroMem (NewPeiUsbDevice, sizeof (PEI_USB_DEVICE));
276
277 NewPeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE;
278 NewPeiUsbDevice->DeviceAddress = 0;
279 NewPeiUsbDevice->MaxPacketSize0 = 8;
280 NewPeiUsbDevice->DataToggle = 0;
281 CopyMem (
282 &(NewPeiUsbDevice->UsbIoPpi),
283 &mUsbIoPpi,
284 sizeof (PEI_USB_IO_PPI)
285 );
286 CopyMem (
287 &(NewPeiUsbDevice->UsbIoPpiList),
288 &mUsbIoPpiList,
289 sizeof (EFI_PEI_PPI_DESCRIPTOR)
290 );
291 NewPeiUsbDevice->UsbIoPpiList.Ppi = &NewPeiUsbDevice->UsbIoPpi;
292 NewPeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress;
293 NewPeiUsbDevice->UsbHcPpi = PeiUsbDevice->UsbHcPpi;
294 NewPeiUsbDevice->Usb2HcPpi = PeiUsbDevice->Usb2HcPpi;
295 NewPeiUsbDevice->IsHub = 0x0;
296 NewPeiUsbDevice->DownStreamPortNo = 0x0;
297
298 PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1));
299
300 PeiHubGetPortStatus (
301 PeiServices,
302 UsbIoPpi,
303 (UINT8) (Index + 1),
304 (UINT32 *) &PortStatus
305 );
306
307 NewPeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus);
308
309 if(NewPeiUsbDevice->DeviceSpeed != EFI_USB_SPEED_HIGH) {
310 if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_HIGH) {
311 NewPeiUsbDevice->Translator.TranslatorPortNumber = (UINT8)Index;
312 NewPeiUsbDevice->Translator.TranslatorHubAddress = *CurrentAddress;
313 } else {
314 CopyMem(&(NewPeiUsbDevice->Translator), &(PeiUsbDevice->Translator), sizeof(EFI_USB2_HC_TRANSACTION_TRANSLATOR));
315 }
316 }
317
318 //
319 // Configure that Usb Device
320 //
321 Status = PeiConfigureUsbDevice (
322 PeiServices,
323 NewPeiUsbDevice,
324 (UINT8) (Index + 1),
325 CurrentAddress
326 );
327
328 if (EFI_ERROR (Status)) {
329 continue;
330 }
331
332 Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList);
333
334 if (NewPeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {
335 NewPeiUsbDevice->IsHub = 0x1;
336
337 Status = PeiDoHubConfig (PeiServices, NewPeiUsbDevice);
338 if (EFI_ERROR (Status)) {
339 return Status;
340 }
341
342 PeiHubEnumeration (PeiServices, NewPeiUsbDevice, CurrentAddress);
343 }
344 }
345
346 }
347 }
348
349
350 return EFI_SUCCESS;
351 }
352
353 /**
354 The enumeration routine to detect device change.
355
356 @param PeiServices Describes the list of possible PEI Services.
357 @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.
358 @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.
359
360 @retval EFI_SUCCESS The usb is enumerated successfully.
361 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
362 @retval Others Other failure occurs.
363
364 **/
365 EFI_STATUS
366 PeiUsbEnumeration (
367 IN EFI_PEI_SERVICES **PeiServices,
368 IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,
369 IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi
370 )
371 {
372 UINT8 NumOfRootPort;
373 EFI_STATUS Status;
374 UINT8 Index;
375 EFI_USB_PORT_STATUS PortStatus;
376 PEI_USB_DEVICE *PeiUsbDevice;
377 UINTN MemPages;
378 EFI_PHYSICAL_ADDRESS AllocateAddress;
379 UINT8 CurrentAddress;
380
381
382 CurrentAddress = 0;
383 if (Usb2HcPpi != NULL) {
384 Usb2HcPpi->GetRootHubPortNumber (
385 PeiServices,
386 Usb2HcPpi,
387 (UINT8 *) &NumOfRootPort
388 );
389 } else if (UsbHcPpi != NULL) {
390 UsbHcPpi->GetRootHubPortNumber (
391 PeiServices,
392 UsbHcPpi,
393 (UINT8 *) &NumOfRootPort
394 );
395 } else {
396 ASSERT (FALSE);
397 return EFI_INVALID_PARAMETER;
398 }
399
400 for (Index = 0; Index < NumOfRootPort; Index++) {
401 //
402 // First get root port status to detect changes happen
403 //
404 if (Usb2HcPpi != NULL) {
405 Usb2HcPpi->GetRootHubPortStatus (
406 PeiServices,
407 Usb2HcPpi,
408 (UINT8) Index,
409 &PortStatus
410 );
411 } else {
412 UsbHcPpi->GetRootHubPortStatus (
413 PeiServices,
414 UsbHcPpi,
415 (UINT8) Index,
416 &PortStatus
417 );
418 }
419 DEBUG ((EFI_D_INFO, "USB Status --- ConnectChange[%04x] Status[%04x]\n", PortStatus.PortChangeStatus, PortStatus.PortStatus));
420 if (IsPortConnectChange (PortStatus.PortChangeStatus)) {
421 //
422 // Changes happen, first clear this change status
423 //
424 if (Usb2HcPpi != NULL) {
425 Usb2HcPpi->ClearRootHubPortFeature (
426 PeiServices,
427 Usb2HcPpi,
428 (UINT8) Index,
429 EfiUsbPortConnectChange
430 );
431 } else {
432 UsbHcPpi->ClearRootHubPortFeature (
433 PeiServices,
434 UsbHcPpi,
435 (UINT8) Index,
436 EfiUsbPortConnectChange
437 );
438 }
439 MicroSecondDelay (100 * 1000);
440
441 if (IsPortConnect (PortStatus.PortStatus)) {
442 if (Usb2HcPpi != NULL) {
443 Usb2HcPpi->GetRootHubPortStatus (
444 PeiServices,
445 Usb2HcPpi,
446 (UINT8) Index,
447 &PortStatus
448 );
449 } else {
450 UsbHcPpi->GetRootHubPortStatus (
451 PeiServices,
452 UsbHcPpi,
453 (UINT8) Index,
454 &PortStatus
455 );
456 }
457
458 //
459 // Connect change happen
460 //
461 MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
462 Status = PeiServicesAllocatePages (
463 EfiBootServicesCode,
464 MemPages,
465 &AllocateAddress
466 );
467 if (EFI_ERROR (Status)) {
468 return EFI_OUT_OF_RESOURCES;
469 }
470
471 PeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress);
472 ZeroMem (PeiUsbDevice, sizeof (PEI_USB_DEVICE));
473
474 PeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE;
475 PeiUsbDevice->DeviceAddress = 0;
476 PeiUsbDevice->MaxPacketSize0 = 8;
477 PeiUsbDevice->DataToggle = 0;
478 CopyMem (
479 &(PeiUsbDevice->UsbIoPpi),
480 &mUsbIoPpi,
481 sizeof (PEI_USB_IO_PPI)
482 );
483 CopyMem (
484 &(PeiUsbDevice->UsbIoPpiList),
485 &mUsbIoPpiList,
486 sizeof (EFI_PEI_PPI_DESCRIPTOR)
487 );
488 PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi;
489 PeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress;
490 PeiUsbDevice->UsbHcPpi = UsbHcPpi;
491 PeiUsbDevice->Usb2HcPpi = Usb2HcPpi;
492 PeiUsbDevice->IsHub = 0x0;
493 PeiUsbDevice->DownStreamPortNo = 0x0;
494
495 ResetRootPort (
496 PeiServices,
497 PeiUsbDevice->UsbHcPpi,
498 PeiUsbDevice->Usb2HcPpi,
499 Index,
500 0
501 );
502
503 if (Usb2HcPpi != NULL) {
504 Usb2HcPpi->GetRootHubPortStatus (
505 PeiServices,
506 Usb2HcPpi,
507 (UINT8) Index,
508 &PortStatus
509 );
510 } else {
511 UsbHcPpi->GetRootHubPortStatus (
512 PeiServices,
513 UsbHcPpi,
514 (UINT8) Index,
515 &PortStatus
516 );
517 }
518
519 PeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus);
520 DEBUG ((EFI_D_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));
521
522 //
523 // Configure that Usb Device
524 //
525 Status = PeiConfigureUsbDevice (
526 PeiServices,
527 PeiUsbDevice,
528 Index,
529 &CurrentAddress
530 );
531
532 if (EFI_ERROR (Status)) {
533 continue;
534 }
535 DEBUG ((EFI_D_INFO, "PeiConfigureUsbDevice Success\n"));
536
537 Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);
538
539 if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {
540 PeiUsbDevice->IsHub = 0x1;
541
542 Status = PeiDoHubConfig (PeiServices, PeiUsbDevice);
543 if (EFI_ERROR (Status)) {
544 return Status;
545 }
546
547 PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress);
548 }
549 } else {
550 //
551 // Disconnect change happen, currently we don't support
552 //
553 }
554 }
555 }
556
557 return EFI_SUCCESS;
558 }
559
560 /**
561 Configure new detected usb device.
562
563 @param PeiServices Describes the list of possible PEI Services.
564 @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.
565 @param Port The port to be configured.
566 @param DeviceAddress The device address to be configured.
567
568 @retval EFI_SUCCESS The new detected usb device is configured successfully.
569 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
570 @retval Others Other failure occurs.
571
572 **/
573 EFI_STATUS
574 PeiConfigureUsbDevice (
575 IN EFI_PEI_SERVICES **PeiServices,
576 IN PEI_USB_DEVICE *PeiUsbDevice,
577 IN UINT8 Port,
578 IN OUT UINT8 *DeviceAddress
579 )
580 {
581 EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor;
582 EFI_STATUS Status;
583 PEI_USB_IO_PPI *UsbIoPpi;
584 UINT8 Retry;
585
586 UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
587 Status = EFI_SUCCESS;
588 ZeroMem (&DeviceDescriptor, sizeof (EFI_USB_DEVICE_DESCRIPTOR));
589 //
590 // Get USB device descriptor
591 //
592
593 for (Retry = 0; Retry < 3; Retry ++) {
594
595 PeiUsbDevice->MaxPacketSize0 = 8;
596
597 Status = PeiUsbGetDescriptor (
598 PeiServices,
599 UsbIoPpi,
600 (USB_DT_DEVICE << 8),
601 0,
602 8,
603 &DeviceDescriptor
604 );
605
606 if (!EFI_ERROR (Status)) {
607 DEBUG ((EFI_D_INFO, "PeiUsbGet Device Descriptor the %d time Sucess\n", Retry));
608 break;
609 }
610 }
611
612 if (Retry == 3) {
613 DEBUG ((EFI_D_ERROR, "PeiUsbGet Device Descriptor fail\n", Retry));
614 return Status;
615 }
616
617 PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0;
618
619 (*DeviceAddress) ++;
620
621 Status = PeiUsbSetDeviceAddress (
622 PeiServices,
623 UsbIoPpi,
624 *DeviceAddress
625 );
626
627 if (EFI_ERROR (Status)) {
628 DEBUG ((EFI_D_ERROR, "PeiUsbSetDeviceAddress Failed\n"));
629 return Status;
630 }
631
632 PeiUsbDevice->DeviceAddress = *DeviceAddress;
633
634 //
635 // Get whole USB device descriptor
636 //
637 Status = PeiUsbGetDescriptor (
638 PeiServices,
639 UsbIoPpi,
640 (USB_DT_DEVICE << 8),
641 0,
642 (UINT16) sizeof (EFI_USB_DEVICE_DESCRIPTOR),
643 &DeviceDescriptor
644 );
645
646 if (EFI_ERROR (Status)) {
647 DEBUG ((EFI_D_ERROR, "PeiUsbGetDescriptor First Failed\n"));
648 return Status;
649 }
650 //
651 // Get its default configuration and its first interface
652 //
653 Status = PeiUsbGetAllConfiguration (
654 PeiServices,
655 PeiUsbDevice
656 );
657
658 if (EFI_ERROR (Status)) {
659 return Status;
660 }
661
662 Status = PeiUsbSetConfiguration (
663 PeiServices,
664 UsbIoPpi
665 );
666
667 if (EFI_ERROR (Status)) {
668 return Status;
669 }
670
671 return EFI_SUCCESS;
672 }
673
674 /**
675 Get all configurations from a detected usb device.
676
677 @param PeiServices Describes the list of possible PEI Services.
678 @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.
679
680 @retval EFI_SUCCESS The new detected usb device is configured successfully.
681 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
682 @retval Others Other failure occurs.
683
684 **/
685 EFI_STATUS
686 PeiUsbGetAllConfiguration (
687 IN EFI_PEI_SERVICES **PeiServices,
688 IN PEI_USB_DEVICE *PeiUsbDevice
689 )
690 {
691 EFI_STATUS Status;
692 EFI_USB_CONFIG_DESCRIPTOR *ConfigDesc;
693 PEI_USB_IO_PPI *UsbIoPpi;
694 UINT16 ConfigDescLength;
695 UINT8 *Ptr;
696 UINTN SkipBytes;
697 UINTN LengthLeft;
698 UINTN Index;
699 UINTN NumOfEndpoint;
700
701 UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
702
703 //
704 // First get its 4-byte configuration descriptor
705 //
706 Status = PeiUsbGetDescriptor (
707 PeiServices,
708 UsbIoPpi,
709 (USB_DT_CONFIG << 8), // Value
710 0, // Index
711 4, // Length
712 PeiUsbDevice->ConfigurationData
713 );
714
715 if (EFI_ERROR (Status)) {
716 DEBUG ((EFI_D_ERROR, "PeiUsbGet Config Descriptor First Failed\n"));
717 return Status;
718 }
719
720 ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *) PeiUsbDevice->ConfigurationData;
721 ConfigDescLength = ConfigDesc->TotalLength;
722
723 //
724 // Then we get the total descriptors for this configuration
725 //
726 Status = PeiUsbGetDescriptor (
727 PeiServices,
728 UsbIoPpi,
729 (USB_DT_CONFIG << 8),
730 0,
731 ConfigDescLength,
732 PeiUsbDevice->ConfigurationData
733 );
734
735 if (EFI_ERROR (Status)) {
736 DEBUG ((EFI_D_ERROR, "PeiUsbGet Config Descriptor all Failed\n"));
737 return Status;
738 }
739 //
740 // Parse this configuration descriptor
741 // First get the current config descriptor;
742 //
743 Status = GetExpectedDescriptor (
744 PeiUsbDevice->ConfigurationData,
745 ConfigDescLength,
746 USB_DT_CONFIG,
747 (UINT8) sizeof (EFI_USB_CONFIG_DESCRIPTOR),
748 &SkipBytes
749 );
750
751 if (EFI_ERROR (Status)) {
752 return Status;
753 }
754
755 Ptr = PeiUsbDevice->ConfigurationData + SkipBytes;
756 PeiUsbDevice->ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *) Ptr;
757
758 Ptr += sizeof (EFI_USB_CONFIG_DESCRIPTOR);
759 LengthLeft = ConfigDescLength - SkipBytes - sizeof (EFI_USB_CONFIG_DESCRIPTOR);
760
761 //
762 // Get the first interface descriptor
763 //
764 Status = GetExpectedDescriptor (
765 Ptr,
766 LengthLeft,
767 USB_DT_INTERFACE,
768 (UINT8) sizeof (EFI_USB_INTERFACE_DESCRIPTOR),
769 &SkipBytes
770 );
771
772 if (EFI_ERROR (Status)) {
773 return Status;
774 }
775
776 Ptr += SkipBytes;
777 PeiUsbDevice->InterfaceDesc = (EFI_USB_INTERFACE_DESCRIPTOR *) Ptr;
778
779 Ptr += sizeof (EFI_USB_INTERFACE_DESCRIPTOR);
780 LengthLeft -= SkipBytes;
781 LengthLeft -= sizeof (EFI_USB_INTERFACE_DESCRIPTOR);
782
783 //
784 // Parse all the endpoint descriptor within this interface
785 //
786 NumOfEndpoint = PeiUsbDevice->InterfaceDesc->NumEndpoints;
787 ASSERT (NumOfEndpoint <= MAX_ENDPOINT);
788
789 for (Index = 0; Index < NumOfEndpoint; Index++) {
790 //
791 // Get the endpoint descriptor
792 //
793 Status = GetExpectedDescriptor (
794 Ptr,
795 LengthLeft,
796 USB_DT_ENDPOINT,
797 (UINT8) sizeof (EFI_USB_ENDPOINT_DESCRIPTOR),
798 &SkipBytes
799 );
800
801 if (EFI_ERROR (Status)) {
802 return Status;
803 }
804
805 Ptr += SkipBytes;
806 PeiUsbDevice->EndpointDesc[Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *) Ptr;
807
808 Ptr += sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);
809 LengthLeft -= SkipBytes;
810 LengthLeft -= sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);
811 }
812
813 return EFI_SUCCESS;
814 }
815
816 /**
817 Get the start position of next wanted descriptor.
818
819 @param Buffer Buffer containing data to parse.
820 @param Length Buffer length.
821 @param DescType Descriptor type.
822 @param DescLength Descriptor length.
823 @param ParsedBytes Bytes has been parsed.
824
825 @retval EFI_SUCCESS Get wanted descriptor successfully.
826 @retval EFI_DEVICE_ERROR Error occurred.
827
828 **/
829 EFI_STATUS
830 GetExpectedDescriptor (
831 IN UINT8 *Buffer,
832 IN UINTN Length,
833 IN UINT8 DescType,
834 IN UINT8 DescLength,
835 OUT UINTN *ParsedBytes
836 )
837 {
838 UINT16 DescriptorHeader;
839 UINT8 Len;
840 UINT8 *Ptr;
841 UINTN Parsed;
842
843 Parsed = 0;
844 Ptr = Buffer;
845
846 while (TRUE) {
847 //
848 // Buffer length should not less than Desc length
849 //
850 if (Length < DescLength) {
851 return EFI_DEVICE_ERROR;
852 }
853
854 DescriptorHeader = (UINT16) (*Ptr + ((*(Ptr + 1)) << 8));
855
856 Len = Buffer[0];
857
858 //
859 // Check to see if it is a start of expected descriptor
860 //
861 if (DescriptorHeader == ((DescType << 8) | DescLength)) {
862 break;
863 }
864
865 if ((UINT8) (DescriptorHeader >> 8) == DescType) {
866 if (Len > DescLength) {
867 return EFI_DEVICE_ERROR;
868 }
869 }
870 //
871 // Descriptor length should be at least 2
872 // and should not exceed the buffer length
873 //
874 if (Len < 2) {
875 return EFI_DEVICE_ERROR;
876 }
877
878 if (Len > Length) {
879 return EFI_DEVICE_ERROR;
880 }
881 //
882 // Skip this mismatch descriptor
883 //
884 Length -= Len;
885 Ptr += Len;
886 Parsed += Len;
887 }
888
889 *ParsedBytes = Parsed;
890
891 return EFI_SUCCESS;
892 }
893
894 /**
895 Send reset signal over the given root hub port.
896
897 @param PeiServices Describes the list of possible PEI Services.
898 @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.
899 @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.
900 @param PortNum The port to be reset.
901 @param RetryIndex The retry times.
902
903 **/
904 VOID
905 ResetRootPort (
906 IN EFI_PEI_SERVICES **PeiServices,
907 IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,
908 IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi,
909 IN UINT8 PortNum,
910 IN UINT8 RetryIndex
911 )
912 {
913 EFI_STATUS Status;
914
915
916 if (Usb2HcPpi != NULL) {
917 MicroSecondDelay (200 * 1000);
918
919 //
920 // reset root port
921 //
922 Status = Usb2HcPpi->SetRootHubPortFeature (
923 PeiServices,
924 Usb2HcPpi,
925 PortNum,
926 EfiUsbPortReset
927 );
928
929 if (EFI_ERROR (Status)) {
930 DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n"));
931 return;
932 }
933
934 MicroSecondDelay (200 * 1000);
935
936 //
937 // clear reset root port
938 //
939 Status = Usb2HcPpi->ClearRootHubPortFeature (
940 PeiServices,
941 Usb2HcPpi,
942 PortNum,
943 EfiUsbPortReset
944 );
945
946 if (EFI_ERROR (Status)) {
947 DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));
948 return;
949 }
950
951 MicroSecondDelay (1 * 1000);
952
953 Usb2HcPpi->ClearRootHubPortFeature (
954 PeiServices,
955 Usb2HcPpi,
956 PortNum,
957 EfiUsbPortConnectChange
958 );
959
960 //
961 // Set port enable
962 //
963 Usb2HcPpi->SetRootHubPortFeature(
964 PeiServices,
965 Usb2HcPpi,
966 PortNum,
967 EfiUsbPortEnable
968 );
969
970 Usb2HcPpi->ClearRootHubPortFeature (
971 PeiServices,
972 Usb2HcPpi,
973 PortNum,
974 EfiUsbPortEnableChange
975 );
976
977 MicroSecondDelay ((RetryIndex + 1) * 50 * 1000);
978 } else {
979 MicroSecondDelay (200 * 1000);
980
981 //
982 // reset root port
983 //
984 Status = UsbHcPpi->SetRootHubPortFeature (
985 PeiServices,
986 UsbHcPpi,
987 PortNum,
988 EfiUsbPortReset
989 );
990
991 if (EFI_ERROR (Status)) {
992 DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n"));
993 return;
994 }
995
996 MicroSecondDelay (200 * 1000);
997
998 //
999 // clear reset root port
1000 //
1001 Status = UsbHcPpi->ClearRootHubPortFeature (
1002 PeiServices,
1003 UsbHcPpi,
1004 PortNum,
1005 EfiUsbPortReset
1006 );
1007
1008 if (EFI_ERROR (Status)) {
1009 DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));
1010 return;
1011 }
1012
1013 MicroSecondDelay (1 * 1000);
1014
1015 UsbHcPpi->ClearRootHubPortFeature (
1016 PeiServices,
1017 UsbHcPpi,
1018 PortNum,
1019 EfiUsbPortConnectChange
1020 );
1021
1022 //
1023 // Set port enable
1024 //
1025 UsbHcPpi->SetRootHubPortFeature(
1026 PeiServices,
1027 UsbHcPpi,
1028 PortNum,
1029 EfiUsbPortEnable
1030 );
1031
1032 UsbHcPpi->ClearRootHubPortFeature (
1033 PeiServices,
1034 UsbHcPpi,
1035 PortNum,
1036 EfiUsbPortEnableChange
1037 );
1038
1039 MicroSecondDelay ((RetryIndex + 1) * 50 * 1000);
1040 }
1041 return;
1042 }
1043
1044