+/**\r
+ Detect media status for specified network device.\r
+\r
+ The underlying UNDI driver may or may not support reporting media status from\r
+ GET_STATUS command (PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED). This routine\r
+ will try to invoke Snp->GetStatus() to get the media status: if media already\r
+ present, it return directly; if media not present, it will stop SNP and then\r
+ restart SNP to get the latest media status, this give chance to get the correct\r
+ media status for old UNDI driver which doesn't support reporting media status\r
+ from GET_STATUS command.\r
+ Note: there will be two limitations for current algorithm:\r
+ 1) for UNDI with this capability, in case of cable is not attached, there will\r
+ be an redundant Stop/Start() process;\r
+ 2) for UNDI without this capability, in case cable is attached in UNDI\r
+ initialize while unattached latter, NetLibDetectMedia() will report\r
+ MediaPresent as TRUE, this cause upper layer apps wait for timeout time.\r
+\r
+ @param[in] ServiceHandle The handle where network service binding protocols are\r
+ installed on.\r
+ @param[out] MediaPresent The pointer to store the media status.\r
+\r
+ @retval EFI_SUCCESS Media detection success.\r
+ @retval EFI_INVALID_PARAMETER ServiceHandle is not valid network device handle.\r
+ @retval EFI_UNSUPPORTED Network device does not support media detection.\r
+ @retval EFI_DEVICE_ERROR SNP is in unknown state.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NetLibDetectMedia (\r
+ IN EFI_HANDLE ServiceHandle,\r
+ OUT BOOLEAN *MediaPresent\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE SnpHandle;\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+ UINT32 InterruptStatus;\r
+ UINT32 OldState;\r
+ EFI_MAC_ADDRESS *MCastFilter;\r
+ UINT32 MCastFilterCount;\r
+ UINT32 EnableFilterBits;\r
+ UINT32 DisableFilterBits;\r
+ BOOLEAN ResetMCastFilters;\r
+\r
+ ASSERT (MediaPresent != NULL);\r
+\r
+ //\r
+ // Get SNP handle\r
+ //\r
+ Snp = NULL;\r
+ SnpHandle = NetLibGetSnpHandle (ServiceHandle, &Snp);\r
+ if (SnpHandle == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Check whether SNP support media detection\r
+ //\r
+ if (!Snp->Mode->MediaPresentSupported) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data\r
+ //\r
+ Status = Snp->GetStatus (Snp, &InterruptStatus, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Snp->Mode->MediaPresent) {\r
+ //\r
+ // Media is present, return directly\r
+ //\r
+ *MediaPresent = TRUE;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Till now, GetStatus() report no media; while, in case UNDI not support\r
+ // reporting media status from GetStatus(), this media status may be incorrect.\r
+ // So, we will stop SNP and then restart it to get the correct media status.\r
+ //\r
+ OldState = Snp->Mode->State;\r
+ if (OldState >= EfiSimpleNetworkMaxState) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ MCastFilter = NULL;\r
+\r
+ if (OldState == EfiSimpleNetworkInitialized) {\r
+ //\r
+ // SNP is already in use, need Shutdown/Stop and then Start/Initialize\r
+ //\r
+\r
+ //\r
+ // Backup current SNP receive filter settings\r
+ //\r
+ EnableFilterBits = Snp->Mode->ReceiveFilterSetting;\r
+ DisableFilterBits = Snp->Mode->ReceiveFilterMask ^ EnableFilterBits;\r
+\r
+ ResetMCastFilters = TRUE;\r
+ MCastFilterCount = Snp->Mode->MCastFilterCount;\r
+ if (MCastFilterCount != 0) {\r
+ MCastFilter = AllocateCopyPool (\r
+ MCastFilterCount * sizeof (EFI_MAC_ADDRESS),\r
+ Snp->Mode->MCastFilter\r
+ );\r
+ ASSERT (MCastFilter != NULL);\r
+\r
+ ResetMCastFilters = FALSE;\r
+ }\r
+\r
+ //\r
+ // Shutdown/Stop the simple network\r
+ //\r
+ Status = Snp->Shutdown (Snp);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = Snp->Stop (Snp);\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Start/Initialize the simple network\r
+ //\r
+ Status = Snp->Start (Snp);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = Snp->Initialize (Snp, 0, 0);\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Here we get the correct media status\r
+ //\r
+ *MediaPresent = Snp->Mode->MediaPresent;\r
+\r
+ //\r
+ // Restore SNP receive filter settings\r
+ //\r
+ Status = Snp->ReceiveFilters (\r
+ Snp,\r
+ EnableFilterBits,\r
+ DisableFilterBits,\r
+ ResetMCastFilters,\r
+ MCastFilterCount,\r
+ MCastFilter\r
+ );\r
+\r
+ if (MCastFilter != NULL) {\r
+ FreePool (MCastFilter);\r
+ }\r
+\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // SNP is not in use, it's in state of EfiSimpleNetworkStopped or EfiSimpleNetworkStarted\r
+ //\r
+ if (OldState == EfiSimpleNetworkStopped) {\r
+ //\r
+ // SNP not start yet, start it\r
+ //\r
+ Status = Snp->Start (Snp);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Initialize the simple network\r
+ //\r
+ Status = Snp->Initialize (Snp, 0, 0);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Here we get the correct media status\r
+ //\r
+ *MediaPresent = Snp->Mode->MediaPresent;\r
+\r
+ //\r
+ // Shut down the simple network\r
+ //\r
+ Snp->Shutdown (Snp);\r
+\r
+Exit:\r
+ if (OldState == EfiSimpleNetworkStopped) {\r
+ //\r
+ // Original SNP sate is Stopped, restore to original state\r
+ //\r
+ Snp->Stop (Snp);\r
+ }\r
+\r
+ if (MCastFilter != NULL) {\r
+ FreePool (MCastFilter);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r