]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c
MdeModulePkg: Clean up source files
[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 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 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 ((EFI_D_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 MicroSecondDelay (USB_GET_CONFIG_DESCRIPTOR_STALL);
755
756 Status = PeiUsbSetConfiguration (
757 PeiServices,
758 UsbIoPpi
759 );
760
761 if (EFI_ERROR (Status)) {
762 return Status;
763 }
764
765 return EFI_SUCCESS;
766 }
767
768 /**
769 Get all configurations from a detected usb device.
770
771 @param PeiServices Describes the list of possible PEI Services.
772 @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.
773
774 @retval EFI_SUCCESS The new detected usb device is configured successfully.
775 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
776 @retval Others Other failure occurs.
777
778 **/
779 EFI_STATUS
780 PeiUsbGetAllConfiguration (
781 IN EFI_PEI_SERVICES **PeiServices,
782 IN PEI_USB_DEVICE *PeiUsbDevice
783 )
784 {
785 EFI_STATUS Status;
786 EFI_USB_CONFIG_DESCRIPTOR *ConfigDesc;
787 PEI_USB_IO_PPI *UsbIoPpi;
788 UINT16 ConfigDescLength;
789 UINT8 *Ptr;
790 UINTN SkipBytes;
791 UINTN LengthLeft;
792 UINTN InterfaceIndex;
793 UINTN Index;
794 UINTN NumOfEndpoint;
795
796 UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
797
798 //
799 // First get its 4-byte configuration descriptor
800 //
801 Status = PeiUsbGetDescriptor (
802 PeiServices,
803 UsbIoPpi,
804 (USB_DT_CONFIG << 8), // Value
805 0, // Index
806 4, // Length
807 PeiUsbDevice->ConfigurationData
808 );
809
810 if (EFI_ERROR (Status)) {
811 DEBUG ((EFI_D_ERROR, "PeiUsbGet Config Descriptor First Failed\n"));
812 return Status;
813 }
814 MicroSecondDelay (USB_GET_CONFIG_DESCRIPTOR_STALL);
815
816 ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *) PeiUsbDevice->ConfigurationData;
817 ConfigDescLength = ConfigDesc->TotalLength;
818
819 //
820 // Then we get the total descriptors for this configuration
821 //
822 Status = PeiUsbGetDescriptor (
823 PeiServices,
824 UsbIoPpi,
825 (USB_DT_CONFIG << 8),
826 0,
827 ConfigDescLength,
828 PeiUsbDevice->ConfigurationData
829 );
830
831 if (EFI_ERROR (Status)) {
832 DEBUG ((EFI_D_ERROR, "PeiUsbGet Config Descriptor all Failed\n"));
833 return Status;
834 }
835 //
836 // Parse this configuration descriptor
837 // First get the current config descriptor;
838 //
839 Status = GetExpectedDescriptor (
840 PeiUsbDevice->ConfigurationData,
841 ConfigDescLength,
842 USB_DT_CONFIG,
843 (UINT8) sizeof (EFI_USB_CONFIG_DESCRIPTOR),
844 &SkipBytes
845 );
846
847 if (EFI_ERROR (Status)) {
848 return Status;
849 }
850
851 Ptr = PeiUsbDevice->ConfigurationData + SkipBytes;
852 PeiUsbDevice->ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *) Ptr;
853
854 Ptr += sizeof (EFI_USB_CONFIG_DESCRIPTOR);
855 LengthLeft = ConfigDescLength - SkipBytes - sizeof (EFI_USB_CONFIG_DESCRIPTOR);
856
857 for (InterfaceIndex = 0; InterfaceIndex < PeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) {
858
859 //
860 // Get the interface descriptor
861 //
862 Status = GetExpectedDescriptor (
863 Ptr,
864 LengthLeft,
865 USB_DT_INTERFACE,
866 (UINT8) sizeof (EFI_USB_INTERFACE_DESCRIPTOR),
867 &SkipBytes
868 );
869
870 if (EFI_ERROR (Status)) {
871 return Status;
872 }
873
874 Ptr += SkipBytes;
875 if (InterfaceIndex == 0) {
876 PeiUsbDevice->InterfaceDesc = (EFI_USB_INTERFACE_DESCRIPTOR *) Ptr;
877 }
878 PeiUsbDevice->InterfaceDescList[InterfaceIndex] = (EFI_USB_INTERFACE_DESCRIPTOR *) Ptr;
879
880 Ptr += sizeof (EFI_USB_INTERFACE_DESCRIPTOR);
881 LengthLeft -= SkipBytes;
882 LengthLeft -= sizeof (EFI_USB_INTERFACE_DESCRIPTOR);
883
884 //
885 // Parse all the endpoint descriptor within this interface
886 //
887 NumOfEndpoint = PeiUsbDevice->InterfaceDescList[InterfaceIndex]->NumEndpoints;
888 ASSERT (NumOfEndpoint <= MAX_ENDPOINT);
889
890 for (Index = 0; Index < NumOfEndpoint; Index++) {
891 //
892 // Get the endpoint descriptor
893 //
894 Status = GetExpectedDescriptor (
895 Ptr,
896 LengthLeft,
897 USB_DT_ENDPOINT,
898 (UINT8) sizeof (EFI_USB_ENDPOINT_DESCRIPTOR),
899 &SkipBytes
900 );
901
902 if (EFI_ERROR (Status)) {
903 return Status;
904 }
905
906 Ptr += SkipBytes;
907 if (InterfaceIndex == 0) {
908 PeiUsbDevice->EndpointDesc[Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *) Ptr;
909 }
910 PeiUsbDevice->EndpointDescList[InterfaceIndex][Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *) Ptr;
911
912 Ptr += sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);
913 LengthLeft -= SkipBytes;
914 LengthLeft -= sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);
915 }
916 }
917
918 return EFI_SUCCESS;
919 }
920
921 /**
922 Get the start position of next wanted descriptor.
923
924 @param Buffer Buffer containing data to parse.
925 @param Length Buffer length.
926 @param DescType Descriptor type.
927 @param DescLength Descriptor length.
928 @param ParsedBytes Bytes has been parsed.
929
930 @retval EFI_SUCCESS Get wanted descriptor successfully.
931 @retval EFI_DEVICE_ERROR Error occurred.
932
933 **/
934 EFI_STATUS
935 GetExpectedDescriptor (
936 IN UINT8 *Buffer,
937 IN UINTN Length,
938 IN UINT8 DescType,
939 IN UINT8 DescLength,
940 OUT UINTN *ParsedBytes
941 )
942 {
943 UINT16 DescriptorHeader;
944 UINT8 Len;
945 UINT8 *Ptr;
946 UINTN Parsed;
947
948 Parsed = 0;
949 Ptr = Buffer;
950
951 while (TRUE) {
952 //
953 // Buffer length should not less than Desc length
954 //
955 if (Length < DescLength) {
956 return EFI_DEVICE_ERROR;
957 }
958
959 DescriptorHeader = (UINT16) (*Ptr + ((*(Ptr + 1)) << 8));
960
961 Len = Buffer[0];
962
963 //
964 // Check to see if it is a start of expected descriptor
965 //
966 if (DescriptorHeader == ((DescType << 8) | DescLength)) {
967 break;
968 }
969
970 if ((UINT8) (DescriptorHeader >> 8) == DescType) {
971 if (Len > DescLength) {
972 return EFI_DEVICE_ERROR;
973 }
974 }
975 //
976 // Descriptor length should be at least 2
977 // and should not exceed the buffer length
978 //
979 if (Len < 2) {
980 return EFI_DEVICE_ERROR;
981 }
982
983 if (Len > Length) {
984 return EFI_DEVICE_ERROR;
985 }
986 //
987 // Skip this mismatch descriptor
988 //
989 Length -= Len;
990 Ptr += Len;
991 Parsed += Len;
992 }
993
994 *ParsedBytes = Parsed;
995
996 return EFI_SUCCESS;
997 }
998
999 /**
1000 Send reset signal over the given root hub port.
1001
1002 @param PeiServices Describes the list of possible PEI Services.
1003 @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.
1004 @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.
1005 @param PortNum The port to be reset.
1006 @param RetryIndex The retry times.
1007
1008 **/
1009 VOID
1010 ResetRootPort (
1011 IN EFI_PEI_SERVICES **PeiServices,
1012 IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,
1013 IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi,
1014 IN UINT8 PortNum,
1015 IN UINT8 RetryIndex
1016 )
1017 {
1018 EFI_STATUS Status;
1019 UINTN Index;
1020 EFI_USB_PORT_STATUS PortStatus;
1021
1022
1023 if (Usb2HcPpi != NULL) {
1024 MicroSecondDelay (200 * 1000);
1025
1026 //
1027 // reset root port
1028 //
1029 Status = Usb2HcPpi->SetRootHubPortFeature (
1030 PeiServices,
1031 Usb2HcPpi,
1032 PortNum,
1033 EfiUsbPortReset
1034 );
1035
1036 if (EFI_ERROR (Status)) {
1037 DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n"));
1038 return;
1039 }
1040
1041 //
1042 // Drive the reset signal for at least 50ms. Check USB 2.0 Spec
1043 // section 7.1.7.5 for timing requirements.
1044 //
1045 MicroSecondDelay (USB_SET_ROOT_PORT_RESET_STALL);
1046
1047 //
1048 // clear reset root port
1049 //
1050 Status = Usb2HcPpi->ClearRootHubPortFeature (
1051 PeiServices,
1052 Usb2HcPpi,
1053 PortNum,
1054 EfiUsbPortReset
1055 );
1056
1057 if (EFI_ERROR (Status)) {
1058 DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));
1059 return;
1060 }
1061
1062 MicroSecondDelay (USB_CLR_ROOT_PORT_RESET_STALL);
1063
1064 //
1065 // USB host controller won't clear the RESET bit until
1066 // reset is actually finished.
1067 //
1068 ZeroMem (&PortStatus, sizeof (EFI_USB_PORT_STATUS));
1069
1070 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
1071 Status = Usb2HcPpi->GetRootHubPortStatus (
1072 PeiServices,
1073 Usb2HcPpi,
1074 PortNum,
1075 &PortStatus
1076 );
1077 if (EFI_ERROR (Status)) {
1078 return;
1079 }
1080
1081 if (!USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_RESET)) {
1082 break;
1083 }
1084
1085 MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
1086 }
1087
1088 if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
1089 DEBUG ((EFI_D_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum));
1090 return;
1091 }
1092
1093 Usb2HcPpi->ClearRootHubPortFeature (
1094 PeiServices,
1095 Usb2HcPpi,
1096 PortNum,
1097 EfiUsbPortResetChange
1098 );
1099
1100 Usb2HcPpi->ClearRootHubPortFeature (
1101 PeiServices,
1102 Usb2HcPpi,
1103 PortNum,
1104 EfiUsbPortConnectChange
1105 );
1106
1107 //
1108 // Set port enable
1109 //
1110 Usb2HcPpi->SetRootHubPortFeature(
1111 PeiServices,
1112 Usb2HcPpi,
1113 PortNum,
1114 EfiUsbPortEnable
1115 );
1116
1117 Usb2HcPpi->ClearRootHubPortFeature (
1118 PeiServices,
1119 Usb2HcPpi,
1120 PortNum,
1121 EfiUsbPortEnableChange
1122 );
1123
1124 MicroSecondDelay ((RetryIndex + 1) * 50 * 1000);
1125 } else {
1126 MicroSecondDelay (200 * 1000);
1127
1128 //
1129 // reset root port
1130 //
1131 Status = UsbHcPpi->SetRootHubPortFeature (
1132 PeiServices,
1133 UsbHcPpi,
1134 PortNum,
1135 EfiUsbPortReset
1136 );
1137
1138 if (EFI_ERROR (Status)) {
1139 DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n"));
1140 return;
1141 }
1142
1143 //
1144 // Drive the reset signal for at least 50ms. Check USB 2.0 Spec
1145 // section 7.1.7.5 for timing requirements.
1146 //
1147 MicroSecondDelay (USB_SET_ROOT_PORT_RESET_STALL);
1148
1149 //
1150 // clear reset root port
1151 //
1152 Status = UsbHcPpi->ClearRootHubPortFeature (
1153 PeiServices,
1154 UsbHcPpi,
1155 PortNum,
1156 EfiUsbPortReset
1157 );
1158
1159 if (EFI_ERROR (Status)) {
1160 DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));
1161 return;
1162 }
1163
1164 MicroSecondDelay (USB_CLR_ROOT_PORT_RESET_STALL);
1165
1166 //
1167 // USB host controller won't clear the RESET bit until
1168 // reset is actually finished.
1169 //
1170 ZeroMem (&PortStatus, sizeof (EFI_USB_PORT_STATUS));
1171
1172 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
1173 Status = UsbHcPpi->GetRootHubPortStatus (
1174 PeiServices,
1175 UsbHcPpi,
1176 PortNum,
1177 &PortStatus
1178 );
1179 if (EFI_ERROR (Status)) {
1180 return;
1181 }
1182
1183 if (!USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_RESET)) {
1184 break;
1185 }
1186
1187 MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
1188 }
1189
1190 if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
1191 DEBUG ((EFI_D_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum));
1192 return;
1193 }
1194
1195 UsbHcPpi->ClearRootHubPortFeature (
1196 PeiServices,
1197 UsbHcPpi,
1198 PortNum,
1199 EfiUsbPortResetChange
1200 );
1201
1202 UsbHcPpi->ClearRootHubPortFeature (
1203 PeiServices,
1204 UsbHcPpi,
1205 PortNum,
1206 EfiUsbPortConnectChange
1207 );
1208
1209 //
1210 // Set port enable
1211 //
1212 UsbHcPpi->SetRootHubPortFeature(
1213 PeiServices,
1214 UsbHcPpi,
1215 PortNum,
1216 EfiUsbPortEnable
1217 );
1218
1219 UsbHcPpi->ClearRootHubPortFeature (
1220 PeiServices,
1221 UsbHcPpi,
1222 PortNum,
1223 EfiUsbPortEnableChange
1224 );
1225
1226 MicroSecondDelay ((RetryIndex + 1) * 50 * 1000);
1227 }
1228 return;
1229 }
1230
1231