Move SmmLib from IntelFrameworkPkg to MdePkg because this library is useful to both...
[mirror_edk2.git] / OptionRomPkg / UndiRuntimeDxe / Init.c
1 /** @file
2 Initialization functions for EFI UNDI32 driver.
3
4 Copyright (c) 2006 - 2008, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "Undi32.h"
16 //
17 // Global Variables
18 //
19
20 PXE_SW_UNDI *pxe_31 = NULL; // 3.1 entry
21 UNDI32_DEV *UNDI32DeviceList[MAX_NIC_INTERFACES];
22 NII_TABLE *UndiDataPointer = NULL;
23
24 //
25 // UNDI Class Driver Global Variables
26 //
27 EFI_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 **/
46 VOID
47 EFIAPI
48 UndiNotifyVirtual (
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; 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 **/
100 VOID
101 EFIAPI
102 UndiNotifyExitBs (
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 **/
126 EFI_STATUS
127 EFIAPI
128 UndiDriverSupported (
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 **/
231 EFI_STATUS
232 EFIAPI
233 UndiDriverStart (
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;
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 = FALSE;
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 //
448 // install both the 3.0 and 3.1 NII protocols.
449 //
450 Status = gBS->InstallMultipleProtocolInterfaces (
451 &UNDI32Device->DeviceHandle,
452 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
453 &UNDI32Device->NIIProtocol_31,
454 &gEfiDevicePathProtocolGuid,
455 UNDI32Device->Undi32DevPath,
456 NULL
457 );
458
459 if (EFI_ERROR (Status)) {
460 goto UndiErrorDeleteDevicePath;
461 }
462
463 //
464 // if the table exists, free it and alloc again, or alloc it directly
465 //
466 if (UndiDataPointer != NULL) {
467 Status = gBS->FreePool(UndiDataPointer);
468 }
469 if (EFI_ERROR (Status)) {
470 goto UndiErrorDeleteDevicePath;
471 }
472
473 Len = (pxe_31->IFcnt * sizeof (NII_ENTRY)) + sizeof (UndiDataPointer);
474 Status = gBS->AllocatePool (EfiRuntimeServicesData, Len, (VOID **) &UndiDataPointer);
475
476 if (EFI_ERROR (Status)) {
477 goto UndiErrorAllocDataPointer;
478 }
479
480 //
481 // Open For Child Device
482 //
483 Status = gBS->OpenProtocol (
484 Controller,
485 &gEfiPciIoProtocolGuid,
486 (VOID **) &PciIoFncs,
487 This->DriverBindingHandle,
488 UNDI32Device->DeviceHandle,
489 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
490 );
491
492 return EFI_SUCCESS;
493 UndiErrorAllocDataPointer:
494 gBS->UninstallMultipleProtocolInterfaces (
495 &UNDI32Device->DeviceHandle,
496 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
497 &UNDI32Device->NIIProtocol_31,
498 &gEfiDevicePathProtocolGuid,
499 UNDI32Device->Undi32DevPath,
500 NULL
501 );
502
503 UndiErrorDeleteDevicePath:
504 UNDI32DeviceList[UNDI32Device->NIIProtocol_31.IfNum] = NULL;
505 gBS->FreePool (UNDI32Device->Undi32DevPath);
506
507 UndiErrorDeletePxe:
508 PxeUpdate (NULL, pxe_31);
509 if (TmpPxePointer != NULL) {
510 gBS->FreePool (TmpPxePointer);
511
512 }
513
514 UndiErrorDeleteDevice:
515 if (PciAttributesSaved) {
516 //
517 // Restore original PCI attributes
518 //
519 PciIoFncs->Attributes (
520 PciIoFncs,
521 EfiPciIoAttributeOperationSet,
522 UNDI32Device->NicInfo.OriginalPciAttributes,
523 NULL
524 );
525 }
526
527 gBS->FreePool (UNDI32Device);
528
529 UndiError:
530 gBS->CloseProtocol (
531 Controller,
532 &gEfiDevicePathProtocolGuid,
533 This->DriverBindingHandle,
534 Controller
535 );
536
537 gBS->CloseProtocol (
538 Controller,
539 &gEfiPciIoProtocolGuid,
540 This->DriverBindingHandle,
541 Controller
542 );
543
544 return Status;
545 }
546
547
548 /**
549 Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and
550 closing the DevicePath and PciIo protocols on Controller.
551
552 @param This Protocol instance pointer.
553 @param Controller Handle of device to stop driver on.
554 @param NumberOfChildren How many children need to be stopped.
555 @param ChildHandleBuffer Not used.
556
557 @retval EFI_SUCCESS This driver is removed Controller.
558 @retval other This driver was not removed from this device.
559
560 **/
561 // TODO: EFI_DEVICE_ERROR - add return value to function comment
562 EFI_STATUS
563 EFIAPI
564 UndiDriverStop (
565 IN EFI_DRIVER_BINDING_PROTOCOL *This,
566 IN EFI_HANDLE Controller,
567 IN UINTN NumberOfChildren,
568 IN EFI_HANDLE *ChildHandleBuffer
569 )
570 {
571 EFI_STATUS Status;
572 BOOLEAN AllChildrenStopped;
573 UINTN Index;
574 UNDI32_DEV *UNDI32Device;
575 EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NIIProtocol;
576 EFI_PCI_IO_PROTOCOL *PciIo;
577
578 //
579 // Complete all outstanding transactions to Controller.
580 // Don't allow any new transaction to Controller to be started.
581 //
582 if (NumberOfChildren == 0) {
583
584 //
585 // Close the bus driver
586 //
587 Status = gBS->CloseProtocol (
588 Controller,
589 &gEfiDevicePathProtocolGuid,
590 This->DriverBindingHandle,
591 Controller
592 );
593
594 Status = gBS->CloseProtocol (
595 Controller,
596 &gEfiPciIoProtocolGuid,
597 This->DriverBindingHandle,
598 Controller
599 );
600
601 return Status;
602 }
603
604 AllChildrenStopped = TRUE;
605
606 for (Index = 0; Index < NumberOfChildren; Index++) {
607
608 Status = gBS->OpenProtocol (
609 ChildHandleBuffer[Index],
610 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
611 (VOID **) &NIIProtocol,
612 This->DriverBindingHandle,
613 Controller,
614 EFI_OPEN_PROTOCOL_GET_PROTOCOL
615 );
616 if (!EFI_ERROR (Status)) {
617
618 UNDI32Device = UNDI_DEV_FROM_THIS (NIIProtocol);
619
620 //
621 // Restore original PCI attributes
622 //
623 Status = UNDI32Device->NicInfo.Io_Function->Attributes (
624 UNDI32Device->NicInfo.Io_Function,
625 EfiPciIoAttributeOperationSet,
626 UNDI32Device->NicInfo.OriginalPciAttributes,
627 NULL
628 );
629 ASSERT_EFI_ERROR (Status);
630
631 Status = gBS->CloseProtocol (
632 Controller,
633 &gEfiPciIoProtocolGuid,
634 This->DriverBindingHandle,
635 ChildHandleBuffer[Index]
636 );
637
638 Status = gBS->UninstallMultipleProtocolInterfaces (
639 ChildHandleBuffer[Index],
640 &gEfiDevicePathProtocolGuid,
641 UNDI32Device->Undi32DevPath,
642 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
643 &UNDI32Device->NIIProtocol_31,
644 NULL
645 );
646
647 if (EFI_ERROR (Status)) {
648 gBS->OpenProtocol (
649 Controller,
650 &gEfiPciIoProtocolGuid,
651 (VOID **) &PciIo,
652 This->DriverBindingHandle,
653 ChildHandleBuffer[Index],
654 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
655 );
656 } else {
657 gBS->FreePool (UNDI32Device->Undi32DevPath);
658 gBS->FreePool (UNDI32Device);
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 **/
688 VOID
689 TmpDelay (
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 **/
713 VOID
714 TmpMemIo (
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 **/
809 EFI_STATUS
810 AppendMac2DevPath (
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] = 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
939 EFI_STATUS
940 InstallConfigTable (
941 IN VOID
942 )
943 {
944 EFI_STATUS Status;
945 EFI_CONFIGURATION_TABLE *CfgPtr;
946 NII_TABLE *TmpData;
947 UINT16 Index;
948 NII_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 = (NII_TABLE *)UndiDataPointer;
959
960 UndiData->NumEntries = pxe_31->IFcnt;
961 UndiData->NextLink = NULL;
962
963 for (Index = 0; Index < pxe_31->IFcnt; Index++) {
964 UndiData->NiiEntry[Index].InterfacePointer = &UNDI32DeviceList[Index]->NIIProtocol_31;
965 UndiData->NiiEntry[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 = (NII_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 = (NII_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 **/
1016 EFI_STATUS
1017 EFIAPI
1018 InitializeUndi(
1019 IN EFI_HANDLE ImageHandle,
1020 IN EFI_SYSTEM_TABLE *SystemTable
1021 )
1022 {
1023 EFI_EVENT Event;
1024 EFI_STATUS Status;
1025
1026 Status = EfiLibInstallDriverBinding (
1027 ImageHandle,
1028 SystemTable,
1029 &gUndiDriverBinding,
1030 ImageHandle
1031 );
1032 ASSERT_EFI_ERROR (Status);
1033
1034 Status = gBS->CreateEventEx (
1035 EVT_NOTIFY_SIGNAL,
1036 TPL_NOTIFY,
1037 UndiNotifyExitBs,
1038 NULL,
1039 &gEfiEventExitBootServicesGuid,
1040 &Event
1041 );
1042 ASSERT_EFI_ERROR (Status);
1043
1044 Status = gBS->CreateEventEx (
1045 EVT_NOTIFY_SIGNAL,
1046 TPL_NOTIFY,
1047 UndiNotifyVirtual,
1048 NULL,
1049 &gEfiEventVirtualAddressChangeGuid,
1050 &Event
1051 );
1052 ASSERT_EFI_ERROR (Status);
1053
1054 return Status;
1055 }