1 /** @file
2 
3   Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
4   Copyright (c) 2013 - 2014, ARM Ltd. All rights reserved.<BR>
5 
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "PciEmulation.h"
17 
18 #define HOST_CONTROLLER_OPERATION_REG_SIZE  0x44
19 
20 typedef struct {
21   ACPI_HID_DEVICE_PATH      AcpiDevicePath;
22   PCI_DEVICE_PATH           PciDevicePath;
23   EFI_DEVICE_PATH_PROTOCOL  EndDevicePath;
24 } EFI_PCI_IO_DEVICE_PATH;
25 
26 typedef struct {
27   UINT32                  Signature;
28   EFI_PCI_IO_DEVICE_PATH  DevicePath;
29   EFI_PCI_IO_PROTOCOL     PciIoProtocol;
30   PCI_TYPE00              *ConfigSpace;
31   PCI_ROOT_BRIDGE         RootBridge;
32   UINTN                   Segment;
33 } EFI_PCI_IO_PRIVATE_DATA;
34 
35 #define EFI_PCI_IO_PRIVATE_DATA_SIGNATURE     SIGNATURE_32('p', 'c', 'i', 'o')
36 #define EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(a)  CR (a, EFI_PCI_IO_PRIVATE_DATA, PciIoProtocol, EFI_PCI_IO_PRIVATE_DATA_SIGNATURE)
37 
38 EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplate =
39 {
40   {
41     { ACPI_DEVICE_PATH, ACPI_DP, { sizeof (ACPI_HID_DEVICE_PATH), 0 } },
42     EISA_PNP_ID(0x0A03),  // HID
43     0                     // UID
44   },
45   {
46     { HARDWARE_DEVICE_PATH, HW_PCI_DP, { sizeof (PCI_DEVICE_PATH), 0 } },
47     0,
48     0
49   },
50   { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0} }
51 };
52 
53 STATIC
54 VOID
ConfigureUSBHost(VOID)55 ConfigureUSBHost (
56   VOID
57   )
58 {
59 }
60 
61 
62 EFI_STATUS
PciIoPollMem(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 BarIndex,IN UINT64 Offset,IN UINT64 Mask,IN UINT64 Value,IN UINT64 Delay,OUT UINT64 * Result)63 PciIoPollMem (
64   IN EFI_PCI_IO_PROTOCOL           *This,
65   IN  EFI_PCI_IO_PROTOCOL_WIDTH    Width,
66   IN  UINT8                        BarIndex,
67   IN  UINT64                       Offset,
68   IN  UINT64                       Mask,
69   IN  UINT64                       Value,
70   IN  UINT64                       Delay,
71   OUT UINT64                       *Result
72   )
73 {
74   ASSERT (FALSE);
75   return EFI_UNSUPPORTED;
76 }
77 
78 EFI_STATUS
PciIoPollIo(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 BarIndex,IN UINT64 Offset,IN UINT64 Mask,IN UINT64 Value,IN UINT64 Delay,OUT UINT64 * Result)79 PciIoPollIo (
80   IN EFI_PCI_IO_PROTOCOL           *This,
81   IN  EFI_PCI_IO_PROTOCOL_WIDTH    Width,
82   IN  UINT8                        BarIndex,
83   IN  UINT64                       Offset,
84   IN  UINT64                       Mask,
85   IN  UINT64                       Value,
86   IN  UINT64                       Delay,
87   OUT UINT64                       *Result
88   )
89 {
90   ASSERT (FALSE);
91   return EFI_UNSUPPORTED;
92 }
93 
94 EFI_STATUS
PciIoMemRead(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 BarIndex,IN UINT64 Offset,IN UINTN Count,IN OUT VOID * Buffer)95 PciIoMemRead (
96   IN EFI_PCI_IO_PROTOCOL              *This,
97   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
98   IN     UINT8                        BarIndex,
99   IN     UINT64                       Offset,
100   IN     UINTN                        Count,
101   IN OUT VOID                         *Buffer
102   )
103 {
104   EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
105 
106   return PciRootBridgeIoMemRead (&Private->RootBridge.Io,
107                                 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
108                                 Private->ConfigSpace->Device.Bar[BarIndex] + Offset, //Fix me ConfigSpace
109                                 Count,
110                                 Buffer
111                                 );
112 }
113 
114 EFI_STATUS
PciIoMemWrite(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 BarIndex,IN UINT64 Offset,IN UINTN Count,IN OUT VOID * Buffer)115 PciIoMemWrite (
116   IN EFI_PCI_IO_PROTOCOL              *This,
117   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
118   IN     UINT8                        BarIndex,
119   IN     UINT64                       Offset,
120   IN     UINTN                        Count,
121   IN OUT VOID                         *Buffer
122   )
123 {
124   EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
125 
126   return PciRootBridgeIoMemWrite (&Private->RootBridge.Io,
127                                  (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
128                                  Private->ConfigSpace->Device.Bar[BarIndex] + Offset,  //Fix me ConfigSpace
129                                  Count,
130                                  Buffer
131                                  );
132 }
133 
134 EFI_STATUS
PciIoIoRead(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 BarIndex,IN UINT64 Offset,IN UINTN Count,IN OUT VOID * Buffer)135 PciIoIoRead (
136   IN EFI_PCI_IO_PROTOCOL              *This,
137   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
138   IN     UINT8                        BarIndex,
139   IN     UINT64                       Offset,
140   IN     UINTN                        Count,
141   IN OUT VOID                         *Buffer
142   )
143 {
144   ASSERT (FALSE);
145   return EFI_UNSUPPORTED;
146 }
147 
148 EFI_STATUS
PciIoIoWrite(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 BarIndex,IN UINT64 Offset,IN UINTN Count,IN OUT VOID * Buffer)149 PciIoIoWrite (
150   IN EFI_PCI_IO_PROTOCOL              *This,
151   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
152   IN     UINT8                        BarIndex,
153   IN     UINT64                       Offset,
154   IN     UINTN                        Count,
155   IN OUT VOID                         *Buffer
156   )
157 {
158   ASSERT (FALSE);
159   return EFI_UNSUPPORTED;
160 }
161 
162 /**
163   Enable a PCI driver to read PCI controller registers in PCI configuration space.
164 
165   @param[in]      This    A pointer to the EFI_PCI_IO_PROTOCOL instance.
166   @param[in]      Width   Signifies the width of the memory operations.
167   @param[in]      Offset  The offset within the PCI configuration space for
168                           the PCI controller.
169   @param[in]      Count   The number of PCI configuration operations to
170                           perform. Bytes moved is Width size * Count,
171                           starting at Offset.
172 
173   @param[in out]  Buffer  The destination buffer to store the results.
174 
175   @retval  EFI_SUCCESS            The data was read from the PCI controller.
176   @retval  EFI_INVALID_PARAMETER  "Width" is invalid.
177   @retval  EFI_INVALID_PARAMETER  "Buffer" is NULL.
178 
179 **/
180 EFI_STATUS
PciIoPciRead(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT32 Offset,IN UINTN Count,IN OUT VOID * Buffer)181 PciIoPciRead (
182   IN     EFI_PCI_IO_PROTOCOL       *This,
183   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
184   IN     UINT32                     Offset,
185   IN     UINTN                      Count,
186   IN OUT VOID                      *Buffer
187   )
188 {
189   EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
190   EFI_STATUS Status;
191 
192   if ((Width < 0) || (Width >= EfiPciIoWidthMaximum) || (Buffer == NULL)) {
193     return EFI_INVALID_PARAMETER;
194   }
195 
196   Status = PciRootBridgeIoMemRW (
197              (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width,
198              Count,
199              TRUE,
200              (PTR)(UINTN)Buffer,
201              TRUE,
202              (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset)  //Fix me ConfigSpace
203              );
204 
205   return Status;
206 }
207 
208 /**
209   Enable a PCI driver to write PCI controller registers in PCI configuration space.
210 
211   @param[in]      This    A pointer to the EFI_PCI_IO_PROTOCOL instance.
212   @param[in]      Width   Signifies the width of the memory operations.
213   @param[in]      Offset  The offset within the PCI configuration space for
214                           the PCI controller.
215   @param[in]      Count   The number of PCI configuration operations to
216                           perform. Bytes moved is Width size * Count,
217                           starting at Offset.
218 
219   @param[in out]  Buffer  The source buffer to write data from.
220 
221   @retval  EFI_SUCCESS            The data was read from the PCI controller.
222   @retval  EFI_INVALID_PARAMETER  "Width" is invalid.
223   @retval  EFI_INVALID_PARAMETER  "Buffer" is NULL.
224 
225 **/
226 EFI_STATUS
PciIoPciWrite(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT32 Offset,IN UINTN Count,IN OUT VOID * Buffer)227 PciIoPciWrite (
228   IN EFI_PCI_IO_PROTOCOL              *This,
229   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
230   IN     UINT32                       Offset,
231   IN     UINTN                        Count,
232   IN OUT VOID                         *Buffer
233   )
234 {
235   EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
236 
237   if ((Width < 0) || (Width >= EfiPciIoWidthMaximum) || (Buffer == NULL)) {
238     return EFI_INVALID_PARAMETER;
239   }
240 
241   return PciRootBridgeIoMemRW ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
242                                Count,
243                                TRUE,
244                                (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset),  //Fix me ConfigSpace
245                                TRUE,
246                                (PTR)(UINTN)Buffer
247                                );
248 }
249 
250 EFI_STATUS
PciIoCopyMem(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_WIDTH Width,IN UINT8 DestBarIndex,IN UINT64 DestOffset,IN UINT8 SrcBarIndex,IN UINT64 SrcOffset,IN UINTN Count)251 PciIoCopyMem (
252   IN EFI_PCI_IO_PROTOCOL              *This,
253   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
254   IN     UINT8                        DestBarIndex,
255   IN     UINT64                       DestOffset,
256   IN     UINT8                        SrcBarIndex,
257   IN     UINT64                       SrcOffset,
258   IN     UINTN                        Count
259   )
260 {
261   ASSERT (FALSE);
262   return EFI_UNSUPPORTED;
263 }
264 
265 EFI_STATUS
PciIoMap(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,IN VOID * HostAddress,IN OUT UINTN * NumberOfBytes,OUT EFI_PHYSICAL_ADDRESS * DeviceAddress,OUT VOID ** Mapping)266 PciIoMap (
267   IN EFI_PCI_IO_PROTOCOL                *This,
268   IN     EFI_PCI_IO_PROTOCOL_OPERATION  Operation,
269   IN     VOID                           *HostAddress,
270   IN OUT UINTN                          *NumberOfBytes,
271   OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,
272   OUT    VOID                           **Mapping
273   )
274 {
275   DMA_MAP_OPERATION   DmaOperation;
276 
277   if (Operation == EfiPciIoOperationBusMasterRead) {
278     DmaOperation = MapOperationBusMasterRead;
279   } else if (Operation == EfiPciIoOperationBusMasterWrite) {
280     DmaOperation = MapOperationBusMasterWrite;
281   } else if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
282     DmaOperation = MapOperationBusMasterCommonBuffer;
283   } else {
284     return EFI_INVALID_PARAMETER;
285   }
286   return DmaMap (DmaOperation, HostAddress, NumberOfBytes, DeviceAddress, Mapping);
287 }
288 
289 EFI_STATUS
PciIoUnmap(IN EFI_PCI_IO_PROTOCOL * This,IN VOID * Mapping)290 PciIoUnmap (
291   IN EFI_PCI_IO_PROTOCOL           *This,
292   IN  VOID                         *Mapping
293   )
294 {
295   return DmaUnmap (Mapping);
296 }
297 
298 /**
299   Allocate pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer
300   mapping.
301 
302   @param[in]   This         A pointer to the EFI_PCI_IO_PROTOCOL instance.
303   @param[in]   Type         This parameter is not used and must be ignored.
304   @param[in]   MemoryType   The type of memory to allocate, EfiBootServicesData or
305                             EfiRuntimeServicesData.
306   @param[in]   Pages        The number of pages to allocate.
307   @param[out]  HostAddress  A pointer to store the base system memory address of
308                             the allocated range.
309   @param[in]   Attributes   The requested bit mask of attributes for the allocated
310                             range. Only the attributes,
311                             EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE and
312                             EFI_PCI_ATTRIBUTE_MEMORY_CACHED may be used with this
313                             function. If any other bits are set, then EFI_UNSUPPORTED
314                             is returned. This function ignores this bit mask.
315 
316   @retval  EFI_SUCCESS            The requested memory pages were allocated.
317   @retval  EFI_INVALID_PARAMETER  HostAddress is NULL.
318   @retval  EFI_INVALID_PARAMETER  MemoryType is invalid.
319   @retval  EFI_UNSUPPORTED        Attributes is unsupported.
320   @retval  EFI_OUT_OF_RESOURCES   The memory pages could not be allocated.
321 
322 **/
323 EFI_STATUS
PciIoAllocateBuffer(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_ALLOCATE_TYPE Type,IN EFI_MEMORY_TYPE MemoryType,IN UINTN Pages,OUT VOID ** HostAddress,IN UINT64 Attributes)324 PciIoAllocateBuffer (
325   IN EFI_PCI_IO_PROTOCOL  *This,
326   IN  EFI_ALLOCATE_TYPE   Type,
327   IN  EFI_MEMORY_TYPE     MemoryType,
328   IN  UINTN               Pages,
329   OUT VOID                **HostAddress,
330   IN  UINT64              Attributes
331   )
332 {
333   if (Attributes &
334       (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE |
335          EFI_PCI_ATTRIBUTE_MEMORY_CACHED         ))) {
336     return EFI_UNSUPPORTED;
337   }
338 
339   return DmaAllocateBuffer (MemoryType, Pages, HostAddress);
340 }
341 
342 
343 EFI_STATUS
PciIoFreeBuffer(IN EFI_PCI_IO_PROTOCOL * This,IN UINTN Pages,IN VOID * HostAddress)344 PciIoFreeBuffer (
345   IN EFI_PCI_IO_PROTOCOL           *This,
346   IN  UINTN                        Pages,
347   IN  VOID                         *HostAddress
348   )
349 {
350   return DmaFreeBuffer (Pages, HostAddress);
351 }
352 
353 
354 EFI_STATUS
PciIoFlush(IN EFI_PCI_IO_PROTOCOL * This)355 PciIoFlush (
356   IN EFI_PCI_IO_PROTOCOL  *This
357   )
358 {
359   return EFI_SUCCESS;
360 }
361 
362 /**
363   Retrieves this PCI controller's current PCI bus number, device number, and function number.
364 
365   @param[in]   This            A pointer to the EFI_PCI_IO_PROTOCOL instance.
366   @param[out]  SegmentNumber   The PCI controller's current PCI segment number.
367   @param[out]  BusNumber       The PCI controller's current PCI bus number.
368   @param[out]  DeviceNumber    The PCI controller's current PCI device number.
369   @param[out]  FunctionNumber  The PCI controller’s current PCI function number.
370 
371   @retval  EFI_SUCCESS            The PCI controller location was returned.
372   @retval  EFI_INVALID_PARAMETER  At least one out of the four output parameters is
373                                   a NULL pointer.
374 **/
375 EFI_STATUS
PciIoGetLocation(IN EFI_PCI_IO_PROTOCOL * This,OUT UINTN * SegmentNumber,OUT UINTN * BusNumber,OUT UINTN * DeviceNumber,OUT UINTN * FunctionNumber)376 PciIoGetLocation (
377   IN   EFI_PCI_IO_PROTOCOL  *This,
378   OUT  UINTN                *SegmentNumber,
379   OUT  UINTN                *BusNumber,
380   OUT  UINTN                *DeviceNumber,
381   OUT  UINTN                *FunctionNumber
382   )
383 {
384   EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
385 
386   if ((SegmentNumber == NULL) || (BusNumber      == NULL) ||
387       (DeviceNumber  == NULL) || (FunctionNumber == NULL)    ) {
388     return EFI_INVALID_PARAMETER;
389   }
390 
391   *SegmentNumber  = Private->Segment;
392   *BusNumber      = 0xff;
393   *DeviceNumber   = 0;
394   *FunctionNumber = 0;
395 
396   return EFI_SUCCESS;
397 }
398 
399 /**
400   Performs an operation on the attributes that this PCI controller supports.
401 
402   The operations include getting the set of supported attributes, retrieving
403   the current attributes, setting the current attributes, enabling attributes,
404   and disabling attributes.
405 
406   @param[in]   This        A pointer to the EFI_PCI_IO_PROTOCOL instance.
407   @param[in]   Operation   The operation to perform on the attributes for this
408                            PCI controller.
409   @param[in]   Attributes  The mask of attributes that are used for Set,
410                            Enable and Disable operations.
411   @param[out]  Result      A pointer to the result mask of attributes that are
412                            returned for the Get and Supported operations. This
413                            is an optional parameter that may be NULL for the
414                            Set, Enable, and Disable operations.
415 
416   @retval  EFI_SUCCESS            The operation on the PCI controller's
417                                   attributes was completed. If the operation
418                                   was Get or Supported, then the attribute mask
419                                   is returned in Result.
420   @retval  EFI_INVALID_PARAMETER  Operation is greater than or equal to
421                                   EfiPciIoAttributeOperationMaximum.
422   @retval  EFI_INVALID_PARAMETER  Operation is Get and Result is NULL.
423   @retval  EFI_INVALID_PARAMETER  Operation is Supported and Result is NULL.
424 
425 **/
426 EFI_STATUS
PciIoAttributes(IN EFI_PCI_IO_PROTOCOL * This,IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,IN UINT64 Attributes,OUT UINT64 * Result OPTIONAL)427 PciIoAttributes (
428   IN EFI_PCI_IO_PROTOCOL                       *This,
429   IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,
430   IN  UINT64                                   Attributes,
431   OUT UINT64                                   *Result OPTIONAL
432   )
433 {
434   switch (Operation) {
435   case EfiPciIoAttributeOperationGet:
436   case EfiPciIoAttributeOperationSupported:
437     if (Result == NULL) {
438       return EFI_INVALID_PARAMETER;
439     }
440     //
441     // We are not a real PCI device so just say things we kind of do
442     //
443     *Result = EFI_PCI_DEVICE_ENABLE;
444     break;
445 
446   case EfiPciIoAttributeOperationSet:
447   case EfiPciIoAttributeOperationEnable:
448   case EfiPciIoAttributeOperationDisable:
449     if (Attributes & (~EFI_PCI_DEVICE_ENABLE)) {
450       return EFI_UNSUPPORTED;
451     }
452     // Since we are not a real PCI device no enable/set or disable operations exist.
453     return EFI_SUCCESS;
454 
455   default:
456     return EFI_INVALID_PARAMETER;
457   };
458   return EFI_SUCCESS;
459 }
460 
461 EFI_STATUS
PciIoGetBarAttributes(IN EFI_PCI_IO_PROTOCOL * This,IN UINT8 BarIndex,OUT UINT64 * Supports,OPTIONAL OUT VOID ** Resources OPTIONAL)462 PciIoGetBarAttributes (
463   IN EFI_PCI_IO_PROTOCOL             *This,
464   IN  UINT8                          BarIndex,
465   OUT UINT64                         *Supports, OPTIONAL
466   OUT VOID                           **Resources OPTIONAL
467   )
468 {
469   ASSERT (FALSE);
470   return EFI_UNSUPPORTED;
471 }
472 
473 EFI_STATUS
PciIoSetBarAttributes(IN EFI_PCI_IO_PROTOCOL * This,IN UINT64 Attributes,IN UINT8 BarIndex,IN OUT UINT64 * Offset,IN OUT UINT64 * Length)474 PciIoSetBarAttributes (
475   IN EFI_PCI_IO_PROTOCOL              *This,
476   IN     UINT64                       Attributes,
477   IN     UINT8                        BarIndex,
478   IN OUT UINT64                       *Offset,
479   IN OUT UINT64                       *Length
480   )
481 {
482   ASSERT (FALSE);
483   return EFI_UNSUPPORTED;
484 }
485 
486 EFI_PCI_IO_PROTOCOL PciIoTemplate =
487 {
488   PciIoPollMem,
489   PciIoPollIo,
490   { PciIoMemRead, PciIoMemWrite },
491   { PciIoIoRead,  PciIoIoWrite },
492   { PciIoPciRead, PciIoPciWrite },
493   PciIoCopyMem,
494   PciIoMap,
495   PciIoUnmap,
496   PciIoAllocateBuffer,
497   PciIoFreeBuffer,
498   PciIoFlush,
499   PciIoGetLocation,
500   PciIoAttributes,
501   PciIoGetBarAttributes,
502   PciIoSetBarAttributes,
503   0,
504   0
505 };
506 
507 EFI_STATUS
PciInstallDevice(IN UINTN DeviceId,IN PHYSICAL_ADDRESS MemoryStart,IN UINT64 MemorySize,IN UINTN ClassCode1,IN UINTN ClassCode2,IN UINTN ClassCode3)508 PciInstallDevice (
509   IN UINTN            DeviceId,
510   IN PHYSICAL_ADDRESS MemoryStart,
511   IN UINT64           MemorySize,
512   IN UINTN            ClassCode1,
513   IN UINTN            ClassCode2,
514   IN UINTN            ClassCode3
515   )
516 {
517   EFI_STATUS              Status;
518   EFI_HANDLE              Handle;
519   EFI_PCI_IO_PRIVATE_DATA *Private;
520 
521   // Configure USB host
522   ConfigureUSBHost ();
523 
524   // Create a private structure
525   Private = AllocatePool (sizeof (EFI_PCI_IO_PRIVATE_DATA));
526   if (Private == NULL) {
527     Status = EFI_OUT_OF_RESOURCES;
528     return Status;
529   }
530 
531   Private->Signature              = EFI_PCI_IO_PRIVATE_DATA_SIGNATURE;  // Fill in signature
532   Private->RootBridge.Signature   = PCI_ROOT_BRIDGE_SIGNATURE;          // Fake Root Bridge structure needs a signature too
533   Private->RootBridge.MemoryStart = MemoryStart; // Get the USB capability register base
534   Private->Segment                = 0;                                  // Default to segment zero
535 
536   // Calculate the total size of the USB controller (OHCI + EHCI).
537   Private->RootBridge.MemorySize = MemorySize; //CapabilityLength + (HOST_CONTROLLER_OPERATION_REG_SIZE + ((4 * PhysicalPorts) - 1));
538 
539   // Create fake PCI config space: OHCI + EHCI
540   Private->ConfigSpace = AllocateZeroPool (sizeof (PCI_TYPE00));
541   if (Private->ConfigSpace == NULL) {
542     Status = EFI_OUT_OF_RESOURCES;
543     FreePool (Private);
544     return Status;
545   }
546 
547   //
548   // Configure PCI config space: OHCI + EHCI
549   //
550   Private->ConfigSpace->Hdr.VendorId = 0xFFFF; // Invalid vendor Id as it is not an actual device.
551   Private->ConfigSpace->Hdr.DeviceId = 0x0000; // Not relevant as the vendor id is not valid.
552   Private->ConfigSpace->Hdr.ClassCode[0] = ClassCode1;
553   Private->ConfigSpace->Hdr.ClassCode[1] = ClassCode2;
554   Private->ConfigSpace->Hdr.ClassCode[2] = ClassCode3;
555   Private->ConfigSpace->Device.Bar[0] = MemoryStart;
556 
557   Handle = NULL;
558 
559   // Unique device path.
560   CopyMem (&Private->DevicePath, &PciIoDevicePathTemplate, sizeof (PciIoDevicePathTemplate));
561   Private->DevicePath.AcpiDevicePath.UID = 1; // Use '1' to differentiate from PLDA root complex
562   Private->DevicePath.PciDevicePath.Device = DeviceId;
563 
564   // Copy protocol structure
565   CopyMem (&Private->PciIoProtocol, &PciIoTemplate, sizeof (PciIoTemplate));
566 
567   Status = gBS->InstallMultipleProtocolInterfaces (&Handle,
568                                                   &gEfiPciIoProtocolGuid,       &Private->PciIoProtocol,
569                                                   &gEfiDevicePathProtocolGuid,  &Private->DevicePath,
570                                                   NULL);
571   if (EFI_ERROR (Status)) {
572     DEBUG ((EFI_D_ERROR, "PciEmulationEntryPoint InstallMultipleProtocolInterfaces () failed.\n"));
573   }
574 
575   return Status;
576 }
577 
578 EFI_STATUS
PciEmulationEntryPoint(VOID)579 PciEmulationEntryPoint (
580   VOID
581   )
582 {
583   EFI_STATUS              Status;
584 
585   Status = PciInstallDevice (0, FixedPcdGet32 (PcdSynopsysUsbOhciBaseAddress), SIZE_64KB, PCI_IF_OHCI, PCI_CLASS_SERIAL_USB, PCI_CLASS_SERIAL);
586   if (EFI_ERROR (Status)) {
587     DEBUG ((EFI_D_ERROR, "PciEmulation: failed to install OHCI device.\n"));
588   }
589 
590   Status = PciInstallDevice (1, FixedPcdGet32 (PcdSynopsysUsbEhciBaseAddress), SIZE_64KB, PCI_IF_EHCI, PCI_CLASS_SERIAL_USB, PCI_CLASS_SERIAL);
591   if (EFI_ERROR (Status)) {
592     DEBUG ((EFI_D_ERROR, "PciEmulation: failed to install EHCI device.\n"));
593   }
594 
595   return Status;
596 }
597