BaseTools:Change the path of the file that Binary Cache
[mirror_edk2.git] / MdeModulePkg / Universal / Network / SnpDxe / Snp.c
1 /** @file\r
2   Implementation of driver entry point and driver binding protocol.\r
3 \r
4 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6 \r
7 **/\r
8 \r
9 #include "Snp.h"\r
10 \r
11 /**\r
12   One notified function to stop UNDI device when gBS->ExitBootServices() called.\r
13 \r
14   @param  Event                   Pointer to this event\r
15   @param  Context                 Event handler private data\r
16 \r
17 **/\r
18 VOID\r
19 EFIAPI\r
20 SnpNotifyExitBootServices (\r
21   EFI_EVENT Event,\r
22   VOID      *Context\r
23   )\r
24 {\r
25   SNP_DRIVER             *Snp;\r
26 \r
27   Snp  = (SNP_DRIVER *)Context;\r
28 \r
29   //\r
30   // Shutdown and stop UNDI driver\r
31   //\r
32   PxeShutdown (Snp);\r
33   PxeStop (Snp);\r
34 }\r
35 \r
36 /**\r
37   Send command to UNDI. It does nothing currently.\r
38 \r
39   @param Cdb   command to be sent to UNDI.\r
40 \r
41   @retval EFI_INVALID_PARAMETER  The command is 0.\r
42   @retval EFI_UNSUPPORTED        Default return status because it's not\r
43                                  supported currently.\r
44 \r
45 **/\r
46 EFI_STATUS\r
47 EFIAPI\r
48 IssueHwUndiCommand (\r
49   UINT64 Cdb\r
50   )\r
51 {\r
52   DEBUG ((EFI_D_ERROR, "\nIssueHwUndiCommand() - This should not be called!"));\r
53 \r
54   if (Cdb == 0) {\r
55     return EFI_INVALID_PARAMETER;\r
56 \r
57   }\r
58   //\r
59   //  %%TBD - For now, nothing is done.\r
60   //\r
61   return EFI_UNSUPPORTED;\r
62 }\r
63 \r
64 \r
65 /**\r
66   Compute 8-bit checksum of a buffer.\r
67 \r
68   @param  Buffer               Pointer to buffer.\r
69   @param  Length               Length of buffer in bytes.\r
70 \r
71   @return 8-bit checksum of all bytes in buffer, or zero if ptr is NULL or len\r
72           is zero.\r
73 \r
74 **/\r
75 UINT8\r
76 Calc8BitCksum (\r
77   VOID  *Buffer,\r
78   UINTN Length\r
79   )\r
80 {\r
81   UINT8 *Ptr;\r
82   UINT8 Cksum;\r
83 \r
84   Ptr   = Buffer;\r
85   Cksum = 0;\r
86 \r
87   if (Ptr == NULL || Length == 0) {\r
88     return 0;\r
89   }\r
90 \r
91   while (Length-- != 0) {\r
92     Cksum = (UINT8) (Cksum + *Ptr++);\r
93   }\r
94 \r
95   return Cksum;\r
96 }\r
97 \r
98 /**\r
99   Test to see if this driver supports ControllerHandle. This service\r
100   is called by the EFI boot service ConnectController(). In\r
101   order to make drivers as small as possible, there are a few calling\r
102   restrictions for this service. ConnectController() must\r
103   follow these calling restrictions. If any other agent wishes to call\r
104   Supported() it must also follow these calling restrictions.\r
105 \r
106   @param  This                Protocol instance pointer.\r
107   @param  ControllerHandle    Handle of device to test.\r
108   @param  RemainingDevicePath Optional parameter use to pick a specific child\r
109                               device to start.\r
110 \r
111   @retval EFI_SUCCESS         This driver supports this device.\r
112   @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
113   @retval other               This driver does not support this device.\r
114 \r
115 **/\r
116 EFI_STATUS\r
117 EFIAPI\r
118 SimpleNetworkDriverSupported (\r
119   IN EFI_DRIVER_BINDING_PROTOCOL    *This,\r
120   IN EFI_HANDLE                     Controller,\r
121   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath\r
122   )\r
123 {\r
124   EFI_STATUS                                Status;\r
125   EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;\r
126   PXE_UNDI                                  *Pxe;\r
127 \r
128   Status = gBS->OpenProtocol (\r
129                   Controller,\r
130                   &gEfiDevicePathProtocolGuid,\r
131                   NULL,\r
132                   This->DriverBindingHandle,\r
133                   Controller,\r
134                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
135                   );\r
136   if (EFI_ERROR (Status)) {\r
137     return Status;\r
138   }\r
139 \r
140   Status = gBS->OpenProtocol (\r
141                   Controller,\r
142                   &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
143                   (VOID **) &NiiProtocol,\r
144                   This->DriverBindingHandle,\r
145                   Controller,\r
146                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
147                   );\r
148 \r
149   if (EFI_ERROR (Status)) {\r
150     if (Status == EFI_ALREADY_STARTED) {\r
151       DEBUG ((EFI_D_INFO, "Support(): Already Started. on handle %p\n", Controller));\r
152     }\r
153     return Status;\r
154   }\r
155 \r
156   DEBUG ((EFI_D_INFO, "Support(): UNDI3.1 found on handle %p\n", Controller));\r
157 \r
158   //\r
159   // check the version, we don't want to connect to the undi16\r
160   //\r
161   if (NiiProtocol->Type != EfiNetworkInterfaceUndi) {\r
162     Status = EFI_UNSUPPORTED;\r
163     goto Done;\r
164   }\r
165   //\r
166   // Check to see if !PXE structure is valid. Paragraph alignment of !PXE structure is required.\r
167   //\r
168   if ((NiiProtocol->Id & 0x0F) != 0) {\r
169     DEBUG ((EFI_D_NET, "\n!PXE structure is not paragraph aligned.\n"));\r
170     Status = EFI_UNSUPPORTED;\r
171     goto Done;\r
172   }\r
173 \r
174   Pxe = (PXE_UNDI *) (UINTN) (NiiProtocol->Id);\r
175 \r
176   //\r
177   //  Verify !PXE revisions.\r
178   //\r
179   if (Pxe->hw.Signature != PXE_ROMID_SIGNATURE) {\r
180     DEBUG ((EFI_D_NET, "\n!PXE signature is not valid.\n"));\r
181     Status = EFI_UNSUPPORTED;\r
182     goto Done;\r
183   }\r
184 \r
185   if (Pxe->hw.Rev < PXE_ROMID_REV) {\r
186     DEBUG ((EFI_D_NET, "\n!PXE.Rev is not supported.\n"));\r
187     Status = EFI_UNSUPPORTED;\r
188     goto Done;\r
189   }\r
190 \r
191   if (Pxe->hw.MajorVer < PXE_ROMID_MAJORVER) {\r
192 \r
193     DEBUG ((EFI_D_NET, "\n!PXE.MajorVer is not supported.\n"));\r
194     Status = EFI_UNSUPPORTED;\r
195     goto Done;\r
196 \r
197   } else if (Pxe->hw.MajorVer == PXE_ROMID_MAJORVER && Pxe->hw.MinorVer < PXE_ROMID_MINORVER) {\r
198     DEBUG ((EFI_D_NET, "\n!PXE.MinorVer is not supported."));\r
199     Status = EFI_UNSUPPORTED;\r
200     goto Done;\r
201   }\r
202   //\r
203   // Do S/W UNDI specific checks.\r
204   //\r
205   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) == 0) {\r
206     if (Pxe->sw.EntryPoint < Pxe->sw.Len) {\r
207       DEBUG ((EFI_D_NET, "\n!PXE S/W entry point is not valid."));\r
208       Status = EFI_UNSUPPORTED;\r
209       goto Done;\r
210     }\r
211 \r
212     if (Pxe->sw.BusCnt == 0) {\r
213       DEBUG ((EFI_D_NET, "\n!PXE.BusCnt is zero."));\r
214       Status = EFI_UNSUPPORTED;\r
215       goto Done;\r
216     }\r
217   }\r
218 \r
219   Status = EFI_SUCCESS;\r
220   DEBUG ((EFI_D_INFO, "Support(): supported on %p\n", Controller));\r
221 \r
222 Done:\r
223   gBS->CloseProtocol (\r
224         Controller,\r
225         &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
226         This->DriverBindingHandle,\r
227         Controller\r
228         );\r
229 \r
230   return Status;\r
231 }\r
232 \r
233 /**\r
234   Start this driver on ControllerHandle. This service is called by the\r
235   EFI boot service ConnectController(). In order to make\r
236   drivers as small as possible, there are a few calling restrictions for\r
237   this service. ConnectController() must follow these\r
238   calling restrictions. If any other agent wishes to call Start() it\r
239   must also follow these calling restrictions.\r
240 \r
241   @param  This                 Protocol instance pointer.\r
242   @param  ControllerHandle     Handle of device to bind driver to.\r
243   @param  RemainingDevicePath  Optional parameter use to pick a specific child\r
244                                device to start.\r
245 \r
246   @retval EFI_SUCCESS          This driver is added to ControllerHandle\r
247   @retval EFI_DEVICE_ERROR     This driver could not be started due to a device error\r
248   @retval other                This driver does not support this device\r
249 \r
250 **/\r
251 EFI_STATUS\r
252 EFIAPI\r
253 SimpleNetworkDriverStart (\r
254   IN EFI_DRIVER_BINDING_PROTOCOL    *This,\r
255   IN EFI_HANDLE                     Controller,\r
256   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath\r
257   )\r
258 {\r
259   EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;\r
260   EFI_DEVICE_PATH_PROTOCOL                  *NiiDevicePath;\r
261   EFI_STATUS                                Status;\r
262   PXE_UNDI                                  *Pxe;\r
263   SNP_DRIVER                                *Snp;\r
264   VOID                                      *Address;\r
265   EFI_HANDLE                                Handle;\r
266   UINT8                                     BarIndex;\r
267   PXE_STATFLAGS                             InitStatFlags;\r
268   EFI_PCI_IO_PROTOCOL                       *PciIo;\r
269   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR         *BarDesc;\r
270   BOOLEAN                                   FoundIoBar;\r
271   BOOLEAN                                   FoundMemoryBar;\r
272 \r
273   DEBUG ((EFI_D_NET, "\nSnpNotifyNetworkInterfaceIdentifier()  "));\r
274 \r
275   Status = gBS->OpenProtocol (\r
276                   Controller,\r
277                   &gEfiDevicePathProtocolGuid,\r
278                   (VOID **) &NiiDevicePath,\r
279                   This->DriverBindingHandle,\r
280                   Controller,\r
281                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
282                   );\r
283 \r
284   if (EFI_ERROR (Status)) {\r
285     return Status;\r
286   }\r
287 \r
288   Status = gBS->LocateDevicePath (\r
289                   &gEfiPciIoProtocolGuid,\r
290                   &NiiDevicePath,\r
291                   &Handle\r
292                   );\r
293 \r
294   if (EFI_ERROR (Status)) {\r
295     return Status;\r
296   }\r
297 \r
298   Status = gBS->OpenProtocol (\r
299                   Handle,\r
300                   &gEfiPciIoProtocolGuid,\r
301                   (VOID **) &PciIo,\r
302                   This->DriverBindingHandle,\r
303                   Controller,\r
304                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
305                   );\r
306   if (EFI_ERROR (Status)) {\r
307     return Status;\r
308   }\r
309   //\r
310   // Get the NII interface.\r
311   //\r
312   Status = gBS->OpenProtocol (\r
313                   Controller,\r
314                   &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
315                   (VOID **) &Nii,\r
316                   This->DriverBindingHandle,\r
317                   Controller,\r
318                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
319                   );\r
320   if (EFI_ERROR (Status)) {\r
321     gBS->CloseProtocol (\r
322           Controller,\r
323           &gEfiDevicePathProtocolGuid,\r
324           This->DriverBindingHandle,\r
325           Controller\r
326           );\r
327     return Status;\r
328   }\r
329 \r
330   DEBUG ((EFI_D_INFO, "Start(): UNDI3.1 found\n"));\r
331 \r
332   Pxe = (PXE_UNDI *) (UINTN) (Nii->Id);\r
333 \r
334   if (Calc8BitCksum (Pxe, Pxe->hw.Len) != 0) {\r
335     DEBUG ((EFI_D_NET, "\n!PXE checksum is not correct.\n"));\r
336     goto NiiError;\r
337   }\r
338 \r
339   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {\r
340     //\r
341     //  We can get any packets.\r
342     //\r
343   } else if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {\r
344     //\r
345     //  We need to be able to get broadcast packets for DHCP.\r
346     //  If we do not have promiscuous support, we must at least have\r
347     //  broadcast support or we cannot do DHCP!\r
348     //\r
349   } else {\r
350     DEBUG ((EFI_D_NET, "\nUNDI does not have promiscuous or broadcast support."));\r
351     goto NiiError;\r
352   }\r
353   //\r
354   // OK, we like this UNDI, and we know snp is not already there on this handle\r
355   // Allocate and initialize a new simple network protocol structure.\r
356   //\r
357   Status = PciIo->AllocateBuffer (\r
358                     PciIo,\r
359                     AllocateAnyPages,\r
360                     EfiBootServicesData,\r
361                     SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
362                     &Address,\r
363                     0\r
364                     );\r
365 \r
366   if (Status != EFI_SUCCESS) {\r
367     DEBUG ((EFI_D_NET, "\nCould not allocate SNP_DRIVER structure.\n"));\r
368     goto NiiError;\r
369   }\r
370 \r
371   Snp = (SNP_DRIVER *) (UINTN) Address;\r
372 \r
373   ZeroMem (Snp, sizeof (SNP_DRIVER));\r
374 \r
375   Snp->PciIo      = PciIo;\r
376   Snp->Signature  = SNP_DRIVER_SIGNATURE;\r
377 \r
378   EfiInitializeLock (&Snp->Lock, TPL_NOTIFY);\r
379 \r
380   Snp->Snp.Revision       = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;\r
381   Snp->Snp.Start          = SnpUndi32Start;\r
382   Snp->Snp.Stop           = SnpUndi32Stop;\r
383   Snp->Snp.Initialize     = SnpUndi32Initialize;\r
384   Snp->Snp.Reset          = SnpUndi32Reset;\r
385   Snp->Snp.Shutdown       = SnpUndi32Shutdown;\r
386   Snp->Snp.ReceiveFilters = SnpUndi32ReceiveFilters;\r
387   Snp->Snp.StationAddress = SnpUndi32StationAddress;\r
388   Snp->Snp.Statistics     = SnpUndi32Statistics;\r
389   Snp->Snp.MCastIpToMac   = SnpUndi32McastIpToMac;\r
390   Snp->Snp.NvData         = SnpUndi32NvData;\r
391   Snp->Snp.GetStatus      = SnpUndi32GetStatus;\r
392   Snp->Snp.Transmit       = SnpUndi32Transmit;\r
393   Snp->Snp.Receive        = SnpUndi32Receive;\r
394   Snp->Snp.WaitForPacket  = NULL;\r
395 \r
396   Snp->Snp.Mode           = &Snp->Mode;\r
397 \r
398   Snp->TxRxBufferSize     = 0;\r
399   Snp->TxRxBuffer         = NULL;\r
400 \r
401   Snp->RecycledTxBuf = AllocatePool (sizeof (UINT64) * SNP_TX_BUFFER_INCREASEMENT);\r
402   if (Snp->RecycledTxBuf == NULL) {\r
403     Status = EFI_OUT_OF_RESOURCES;\r
404     goto Error_DeleteSNP;\r
405   }\r
406   Snp->MaxRecycledTxBuf    = SNP_TX_BUFFER_INCREASEMENT;\r
407   Snp->RecycledTxBufCount  = 0;\r
408 \r
409   if (Nii->Revision >= EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION) {\r
410     Snp->IfNum = Nii->IfNum;\r
411 \r
412   } else {\r
413     Snp->IfNum = (UINT8) (Nii->IfNum & 0xFF);\r
414   }\r
415 \r
416   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) != 0) {\r
417     Snp->IsSwUndi             = FALSE;\r
418     Snp->IssueUndi32Command   = &IssueHwUndiCommand;\r
419   } else {\r
420     Snp->IsSwUndi = TRUE;\r
421 \r
422     if ((Pxe->sw.Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR) != 0) {\r
423       Snp->IssueUndi32Command = (ISSUE_UNDI32_COMMAND) (UINTN) Pxe->sw.EntryPoint;\r
424     } else {\r
425       Snp->IssueUndi32Command = (ISSUE_UNDI32_COMMAND) (UINTN) ((UINT8) (UINTN) Pxe + Pxe->sw.EntryPoint);\r
426     }\r
427   }\r
428   //\r
429   // Allocate a global CPB and DB buffer for this UNDI interface.\r
430   // we do this because:\r
431   //\r
432   // -UNDI 3.0 wants all the addresses passed to it (even the cpb and db) to be\r
433   // within 2GB limit, create them here and map them so that when undi calls\r
434   // v2p callback to check if the physical address is < 2gb, we will pass.\r
435   //\r
436   // -This is not a requirement for 3.1 or later UNDIs but the code looks\r
437   // simpler if we use the same cpb, db variables for both old and new undi\r
438   // interfaces from all the SNP interface calls (we don't map the buffers\r
439   // for the newer undi interfaces though)\r
440   // .\r
441   // -it is OK to allocate one global set of CPB, DB pair for each UNDI\r
442   // interface as EFI does not multi-task and so SNP will not be re-entered!\r
443   //\r
444   Status = PciIo->AllocateBuffer (\r
445                     PciIo,\r
446                     AllocateAnyPages,\r
447                     EfiBootServicesData,\r
448                     SNP_MEM_PAGES (4096),\r
449                     &Address,\r
450                     0\r
451                     );\r
452 \r
453   if (Status != EFI_SUCCESS) {\r
454     DEBUG ((EFI_D_NET, "\nCould not allocate CPB and DB structures.\n"));\r
455     goto Error_DeleteSNP;\r
456   }\r
457 \r
458   Snp->Cpb  = (VOID *) (UINTN) Address;\r
459   Snp->Db   = (VOID *) ((UINTN) Address + 2048);\r
460 \r
461   //\r
462   // Find the correct BAR to do IO.\r
463   //\r
464   // Enumerate through the PCI BARs for the device to determine which one is\r
465   // the IO BAR.  Save the index of the BAR into the adapter info structure.\r
466   // for regular 32bit BARs, 0 is memory mapped, 1 is io mapped\r
467   //\r
468   Snp->MemoryBarIndex = 0;\r
469   Snp->IoBarIndex     = 1;\r
470   FoundMemoryBar      = FALSE;\r
471   FoundIoBar          = FALSE;\r
472   for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) {\r
473     Status = PciIo->GetBarAttributes (\r
474                       PciIo,\r
475                       BarIndex,\r
476                       NULL,\r
477                       (VOID**) &BarDesc\r
478                       );\r
479     if (Status == EFI_UNSUPPORTED) {\r
480       continue;\r
481     } else if (EFI_ERROR (Status)) {\r
482       goto Error_DeleteSNP;\r
483     }\r
484 \r
485     if ((!FoundMemoryBar) && (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM)) {\r
486       Snp->MemoryBarIndex = BarIndex;\r
487       FoundMemoryBar      = TRUE;\r
488     } else if ((!FoundIoBar) && (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_IO)) {\r
489       Snp->IoBarIndex = BarIndex;\r
490       FoundIoBar      = TRUE;\r
491     }\r
492 \r
493     FreePool (BarDesc);\r
494 \r
495     if (FoundMemoryBar && FoundIoBar) {\r
496       break;\r
497     }\r
498   }\r
499 \r
500   Status = PxeStart (Snp);\r
501 \r
502   if (Status != EFI_SUCCESS) {\r
503     goto Error_DeleteSNP;\r
504   }\r
505 \r
506   Snp->Cdb.OpCode     = PXE_OPCODE_GET_INIT_INFO;\r
507   Snp->Cdb.OpFlags    = PXE_OPFLAGS_NOT_USED;\r
508 \r
509   Snp->Cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;\r
510   Snp->Cdb.CPBaddr    = PXE_DBADDR_NOT_USED;\r
511 \r
512   Snp->Cdb.DBsize     = (UINT16) sizeof (Snp->InitInfo);\r
513   Snp->Cdb.DBaddr     = (UINT64)(UINTN) (&Snp->InitInfo);\r
514 \r
515   Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
516   Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
517 \r
518   Snp->Cdb.IFnum      = Snp->IfNum;\r
519   Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
520 \r
521   DEBUG ((EFI_D_NET, "\nSnp->undi.get_init_info()  "));\r
522 \r
523   (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);\r
524 \r
525   //\r
526   // Save the INIT Stat Code...\r
527   //\r
528   InitStatFlags = Snp->Cdb.StatFlags;\r
529 \r
530   if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
531     DEBUG ((EFI_D_NET, "\nSnp->undi.init_info()  %xh:%xh\n", Snp->Cdb.StatFlags, Snp->Cdb.StatCode));\r
532     PxeStop (Snp);\r
533     goto Error_DeleteSNP;\r
534   }\r
535 \r
536   //\r
537   //  Initialize simple network protocol mode structure\r
538   //\r
539   Snp->Mode.State               = EfiSimpleNetworkStopped;\r
540   Snp->Mode.HwAddressSize       = Snp->InitInfo.HWaddrLen;\r
541   Snp->Mode.MediaHeaderSize     = Snp->InitInfo.MediaHeaderLen;\r
542   Snp->Mode.MaxPacketSize       = Snp->InitInfo.FrameDataLen;\r
543   Snp->Mode.NvRamAccessSize     = Snp->InitInfo.NvWidth;\r
544   Snp->Mode.NvRamSize           = Snp->InitInfo.NvCount * Snp->Mode.NvRamAccessSize;\r
545   Snp->Mode.IfType              = Snp->InitInfo.IFtype;\r
546   Snp->Mode.MaxMCastFilterCount = Snp->InitInfo.MCastFilterCnt;\r
547   Snp->Mode.MCastFilterCount    = 0;\r
548 \r
549   switch (InitStatFlags & PXE_STATFLAGS_CABLE_DETECT_MASK) {\r
550   case PXE_STATFLAGS_CABLE_DETECT_SUPPORTED:\r
551     Snp->CableDetectSupported = TRUE;\r
552     break;\r
553 \r
554   case PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED:\r
555   default:\r
556     Snp->CableDetectSupported = FALSE;\r
557   }\r
558 \r
559   switch (InitStatFlags & PXE_STATFLAGS_GET_STATUS_NO_MEDIA_MASK) {\r
560   case PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED:\r
561     Snp->MediaStatusSupported = TRUE;\r
562     break;\r
563 \r
564   case PXE_STATFLAGS_GET_STATUS_NO_MEDIA_NOT_SUPPORTED:\r
565   default:\r
566     Snp->MediaStatusSupported = FALSE;\r
567   }\r
568 \r
569   if (Snp->CableDetectSupported || Snp->MediaStatusSupported) {\r
570     Snp->Mode.MediaPresentSupported = TRUE;\r
571   }\r
572 \r
573   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE) != 0) {\r
574     Snp->Mode.MacAddressChangeable = TRUE;\r
575   } else {\r
576     Snp->Mode.MacAddressChangeable = FALSE;\r
577   }\r
578 \r
579   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED) != 0) {\r
580     Snp->Mode.MultipleTxSupported = TRUE;\r
581   } else {\r
582     Snp->Mode.MultipleTxSupported = FALSE;\r
583   }\r
584 \r
585   Snp->Mode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;\r
586 \r
587   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {\r
588     Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
589 \r
590   }\r
591 \r
592   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {\r
593     Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
594 \r
595   }\r
596 \r
597   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {\r
598     Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;\r
599 \r
600   }\r
601 \r
602   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED) != 0) {\r
603     Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;\r
604 \r
605   }\r
606 \r
607   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {\r
608     Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
609 \r
610   }\r
611 \r
612   Snp->Mode.ReceiveFilterSetting = 0;\r
613 \r
614   //\r
615   //  need to get the station address to save in the mode structure. we need to\r
616   // initialize the UNDI first for this.\r
617   //\r
618   Snp->TxRxBufferSize = Snp->InitInfo.MemoryRequired;\r
619   Status              = PxeInit (Snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);\r
620 \r
621   if (EFI_ERROR (Status)) {\r
622     PxeStop (Snp);\r
623     goto Error_DeleteSNP;\r
624   }\r
625 \r
626   Status = PxeGetStnAddr (Snp);\r
627 \r
628   if (Status != EFI_SUCCESS) {\r
629     DEBUG ((EFI_D_ERROR, "\nSnp->undi.get_station_addr() failed.\n"));\r
630     PxeShutdown (Snp);\r
631     PxeStop (Snp);\r
632     goto Error_DeleteSNP;\r
633   }\r
634 \r
635   Snp->Mode.MediaPresent = FALSE;\r
636 \r
637   //\r
638   // We should not leave UNDI started and initialized here. this DriverStart()\r
639   // routine must only find and attach the SNP interface to UNDI layer that it\r
640   // finds on the given handle!\r
641   // The UNDI layer will be started when upper layers call Snp->start.\r
642   // How ever, this DriverStart() must fill up the snp mode structure which\r
643   // contains the MAC address of the NIC. For this reason we started and\r
644   // initialized UNDI here, now we are done, do a shutdown and stop of the\r
645   // UNDI interface!\r
646   //\r
647   PxeShutdown (Snp);\r
648   PxeStop (Snp);\r
649 \r
650   //\r
651   // Create EXIT_BOOT_SERIVES Event\r
652   //\r
653   Status = gBS->CreateEventEx (\r
654                   EVT_NOTIFY_SIGNAL,\r
655                   TPL_NOTIFY,\r
656                   SnpNotifyExitBootServices,\r
657                   Snp,\r
658                   &gEfiEventExitBootServicesGuid,\r
659                   &Snp->ExitBootServicesEvent\r
660                   );\r
661   if (EFI_ERROR (Status)) {\r
662     goto Error_DeleteSNP;\r
663   }\r
664 \r
665   //\r
666   //  add SNP to the undi handle\r
667   //\r
668   Status = gBS->InstallProtocolInterface (\r
669                   &Controller,\r
670                   &gEfiSimpleNetworkProtocolGuid,\r
671                   EFI_NATIVE_INTERFACE,\r
672                   &(Snp->Snp)\r
673                   );\r
674 \r
675   if (!EFI_ERROR (Status)) {\r
676     return Status;\r
677   }\r
678 \r
679   PciIo->FreeBuffer (\r
680            PciIo,\r
681            SNP_MEM_PAGES (4096),\r
682            Snp->Cpb\r
683            );\r
684 \r
685 Error_DeleteSNP:\r
686 \r
687   if (Snp->RecycledTxBuf != NULL) {\r
688     FreePool (Snp->RecycledTxBuf);\r
689   }\r
690 \r
691   PciIo->FreeBuffer (\r
692            PciIo,\r
693            SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
694            Snp\r
695            );\r
696 NiiError:\r
697   gBS->CloseProtocol (\r
698         Controller,\r
699         &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
700         This->DriverBindingHandle,\r
701         Controller\r
702         );\r
703 \r
704   gBS->CloseProtocol (\r
705         Controller,\r
706         &gEfiDevicePathProtocolGuid,\r
707         This->DriverBindingHandle,\r
708         Controller\r
709         );\r
710 \r
711   //\r
712   // If we got here that means we are in error state.\r
713   //\r
714   if (!EFI_ERROR (Status)) {\r
715     Status = EFI_DEVICE_ERROR;\r
716   }\r
717 \r
718   return Status;\r
719 }\r
720 \r
721 /**\r
722   Stop this driver on ControllerHandle. This service is called by the\r
723   EFI boot service DisconnectController(). In order to\r
724   make drivers as small as possible, there are a few calling\r
725   restrictions for this service. DisconnectController()\r
726   must follow these calling restrictions. If any other agent wishes\r
727   to call Stop() it must also follow these calling restrictions.\r
728 \r
729   @param  This              Protocol instance pointer.\r
730   @param  ControllerHandle  Handle of device to stop driver on\r
731   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of\r
732                             children is zero stop the entire bus driver.\r
733   @param  ChildHandleBuffer List of Child Handles to Stop.\r
734 \r
735   @retval EFI_SUCCESS       This driver is removed ControllerHandle\r
736   @retval other             This driver was not removed from this device\r
737 \r
738 **/\r
739 EFI_STATUS\r
740 EFIAPI\r
741 SimpleNetworkDriverStop (\r
742   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,\r
743   IN  EFI_HANDLE                     Controller,\r
744   IN  UINTN                          NumberOfChildren,\r
745   IN  EFI_HANDLE                     *ChildHandleBuffer\r
746   )\r
747 {\r
748   EFI_STATUS                  Status;\r
749   EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol;\r
750   SNP_DRIVER                  *Snp;\r
751   EFI_PCI_IO_PROTOCOL         *PciIo;\r
752 \r
753   //\r
754   // Get our context back.\r
755   //\r
756   Status = gBS->OpenProtocol (\r
757                   Controller,\r
758                   &gEfiSimpleNetworkProtocolGuid,\r
759                   (VOID **) &SnpProtocol,\r
760                   This->DriverBindingHandle,\r
761                   Controller,\r
762                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
763                   );\r
764 \r
765   if (EFI_ERROR (Status)) {\r
766     return EFI_UNSUPPORTED;\r
767   }\r
768 \r
769   Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SnpProtocol);\r
770 \r
771   Status = gBS->UninstallProtocolInterface (\r
772                   Controller,\r
773                   &gEfiSimpleNetworkProtocolGuid,\r
774                   &Snp->Snp\r
775                   );\r
776 \r
777   if (EFI_ERROR (Status)) {\r
778     return Status;\r
779   }\r
780 \r
781   //\r
782   // Close EXIT_BOOT_SERIVES Event\r
783   //\r
784   gBS->CloseEvent (Snp->ExitBootServicesEvent);\r
785 \r
786   Status = gBS->CloseProtocol (\r
787                   Controller,\r
788                   &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
789                   This->DriverBindingHandle,\r
790                   Controller\r
791                   );\r
792 \r
793   Status = gBS->CloseProtocol (\r
794                   Controller,\r
795                   &gEfiDevicePathProtocolGuid,\r
796                   This->DriverBindingHandle,\r
797                   Controller\r
798                   );\r
799 \r
800   PxeShutdown (Snp);\r
801   PxeStop (Snp);\r
802 \r
803   FreePool (Snp->RecycledTxBuf);\r
804 \r
805   PciIo = Snp->PciIo;\r
806   PciIo->FreeBuffer (\r
807            PciIo,\r
808            SNP_MEM_PAGES (4096),\r
809            Snp->Cpb\r
810            );\r
811 \r
812   PciIo->FreeBuffer (\r
813            PciIo,\r
814            SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
815            Snp\r
816            );\r
817 \r
818   return Status;\r
819 }\r
820 \r
821 //\r
822 // Simple Network Protocol Driver Global Variables\r
823 //\r
824 EFI_DRIVER_BINDING_PROTOCOL gSimpleNetworkDriverBinding = {\r
825   SimpleNetworkDriverSupported,\r
826   SimpleNetworkDriverStart,\r
827   SimpleNetworkDriverStop,\r
828   0xa,\r
829   NULL,\r
830   NULL\r
831 };\r
832 \r
833 /**\r
834   The SNP driver entry point.\r
835 \r
836   @param ImageHandle       The driver image handle.\r
837   @param SystemTable       The system table.\r
838 \r
839   @retval EFI_SUCEESS      Initialization routine has found UNDI hardware,\r
840                            loaded it's ROM, and installed a notify event for\r
841                            the Network Indentifier Interface Protocol\r
842                            successfully.\r
843   @retval Other            Return value from HandleProtocol for\r
844                            DeviceIoProtocol or LoadedImageProtocol\r
845 \r
846 **/\r
847 EFI_STATUS\r
848 EFIAPI\r
849 InitializeSnpNiiDriver (\r
850   IN EFI_HANDLE       ImageHandle,\r
851   IN EFI_SYSTEM_TABLE *SystemTable\r
852   )\r
853 {\r
854   return EfiLibInstallDriverBindingComponentName2 (\r
855            ImageHandle,\r
856            SystemTable,\r
857            &gSimpleNetworkDriverBinding,\r
858            ImageHandle,\r
859            &gSimpleNetworkComponentName,\r
860            &gSimpleNetworkComponentName2\r
861            );\r
862 }\r