]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c
MdeModulePkg XhciPei/UsbBusPei: Add XHCI recovery support.
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusPei / UsbPeim.c
1 /** @file
2 The module to produce Usb Bus PPI.
3
4 Copyright (c) 2006 - 2014, 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 UINTN InterfaceIndex;
226 UINTN EndpointIndex;
227
228
229 UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
230
231 DEBUG ((EFI_D_INFO, "PeiHubEnumeration: DownStreamPortNo: %x\n", PeiUsbDevice->DownStreamPortNo));
232
233 for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {
234
235 Status = PeiHubGetPortStatus (
236 PeiServices,
237 UsbIoPpi,
238 (UINT8) (Index + 1),
239 (UINT32 *) &PortStatus
240 );
241
242 if (EFI_ERROR (Status)) {
243 continue;
244 }
245
246 DEBUG ((EFI_D_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus));
247 //
248 // Only handle connection/enable/overcurrent/reset change.
249 //
250 if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
251 continue;
252 } else {
253 if (IsPortConnect (PortStatus.PortStatus)) {
254 //
255 // Begin to deal with the new device
256 //
257 MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
258 Status = PeiServicesAllocatePages (
259 EfiBootServicesCode,
260 MemPages,
261 &AllocateAddress
262 );
263 if (EFI_ERROR (Status)) {
264 return EFI_OUT_OF_RESOURCES;
265 }
266
267 NewPeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress);
268 ZeroMem (NewPeiUsbDevice, sizeof (PEI_USB_DEVICE));
269
270 NewPeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE;
271 NewPeiUsbDevice->DeviceAddress = 0;
272 NewPeiUsbDevice->MaxPacketSize0 = 8;
273 NewPeiUsbDevice->DataToggle = 0;
274 CopyMem (
275 &(NewPeiUsbDevice->UsbIoPpi),
276 &mUsbIoPpi,
277 sizeof (PEI_USB_IO_PPI)
278 );
279 CopyMem (
280 &(NewPeiUsbDevice->UsbIoPpiList),
281 &mUsbIoPpiList,
282 sizeof (EFI_PEI_PPI_DESCRIPTOR)
283 );
284 NewPeiUsbDevice->UsbIoPpiList.Ppi = &NewPeiUsbDevice->UsbIoPpi;
285 NewPeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress;
286 NewPeiUsbDevice->UsbHcPpi = PeiUsbDevice->UsbHcPpi;
287 NewPeiUsbDevice->Usb2HcPpi = PeiUsbDevice->Usb2HcPpi;
288 NewPeiUsbDevice->Tier = (UINT8) (PeiUsbDevice->Tier + 1);
289 NewPeiUsbDevice->IsHub = 0x0;
290 NewPeiUsbDevice->DownStreamPortNo = 0x0;
291
292 if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) ||
293 ((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0)) {
294 //
295 // If the port already has reset change flag and is connected and enabled, skip the port reset logic.
296 //
297 PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1));
298
299 PeiHubGetPortStatus (
300 PeiServices,
301 UsbIoPpi,
302 (UINT8) (Index + 1),
303 (UINT32 *) &PortStatus
304 );
305 } else {
306 PeiHubClearPortFeature (
307 PeiServices,
308 UsbIoPpi,
309 (UINT8) (Index + 1),
310 EfiUsbPortResetChange
311 );
312 }
313
314 NewPeiUsbDevice->DeviceSpeed = (UINT8) PeiUsbGetDeviceSpeed (PortStatus.PortStatus);
315 DEBUG ((EFI_D_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));
316
317 if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)){
318 NewPeiUsbDevice->MaxPacketSize0 = 512;
319 } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
320 NewPeiUsbDevice->MaxPacketSize0 = 64;
321 } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
322 NewPeiUsbDevice->MaxPacketSize0 = 8;
323 } else {
324 NewPeiUsbDevice->MaxPacketSize0 = 8;
325 }
326
327 if(NewPeiUsbDevice->DeviceSpeed != EFI_USB_SPEED_HIGH) {
328 if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_HIGH) {
329 NewPeiUsbDevice->Translator.TranslatorPortNumber = (UINT8)Index;
330 NewPeiUsbDevice->Translator.TranslatorHubAddress = *CurrentAddress;
331 } else {
332 CopyMem(&(NewPeiUsbDevice->Translator), &(PeiUsbDevice->Translator), sizeof(EFI_USB2_HC_TRANSACTION_TRANSLATOR));
333 }
334 }
335
336 //
337 // Configure that Usb Device
338 //
339 Status = PeiConfigureUsbDevice (
340 PeiServices,
341 NewPeiUsbDevice,
342 (UINT8) (Index + 1),
343 CurrentAddress
344 );
345
346 if (EFI_ERROR (Status)) {
347 continue;
348 }
349 DEBUG ((EFI_D_INFO, "PeiHubEnumeration: PeiConfigureUsbDevice Success\n"));
350
351 Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList);
352
353 if (NewPeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {
354 NewPeiUsbDevice->IsHub = 0x1;
355
356 Status = PeiDoHubConfig (PeiServices, NewPeiUsbDevice);
357 if (EFI_ERROR (Status)) {
358 return Status;
359 }
360
361 PeiHubEnumeration (PeiServices, NewPeiUsbDevice, CurrentAddress);
362 }
363
364 for (InterfaceIndex = 1; InterfaceIndex < NewPeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) {
365 //
366 // Begin to deal with the new device
367 //
368 MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
369 Status = PeiServicesAllocatePages (
370 EfiBootServicesCode,
371 MemPages,
372 &AllocateAddress
373 );
374 if (EFI_ERROR (Status)) {
375 return EFI_OUT_OF_RESOURCES;
376 }
377 CopyMem ((VOID *)(UINTN)AllocateAddress, NewPeiUsbDevice, sizeof (PEI_USB_DEVICE));
378 NewPeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress);
379 NewPeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress;
380 NewPeiUsbDevice->UsbIoPpiList.Ppi = &NewPeiUsbDevice->UsbIoPpi;
381 NewPeiUsbDevice->InterfaceDesc = NewPeiUsbDevice->InterfaceDescList[InterfaceIndex];
382 for (EndpointIndex = 0; EndpointIndex < NewPeiUsbDevice->InterfaceDesc->NumEndpoints; EndpointIndex++) {
383 NewPeiUsbDevice->EndpointDesc[EndpointIndex] = NewPeiUsbDevice->EndpointDescList[InterfaceIndex][EndpointIndex];
384 }
385
386 Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList);
387
388 if (NewPeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {
389 NewPeiUsbDevice->IsHub = 0x1;
390
391 Status = PeiDoHubConfig (PeiServices, NewPeiUsbDevice);
392 if (EFI_ERROR (Status)) {
393 return Status;
394 }
395
396 PeiHubEnumeration (PeiServices, NewPeiUsbDevice, CurrentAddress);
397 }
398 }
399 }
400 }
401 }
402
403
404 return EFI_SUCCESS;
405 }
406
407 /**
408 The enumeration routine to detect device change.
409
410 @param PeiServices Describes the list of possible PEI Services.
411 @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.
412 @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.
413
414 @retval EFI_SUCCESS The usb is enumerated successfully.
415 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
416 @retval Others Other failure occurs.
417
418 **/
419 EFI_STATUS
420 PeiUsbEnumeration (
421 IN EFI_PEI_SERVICES **PeiServices,
422 IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,
423 IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi
424 )
425 {
426 UINT8 NumOfRootPort;
427 EFI_STATUS Status;
428 UINT8 Index;
429 EFI_USB_PORT_STATUS PortStatus;
430 PEI_USB_DEVICE *PeiUsbDevice;
431 UINTN MemPages;
432 EFI_PHYSICAL_ADDRESS AllocateAddress;
433 UINT8 CurrentAddress;
434 UINTN InterfaceIndex;
435 UINTN EndpointIndex;
436
437 CurrentAddress = 0;
438 if (Usb2HcPpi != NULL) {
439 Usb2HcPpi->GetRootHubPortNumber (
440 PeiServices,
441 Usb2HcPpi,
442 (UINT8 *) &NumOfRootPort
443 );
444 } else if (UsbHcPpi != NULL) {
445 UsbHcPpi->GetRootHubPortNumber (
446 PeiServices,
447 UsbHcPpi,
448 (UINT8 *) &NumOfRootPort
449 );
450 } else {
451 ASSERT (FALSE);
452 return EFI_INVALID_PARAMETER;
453 }
454
455 DEBUG ((EFI_D_INFO, "PeiUsbEnumeration: NumOfRootPort: %x\n", NumOfRootPort));
456
457 for (Index = 0; Index < NumOfRootPort; Index++) {
458 //
459 // First get root port status to detect changes happen
460 //
461 if (Usb2HcPpi != NULL) {
462 Usb2HcPpi->GetRootHubPortStatus (
463 PeiServices,
464 Usb2HcPpi,
465 (UINT8) Index,
466 &PortStatus
467 );
468 } else {
469 UsbHcPpi->GetRootHubPortStatus (
470 PeiServices,
471 UsbHcPpi,
472 (UINT8) Index,
473 &PortStatus
474 );
475 }
476 DEBUG ((EFI_D_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus));
477 //
478 // Only handle connection/enable/overcurrent/reset change.
479 //
480 if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
481 continue;
482 } else {
483 if (IsPortConnect (PortStatus.PortStatus)) {
484 MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
485 Status = PeiServicesAllocatePages (
486 EfiBootServicesCode,
487 MemPages,
488 &AllocateAddress
489 );
490 if (EFI_ERROR (Status)) {
491 return EFI_OUT_OF_RESOURCES;
492 }
493
494 PeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress);
495 ZeroMem (PeiUsbDevice, sizeof (PEI_USB_DEVICE));
496
497 PeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE;
498 PeiUsbDevice->DeviceAddress = 0;
499 PeiUsbDevice->MaxPacketSize0 = 8;
500 PeiUsbDevice->DataToggle = 0;
501 CopyMem (
502 &(PeiUsbDevice->UsbIoPpi),
503 &mUsbIoPpi,
504 sizeof (PEI_USB_IO_PPI)
505 );
506 CopyMem (
507 &(PeiUsbDevice->UsbIoPpiList),
508 &mUsbIoPpiList,
509 sizeof (EFI_PEI_PPI_DESCRIPTOR)
510 );
511 PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi;
512 PeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress;
513 PeiUsbDevice->UsbHcPpi = UsbHcPpi;
514 PeiUsbDevice->Usb2HcPpi = Usb2HcPpi;
515 PeiUsbDevice->IsHub = 0x0;
516 PeiUsbDevice->DownStreamPortNo = 0x0;
517
518 if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) ||
519 ((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0)) {
520 //
521 // If the port already has reset change flag and is connected and enabled, skip the port reset logic.
522 //
523 ResetRootPort (
524 PeiServices,
525 PeiUsbDevice->UsbHcPpi,
526 PeiUsbDevice->Usb2HcPpi,
527 Index,
528 0
529 );
530
531 if (Usb2HcPpi != NULL) {
532 Usb2HcPpi->GetRootHubPortStatus (
533 PeiServices,
534 Usb2HcPpi,
535 (UINT8) Index,
536 &PortStatus
537 );
538 } else {
539 UsbHcPpi->GetRootHubPortStatus (
540 PeiServices,
541 UsbHcPpi,
542 (UINT8) Index,
543 &PortStatus
544 );
545 }
546 } else {
547 if (Usb2HcPpi != NULL) {
548 Usb2HcPpi->ClearRootHubPortFeature (
549 PeiServices,
550 Usb2HcPpi,
551 (UINT8) Index,
552 EfiUsbPortResetChange
553 );
554 } else {
555 UsbHcPpi->ClearRootHubPortFeature (
556 PeiServices,
557 UsbHcPpi,
558 (UINT8) Index,
559 EfiUsbPortResetChange
560 );
561 }
562 }
563
564 PeiUsbDevice->DeviceSpeed = (UINT8) PeiUsbGetDeviceSpeed (PortStatus.PortStatus);
565 DEBUG ((EFI_D_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));
566
567 if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)){
568 PeiUsbDevice->MaxPacketSize0 = 512;
569 } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
570 PeiUsbDevice->MaxPacketSize0 = 64;
571 } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
572 PeiUsbDevice->MaxPacketSize0 = 8;
573 } else {
574 PeiUsbDevice->MaxPacketSize0 = 8;
575 }
576
577 //
578 // Configure that Usb Device
579 //
580 Status = PeiConfigureUsbDevice (
581 PeiServices,
582 PeiUsbDevice,
583 Index,
584 &CurrentAddress
585 );
586
587 if (EFI_ERROR (Status)) {
588 continue;
589 }
590 DEBUG ((EFI_D_INFO, "PeiUsbEnumeration: PeiConfigureUsbDevice Success\n"));
591
592 Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);
593
594 if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {
595 PeiUsbDevice->IsHub = 0x1;
596
597 Status = PeiDoHubConfig (PeiServices, PeiUsbDevice);
598 if (EFI_ERROR (Status)) {
599 return Status;
600 }
601
602 PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress);
603 }
604
605 for (InterfaceIndex = 1; InterfaceIndex < PeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) {
606 //
607 // Begin to deal with the new device
608 //
609 MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
610 Status = PeiServicesAllocatePages (
611 EfiBootServicesCode,
612 MemPages,
613 &AllocateAddress
614 );
615 if (EFI_ERROR (Status)) {
616 return EFI_OUT_OF_RESOURCES;
617 }
618 CopyMem ((VOID *)(UINTN)AllocateAddress, PeiUsbDevice, sizeof (PEI_USB_DEVICE));
619 PeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress);
620 PeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress;
621 PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi;
622 PeiUsbDevice->InterfaceDesc = PeiUsbDevice->InterfaceDescList[InterfaceIndex];
623 for (EndpointIndex = 0; EndpointIndex < PeiUsbDevice->InterfaceDesc->NumEndpoints; EndpointIndex++) {
624 PeiUsbDevice->EndpointDesc[EndpointIndex] = PeiUsbDevice->EndpointDescList[InterfaceIndex][EndpointIndex];
625 }
626
627 Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);
628
629 if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {
630 PeiUsbDevice->IsHub = 0x1;
631
632 Status = PeiDoHubConfig (PeiServices, PeiUsbDevice);
633 if (EFI_ERROR (Status)) {
634 return Status;
635 }
636
637 PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress);
638 }
639 }
640 } else {
641 //
642 // Disconnect change happen, currently we don't support
643 //
644 }
645 }
646 }
647
648 return EFI_SUCCESS;
649 }
650
651 /**
652 Configure new detected usb device.
653
654 @param PeiServices Describes the list of possible PEI Services.
655 @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.
656 @param Port The port to be configured.
657 @param DeviceAddress The device address to be configured.
658
659 @retval EFI_SUCCESS The new detected usb device is configured successfully.
660 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
661 @retval Others Other failure occurs.
662
663 **/
664 EFI_STATUS
665 PeiConfigureUsbDevice (
666 IN EFI_PEI_SERVICES **PeiServices,
667 IN PEI_USB_DEVICE *PeiUsbDevice,
668 IN UINT8 Port,
669 IN OUT UINT8 *DeviceAddress
670 )
671 {
672 EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor;
673 EFI_STATUS Status;
674 PEI_USB_IO_PPI *UsbIoPpi;
675 UINT8 Retry;
676
677 UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
678 Status = EFI_SUCCESS;
679 ZeroMem (&DeviceDescriptor, sizeof (EFI_USB_DEVICE_DESCRIPTOR));
680 //
681 // Get USB device descriptor
682 //
683
684 for (Retry = 0; Retry < 3; Retry ++) {
685 Status = PeiUsbGetDescriptor (
686 PeiServices,
687 UsbIoPpi,
688 (USB_DT_DEVICE << 8),
689 0,
690 8,
691 &DeviceDescriptor
692 );
693
694 if (!EFI_ERROR (Status)) {
695 DEBUG ((EFI_D_INFO, "PeiUsbGet Device Descriptor the %d time Success\n", Retry));
696 break;
697 }
698 }
699
700 if (Retry == 3) {
701 DEBUG ((EFI_D_ERROR, "PeiUsbGet Device Descriptor fail: %x %r\n", Retry, Status));
702 return Status;
703 }
704
705 if ((DeviceDescriptor.BcdUSB == 0x0300) && (DeviceDescriptor.MaxPacketSize0 == 9)) {
706 PeiUsbDevice->MaxPacketSize0 = 1 << 9;
707 } else {
708 PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0;
709 }
710
711 (*DeviceAddress) ++;
712
713 Status = PeiUsbSetDeviceAddress (
714 PeiServices,
715 UsbIoPpi,
716 *DeviceAddress
717 );
718
719 if (EFI_ERROR (Status)) {
720 DEBUG ((EFI_D_ERROR, "PeiUsbSetDeviceAddress Failed: %r\n", Status));
721 return Status;
722 }
723
724 PeiUsbDevice->DeviceAddress = *DeviceAddress;
725
726 //
727 // Get whole USB device descriptor
728 //
729 Status = PeiUsbGetDescriptor (
730 PeiServices,
731 UsbIoPpi,
732 (USB_DT_DEVICE << 8),
733 0,
734 (UINT16) sizeof (EFI_USB_DEVICE_DESCRIPTOR),
735 &DeviceDescriptor
736 );
737
738 if (EFI_ERROR (Status)) {
739 DEBUG ((EFI_D_ERROR, "PeiUsbGetDescriptor First Failed\n"));
740 return Status;
741 }
742
743 //
744 // Get its default configuration and its first interface
745 //
746 Status = PeiUsbGetAllConfiguration (
747 PeiServices,
748 PeiUsbDevice
749 );
750 if (EFI_ERROR (Status)) {
751 return Status;
752 }
753
754 Status = PeiUsbSetConfiguration (
755 PeiServices,
756 UsbIoPpi
757 );
758
759 if (EFI_ERROR (Status)) {
760 return Status;
761 }
762
763 return EFI_SUCCESS;
764 }
765
766 /**
767 Get all configurations from a detected usb device.
768
769 @param PeiServices Describes the list of possible PEI Services.
770 @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.
771
772 @retval EFI_SUCCESS The new detected usb device is configured successfully.
773 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
774 @retval Others Other failure occurs.
775
776 **/
777 EFI_STATUS
778 PeiUsbGetAllConfiguration (
779 IN EFI_PEI_SERVICES **PeiServices,
780 IN PEI_USB_DEVICE *PeiUsbDevice
781 )
782 {
783 EFI_STATUS Status;
784 EFI_USB_CONFIG_DESCRIPTOR *ConfigDesc;
785 PEI_USB_IO_PPI *UsbIoPpi;
786 UINT16 ConfigDescLength;
787 UINT8 *Ptr;
788 UINTN SkipBytes;
789 UINTN LengthLeft;
790 UINTN InterfaceIndex;
791 UINTN Index;
792 UINTN NumOfEndpoint;
793
794 UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
795
796 //
797 // First get its 4-byte configuration descriptor
798 //
799 Status = PeiUsbGetDescriptor (
800 PeiServices,
801 UsbIoPpi,
802 (USB_DT_CONFIG << 8), // Value
803 0, // Index
804 4, // Length
805 PeiUsbDevice->ConfigurationData
806 );
807
808 if (EFI_ERROR (Status)) {
809 DEBUG ((EFI_D_ERROR, "PeiUsbGet Config Descriptor First Failed\n"));
810 return Status;
811 }
812
813 ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *) PeiUsbDevice->ConfigurationData;
814 ConfigDescLength = ConfigDesc->TotalLength;
815
816 //
817 // Then we get the total descriptors for this configuration
818 //
819 Status = PeiUsbGetDescriptor (
820 PeiServices,
821 UsbIoPpi,
822 (USB_DT_CONFIG << 8),
823 0,
824 ConfigDescLength,
825 PeiUsbDevice->ConfigurationData
826 );
827
828 if (EFI_ERROR (Status)) {
829 DEBUG ((EFI_D_ERROR, "PeiUsbGet Config Descriptor all Failed\n"));
830 return Status;
831 }
832 //
833 // Parse this configuration descriptor
834 // First get the current config descriptor;
835 //
836 Status = GetExpectedDescriptor (
837 PeiUsbDevice->ConfigurationData,
838 ConfigDescLength,
839 USB_DT_CONFIG,
840 (UINT8) sizeof (EFI_USB_CONFIG_DESCRIPTOR),
841 &SkipBytes
842 );
843
844 if (EFI_ERROR (Status)) {
845 return Status;
846 }
847
848 Ptr = PeiUsbDevice->ConfigurationData + SkipBytes;
849 PeiUsbDevice->ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *) Ptr;
850
851 Ptr += sizeof (EFI_USB_CONFIG_DESCRIPTOR);
852 LengthLeft = ConfigDescLength - SkipBytes - sizeof (EFI_USB_CONFIG_DESCRIPTOR);
853
854 for (InterfaceIndex = 0; InterfaceIndex < PeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) {
855
856 //
857 // Get the interface descriptor
858 //
859 Status = GetExpectedDescriptor (
860 Ptr,
861 LengthLeft,
862 USB_DT_INTERFACE,
863 (UINT8) sizeof (EFI_USB_INTERFACE_DESCRIPTOR),
864 &SkipBytes
865 );
866
867 if (EFI_ERROR (Status)) {
868 return Status;
869 }
870
871 Ptr += SkipBytes;
872 if (InterfaceIndex == 0) {
873 PeiUsbDevice->InterfaceDesc = (EFI_USB_INTERFACE_DESCRIPTOR *) Ptr;
874 }
875 PeiUsbDevice->InterfaceDescList[InterfaceIndex] = (EFI_USB_INTERFACE_DESCRIPTOR *) Ptr;
876
877 Ptr += sizeof (EFI_USB_INTERFACE_DESCRIPTOR);
878 LengthLeft -= SkipBytes;
879 LengthLeft -= sizeof (EFI_USB_INTERFACE_DESCRIPTOR);
880
881 //
882 // Parse all the endpoint descriptor within this interface
883 //
884 NumOfEndpoint = PeiUsbDevice->InterfaceDescList[InterfaceIndex]->NumEndpoints;
885 ASSERT (NumOfEndpoint <= MAX_ENDPOINT);
886
887 for (Index = 0; Index < NumOfEndpoint; Index++) {
888 //
889 // Get the endpoint descriptor
890 //
891 Status = GetExpectedDescriptor (
892 Ptr,
893 LengthLeft,
894 USB_DT_ENDPOINT,
895 (UINT8) sizeof (EFI_USB_ENDPOINT_DESCRIPTOR),
896 &SkipBytes
897 );
898
899 if (EFI_ERROR (Status)) {
900 return Status;
901 }
902
903 Ptr += SkipBytes;
904 if (InterfaceIndex == 0) {
905 PeiUsbDevice->EndpointDesc[Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *) Ptr;
906 }
907 PeiUsbDevice->EndpointDescList[InterfaceIndex][Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *) Ptr;
908
909 Ptr += sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);
910 LengthLeft -= SkipBytes;
911 LengthLeft -= sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);
912 }
913 }
914
915 return EFI_SUCCESS;
916 }
917
918 /**
919 Get the start position of next wanted descriptor.
920
921 @param Buffer Buffer containing data to parse.
922 @param Length Buffer length.
923 @param DescType Descriptor type.
924 @param DescLength Descriptor length.
925 @param ParsedBytes Bytes has been parsed.
926
927 @retval EFI_SUCCESS Get wanted descriptor successfully.
928 @retval EFI_DEVICE_ERROR Error occurred.
929
930 **/
931 EFI_STATUS
932 GetExpectedDescriptor (
933 IN UINT8 *Buffer,
934 IN UINTN Length,
935 IN UINT8 DescType,
936 IN UINT8 DescLength,
937 OUT UINTN *ParsedBytes
938 )
939 {
940 UINT16 DescriptorHeader;
941 UINT8 Len;
942 UINT8 *Ptr;
943 UINTN Parsed;
944
945 Parsed = 0;
946 Ptr = Buffer;
947
948 while (TRUE) {
949 //
950 // Buffer length should not less than Desc length
951 //
952 if (Length < DescLength) {
953 return EFI_DEVICE_ERROR;
954 }
955
956 DescriptorHeader = (UINT16) (*Ptr + ((*(Ptr + 1)) << 8));
957
958 Len = Buffer[0];
959
960 //
961 // Check to see if it is a start of expected descriptor
962 //
963 if (DescriptorHeader == ((DescType << 8) | DescLength)) {
964 break;
965 }
966
967 if ((UINT8) (DescriptorHeader >> 8) == DescType) {
968 if (Len > DescLength) {
969 return EFI_DEVICE_ERROR;
970 }
971 }
972 //
973 // Descriptor length should be at least 2
974 // and should not exceed the buffer length
975 //
976 if (Len < 2) {
977 return EFI_DEVICE_ERROR;
978 }
979
980 if (Len > Length) {
981 return EFI_DEVICE_ERROR;
982 }
983 //
984 // Skip this mismatch descriptor
985 //
986 Length -= Len;
987 Ptr += Len;
988 Parsed += Len;
989 }
990
991 *ParsedBytes = Parsed;
992
993 return EFI_SUCCESS;
994 }
995
996 /**
997 Send reset signal over the given root hub port.
998
999 @param PeiServices Describes the list of possible PEI Services.
1000 @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.
1001 @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.
1002 @param PortNum The port to be reset.
1003 @param RetryIndex The retry times.
1004
1005 **/
1006 VOID
1007 ResetRootPort (
1008 IN EFI_PEI_SERVICES **PeiServices,
1009 IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,
1010 IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi,
1011 IN UINT8 PortNum,
1012 IN UINT8 RetryIndex
1013 )
1014 {
1015 EFI_STATUS Status;
1016 UINTN Index;
1017 EFI_USB_PORT_STATUS PortStatus;
1018
1019
1020 if (Usb2HcPpi != NULL) {
1021 MicroSecondDelay (200 * 1000);
1022
1023 //
1024 // reset root port
1025 //
1026 Status = Usb2HcPpi->SetRootHubPortFeature (
1027 PeiServices,
1028 Usb2HcPpi,
1029 PortNum,
1030 EfiUsbPortReset
1031 );
1032
1033 if (EFI_ERROR (Status)) {
1034 DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n"));
1035 return;
1036 }
1037
1038 //
1039 // Drive the reset signal for at least 50ms. Check USB 2.0 Spec
1040 // section 7.1.7.5 for timing requirements.
1041 //
1042 MicroSecondDelay (USB_SET_ROOT_PORT_RESET_STALL);
1043
1044 //
1045 // clear reset root port
1046 //
1047 Status = Usb2HcPpi->ClearRootHubPortFeature (
1048 PeiServices,
1049 Usb2HcPpi,
1050 PortNum,
1051 EfiUsbPortReset
1052 );
1053
1054 if (EFI_ERROR (Status)) {
1055 DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));
1056 return;
1057 }
1058
1059 MicroSecondDelay (USB_CLR_ROOT_PORT_RESET_STALL);
1060
1061 //
1062 // USB host controller won't clear the RESET bit until
1063 // reset is actually finished.
1064 //
1065 ZeroMem (&PortStatus, sizeof (EFI_USB_PORT_STATUS));
1066
1067 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
1068 Status = Usb2HcPpi->GetRootHubPortStatus (
1069 PeiServices,
1070 Usb2HcPpi,
1071 PortNum,
1072 &PortStatus
1073 );
1074 if (EFI_ERROR (Status)) {
1075 return;
1076 }
1077
1078 if (!USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_RESET)) {
1079 break;
1080 }
1081
1082 MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
1083 }
1084
1085 if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
1086 DEBUG ((EFI_D_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum));
1087 return;
1088 }
1089
1090 Usb2HcPpi->ClearRootHubPortFeature (
1091 PeiServices,
1092 Usb2HcPpi,
1093 PortNum,
1094 EfiUsbPortResetChange
1095 );
1096
1097 Usb2HcPpi->ClearRootHubPortFeature (
1098 PeiServices,
1099 Usb2HcPpi,
1100 PortNum,
1101 EfiUsbPortConnectChange
1102 );
1103
1104 //
1105 // Set port enable
1106 //
1107 Usb2HcPpi->SetRootHubPortFeature(
1108 PeiServices,
1109 Usb2HcPpi,
1110 PortNum,
1111 EfiUsbPortEnable
1112 );
1113
1114 Usb2HcPpi->ClearRootHubPortFeature (
1115 PeiServices,
1116 Usb2HcPpi,
1117 PortNum,
1118 EfiUsbPortEnableChange
1119 );
1120
1121 MicroSecondDelay ((RetryIndex + 1) * 50 * 1000);
1122 } else {
1123 MicroSecondDelay (200 * 1000);
1124
1125 //
1126 // reset root port
1127 //
1128 Status = UsbHcPpi->SetRootHubPortFeature (
1129 PeiServices,
1130 UsbHcPpi,
1131 PortNum,
1132 EfiUsbPortReset
1133 );
1134
1135 if (EFI_ERROR (Status)) {
1136 DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n"));
1137 return;
1138 }
1139
1140 //
1141 // Drive the reset signal for at least 50ms. Check USB 2.0 Spec
1142 // section 7.1.7.5 for timing requirements.
1143 //
1144 MicroSecondDelay (USB_SET_ROOT_PORT_RESET_STALL);
1145
1146 //
1147 // clear reset root port
1148 //
1149 Status = UsbHcPpi->ClearRootHubPortFeature (
1150 PeiServices,
1151 UsbHcPpi,
1152 PortNum,
1153 EfiUsbPortReset
1154 );
1155
1156 if (EFI_ERROR (Status)) {
1157 DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));
1158 return;
1159 }
1160
1161 MicroSecondDelay (USB_CLR_ROOT_PORT_RESET_STALL);
1162
1163 //
1164 // USB host controller won't clear the RESET bit until
1165 // reset is actually finished.
1166 //
1167 ZeroMem (&PortStatus, sizeof (EFI_USB_PORT_STATUS));
1168
1169 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
1170 Status = UsbHcPpi->GetRootHubPortStatus (
1171 PeiServices,
1172 UsbHcPpi,
1173 PortNum,
1174 &PortStatus
1175 );
1176 if (EFI_ERROR (Status)) {
1177 return;
1178 }
1179
1180 if (!USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_RESET)) {
1181 break;
1182 }
1183
1184 MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
1185 }
1186
1187 if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
1188 DEBUG ((EFI_D_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum));
1189 return;
1190 }
1191
1192 UsbHcPpi->ClearRootHubPortFeature (
1193 PeiServices,
1194 UsbHcPpi,
1195 PortNum,
1196 EfiUsbPortResetChange
1197 );
1198
1199 UsbHcPpi->ClearRootHubPortFeature (
1200 PeiServices,
1201 UsbHcPpi,
1202 PortNum,
1203 EfiUsbPortConnectChange
1204 );
1205
1206 //
1207 // Set port enable
1208 //
1209 UsbHcPpi->SetRootHubPortFeature(
1210 PeiServices,
1211 UsbHcPpi,
1212 PortNum,
1213 EfiUsbPortEnable
1214 );
1215
1216 UsbHcPpi->ClearRootHubPortFeature (
1217 PeiServices,
1218 UsbHcPpi,
1219 PortNum,
1220 EfiUsbPortEnableChange
1221 );
1222
1223 MicroSecondDelay ((RetryIndex + 1) * 50 * 1000);
1224 }
1225 return;
1226 }
1227
1228