Coverage Report

Created: 2026-05-11 06:43

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