]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c
MdeModulePkg: Apply uncrustify changes
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusPei / UsbPeim.c
1 /** @file
2 The module to produce Usb Bus PPI.
3
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "UsbPeim.h"
11 #include "HubPeim.h"
12 #include "PeiUsbLib.h"
13
14 //
15 // UsbIo PPI interface function
16 //
17 PEI_USB_IO_PPI mUsbIoPpi = {
18 PeiUsbControlTransfer,
19 PeiUsbBulkTransfer,
20 PeiUsbGetInterfaceDescriptor,
21 PeiUsbGetEndpointDescriptor,
22 PeiUsbPortReset
23 };
24
25 EFI_PEI_PPI_DESCRIPTOR mUsbIoPpiList = {
26 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
27 &gPeiUsbIoPpiGuid,
28 NULL
29 };
30
31 /**
32 The enumeration routine to detect device change.
33
34 @param PeiServices Describes the list of possible PEI Services.
35 @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.
36 @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.
37
38 @retval EFI_SUCCESS The usb is enumerated successfully.
39 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
40 @retval Others Other failure occurs.
41
42 **/
43 EFI_STATUS
44 PeiUsbEnumeration (
45 IN EFI_PEI_SERVICES **PeiServices,
46 IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,
47 IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi
48 );
49
50 /**
51 Configure new detected usb device.
52
53 @param PeiServices Describes the list of possible PEI Services.
54 @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.
55 @param Port The port to be configured.
56 @param DeviceAddress The device address to be configured.
57
58 @retval EFI_SUCCESS The new detected usb device is configured successfully.
59 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
60 @retval Others Other failure occurs.
61
62 **/
63 EFI_STATUS
64 PeiConfigureUsbDevice (
65 IN EFI_PEI_SERVICES **PeiServices,
66 IN PEI_USB_DEVICE *PeiUsbDevice,
67 IN UINT8 Port,
68 IN OUT UINT8 *DeviceAddress
69 );
70
71 /**
72 Get all configurations from a detected usb device.
73
74 @param PeiServices Describes the list of possible PEI Services.
75 @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.
76
77 @retval EFI_SUCCESS The new detected usb device is configured successfully.
78 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
79 @retval Others Other failure occurs.
80
81 **/
82 EFI_STATUS
83 PeiUsbGetAllConfiguration (
84 IN EFI_PEI_SERVICES **PeiServices,
85 IN PEI_USB_DEVICE *PeiUsbDevice
86 );
87
88 /**
89 Get the start position of next wanted descriptor.
90
91 @param Buffer Buffer containing data to parse.
92 @param Length Buffer length.
93 @param DescType Descriptor type.
94 @param DescLength Descriptor length.
95 @param ParsedBytes Bytes has been parsed.
96
97 @retval EFI_SUCCESS Get wanted descriptor successfully.
98 @retval EFI_DEVICE_ERROR Error occurred.
99
100 **/
101 EFI_STATUS
102 GetExpectedDescriptor (
103 IN UINT8 *Buffer,
104 IN UINTN Length,
105 IN UINT8 DescType,
106 IN UINT8 DescLength,
107 OUT UINTN *ParsedBytes
108 );
109
110 /**
111 The entrypoint of the module, it will enumerate all HCs.
112
113 @param FileHandle Handle of the file being invoked.
114 @param PeiServices Describes the list of possible PEI Services.
115
116 @retval EFI_SUCCESS Usb initialization is done successfully.
117 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
118 @retval EFI_UNSUPPORTED Can't find required PPI.
119
120 **/
121 EFI_STATUS
122 EFIAPI
123 PeimInitializeUsb (
124 IN EFI_PEI_FILE_HANDLE FileHandle,
125 IN CONST EFI_PEI_SERVICES **PeiServices
126 )
127 {
128 EFI_STATUS Status;
129 UINTN Index;
130 PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi;
131 PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi;
132
133 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
134 return EFI_SUCCESS;
135 }
136
137 //
138 // gPeiUsbHostControllerPpiGuid and gPeiUsb2HostControllerPpiGuid should not
139 // be produced at the same time
140 //
141 Index = 0;
142 while (TRUE) {
143 //
144 // Get UsbHcPpi at first.
145 //
146 Status = PeiServicesLocatePpi (
147 &gPeiUsbHostControllerPpiGuid,
148 Index,
149 NULL,
150 (VOID **)&UsbHcPpi
151 );
152 if (EFI_ERROR (Status)) {
153 //
154 // No more host controller, break out
155 //
156 break;
157 }
158
159 PeiUsbEnumeration ((EFI_PEI_SERVICES **)PeiServices, UsbHcPpi, NULL);
160 Index++;
161 }
162
163 if (Index == 0) {
164 //
165 // Then try to get Usb2HcPpi.
166 //
167 while (TRUE) {
168 Status = PeiServicesLocatePpi (
169 &gPeiUsb2HostControllerPpiGuid,
170 Index,
171 NULL,
172 (VOID **)&Usb2HcPpi
173 );
174 if (EFI_ERROR (Status)) {
175 //
176 // No more host controller, break out
177 //
178 break;
179 }
180
181 PeiUsbEnumeration ((EFI_PEI_SERVICES **)PeiServices, NULL, Usb2HcPpi);
182 Index++;
183 }
184 }
185
186 if (Index == 0) {
187 return EFI_UNSUPPORTED;
188 }
189
190 return EFI_SUCCESS;
191 }
192
193 /**
194 The Hub Enumeration just scans the hub ports one time. It also
195 doesn't support hot-plug.
196
197 @param PeiServices Describes the list of possible PEI Services.
198 @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.
199 @param CurrentAddress The DeviceAddress of usb device.
200
201 @retval EFI_SUCCESS The usb hub is enumerated successfully.
202 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
203 @retval Others Other failure occurs.
204
205 **/
206 EFI_STATUS
207 PeiHubEnumeration (
208 IN EFI_PEI_SERVICES **PeiServices,
209 IN PEI_USB_DEVICE *PeiUsbDevice,
210 IN UINT8 *CurrentAddress
211 )
212 {
213 UINTN Index;
214 EFI_STATUS Status;
215 PEI_USB_IO_PPI *UsbIoPpi;
216 EFI_USB_PORT_STATUS PortStatus;
217 UINTN MemPages;
218 EFI_PHYSICAL_ADDRESS AllocateAddress;
219 PEI_USB_DEVICE *NewPeiUsbDevice;
220 UINTN InterfaceIndex;
221 UINTN EndpointIndex;
222
223 UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
224
225 DEBUG ((DEBUG_INFO, "PeiHubEnumeration: DownStreamPortNo: %x\n", PeiUsbDevice->DownStreamPortNo));
226
227 for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {
228 Status = PeiHubGetPortStatus (
229 PeiServices,
230 UsbIoPpi,
231 (UINT8)(Index + 1),
232 (UINT32 *)&PortStatus
233 );
234
235 if (EFI_ERROR (Status)) {
236 continue;
237 }
238
239 DEBUG ((DEBUG_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus));
240 //
241 // Only handle connection/enable/overcurrent/reset change.
242 //
243 if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
244 continue;
245 } else {
246 if (IsPortConnect (PortStatus.PortStatus)) {
247 //
248 // Begin to deal with the new device
249 //
250 MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
251 Status = PeiServicesAllocatePages (
252 EfiBootServicesCode,
253 MemPages,
254 &AllocateAddress
255 );
256 if (EFI_ERROR (Status)) {
257 return EFI_OUT_OF_RESOURCES;
258 }
259
260 NewPeiUsbDevice = (PEI_USB_DEVICE *)((UINTN)AllocateAddress);
261 ZeroMem (NewPeiUsbDevice, sizeof (PEI_USB_DEVICE));
262
263 NewPeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE;
264 NewPeiUsbDevice->DeviceAddress = 0;
265 NewPeiUsbDevice->MaxPacketSize0 = 8;
266 NewPeiUsbDevice->DataToggle = 0;
267 CopyMem (
268 &(NewPeiUsbDevice->UsbIoPpi),
269 &mUsbIoPpi,
270 sizeof (PEI_USB_IO_PPI)
271 );
272 CopyMem (
273 &(NewPeiUsbDevice->UsbIoPpiList),
274 &mUsbIoPpiList,
275 sizeof (EFI_PEI_PPI_DESCRIPTOR)
276 );
277 NewPeiUsbDevice->UsbIoPpiList.Ppi = &NewPeiUsbDevice->UsbIoPpi;
278 NewPeiUsbDevice->AllocateAddress = (UINTN)AllocateAddress;
279 NewPeiUsbDevice->UsbHcPpi = PeiUsbDevice->UsbHcPpi;
280 NewPeiUsbDevice->Usb2HcPpi = PeiUsbDevice->Usb2HcPpi;
281 NewPeiUsbDevice->Tier = (UINT8)(PeiUsbDevice->Tier + 1);
282 NewPeiUsbDevice->IsHub = 0x0;
283 NewPeiUsbDevice->DownStreamPortNo = 0x0;
284
285 if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) ||
286 ((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0))
287 {
288 //
289 // If the port already has reset change flag and is connected and enabled, skip the port reset logic.
290 //
291 PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1));
292
293 PeiHubGetPortStatus (
294 PeiServices,
295 UsbIoPpi,
296 (UINT8)(Index + 1),
297 (UINT32 *)&PortStatus
298 );
299 } else {
300 PeiHubClearPortFeature (
301 PeiServices,
302 UsbIoPpi,
303 (UINT8)(Index + 1),
304 EfiUsbPortResetChange
305 );
306 }
307
308 NewPeiUsbDevice->DeviceSpeed = (UINT8)PeiUsbGetDeviceSpeed (PortStatus.PortStatus);
309 DEBUG ((DEBUG_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));
310
311 if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)) {
312 NewPeiUsbDevice->MaxPacketSize0 = 512;
313 } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
314 NewPeiUsbDevice->MaxPacketSize0 = 64;
315 } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
316 NewPeiUsbDevice->MaxPacketSize0 = 8;
317 } else {
318 NewPeiUsbDevice->MaxPacketSize0 = 8;
319 }
320
321 if (NewPeiUsbDevice->DeviceSpeed != EFI_USB_SPEED_HIGH) {
322 if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_HIGH) {
323 NewPeiUsbDevice->Translator.TranslatorPortNumber = (UINT8)Index;
324 NewPeiUsbDevice->Translator.TranslatorHubAddress = *CurrentAddress;
325 } else {
326 CopyMem (&(NewPeiUsbDevice->Translator), &(PeiUsbDevice->Translator), sizeof (EFI_USB2_HC_TRANSACTION_TRANSLATOR));
327 }
328 }
329
330 //
331 // Configure that Usb Device
332 //
333 Status = PeiConfigureUsbDevice (
334 PeiServices,
335 NewPeiUsbDevice,
336 (UINT8)(Index + 1),
337 CurrentAddress
338 );
339
340 if (EFI_ERROR (Status)) {
341 continue;
342 }
343
344 DEBUG ((DEBUG_INFO, "PeiHubEnumeration: PeiConfigureUsbDevice Success\n"));
345
346 Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList);
347
348 if (NewPeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {
349 NewPeiUsbDevice->IsHub = 0x1;
350
351 Status = PeiDoHubConfig (PeiServices, NewPeiUsbDevice);
352 if (EFI_ERROR (Status)) {
353 return Status;
354 }
355
356 PeiHubEnumeration (PeiServices, NewPeiUsbDevice, CurrentAddress);
357 }
358
359 for (InterfaceIndex = 1; InterfaceIndex < NewPeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) {
360 //
361 // Begin to deal with the new device
362 //
363 MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
364 Status = PeiServicesAllocatePages (
365 EfiBootServicesCode,
366 MemPages,
367 &AllocateAddress
368 );
369 if (EFI_ERROR (Status)) {
370 return EFI_OUT_OF_RESOURCES;
371 }
372
373 CopyMem ((VOID *)(UINTN)AllocateAddress, NewPeiUsbDevice, sizeof (PEI_USB_DEVICE));
374 NewPeiUsbDevice = (PEI_USB_DEVICE *)((UINTN)AllocateAddress);
375 NewPeiUsbDevice->AllocateAddress = (UINTN)AllocateAddress;
376 NewPeiUsbDevice->UsbIoPpiList.Ppi = &NewPeiUsbDevice->UsbIoPpi;
377 NewPeiUsbDevice->InterfaceDesc = NewPeiUsbDevice->InterfaceDescList[InterfaceIndex];
378 for (EndpointIndex = 0; EndpointIndex < NewPeiUsbDevice->InterfaceDesc->NumEndpoints; EndpointIndex++) {
379 NewPeiUsbDevice->EndpointDesc[EndpointIndex] = NewPeiUsbDevice->EndpointDescList[InterfaceIndex][EndpointIndex];
380 }
381
382 Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList);
383
384 if (NewPeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {
385 NewPeiUsbDevice->IsHub = 0x1;
386
387 Status = PeiDoHubConfig (PeiServices, NewPeiUsbDevice);
388 if (EFI_ERROR (Status)) {
389 return Status;
390 }
391
392 PeiHubEnumeration (PeiServices, NewPeiUsbDevice, CurrentAddress);
393 }
394 }
395 }
396 }
397 }
398
399 return EFI_SUCCESS;
400 }
401
402 /**
403 The enumeration routine to detect device change.
404
405 @param PeiServices Describes the list of possible PEI Services.
406 @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.
407 @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.
408
409 @retval EFI_SUCCESS The usb is enumerated successfully.
410 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
411 @retval Others Other failure occurs.
412
413 **/
414 EFI_STATUS
415 PeiUsbEnumeration (
416 IN EFI_PEI_SERVICES **PeiServices,
417 IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,
418 IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi
419 )
420 {
421 UINT8 NumOfRootPort;
422 EFI_STATUS Status;
423 UINT8 Index;
424 EFI_USB_PORT_STATUS PortStatus;
425 PEI_USB_DEVICE *PeiUsbDevice;
426 UINTN MemPages;
427 EFI_PHYSICAL_ADDRESS AllocateAddress;
428 UINT8 CurrentAddress;
429 UINTN InterfaceIndex;
430 UINTN EndpointIndex;
431
432 CurrentAddress = 0;
433 if (Usb2HcPpi != NULL) {
434 Usb2HcPpi->GetRootHubPortNumber (
435 PeiServices,
436 Usb2HcPpi,
437 (UINT8 *)&NumOfRootPort
438 );
439 } else if (UsbHcPpi != NULL) {
440 UsbHcPpi->GetRootHubPortNumber (
441 PeiServices,
442 UsbHcPpi,
443 (UINT8 *)&NumOfRootPort
444 );
445 } else {
446 ASSERT (FALSE);
447 return EFI_INVALID_PARAMETER;
448 }
449
450 DEBUG ((DEBUG_INFO, "PeiUsbEnumeration: NumOfRootPort: %x\n", NumOfRootPort));
451
452 for (Index = 0; Index < NumOfRootPort; Index++) {
453 //
454 // First get root port status to detect changes happen
455 //
456 if (Usb2HcPpi != NULL) {
457 Usb2HcPpi->GetRootHubPortStatus (
458 PeiServices,
459 Usb2HcPpi,
460 (UINT8)Index,
461 &PortStatus
462 );
463 } else {
464 UsbHcPpi->GetRootHubPortStatus (
465 PeiServices,
466 UsbHcPpi,
467 (UINT8)Index,
468 &PortStatus
469 );
470 }
471
472 DEBUG ((DEBUG_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus));
473 //
474 // Only handle connection/enable/overcurrent/reset change.
475 //
476 if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
477 continue;
478 } else {
479 if (IsPortConnect (PortStatus.PortStatus)) {
480 MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
481 Status = PeiServicesAllocatePages (
482 EfiBootServicesCode,
483 MemPages,
484 &AllocateAddress
485 );
486 if (EFI_ERROR (Status)) {
487 return EFI_OUT_OF_RESOURCES;
488 }
489
490 PeiUsbDevice = (PEI_USB_DEVICE *)((UINTN)AllocateAddress);
491 ZeroMem (PeiUsbDevice, sizeof (PEI_USB_DEVICE));
492
493 PeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE;
494 PeiUsbDevice->DeviceAddress = 0;
495 PeiUsbDevice->MaxPacketSize0 = 8;
496 PeiUsbDevice->DataToggle = 0;
497 CopyMem (
498 &(PeiUsbDevice->UsbIoPpi),
499 &mUsbIoPpi,
500 sizeof (PEI_USB_IO_PPI)
501 );
502 CopyMem (
503 &(PeiUsbDevice->UsbIoPpiList),
504 &mUsbIoPpiList,
505 sizeof (EFI_PEI_PPI_DESCRIPTOR)
506 );
507 PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi;
508 PeiUsbDevice->AllocateAddress = (UINTN)AllocateAddress;
509 PeiUsbDevice->UsbHcPpi = UsbHcPpi;
510 PeiUsbDevice->Usb2HcPpi = Usb2HcPpi;
511 PeiUsbDevice->IsHub = 0x0;
512 PeiUsbDevice->DownStreamPortNo = 0x0;
513
514 if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) ||
515 ((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0))
516 {
517 //
518 // If the port already has reset change flag and is connected and enabled, skip the port reset logic.
519 //
520 ResetRootPort (
521 PeiServices,
522 PeiUsbDevice->UsbHcPpi,
523 PeiUsbDevice->Usb2HcPpi,
524 Index,
525 0
526 );
527
528 if (Usb2HcPpi != NULL) {
529 Usb2HcPpi->GetRootHubPortStatus (
530 PeiServices,
531 Usb2HcPpi,
532 (UINT8)Index,
533 &PortStatus
534 );
535 } else {
536 UsbHcPpi->GetRootHubPortStatus (
537 PeiServices,
538 UsbHcPpi,
539 (UINT8)Index,
540 &PortStatus
541 );
542 }
543 } else {
544 if (Usb2HcPpi != NULL) {
545 Usb2HcPpi->ClearRootHubPortFeature (
546 PeiServices,
547 Usb2HcPpi,
548 (UINT8)Index,
549 EfiUsbPortResetChange
550 );
551 } else {
552 UsbHcPpi->ClearRootHubPortFeature (
553 PeiServices,
554 UsbHcPpi,
555 (UINT8)Index,
556 EfiUsbPortResetChange
557 );
558 }
559 }
560
561 PeiUsbDevice->DeviceSpeed = (UINT8)PeiUsbGetDeviceSpeed (PortStatus.PortStatus);
562 DEBUG ((DEBUG_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));
563
564 if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)) {
565 PeiUsbDevice->MaxPacketSize0 = 512;
566 } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
567 PeiUsbDevice->MaxPacketSize0 = 64;
568 } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
569 PeiUsbDevice->MaxPacketSize0 = 8;
570 } else {
571 PeiUsbDevice->MaxPacketSize0 = 8;
572 }
573
574 //
575 // Configure that Usb Device
576 //
577 Status = PeiConfigureUsbDevice (
578 PeiServices,
579 PeiUsbDevice,
580 Index,
581 &CurrentAddress
582 );
583
584 if (EFI_ERROR (Status)) {
585 continue;
586 }
587
588 DEBUG ((DEBUG_INFO, "PeiUsbEnumeration: PeiConfigureUsbDevice Success\n"));
589
590 Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);
591
592 if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {
593 PeiUsbDevice->IsHub = 0x1;
594
595 Status = PeiDoHubConfig (PeiServices, PeiUsbDevice);
596 if (EFI_ERROR (Status)) {
597 return Status;
598 }
599
600 PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress);
601 }
602
603 for (InterfaceIndex = 1; InterfaceIndex < PeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) {
604 //
605 // Begin to deal with the new device
606 //
607 MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
608 Status = PeiServicesAllocatePages (
609 EfiBootServicesCode,
610 MemPages,
611 &AllocateAddress
612 );
613 if (EFI_ERROR (Status)) {
614 return EFI_OUT_OF_RESOURCES;
615 }
616
617 CopyMem ((VOID *)(UINTN)AllocateAddress, PeiUsbDevice, sizeof (PEI_USB_DEVICE));
618 PeiUsbDevice = (PEI_USB_DEVICE *)((UINTN)AllocateAddress);
619 PeiUsbDevice->AllocateAddress = (UINTN)AllocateAddress;
620 PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi;
621 PeiUsbDevice->InterfaceDesc = PeiUsbDevice->InterfaceDescList[InterfaceIndex];
622 for (EndpointIndex = 0; EndpointIndex < PeiUsbDevice->InterfaceDesc->NumEndpoints; EndpointIndex++) {
623 PeiUsbDevice->EndpointDesc[EndpointIndex] = PeiUsbDevice->EndpointDescList[InterfaceIndex][EndpointIndex];
624 }
625
626 Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);
627
628 if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {
629 PeiUsbDevice->IsHub = 0x1;
630
631 Status = PeiDoHubConfig (PeiServices, PeiUsbDevice);
632 if (EFI_ERROR (Status)) {
633 return Status;
634 }
635
636 PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress);
637 }
638 }
639 } else {
640 //
641 // Disconnect change happen, currently we don't support
642 //
643 }
644 }
645 }
646
647 return EFI_SUCCESS;
648 }
649
650 /**
651 Configure new detected usb device.
652
653 @param PeiServices Describes the list of possible PEI Services.
654 @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.
655 @param Port The port to be configured.
656 @param DeviceAddress The device address to be configured.
657
658 @retval EFI_SUCCESS The new detected usb device is configured successfully.
659 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
660 @retval Others Other failure occurs.
661
662 **/
663 EFI_STATUS
664 PeiConfigureUsbDevice (
665 IN EFI_PEI_SERVICES **PeiServices,
666 IN PEI_USB_DEVICE *PeiUsbDevice,
667 IN UINT8 Port,
668 IN OUT UINT8 *DeviceAddress
669 )
670 {
671 EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor;
672 EFI_STATUS Status;
673 PEI_USB_IO_PPI *UsbIoPpi;
674 UINT8 Retry;
675
676 UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
677 Status = EFI_SUCCESS;
678 ZeroMem (&DeviceDescriptor, sizeof (EFI_USB_DEVICE_DESCRIPTOR));
679 //
680 // Get USB device descriptor
681 //
682
683 for (Retry = 0; Retry < 3; Retry++) {
684 Status = PeiUsbGetDescriptor (
685 PeiServices,
686 UsbIoPpi,
687 (USB_DT_DEVICE << 8),
688 0,
689 8,
690 &DeviceDescriptor
691 );
692
693 if (!EFI_ERROR (Status)) {
694 DEBUG ((DEBUG_INFO, "PeiUsbGet Device Descriptor the %d time Success\n", Retry));
695 break;
696 }
697 }
698
699 if (Retry == 3) {
700 DEBUG ((DEBUG_ERROR, "PeiUsbGet Device Descriptor fail: %x %r\n", Retry, Status));
701 return Status;
702 }
703
704 if ((DeviceDescriptor.BcdUSB >= 0x0300) && (DeviceDescriptor.MaxPacketSize0 == 9)) {
705 PeiUsbDevice->MaxPacketSize0 = 1 << 9;
706 } else {
707 PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0;
708 }
709
710 (*DeviceAddress)++;
711
712 Status = PeiUsbSetDeviceAddress (
713 PeiServices,
714 UsbIoPpi,
715 *DeviceAddress
716 );
717
718 if (EFI_ERROR (Status)) {
719 DEBUG ((DEBUG_ERROR, "PeiUsbSetDeviceAddress Failed: %r\n", Status));
720 return Status;
721 }
722
723 MicroSecondDelay (USB_SET_DEVICE_ADDRESS_STALL);
724
725 PeiUsbDevice->DeviceAddress = *DeviceAddress;
726
727 //
728 // Get whole USB device descriptor
729 //
730 Status = PeiUsbGetDescriptor (
731 PeiServices,
732 UsbIoPpi,
733 (USB_DT_DEVICE << 8),
734 0,
735 (UINT16)sizeof (EFI_USB_DEVICE_DESCRIPTOR),
736 &DeviceDescriptor
737 );
738
739 if (EFI_ERROR (Status)) {
740 DEBUG ((DEBUG_ERROR, "PeiUsbGetDescriptor First Failed\n"));
741 return Status;
742 }
743
744 //
745 // Get its default configuration and its first interface
746 //
747 Status = PeiUsbGetAllConfiguration (
748 PeiServices,
749 PeiUsbDevice
750 );
751 if (EFI_ERROR (Status)) {
752 return Status;
753 }
754
755 MicroSecondDelay (USB_GET_CONFIG_DESCRIPTOR_STALL);
756
757 Status = PeiUsbSetConfiguration (
758 PeiServices,
759 UsbIoPpi
760 );
761
762 if (EFI_ERROR (Status)) {
763 return Status;
764 }
765
766 return EFI_SUCCESS;
767 }
768
769 /**
770 Get all configurations from a detected usb device.
771
772 @param PeiServices Describes the list of possible PEI Services.
773 @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.
774
775 @retval EFI_SUCCESS The new detected usb device is configured successfully.
776 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
777 @retval Others Other failure occurs.
778
779 **/
780 EFI_STATUS
781 PeiUsbGetAllConfiguration (
782 IN EFI_PEI_SERVICES **PeiServices,
783 IN PEI_USB_DEVICE *PeiUsbDevice
784 )
785 {
786 EFI_STATUS Status;
787 EFI_USB_CONFIG_DESCRIPTOR *ConfigDesc;
788 PEI_USB_IO_PPI *UsbIoPpi;
789 UINT16 ConfigDescLength;
790 UINT8 *Ptr;
791 UINTN SkipBytes;
792 UINTN LengthLeft;
793 UINTN InterfaceIndex;
794 UINTN Index;
795 UINTN NumOfEndpoint;
796
797 UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
798
799 //
800 // First get its 4-byte configuration descriptor
801 //
802 Status = PeiUsbGetDescriptor (
803 PeiServices,
804 UsbIoPpi,
805 (USB_DT_CONFIG << 8), // Value
806 0, // Index
807 4, // Length
808 PeiUsbDevice->ConfigurationData
809 );
810
811 if (EFI_ERROR (Status)) {
812 DEBUG ((DEBUG_ERROR, "PeiUsbGet Config Descriptor First Failed\n"));
813 return Status;
814 }
815
816 MicroSecondDelay (USB_GET_CONFIG_DESCRIPTOR_STALL);
817
818 ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *)PeiUsbDevice->ConfigurationData;
819 ConfigDescLength = ConfigDesc->TotalLength;
820
821 //
822 // Reject if TotalLength even cannot cover itself.
823 //
824 if (ConfigDescLength < OFFSET_OF (EFI_USB_CONFIG_DESCRIPTOR, TotalLength) + sizeof (ConfigDesc->TotalLength)) {
825 return EFI_DEVICE_ERROR;
826 }
827
828 //
829 // Reject if TotalLength exceeds the PeiUsbDevice->ConfigurationData.
830 //
831 if (ConfigDescLength > sizeof (PeiUsbDevice->ConfigurationData)) {
832 return EFI_DEVICE_ERROR;
833 }
834
835 //
836 // Then we get the total descriptors for this configuration
837 //
838 Status = PeiUsbGetDescriptor (
839 PeiServices,
840 UsbIoPpi,
841 (USB_DT_CONFIG << 8),
842 0,
843 ConfigDescLength,
844 PeiUsbDevice->ConfigurationData
845 );
846
847 if (EFI_ERROR (Status)) {
848 DEBUG ((DEBUG_ERROR, "PeiUsbGet Config Descriptor all Failed\n"));
849 return Status;
850 }
851
852 //
853 // Parse this configuration descriptor
854 // First get the current config descriptor;
855 //
856 Status = GetExpectedDescriptor (
857 PeiUsbDevice->ConfigurationData,
858 ConfigDescLength,
859 USB_DT_CONFIG,
860 (UINT8)sizeof (EFI_USB_CONFIG_DESCRIPTOR),
861 &SkipBytes
862 );
863
864 if (EFI_ERROR (Status)) {
865 return Status;
866 }
867
868 Ptr = PeiUsbDevice->ConfigurationData + SkipBytes;
869 PeiUsbDevice->ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *)Ptr;
870
871 Ptr += sizeof (EFI_USB_CONFIG_DESCRIPTOR);
872 LengthLeft = ConfigDescLength - SkipBytes - sizeof (EFI_USB_CONFIG_DESCRIPTOR);
873
874 for (InterfaceIndex = 0; InterfaceIndex < PeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) {
875 //
876 // Get the interface descriptor
877 //
878 Status = GetExpectedDescriptor (
879 Ptr,
880 LengthLeft,
881 USB_DT_INTERFACE,
882 (UINT8)sizeof (EFI_USB_INTERFACE_DESCRIPTOR),
883 &SkipBytes
884 );
885
886 if (EFI_ERROR (Status)) {
887 return Status;
888 }
889
890 Ptr += SkipBytes;
891 if (InterfaceIndex == 0) {
892 PeiUsbDevice->InterfaceDesc = (EFI_USB_INTERFACE_DESCRIPTOR *)Ptr;
893 }
894
895 PeiUsbDevice->InterfaceDescList[InterfaceIndex] = (EFI_USB_INTERFACE_DESCRIPTOR *)Ptr;
896
897 Ptr += sizeof (EFI_USB_INTERFACE_DESCRIPTOR);
898 LengthLeft -= SkipBytes;
899 LengthLeft -= sizeof (EFI_USB_INTERFACE_DESCRIPTOR);
900
901 //
902 // Parse all the endpoint descriptor within this interface
903 //
904 NumOfEndpoint = PeiUsbDevice->InterfaceDescList[InterfaceIndex]->NumEndpoints;
905 ASSERT (NumOfEndpoint <= MAX_ENDPOINT);
906
907 for (Index = 0; Index < NumOfEndpoint; Index++) {
908 //
909 // Get the endpoint descriptor
910 //
911 Status = GetExpectedDescriptor (
912 Ptr,
913 LengthLeft,
914 USB_DT_ENDPOINT,
915 (UINT8)sizeof (EFI_USB_ENDPOINT_DESCRIPTOR),
916 &SkipBytes
917 );
918
919 if (EFI_ERROR (Status)) {
920 return Status;
921 }
922
923 Ptr += SkipBytes;
924 if (InterfaceIndex == 0) {
925 PeiUsbDevice->EndpointDesc[Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *)Ptr;
926 }
927
928 PeiUsbDevice->EndpointDescList[InterfaceIndex][Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *)Ptr;
929
930 Ptr += sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);
931 LengthLeft -= SkipBytes;
932 LengthLeft -= sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);
933 }
934 }
935
936 return EFI_SUCCESS;
937 }
938
939 /**
940 Get the start position of next wanted descriptor.
941
942 @param Buffer Buffer containing data to parse.
943 @param Length Buffer length.
944 @param DescType Descriptor type.
945 @param DescLength Descriptor length.
946 @param ParsedBytes Bytes has been parsed.
947
948 @retval EFI_SUCCESS Get wanted descriptor successfully.
949 @retval EFI_DEVICE_ERROR Error occurred.
950
951 **/
952 EFI_STATUS
953 GetExpectedDescriptor (
954 IN UINT8 *Buffer,
955 IN UINTN Length,
956 IN UINT8 DescType,
957 IN UINT8 DescLength,
958 OUT UINTN *ParsedBytes
959 )
960 {
961 USB_DESC_HEAD *Head;
962 UINTN Offset;
963
964 //
965 // Total length is too small that cannot hold the single descriptor header plus data.
966 //
967 if (Length <= sizeof (USB_DESC_HEAD)) {
968 DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, total length = %d!\n", Length));
969 return EFI_DEVICE_ERROR;
970 }
971
972 //
973 // All the descriptor has a common LTV (Length, Type, Value)
974 // format. Skip the descriptor that isn't of this Type
975 //
976 Offset = 0;
977 Head = (USB_DESC_HEAD *)Buffer;
978 while (Offset < Length - sizeof (USB_DESC_HEAD)) {
979 //
980 // Above condition make sure Head->Len and Head->Type are safe to access
981 //
982 Head = (USB_DESC_HEAD *)&Buffer[Offset];
983
984 if (Head->Len == 0) {
985 DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, Head->Len = 0!\n"));
986 return EFI_DEVICE_ERROR;
987 }
988
989 //
990 // Make sure no overflow when adding Head->Len to Offset.
991 //
992 if (Head->Len > MAX_UINTN - Offset) {
993 DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, Head->Len = %d!\n", Head->Len));
994 return EFI_DEVICE_ERROR;
995 }
996
997 if (Head->Type == DescType) {
998 break;
999 }
1000
1001 Offset += Head->Len;
1002 }
1003
1004 //
1005 // Head->Len is invalid resulting data beyond boundary, or
1006 // Descriptor cannot be found: No such type.
1007 //
1008 if (Length < Offset) {
1009 DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, Offset/Len = %d/%d!\n", Offset, Length));
1010 return EFI_DEVICE_ERROR;
1011 }
1012
1013 if ((Head->Type != DescType) || (Head->Len < DescLength)) {
1014 DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: descriptor cannot be found, Header(T/L) = %d/%d!\n", Head->Type, Head->Len));
1015 return EFI_DEVICE_ERROR;
1016 }
1017
1018 *ParsedBytes = Offset;
1019 return EFI_SUCCESS;
1020 }
1021
1022 /**
1023 Send reset signal over the given root hub port.
1024
1025 @param PeiServices Describes the list of possible PEI Services.
1026 @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.
1027 @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.
1028 @param PortNum The port to be reset.
1029 @param RetryIndex The retry times.
1030
1031 **/
1032 VOID
1033 ResetRootPort (
1034 IN EFI_PEI_SERVICES **PeiServices,
1035 IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,
1036 IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi,
1037 IN UINT8 PortNum,
1038 IN UINT8 RetryIndex
1039 )
1040 {
1041 EFI_STATUS Status;
1042 UINTN Index;
1043 EFI_USB_PORT_STATUS PortStatus;
1044
1045 if (Usb2HcPpi != NULL) {
1046 MicroSecondDelay (200 * 1000);
1047
1048 //
1049 // reset root port
1050 //
1051 Status = Usb2HcPpi->SetRootHubPortFeature (
1052 PeiServices,
1053 Usb2HcPpi,
1054 PortNum,
1055 EfiUsbPortReset
1056 );
1057
1058 if (EFI_ERROR (Status)) {
1059 DEBUG ((DEBUG_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n"));
1060 return;
1061 }
1062
1063 //
1064 // Drive the reset signal for at least 50ms. Check USB 2.0 Spec
1065 // section 7.1.7.5 for timing requirements.
1066 //
1067 MicroSecondDelay (USB_SET_ROOT_PORT_RESET_STALL);
1068
1069 //
1070 // clear reset root port
1071 //
1072 Status = Usb2HcPpi->ClearRootHubPortFeature (
1073 PeiServices,
1074 Usb2HcPpi,
1075 PortNum,
1076 EfiUsbPortReset
1077 );
1078
1079 if (EFI_ERROR (Status)) {
1080 DEBUG ((DEBUG_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));
1081 return;
1082 }
1083
1084 MicroSecondDelay (USB_CLR_ROOT_PORT_RESET_STALL);
1085
1086 //
1087 // USB host controller won't clear the RESET bit until
1088 // reset is actually finished.
1089 //
1090 ZeroMem (&PortStatus, sizeof (EFI_USB_PORT_STATUS));
1091
1092 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
1093 Status = Usb2HcPpi->GetRootHubPortStatus (
1094 PeiServices,
1095 Usb2HcPpi,
1096 PortNum,
1097 &PortStatus
1098 );
1099 if (EFI_ERROR (Status)) {
1100 return;
1101 }
1102
1103 if (!USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_RESET)) {
1104 break;
1105 }
1106
1107 MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
1108 }
1109
1110 if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
1111 DEBUG ((DEBUG_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum));
1112 return;
1113 }
1114
1115 Usb2HcPpi->ClearRootHubPortFeature (
1116 PeiServices,
1117 Usb2HcPpi,
1118 PortNum,
1119 EfiUsbPortResetChange
1120 );
1121
1122 Usb2HcPpi->ClearRootHubPortFeature (
1123 PeiServices,
1124 Usb2HcPpi,
1125 PortNum,
1126 EfiUsbPortConnectChange
1127 );
1128
1129 //
1130 // Set port enable
1131 //
1132 Usb2HcPpi->SetRootHubPortFeature (
1133 PeiServices,
1134 Usb2HcPpi,
1135 PortNum,
1136 EfiUsbPortEnable
1137 );
1138
1139 Usb2HcPpi->ClearRootHubPortFeature (
1140 PeiServices,
1141 Usb2HcPpi,
1142 PortNum,
1143 EfiUsbPortEnableChange
1144 );
1145
1146 MicroSecondDelay ((RetryIndex + 1) * 50 * 1000);
1147 } else {
1148 MicroSecondDelay (200 * 1000);
1149
1150 //
1151 // reset root port
1152 //
1153 Status = UsbHcPpi->SetRootHubPortFeature (
1154 PeiServices,
1155 UsbHcPpi,
1156 PortNum,
1157 EfiUsbPortReset
1158 );
1159
1160 if (EFI_ERROR (Status)) {
1161 DEBUG ((DEBUG_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n"));
1162 return;
1163 }
1164
1165 //
1166 // Drive the reset signal for at least 50ms. Check USB 2.0 Spec
1167 // section 7.1.7.5 for timing requirements.
1168 //
1169 MicroSecondDelay (USB_SET_ROOT_PORT_RESET_STALL);
1170
1171 //
1172 // clear reset root port
1173 //
1174 Status = UsbHcPpi->ClearRootHubPortFeature (
1175 PeiServices,
1176 UsbHcPpi,
1177 PortNum,
1178 EfiUsbPortReset
1179 );
1180
1181 if (EFI_ERROR (Status)) {
1182 DEBUG ((DEBUG_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));
1183 return;
1184 }
1185
1186 MicroSecondDelay (USB_CLR_ROOT_PORT_RESET_STALL);
1187
1188 //
1189 // USB host controller won't clear the RESET bit until
1190 // reset is actually finished.
1191 //
1192 ZeroMem (&PortStatus, sizeof (EFI_USB_PORT_STATUS));
1193
1194 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
1195 Status = UsbHcPpi->GetRootHubPortStatus (
1196 PeiServices,
1197 UsbHcPpi,
1198 PortNum,
1199 &PortStatus
1200 );
1201 if (EFI_ERROR (Status)) {
1202 return;
1203 }
1204
1205 if (!USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_RESET)) {
1206 break;
1207 }
1208
1209 MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
1210 }
1211
1212 if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
1213 DEBUG ((DEBUG_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum));
1214 return;
1215 }
1216
1217 UsbHcPpi->ClearRootHubPortFeature (
1218 PeiServices,
1219 UsbHcPpi,
1220 PortNum,
1221 EfiUsbPortResetChange
1222 );
1223
1224 UsbHcPpi->ClearRootHubPortFeature (
1225 PeiServices,
1226 UsbHcPpi,
1227 PortNum,
1228 EfiUsbPortConnectChange
1229 );
1230
1231 //
1232 // Set port enable
1233 //
1234 UsbHcPpi->SetRootHubPortFeature (
1235 PeiServices,
1236 UsbHcPpi,
1237 PortNum,
1238 EfiUsbPortEnable
1239 );
1240
1241 UsbHcPpi->ClearRootHubPortFeature (
1242 PeiServices,
1243 UsbHcPpi,
1244 PortNum,
1245 EfiUsbPortEnableChange
1246 );
1247
1248 MicroSecondDelay ((RetryIndex + 1) * 50 * 1000);
1249 }
1250
1251 return;
1252 }