1/** @file
2  Initialization functions for EFI UNDI32 driver.
3
4Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include "Undi32.h"
16//
17// Global Variables
18//
19
20PXE_SW_UNDI             *pxe_31 = NULL;  // 3.1 entry
21UNDI32_DEV              *UNDI32DeviceList[MAX_NIC_INTERFACES];
22UNDI_CONFIG_TABLE       *UndiDataPointer = NULL;
23
24//
25// UNDI Class Driver Global Variables
26//
27EFI_DRIVER_BINDING_PROTOCOL  gUndiDriverBinding = {
28  UndiDriverSupported,
29  UndiDriverStart,
30  UndiDriverStop,
31  0xa,
32  NULL,
33  NULL
34};
35
36
37/**
38  When address mapping changes to virtual this should make the appropriate
39  address conversions.
40
41  (Standard Event handler)
42
43  @return None
44
45**/
46VOID
47EFIAPI
48UndiNotifyVirtual (
49  EFI_EVENT Event,
50  VOID      *Context
51  )
52{
53  UINT16  Index;
54  VOID    *Pxe31Pointer;
55
56  if (pxe_31 != NULL) {
57    Pxe31Pointer = (VOID *) pxe_31;
58
59    EfiConvertPointer (
60      EFI_OPTIONAL_PTR,
61      (VOID **) &Pxe31Pointer
62      );
63
64    //
65    // UNDI32DeviceList is an array of pointers
66    //
67    for (Index = 0; Index < (pxe_31->IFcnt | pxe_31->IFcntExt << 8); Index++) {
68      UNDI32DeviceList[Index]->NIIProtocol_31.Id = (UINT64) (UINTN) Pxe31Pointer;
69      EfiConvertPointer (
70        EFI_OPTIONAL_PTR,
71        (VOID **) &(UNDI32DeviceList[Index])
72        );
73    }
74
75    EfiConvertPointer (
76      EFI_OPTIONAL_PTR,
77      (VOID **) &(pxe_31->EntryPoint)
78      );
79    pxe_31 = Pxe31Pointer;
80  }
81
82  for (Index = 0; Index <= PXE_OPCODE_LAST_VALID; Index++) {
83    EfiConvertPointer (
84      EFI_OPTIONAL_PTR,
85      (VOID **) &api_table[Index].api_ptr
86      );
87  }
88}
89
90
91/**
92  When EFI is shuting down the boot services, we need to install a
93  configuration table for UNDI to work at runtime!
94
95  (Standard Event handler)
96
97  @return None
98
99**/
100VOID
101EFIAPI
102UndiNotifyReadyToBoot (
103  EFI_EVENT Event,
104  VOID      *Context
105  )
106{
107  InstallConfigTable ();
108}
109
110
111/**
112  Test to see if this driver supports ControllerHandle. Any ControllerHandle
113  than contains a  DevicePath, PciIo protocol, Class code of 2, Vendor ID of 0x8086,
114  and DeviceId of (D100_DEVICE_ID || D102_DEVICE_ID || ICH3_DEVICE_ID_1 ||
115  ICH3_DEVICE_ID_2 || ICH3_DEVICE_ID_3 || ICH3_DEVICE_ID_4 || ICH3_DEVICE_ID_5 ||
116  ICH3_DEVICE_ID_6 || ICH3_DEVICE_ID_7 || ICH3_DEVICE_ID_8) can be supported.
117
118  @param  This                 Protocol instance pointer.
119  @param  Controller           Handle of device to test.
120  @param  RemainingDevicePath  Not used.
121
122  @retval EFI_SUCCESS          This driver supports this device.
123  @retval other                This driver does not support this device.
124
125**/
126EFI_STATUS
127EFIAPI
128UndiDriverSupported (
129  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
130  IN EFI_HANDLE                     Controller,
131  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
132  )
133{
134  EFI_STATUS          Status;
135  EFI_PCI_IO_PROTOCOL *PciIo;
136  PCI_TYPE00          Pci;
137
138  Status = gBS->OpenProtocol (
139                  Controller,
140                  &gEfiDevicePathProtocolGuid,
141                  NULL,
142                  This->DriverBindingHandle,
143                  Controller,
144                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
145                  );
146  if (EFI_ERROR (Status)) {
147    return Status;
148  }
149
150  Status = gBS->OpenProtocol (
151                  Controller,
152                  &gEfiPciIoProtocolGuid,
153                  (VOID **) &PciIo,
154                  This->DriverBindingHandle,
155                  Controller,
156                  EFI_OPEN_PROTOCOL_BY_DRIVER
157                  );
158  if (EFI_ERROR (Status)) {
159    return Status;
160  }
161
162  Status = PciIo->Pci.Read (
163                        PciIo,
164                        EfiPciIoWidthUint8,
165                        0,
166                        sizeof (PCI_CONFIG_HEADER),
167                        &Pci
168                        );
169
170  if (!EFI_ERROR (Status)) {
171    Status = EFI_UNSUPPORTED;
172
173    if (Pci.Hdr.ClassCode[2] == 0x02 && Pci.Hdr.VendorId == PCI_VENDOR_ID_INTEL) {
174      switch (Pci.Hdr.DeviceId) {
175      case D100_DEVICE_ID:
176      case D102_DEVICE_ID:
177      case ICH3_DEVICE_ID_1:
178      case ICH3_DEVICE_ID_2:
179      case ICH3_DEVICE_ID_3:
180      case ICH3_DEVICE_ID_4:
181      case ICH3_DEVICE_ID_5:
182      case ICH3_DEVICE_ID_6:
183      case ICH3_DEVICE_ID_7:
184      case ICH3_DEVICE_ID_8:
185      case 0x1039:
186      case 0x103A:
187      case 0x103B:
188      case 0x103C:
189      case 0x103D:
190      case 0x103E:
191      case 0x1050:
192      case 0x1051:
193      case 0x1052:
194      case 0x1053:
195      case 0x1054:
196      case 0x1055:
197      case 0x1056:
198      case 0x1057:
199      case 0x1059:
200      case 0x1064:
201        Status = EFI_SUCCESS;
202      }
203    }
204  }
205
206  gBS->CloseProtocol (
207        Controller,
208        &gEfiPciIoProtocolGuid,
209        This->DriverBindingHandle,
210        Controller
211        );
212
213  return Status;
214}
215
216
217/**
218  Start this driver on Controller by opening PciIo and DevicePath protocol.
219  Initialize PXE structures, create a copy of the Controller Device Path with the
220  NIC's MAC address appended to it, install the NetworkInterfaceIdentifier protocol
221  on the newly created Device Path.
222
223  @param  This                 Protocol instance pointer.
224  @param  Controller           Handle of device to work with.
225  @param  RemainingDevicePath  Not used, always produce all possible children.
226
227  @retval EFI_SUCCESS          This driver is added to Controller.
228  @retval other                This driver does not support this device.
229
230**/
231EFI_STATUS
232EFIAPI
233UndiDriverStart (
234  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
235  IN EFI_HANDLE                     Controller,
236  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
237  )
238{
239  EFI_STATUS                Status;
240  EFI_DEVICE_PATH_PROTOCOL  *UndiDevicePath;
241  PCI_CONFIG_HEADER         *CfgHdr;
242  UNDI32_DEV                *UNDI32Device;
243  UINT16                    NewCommand;
244  UINT8                     *TmpPxePointer;
245  EFI_PCI_IO_PROTOCOL       *PciIoFncs;
246  UINTN                     Len;
247  UINT64                    Supports;
248  BOOLEAN                   PciAttributesSaved;
249
250  Status = gBS->OpenProtocol (
251                  Controller,
252                  &gEfiPciIoProtocolGuid,
253                  (VOID **) &PciIoFncs,
254                  This->DriverBindingHandle,
255                  Controller,
256                  EFI_OPEN_PROTOCOL_BY_DRIVER
257                  );
258
259  if (EFI_ERROR (Status)) {
260    return Status;
261  }
262
263  Status = gBS->OpenProtocol (
264                  Controller,
265                  &gEfiDevicePathProtocolGuid,
266                  (VOID **) &UndiDevicePath,
267                  This->DriverBindingHandle,
268                  Controller,
269                  EFI_OPEN_PROTOCOL_BY_DRIVER
270                  );
271
272  if (EFI_ERROR (Status)) {
273    gBS->CloseProtocol (
274          Controller,
275          &gEfiPciIoProtocolGuid,
276          This->DriverBindingHandle,
277          Controller
278          );
279
280    return Status;
281  }
282
283  PciAttributesSaved = FALSE;
284
285  Status = gBS->AllocatePool (
286                  EfiRuntimeServicesData,
287                  sizeof (UNDI32_DEV),
288                  (VOID **) &UNDI32Device
289                  );
290
291  if (EFI_ERROR (Status)) {
292    goto UndiError;
293  }
294
295  ZeroMem ((CHAR8 *) UNDI32Device, sizeof (UNDI32_DEV));
296
297  //
298  // Get original PCI attributes
299  //
300  Status = PciIoFncs->Attributes (
301                    PciIoFncs,
302                    EfiPciIoAttributeOperationGet,
303                    0,
304                    &UNDI32Device->NicInfo.OriginalPciAttributes
305                    );
306
307  if (EFI_ERROR (Status)) {
308    goto UndiErrorDeleteDevice;
309  }
310  PciAttributesSaved = TRUE;
311
312  //
313  // allocate and initialize both (old and new) the !pxe structures here,
314  // there should only be one copy of each of these structure for any number
315  // of NICs this undi supports. Also, these structures need to be on a
316  // paragraph boundary as per the spec. so, while allocating space for these,
317  // make sure that there is space for 2 !pxe structures (old and new) and a
318  // 32 bytes padding for alignment adjustment (in case)
319  //
320  TmpPxePointer = NULL;
321  if (pxe_31 == NULL) {
322    Status = gBS->AllocatePool (
323                    EfiRuntimeServicesData,
324                    (sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32),
325                    (VOID **) &TmpPxePointer
326                    );
327
328    if (EFI_ERROR (Status)) {
329      goto UndiErrorDeleteDevice;
330    }
331
332    ZeroMem (
333      TmpPxePointer,
334      sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32
335      );
336    //
337    // check for paragraph alignment here, assuming that the pointer is
338    // already 8 byte aligned.
339    //
340    if (((UINTN) TmpPxePointer & 0x0F) != 0) {
341      pxe_31 = (PXE_SW_UNDI *) ((UINTN) (TmpPxePointer + 8));
342    } else {
343      pxe_31 = (PXE_SW_UNDI *) TmpPxePointer;
344    }
345
346    PxeStructInit (pxe_31);
347  }
348
349  UNDI32Device->NIIProtocol_31.Id = (UINT64) (UINTN) (pxe_31);
350
351  Status = PciIoFncs->Attributes (
352                        PciIoFncs,
353                        EfiPciIoAttributeOperationSupported,
354                        0,
355                        &Supports
356                        );
357  if (!EFI_ERROR (Status)) {
358    Supports &= EFI_PCI_DEVICE_ENABLE;
359    Status = PciIoFncs->Attributes (
360                          PciIoFncs,
361                          EfiPciIoAttributeOperationEnable,
362                          Supports,
363                          NULL
364                          );
365  }
366  //
367  // Read all the registers from device's PCI Configuration space
368  //
369  Status = PciIoFncs->Pci.Read (
370                            PciIoFncs,
371                            EfiPciIoWidthUint32,
372                            0,
373                            MAX_PCI_CONFIG_LEN,
374                            &UNDI32Device->NicInfo.Config
375                            );
376
377  CfgHdr = (PCI_CONFIG_HEADER *) &(UNDI32Device->NicInfo.Config[0]);
378
379  //
380  // make sure that this device is a PCI bus master
381  //
382
383  NewCommand = (UINT16) (CfgHdr->Command | PCI_COMMAND_MASTER | PCI_COMMAND_IO);
384  if (CfgHdr->Command != NewCommand) {
385    PciIoFncs->Pci.Write (
386                    PciIoFncs,
387                    EfiPciIoWidthUint16,
388                    PCI_COMMAND,
389                    1,
390                    &NewCommand
391                    );
392    CfgHdr->Command = NewCommand;
393  }
394
395  //
396  // make sure that the latency timer is at least 32
397  //
398  if (CfgHdr->LatencyTimer < 32) {
399    CfgHdr->LatencyTimer = 32;
400    PciIoFncs->Pci.Write (
401                    PciIoFncs,
402                    EfiPciIoWidthUint8,
403                    PCI_LATENCY_TIMER,
404                    1,
405                    &CfgHdr->LatencyTimer
406                    );
407  }
408  //
409  // the IfNum index for the current interface will be the total number
410  // of interfaces initialized so far
411  //
412  UNDI32Device->NIIProtocol_31.IfNum  = pxe_31->IFcnt | pxe_31->IFcntExt << 8;
413
414  PxeUpdate (&UNDI32Device->NicInfo, pxe_31);
415
416  UNDI32Device->NicInfo.Io_Function                    = PciIoFncs;
417  UNDI32DeviceList[UNDI32Device->NIIProtocol_31.IfNum] = UNDI32Device;
418  UNDI32Device->Undi32BaseDevPath                      = UndiDevicePath;
419
420  Status = AppendMac2DevPath (
421            &UNDI32Device->Undi32DevPath,
422            UNDI32Device->Undi32BaseDevPath,
423            &UNDI32Device->NicInfo
424            );
425
426  if (Status != 0) {
427    goto UndiErrorDeletePxe;
428  }
429
430  UNDI32Device->Signature                     = UNDI_DEV_SIGNATURE;
431
432  UNDI32Device->NIIProtocol_31.Revision       = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION_31;
433  UNDI32Device->NIIProtocol_31.Type           = EfiNetworkInterfaceUndi;
434  UNDI32Device->NIIProtocol_31.MajorVer       = PXE_ROMID_MAJORVER;
435  UNDI32Device->NIIProtocol_31.MinorVer       = PXE_ROMID_MINORVER_31;
436  UNDI32Device->NIIProtocol_31.ImageSize      = 0;
437  UNDI32Device->NIIProtocol_31.ImageAddr      = 0;
438  UNDI32Device->NIIProtocol_31.Ipv6Supported  = TRUE;
439
440  UNDI32Device->NIIProtocol_31.StringId[0]    = 'U';
441  UNDI32Device->NIIProtocol_31.StringId[1]    = 'N';
442  UNDI32Device->NIIProtocol_31.StringId[2]    = 'D';
443  UNDI32Device->NIIProtocol_31.StringId[3]    = 'I';
444
445  UNDI32Device->DeviceHandle                  = NULL;
446
447  UNDI32Device->Aip.GetInformation            = UndiAipGetInfo;
448  UNDI32Device->Aip.SetInformation            = UndiAipSetInfo;
449  UNDI32Device->Aip.GetSupportedTypes         = UndiAipGetSupportedTypes;
450
451  //
452  // install both the 3.0 and 3.1 NII protocols.
453  //
454  Status = gBS->InstallMultipleProtocolInterfaces (
455                  &UNDI32Device->DeviceHandle,
456                  &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
457                  &UNDI32Device->NIIProtocol_31,
458                  &gEfiDevicePathProtocolGuid,
459                  UNDI32Device->Undi32DevPath,
460                  &gEfiAdapterInformationProtocolGuid,
461                  &UNDI32Device->Aip,
462                  NULL
463                  );
464
465  if (EFI_ERROR (Status)) {
466    goto UndiErrorDeleteDevicePath;
467  }
468
469  //
470  // if the table exists, free it and alloc again, or alloc it directly
471  //
472  if (UndiDataPointer != NULL) {
473    Status = gBS->FreePool(UndiDataPointer);
474  }
475  if (EFI_ERROR (Status)) {
476    goto UndiErrorDeleteDevicePath;
477  }
478
479  Len = ((pxe_31->IFcnt|pxe_31->IFcntExt << 8)* sizeof (UndiDataPointer->NII_entry)) + sizeof (UndiDataPointer);
480  Status = gBS->AllocatePool (EfiRuntimeServicesData, Len, (VOID **) &UndiDataPointer);
481
482  if (EFI_ERROR (Status)) {
483    goto UndiErrorAllocDataPointer;
484  }
485
486  //
487  // Open For Child Device
488  //
489  Status = gBS->OpenProtocol (
490                  Controller,
491                  &gEfiPciIoProtocolGuid,
492                  (VOID **) &PciIoFncs,
493                  This->DriverBindingHandle,
494                  UNDI32Device->DeviceHandle,
495                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
496                  );
497
498  return EFI_SUCCESS;
499UndiErrorAllocDataPointer:
500  gBS->UninstallMultipleProtocolInterfaces (
501                  &UNDI32Device->DeviceHandle,
502                  &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
503                  &UNDI32Device->NIIProtocol_31,
504                  &gEfiDevicePathProtocolGuid,
505                  UNDI32Device->Undi32DevPath,
506                  &gEfiAdapterInformationProtocolGuid,
507                  &UNDI32Device->Aip,
508                  NULL
509                  );
510
511UndiErrorDeleteDevicePath:
512  UNDI32DeviceList[UNDI32Device->NIIProtocol_31.IfNum] = NULL;
513  gBS->FreePool (UNDI32Device->Undi32DevPath);
514
515UndiErrorDeletePxe:
516  PxeUpdate (NULL, pxe_31);
517  if (TmpPxePointer != NULL) {
518    gBS->FreePool (TmpPxePointer);
519
520  }
521
522UndiErrorDeleteDevice:
523  if (PciAttributesSaved) {
524    //
525    // Restore original PCI attributes
526    //
527    PciIoFncs->Attributes (
528                    PciIoFncs,
529                    EfiPciIoAttributeOperationSet,
530                    UNDI32Device->NicInfo.OriginalPciAttributes,
531                    NULL
532                    );
533  }
534
535  gBS->FreePool (UNDI32Device);
536
537UndiError:
538  gBS->CloseProtocol (
539        Controller,
540        &gEfiDevicePathProtocolGuid,
541        This->DriverBindingHandle,
542        Controller
543        );
544
545  gBS->CloseProtocol (
546        Controller,
547        &gEfiPciIoProtocolGuid,
548        This->DriverBindingHandle,
549        Controller
550        );
551
552  return Status;
553}
554
555
556/**
557  Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and
558  closing the DevicePath and PciIo protocols on Controller.
559
560  @param  This                 Protocol instance pointer.
561  @param  Controller           Handle of device to stop driver on.
562  @param  NumberOfChildren     How many children need to be stopped.
563  @param  ChildHandleBuffer    Not used.
564
565  @retval EFI_SUCCESS          This driver is removed Controller.
566  @retval other                This driver was not removed from this device.
567
568**/
569// TODO:    EFI_DEVICE_ERROR - add return value to function comment
570EFI_STATUS
571EFIAPI
572UndiDriverStop (
573  IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
574  IN  EFI_HANDLE                     Controller,
575  IN  UINTN                          NumberOfChildren,
576  IN  EFI_HANDLE                     *ChildHandleBuffer
577  )
578{
579  EFI_STATUS                                Status;
580  BOOLEAN                                   AllChildrenStopped;
581  UINTN                                     Index;
582  UNDI32_DEV                                *UNDI32Device;
583  EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NIIProtocol;
584
585  //
586  // Complete all outstanding transactions to Controller.
587  // Don't allow any new transaction to Controller to be started.
588  //
589  if (NumberOfChildren == 0) {
590
591    //
592    // Close the bus driver
593    //
594    Status = gBS->CloseProtocol (
595                    Controller,
596                    &gEfiDevicePathProtocolGuid,
597                    This->DriverBindingHandle,
598                    Controller
599                    );
600
601    Status = gBS->CloseProtocol (
602                    Controller,
603                    &gEfiPciIoProtocolGuid,
604                    This->DriverBindingHandle,
605                    Controller
606                    );
607
608    return Status;
609  }
610
611  AllChildrenStopped = TRUE;
612
613  for (Index = 0; Index < NumberOfChildren; Index++) {
614
615    Status = gBS->OpenProtocol (
616                    ChildHandleBuffer[Index],
617                    &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
618                    (VOID **) &NIIProtocol,
619                    This->DriverBindingHandle,
620                    Controller,
621                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
622                    );
623    if (!EFI_ERROR (Status)) {
624
625      UNDI32Device = UNDI_DEV_FROM_THIS (NIIProtocol);
626
627      Status = gBS->CloseProtocol (
628                      Controller,
629                      &gEfiPciIoProtocolGuid,
630                      This->DriverBindingHandle,
631                      ChildHandleBuffer[Index]
632                      );
633      if (!EFI_ERROR (Status)) {
634        Status = gBS->UninstallMultipleProtocolInterfaces (
635                        ChildHandleBuffer[Index],
636                        &gEfiDevicePathProtocolGuid,
637                        UNDI32Device->Undi32DevPath,
638                        &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
639                        &UNDI32Device->NIIProtocol_31,
640                        NULL
641                        );
642        if (!EFI_ERROR (Status)) {
643          //
644          // Restore original PCI attributes
645          //
646          Status = UNDI32Device->NicInfo.Io_Function->Attributes (
647                                                        UNDI32Device->NicInfo.Io_Function,
648                                                        EfiPciIoAttributeOperationSet,
649                                                        UNDI32Device->NicInfo.OriginalPciAttributes,
650                                                        NULL
651                                                        );
652
653          ASSERT_EFI_ERROR (Status);
654
655          gBS->FreePool (UNDI32Device->Undi32DevPath);
656          gBS->FreePool (UNDI32Device);
657
658        }
659      }
660    }
661
662    if (EFI_ERROR (Status)) {
663      AllChildrenStopped = FALSE;
664    }
665  }
666
667  if (!AllChildrenStopped) {
668    return EFI_DEVICE_ERROR;
669  }
670
671  return EFI_SUCCESS;
672
673}
674
675
676/**
677  Use the EFI boot services to produce a pause. This is also the routine which
678  gets replaced during RunTime by the O/S in the NIC_DATA_INSTANCE so it can
679  do it's own pause.
680
681  @param  UnqId                Runtime O/S routine might use this, this temp
682                               routine does not use it
683  @param  MicroSeconds         Determines the length of pause.
684
685  @return none
686
687**/
688VOID
689TmpDelay (
690  IN UINT64 UnqId,
691  IN UINTN  MicroSeconds
692  )
693{
694  gBS->Stall ((UINT32) MicroSeconds);
695}
696
697
698/**
699  Use the PCI IO abstraction to issue memory or I/O reads and writes.  This is also the routine which
700  gets replaced during RunTime by the O/S in the NIC_DATA_INSTANCE so it can do it's own I/O abstractions.
701
702  @param  UnqId                Runtime O/S routine may use this field, this temp
703                               routine does not.
704  @param  ReadWrite            Determine if it is an I/O or Memory Read/Write
705                               Operation.
706  @param  Len                  Determines the width of the data operation.
707  @param  Port                 What port to Read/Write from.
708  @param  BuffAddr             Address to read to or write from.
709
710  @return none
711
712**/
713VOID
714TmpMemIo (
715  IN UINT64 UnqId,
716  IN UINT8  ReadWrite,
717  IN UINT8  Len,
718  IN UINT64 Port,
719  IN UINT64 BuffAddr
720  )
721{
722  EFI_PCI_IO_PROTOCOL_WIDTH Width;
723  NIC_DATA_INSTANCE         *AdapterInfo;
724
725  Width       = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;
726  AdapterInfo = (NIC_DATA_INSTANCE *) (UINTN) UnqId;
727  switch (Len) {
728  case 2:
729    Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;
730    break;
731
732  case 4:
733    Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;
734    break;
735
736  case 8:
737    Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;
738    break;
739  }
740
741  switch (ReadWrite) {
742  case PXE_IO_READ:
743    AdapterInfo->Io_Function->Io.Read (
744                                  AdapterInfo->Io_Function,
745                                  Width,
746                                  1,
747                                  Port,
748                                  1,
749                                  (VOID *) (UINTN) (BuffAddr)
750                                  );
751    break;
752
753  case PXE_IO_WRITE:
754    AdapterInfo->Io_Function->Io.Write (
755                                  AdapterInfo->Io_Function,
756                                  Width,
757                                  1,
758                                  Port,
759                                  1,
760                                  (VOID *) (UINTN) (BuffAddr)
761                                  );
762    break;
763
764  case PXE_MEM_READ:
765    AdapterInfo->Io_Function->Mem.Read (
766                                    AdapterInfo->Io_Function,
767                                    Width,
768                                    0,
769                                    Port,
770                                    1,
771                                    (VOID *) (UINTN) (BuffAddr)
772                                    );
773    break;
774
775  case PXE_MEM_WRITE:
776    AdapterInfo->Io_Function->Mem.Write (
777                                    AdapterInfo->Io_Function,
778                                    Width,
779                                    0,
780                                    Port,
781                                    1,
782                                    (VOID *) (UINTN) (BuffAddr)
783                                    );
784    break;
785  }
786
787  return ;
788}
789
790
791/**
792  Using the NIC data structure information, read the EEPROM to get the MAC address and then allocate space
793  for a new devicepath (**DevPtr) which will contain the original device path the NIC was found on (*BaseDevPtr)
794  and an added MAC node.
795
796  @param  DevPtr               Pointer which will point to the newly created device
797                               path with the MAC node attached.
798  @param  BaseDevPtr           Pointer to the device path which the UNDI device
799                               driver is latching on to.
800  @param  AdapterInfo          Pointer to the NIC data structure information which
801                               the UNDI driver is layering on..
802
803  @retval EFI_SUCCESS          A MAC address was successfully appended to the Base
804                               Device Path.
805  @retval other                Not enough resources available to create new Device
806                               Path node.
807
808**/
809EFI_STATUS
810AppendMac2DevPath (
811  IN OUT  EFI_DEVICE_PATH_PROTOCOL **DevPtr,
812  IN      EFI_DEVICE_PATH_PROTOCOL *BaseDevPtr,
813  IN      NIC_DATA_INSTANCE        *AdapterInfo
814  )
815{
816  EFI_MAC_ADDRESS           MACAddress;
817  PCI_CONFIG_HEADER         *CfgHdr;
818  INT32                     Val;
819  INT32                     Index;
820  INT32                     Index2;
821  UINT8                     AddrLen;
822  MAC_ADDR_DEVICE_PATH      MacAddrNode;
823  EFI_DEVICE_PATH_PROTOCOL  *EndNode;
824  UINT8                     *DevicePtr;
825  UINT16                    TotalPathLen;
826  UINT16                    BasePathLen;
827  EFI_STATUS                Status;
828
829  //
830  // set the environment ready (similar to UNDI_Start call) so that we can
831  // execute the other UNDI_ calls to get the mac address
832  // we are using undi 3.1 style
833  //
834  AdapterInfo->Delay      = TmpDelay;
835  AdapterInfo->Virt2Phys  = (VOID *) 0;
836  AdapterInfo->Block      = (VOID *) 0;
837  AdapterInfo->Map_Mem    = (VOID *) 0;
838  AdapterInfo->UnMap_Mem  = (VOID *) 0;
839  AdapterInfo->Sync_Mem   = (VOID *) 0;
840  AdapterInfo->Mem_Io     = TmpMemIo;
841  //
842  // these tmp call-backs follow 3.1 undi style
843  // i.e. they have the unique_id parameter.
844  //
845  AdapterInfo->VersionFlag  = 0x31;
846  AdapterInfo->Unique_ID    = (UINT64) (UINTN) AdapterInfo;
847
848  //
849  // undi init portion
850  //
851  CfgHdr              = (PCI_CONFIG_HEADER *) &(AdapterInfo->Config[0]);
852  AdapterInfo->ioaddr = 0;
853  AdapterInfo->RevID  = CfgHdr->RevID;
854
855  AddrLen             = E100bGetEepromAddrLen (AdapterInfo);
856
857  for (Index = 0, Index2 = 0; Index < 3; Index++) {
858    Val                       = E100bReadEeprom (AdapterInfo, Index, AddrLen);
859    MACAddress.Addr[Index2++] = (UINT8) Val;
860    MACAddress.Addr[Index2++] = (UINT8) (Val >> 8);
861  }
862
863  SetMem (MACAddress.Addr + Index2, sizeof (EFI_MAC_ADDRESS) - Index2, 0);
864  //for (; Index2 < sizeof (EFI_MAC_ADDRESS); Index2++) {
865  //  MACAddress.Addr[Index2] = 0;
866  //}
867  //
868  // stop undi
869  //
870  AdapterInfo->Delay  = (VOID *) 0;
871  AdapterInfo->Mem_Io = (VOID *) 0;
872
873  //
874  // fill the mac address node first
875  //
876  ZeroMem ((CHAR8 *) &MacAddrNode, sizeof MacAddrNode);
877  CopyMem (
878    (CHAR8 *) &MacAddrNode.MacAddress,
879    (CHAR8 *) &MACAddress,
880    sizeof (EFI_MAC_ADDRESS)
881    );
882
883  MacAddrNode.Header.Type       = MESSAGING_DEVICE_PATH;
884  MacAddrNode.Header.SubType    = MSG_MAC_ADDR_DP;
885  MacAddrNode.Header.Length[0]  = (UINT8) sizeof (MacAddrNode);
886  MacAddrNode.Header.Length[1]  = 0;
887
888  //
889  // find the size of the base dev path.
890  //
891  EndNode = BaseDevPtr;
892
893  while (!IsDevicePathEnd (EndNode)) {
894    EndNode = NextDevicePathNode (EndNode);
895  }
896
897  BasePathLen = (UINT16) ((UINTN) (EndNode) - (UINTN) (BaseDevPtr));
898
899  //
900  // create space for full dev path
901  //
902  TotalPathLen = (UINT16) (BasePathLen + sizeof (MacAddrNode) + sizeof (EFI_DEVICE_PATH_PROTOCOL));
903
904  Status = gBS->AllocatePool (
905                  EfiRuntimeServicesData,
906                  TotalPathLen,
907                  (VOID **) &DevicePtr
908                  );
909
910  if (Status != EFI_SUCCESS) {
911    return Status;
912  }
913  //
914  // copy the base path, mac addr and end_dev_path nodes
915  //
916  *DevPtr = (EFI_DEVICE_PATH_PROTOCOL *) DevicePtr;
917  CopyMem (DevicePtr, (CHAR8 *) BaseDevPtr, BasePathLen);
918  DevicePtr += BasePathLen;
919  CopyMem (DevicePtr, (CHAR8 *) &MacAddrNode, sizeof (MacAddrNode));
920  DevicePtr += sizeof (MacAddrNode);
921  CopyMem (DevicePtr, (CHAR8 *) EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL));
922
923  return EFI_SUCCESS;
924}
925
926
927/**
928  Install a GUID/Pointer pair into the system's configuration table.
929
930  none
931
932  @retval EFI_SUCCESS          Install a GUID/Pointer pair into the system's
933                               configuration table.
934  @retval other                Did not successfully install the GUID/Pointer pair
935                               into the configuration table.
936
937**/
938// TODO:    VOID - add argument and description to function comment
939EFI_STATUS
940InstallConfigTable (
941  IN VOID
942  )
943{
944  EFI_STATUS              Status;
945  EFI_CONFIGURATION_TABLE *CfgPtr;
946  UNDI_CONFIG_TABLE       *TmpData;
947  UINT16                  Index;
948  UNDI_CONFIG_TABLE       *UndiData;
949
950  if (pxe_31 == NULL) {
951    return EFI_SUCCESS;
952  }
953
954  if(UndiDataPointer == NULL) {
955    return EFI_SUCCESS;
956  }
957
958  UndiData = (UNDI_CONFIG_TABLE *)UndiDataPointer;
959
960  UndiData->NumberOfInterfaces  = (pxe_31->IFcnt | pxe_31->IFcntExt << 8);
961  UndiData->nextlink            = NULL;
962
963  for (Index = 0; Index < (pxe_31->IFcnt | pxe_31->IFcntExt << 8); Index++) {
964    UndiData->NII_entry[Index].NII_InterfacePointer = &UNDI32DeviceList[Index]->NIIProtocol_31;
965    UndiData->NII_entry[Index].DevicePathPointer    = UNDI32DeviceList[Index]->Undi32DevPath;
966  }
967
968  //
969  // see if there is an entry in the config table already
970  //
971  CfgPtr = gST->ConfigurationTable;
972
973  for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
974    Status = CompareGuid (
975              &CfgPtr->VendorGuid,
976              &gEfiNetworkInterfaceIdentifierProtocolGuid_31
977              );
978    if (Status != EFI_SUCCESS) {
979      break;
980    }
981
982    CfgPtr++;
983  }
984
985  if (Index < gST->NumberOfTableEntries) {
986    TmpData = (UNDI_CONFIG_TABLE *) CfgPtr->VendorTable;
987
988    //
989    // go to the last link
990    //
991    while (TmpData->nextlink != NULL) {
992      TmpData = TmpData->nextlink;
993    }
994
995    TmpData->nextlink = UndiData;
996
997    //
998    // 1st one in chain
999    //
1000    UndiData = (UNDI_CONFIG_TABLE *) CfgPtr->VendorTable;
1001  }
1002
1003  //
1004  // create an entry in the configuration table for our GUID
1005  //
1006  Status = gBS->InstallConfigurationTable (
1007                  &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
1008                  UndiData
1009                  );
1010  return Status;
1011}
1012
1013/**
1014
1015**/
1016EFI_STATUS
1017EFIAPI
1018InitializeUndi(
1019  IN EFI_HANDLE           ImageHandle,
1020  IN EFI_SYSTEM_TABLE     *SystemTable
1021  )
1022{
1023  EFI_EVENT     Event;
1024  EFI_STATUS    Status;
1025
1026  Status = EfiLibInstallDriverBindingComponentName2 (
1027             ImageHandle,
1028             SystemTable,
1029             &gUndiDriverBinding,
1030             ImageHandle,
1031             &gUndiComponentName,
1032             &gUndiComponentName2
1033             );
1034  ASSERT_EFI_ERROR (Status);
1035
1036  Status = gBS->CreateEventEx (
1037                  EVT_NOTIFY_SIGNAL,
1038                  TPL_NOTIFY,
1039                  UndiNotifyReadyToBoot,
1040                  NULL,
1041                  &gEfiEventReadyToBootGuid,
1042                  &Event
1043                  );
1044  ASSERT_EFI_ERROR (Status);
1045
1046  Status = gBS->CreateEventEx (
1047                  EVT_NOTIFY_SIGNAL,
1048                  TPL_NOTIFY,
1049                  UndiNotifyVirtual,
1050                  NULL,
1051                  &gEfiEventVirtualAddressChangeGuid,
1052                  &Event
1053                  );
1054  ASSERT_EFI_ERROR (Status);
1055
1056  return Status;
1057}
1058