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