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