/*++ Copyright (c) 1992 Microsoft Corporation Module Name: Detect.c Abstract: This is the main file for the autodetection DLL for all the net cards which MS is shipping with Windows NT. Author: Sean Selitrennikoff (SeanSe) October 1992. Environment: Revision History: --*/ #include #include #include #include #include #include #include #include "ntddnetd.h" #include "detect.h" #if DBG #define DBGPRINT(x) DbgPrint x #define STATIC #else #define STATIC static #define DBGPRINT(x) #endif // // This is the structure for all the cards which MS is shipping in this DLL. // To add detection for a new adapter(s), simply add the proper routines to // this structure. The rest is automatic. // DETECT_ADAPTER DetectAdapters[] = { #ifdef _M_MRX000 { MipsIdentifyHandler, MipsFirstNextHandler, MipsOpenHandleHandler, MipsCreateHandleHandler, MipsCloseHandleHandler, MipsQueryCfgHandler, MipsVerifyCfgHandler, MipsQueryMaskHandler, MipsParamRangeHandler, MipsQueryParameterNameHandler, 0 }, #endif { PcmciaIdentifyHandler, PcmciaFirstNextHandler, PcmciaOpenHandleHandler, PcmciaCreateHandleHandler, PcmciaCloseHandleHandler, PcmciaQueryCfgHandler, PcmciaVerifyCfgHandler, PcmciaQueryMaskHandler, PcmciaParamRangeHandler, PcmciaQueryParameterNameHandler, 0 }, { McaIdentifyHandler, McaFirstNextHandler, McaOpenHandleHandler, McaCreateHandleHandler, McaCloseHandleHandler, McaQueryCfgHandler, McaVerifyCfgHandler, McaQueryMaskHandler, McaParamRangeHandler, McaQueryParameterNameHandler, 0 }, { EisaIdentifyHandler, EisaFirstNextHandler, EisaOpenHandleHandler, EisaCreateHandleHandler, EisaCloseHandleHandler, EisaQueryCfgHandler, EisaVerifyCfgHandler, EisaQueryMaskHandler, EisaParamRangeHandler, EisaQueryParameterNameHandler, 0 }, { PciIdentifyHandler, PciFirstNextHandler, PciOpenHandleHandler, PciCreateHandleHandler, PciCloseHandleHandler, PciQueryCfgHandler, PciVerifyCfgHandler, PciQueryMaskHandler, PciParamRangeHandler, PciQueryParameterNameHandler, 0 }, { LanceIdentifyHandler, LanceFirstNextHandler, LanceOpenHandleHandler, LanceCreateHandleHandler, LanceCloseHandleHandler, LanceQueryCfgHandler, LanceVerifyCfgHandler, LanceQueryMaskHandler, LanceParamRangeHandler, LanceQueryParameterNameHandler, 0 }, { IbmtokIdentifyHandler, IbmtokFirstNextHandler, IbmtokOpenHandleHandler, IbmtokCreateHandleHandler, IbmtokCloseHandleHandler, IbmtokQueryCfgHandler, IbmtokVerifyCfgHandler, IbmtokQueryMaskHandler, IbmtokParamRangeHandler, IbmtokQueryParameterNameHandler, 0 }, { WdIdentifyHandler, WdFirstNextHandler, WdOpenHandleHandler, WdCreateHandleHandler, WdCloseHandleHandler, WdQueryCfgHandler, WdVerifyCfgHandler, WdQueryMaskHandler, WdParamRangeHandler, WdQueryParameterNameHandler, 0 }, { ElnkiiIdentifyHandler, ElnkiiFirstNextHandler, ElnkiiOpenHandleHandler, ElnkiiCreateHandleHandler, ElnkiiCloseHandleHandler, ElnkiiQueryCfgHandler, ElnkiiVerifyCfgHandler, ElnkiiQueryMaskHandler, ElnkiiParamRangeHandler, ElnkiiQueryParameterNameHandler, 0 }, { Ne2000IdentifyHandler, Ne2000FirstNextHandler, Ne2000OpenHandleHandler, Ne2000CreateHandleHandler, Ne2000CloseHandleHandler, Ne2000QueryCfgHandler, Ne2000VerifyCfgHandler, Ne2000QueryMaskHandler, Ne2000ParamRangeHandler, Ne2000QueryParameterNameHandler, 0 }, { Ne1000IdentifyHandler, Ne1000FirstNextHandler, Ne1000OpenHandleHandler, Ne1000CreateHandleHandler, Ne1000CloseHandleHandler, Ne1000QueryCfgHandler, Ne1000VerifyCfgHandler, Ne1000QueryMaskHandler, Ne1000ParamRangeHandler, Ne1000QueryParameterNameHandler, 0 }, { UbIdentifyHandler, UbFirstNextHandler, UbOpenHandleHandler, UbCreateHandleHandler, UbCloseHandleHandler, UbQueryCfgHandler, UbVerifyCfgHandler, UbQueryMaskHandler, UbParamRangeHandler, UbQueryParameterNameHandler, 0 }, { ProteonIdentifyHandler, ProteonFirstNextHandler, ProteonOpenHandleHandler, ProteonCreateHandleHandler, ProteonCloseHandleHandler, ProteonQueryCfgHandler, ProteonVerifyCfgHandler, ProteonQueryMaskHandler, ProteonParamRangeHandler, ProteonQueryParameterNameHandler, 0 }, { Elnk16IdentifyHandler, Elnk16FirstNextHandler, Elnk16OpenHandleHandler, Elnk16CreateHandleHandler, Elnk16CloseHandleHandler, Elnk16QueryCfgHandler, Elnk16VerifyCfgHandler, Elnk16QueryMaskHandler, Elnk16ParamRangeHandler, Elnk16QueryParameterNameHandler, 0 }, { Ee16IdentifyHandler, Ee16FirstNextHandler, Ee16OpenHandleHandler, Ee16CreateHandleHandler, Ee16CloseHandleHandler, Ee16QueryCfgHandler, Ee16VerifyCfgHandler, Ee16QueryMaskHandler, Ee16ParamRangeHandler, Ee16QueryParameterNameHandler, 0 }, { EProIdentifyHandler, EProFirstNextHandler, EProOpenHandleHandler, EProCreateHandleHandler, EProCloseHandleHandler, EProQueryCfgHandler, EProVerifyCfgHandler, EProQueryMaskHandler, EProParamRangeHandler, EProQueryParameterNameHandler, 0 }, { Elnk3IdentifyHandler, Elnk3FirstNextHandler, Elnk3OpenHandleHandler, Elnk3CreateHandleHandler, Elnk3CloseHandleHandler, Elnk3QueryCfgHandler, Elnk3VerifyCfgHandler, Elnk3QueryMaskHandler, Elnk3ParamRangeHandler, Elnk3QueryParameterNameHandler, 0 }, { Tok162IdentifyHandler, Tok162FirstNextHandler, Tok162OpenHandleHandler, Tok162CreateHandleHandler, Tok162CloseHandleHandler, Tok162QueryCfgHandler, Tok162VerifyCfgHandler, Tok162QueryMaskHandler, Tok162ParamRangeHandler, Tok162QueryParameterNameHandler, 0 } }; // // Constant strings for parameters // WCHAR IrqString[] = L"IRQ"; WCHAR IrqTypeString[] = L"IRQTYPE"; WCHAR IoAddrString[] = L"IOADDR"; WCHAR IoLengthString[] = L"IOADDRLENGTH"; WCHAR MemAddrString[] = L"MEMADDR"; WCHAR MemLengthString[] = L"MEMADDRLENGTH"; WCHAR TransceiverString[] = L"TRANSCEIVER"; WCHAR ZeroWaitStateString[] = L"ZEROWAITSTATE"; WCHAR SlotNumberString[] = L"SLOTNUMBER"; WCHAR IoChannelReadyString[] = L"IOCHANNELREADY"; WCHAR CardTypeString[] = L"CARDTYPE"; WCHAR PcmciaString[] = L"PCMCIA"; WCHAR PCCARDAttributeMemLengthString[] = L"PCCARDATTRIBUTEMEMLENGTH"; WCHAR PCCARDAttributeMemString[] = L"PCCARDATTRIBUTEMEM"; // // Variables for keeping track of the resources that the DLL currently has // claimed. // PNETDTECT_RESOURCE ResourceList; ULONG NumberOfResources = 0; ULONG NumberOfAllocatedResourceSlots = 0; // // Variables for detecting non-network related hardware // typedef struct _DETECT_CONFIG { INTERFACE_TYPE InterfaceType; ULONG BusNumber; struct _DETECT_CONFIG *Next; }DETECT_CONFIG, *PDETECT_CONFIG; PDETECT_CONFIG DetectConfigs = NULL; VOID NcDetectFindOtherHardware( INTERFACE_TYPE InterfaceType, ULONG BusNumber ); BOOLEAN NcDetectInitialInit( IN PVOID DllHandle, IN ULONG Reason, IN PCONTEXT Context OPTIONAL ) /*++ Routine Description: This routine calls CreateFile to open the device driver. Arguments: DllHandle - Not Used Reason - Attach or Detach Context - Not Used Return Value: STATUS_SUCCESS --*/ { LONG SupportedDrivers; LONG CurrentDriver; LONG SupportedAdapters; LONG TotalAdapters = 0; LONG ReturnValue; LONG Length = 0; PDETECT_CONFIG Tmp; BOOLEAN f; if (DLL_PROCESS_DETACH == Reason) { // // This is the close call // FreeEisaAdapterInfo(); FreePciAdapterInfo(); FreeMcaAdapterInfo(); // // Free ResourceList // if (NumberOfAllocatedResourceSlots > 0) { DetectFreeHeap(ResourceList); } // // Now free config list // while (DetectConfigs != NULL) { Tmp = DetectConfigs; DetectConfigs = DetectConfigs->Next; DetectFreeHeap(Tmp); } // // Free any temporary resources // DetectFreeTemporaryResources(); return(TRUE); } // // Load the adapter information out of the registry. // if (DLL_PROCESS_ATTACH == Reason) { // // This is the close call // f = LoadEisaAdapterInfo(); if (!f) { return(FALSE); } f = LoadPciAdapterInfo(); if (!f) { return(FALSE); } f = LoadMcaAdapterInfo(); if (!f) { return(FALSE); } } SupportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER); CurrentDriver = 0; for (; CurrentDriver < SupportedDrivers ; CurrentDriver++) { // // Count the total number of adapters supported by this DLL by // iterating through each module, finding the number of adapters // each module supports. // SupportedAdapters = 0; for ( ; ; SupportedAdapters++) { ReturnValue = (*(DetectAdapters[CurrentDriver].NcDetectIdentifyHandler))( ((SupportedAdapters+10) * 100), NULL, Length); if (ReturnValue == ERROR_NO_MORE_ITEMS) { break; } } TotalAdapters += SupportedAdapters; DetectAdapters[CurrentDriver].SupportedAdapters = SupportedAdapters; } if (TotalAdapters > 0xFFFF) { // // We do not support more than this many adapters in this DLL // because of the way we build the Tokens and NetcardIds. // return(FALSE); } return(TRUE); } LONG NcDetectIdentify( IN LONG Index, OUT WCHAR *Buffer, IN LONG BuffSize ) /*++ Routine Description: This routine returns information about the netcards supported by this DLL. Arguments: Index - The index of the netcard being address. The first cards information is at index 1000, the second at 1100, etc. Buffer - Buffer to store the result into. BuffSize - Number of bytes in pwchBuffer Return Value: 0 if nothing went wrong, else the appropriate WINERROR.H value. --*/ { LONG SupportedDrivers; LONG CurrentDriver; LONG ReturnValue; LONG AdapterNumber = (Index / 100) - 10; LONG CodeNumber = Index % 100; // // First we check the index for any of the 'special' values. // if (Index == 0) { // // Return manufacturers identfication // if (BuffSize < 4) { return(ERROR_NOT_ENOUGH_MEMORY); } // // Copy in the identification number // wsprintf(Buffer,L"0x0"); return(0); } if (Index == 1) { // // Return the date and version // if (BuffSize < 12) { return(ERROR_NOT_ENOUGH_MEMORY); } // // Copy it in // wsprintf(Buffer,L"0x10920301"); return(0); } if (AdapterNumber < 0) { return(ERROR_INVALID_PARAMETER); } // // Now we find the number of drivers this DLL is supporting. // SupportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER); // // Iterate through index until we find the the adapter indicated above. // CurrentDriver = 0; for (; CurrentDriver < SupportedDrivers ; CurrentDriver++) { // // See if the one we want is in here // if (AdapterNumber < DetectAdapters[CurrentDriver].SupportedAdapters) { ReturnValue = (*(DetectAdapters[CurrentDriver].NcDetectIdentifyHandler))( ((AdapterNumber + 10) * 100) + CodeNumber, Buffer, BuffSize); return(ReturnValue); } else { // // No, move on to next driver. // AdapterNumber -= DetectAdapters[CurrentDriver].SupportedAdapters; } } return(ERROR_NO_MORE_ITEMS); } LONG NcDetectFirstNext( IN LONG NetcardId, IN INTERFACE_TYPE InterfaceType, IN ULONG BusNumber, IN BOOL First, OUT PVOID *Token, OUT LONG *Confidence ) /*++ Routine Description: This routine finds the instances of a physical adapter identified by the NetcardId. // Arguments: NetcardId - The index of the netcard being address. The first cards information is id 1000, the second id 1100, etc. InterfaceType - Any bus type. BusNumber - The bus number of the bus to search. First - TRUE is we are to search for the first instance of an adapter, FALSE if we are to continue search from a previous stopping point. Token - A pointer to a handle to return to identify the found instance Confidence - A pointer to a long for storing the confidence factor that the card exists. Return Value: 0 if nothing went wrong, else the appropriate WINERROR.H value. --*/ { LONG SupportedDrivers; LONG CurrentDriver; LONG ReturnValue; LONG AdapterNumber = (NetcardId / 100) - 10; PDETECT_CONFIG TmpConfig; if (AdapterNumber < 0) { return(ERROR_INVALID_PARAMETER); } if ((NetcardId % 100) != 0) { return(ERROR_INVALID_PARAMETER); } // // Find non-network hardware that will cause hangs and claim those // resources. // TmpConfig = DetectConfigs; while (TmpConfig != NULL) { if ((TmpConfig->InterfaceType == InterfaceType) && (TmpConfig->BusNumber == BusNumber)) { break; } TmpConfig = TmpConfig->Next; } if (TmpConfig == NULL) { // // Record this new config // TmpConfig = (PDETECT_CONFIG)DetectAllocateHeap(sizeof(DETECT_CONFIG)); TmpConfig->InterfaceType = InterfaceType; TmpConfig->BusNumber = BusNumber; TmpConfig->Next = DetectConfigs; DetectConfigs = TmpConfig; // // Now find any other hardware on this config // NcDetectFindOtherHardware(InterfaceType, BusNumber); } // // Now we find the number of drivers this DLL is supporting. // SupportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER); // // Iterate through index until we find the the adapter indicated above. // CurrentDriver = 0; for (; CurrentDriver < SupportedDrivers ; CurrentDriver++) { // // See if the one we want is in here // if (AdapterNumber < DetectAdapters[CurrentDriver].SupportedAdapters) { // // Yes, so call to get the right one. // ReturnValue = (*(DetectAdapters[CurrentDriver].NcDetectFirstNextHandler))( (AdapterNumber + 10) * 100, InterfaceType, BusNumber, First, Token, Confidence); if (ReturnValue == 0) { // // Store information // *Token = (PVOID)(((ULONG)(*Token)) | (CurrentDriver << 16)); } else { *Token = 0; } return(ReturnValue); } else { // // No, move on to next driver. // AdapterNumber -= DetectAdapters[CurrentDriver].SupportedAdapters; } } return(ERROR_INVALID_PARAMETER); } LONG NcDetectOpenHandle( IN PVOID Token, OUT PVOID *Handle ) /*++ Routine Description: This routine takes a token returned by FirstNext and converts it into a permanent handle. Arguments: Token - The token. Handle - A pointer to the handle, so we can store the resulting handle. Return Value: 0 if nothing went wrong, else the appropriate WINERROR.H value. --*/ { LONG ReturnValue; LONG DriverToken = ((ULONG)Token & 0xFFFF); LONG DriverNumber = ((ULONG)Token >> 16); PADAPTER_HANDLE Adapter; ReturnValue = (*(DetectAdapters[DriverNumber].NcDetectOpenHandleHandler))( (PVOID)DriverToken, Handle); if (ReturnValue == 0) { // // Store information // Adapter = DetectAllocateHeap(sizeof(ADAPTER_HANDLE)); if (Adapter == NULL) { // // Error // (*(DetectAdapters[DriverNumber].NcDetectCloseHandleHandler))(*Handle); return(ERROR_NOT_ENOUGH_MEMORY); } Adapter->Handle = *Handle; Adapter->DriverNumber = DriverNumber; *Handle = Adapter; } else { *Handle = NULL; } return(ReturnValue); } LONG NcDetectCreateHandle( IN LONG NetcardId, IN INTERFACE_TYPE InterfaceType, IN ULONG BusNumber, OUT PVOID *Handle ) /*++ Routine Description: This routine is used to force the creation of a handle for cases where a card is not found via FirstNext, but the user says it does exist. Arguments: NetcardId - The id of the card to create the handle for. InterfaceType - Any bus type. BusNumber - The bus number of the bus in the system. Handle - A pointer to the handle, for storing the resulting handle. Return Value: 0 if nothing went wrong, else the appropriate WINERROR.H value. --*/ { LONG SupportedDrivers; LONG CurrentDriver; LONG ReturnValue; LONG AdapterNumber = (NetcardId / 100) - 10; PADAPTER_HANDLE Adapter; PDETECT_CONFIG TmpConfig; if (AdapterNumber < 0) { return(ERROR_INVALID_PARAMETER); } if ((NetcardId % 100) != 0) { return(ERROR_INVALID_PARAMETER); } // // Find non-network hardware that will cause hangs and claim those // resources. // TmpConfig = DetectConfigs; while (TmpConfig != NULL) { if ((TmpConfig->InterfaceType == InterfaceType) && (TmpConfig->BusNumber == BusNumber)) { break; } TmpConfig = TmpConfig->Next; } if (TmpConfig == NULL) { // // Record this new config // TmpConfig = (PDETECT_CONFIG)DetectAllocateHeap(sizeof(DETECT_CONFIG)); TmpConfig->InterfaceType = InterfaceType; TmpConfig->BusNumber = BusNumber; TmpConfig->Next = DetectConfigs; DetectConfigs = TmpConfig; // // Now find any other hardware on this config // NcDetectFindOtherHardware(InterfaceType, BusNumber); } // // Now we find the number of drivers this DLL is supporting. // SupportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER); // // Iterate through index until we find the the adapter indicated above. // CurrentDriver = 0; for (; CurrentDriver < SupportedDrivers ; CurrentDriver++) { // // See if the one we want is in here // if (AdapterNumber < DetectAdapters[CurrentDriver].SupportedAdapters) { // // Yes, so call to get the right one. // ReturnValue = (*(DetectAdapters[CurrentDriver].NcDetectCreateHandleHandler))( (AdapterNumber + 10) * 100, InterfaceType, BusNumber, Handle); if (ReturnValue == 0) { // // Store information // Adapter = DetectAllocateHeap(sizeof(ADAPTER_HANDLE)); if (Adapter == NULL) { // // Error // (*(DetectAdapters[CurrentDriver].NcDetectCloseHandleHandler))( *Handle); return(ERROR_NOT_ENOUGH_MEMORY); } Adapter->Handle = *Handle; Adapter->DriverNumber = CurrentDriver; *Handle = Adapter; } else { *Handle = NULL; } return(ReturnValue); } else { // // No, move on to next driver. // AdapterNumber -= DetectAdapters[CurrentDriver].SupportedAdapters; } } return(ERROR_INVALID_PARAMETER); } LONG NcDetectCloseHandle( IN PVOID Handle ) /*++ Routine Description: This frees any resources associated with a handle. Arguments: pvHandle - The handle. Return Value: 0 if nothing went wrong, else the appropriate WINERROR.H value. --*/ { PADAPTER_HANDLE Adapter = (PADAPTER_HANDLE)(Handle); (*(DetectAdapters[Adapter->DriverNumber].NcDetectCloseHandleHandler))( Adapter->Handle); DetectFreeHeap( Adapter ); return(0); } LONG NcDetectQueryCfg( IN PVOID Handle, OUT WCHAR *Buffer, IN LONG BuffSize ) /*++ Routine Description: This routine calls the appropriate driver's query config handler to get the parameters for the adapter associated with the handle. Arguments: Handle - The handle. Buffer - The resulting parameter list. BuffSize - Length of the given buffer in WCHARs. Return Value: 0 if nothing went wrong, else the appropriate WINERROR.H value. --*/ { PADAPTER_HANDLE Adapter = (PADAPTER_HANDLE)(Handle); LONG ReturnValue; ReturnValue = (*(DetectAdapters[Adapter->DriverNumber].NcDetectQueryCfgHandler))( Adapter->Handle, Buffer, BuffSize); return(ReturnValue); } LONG NcDetectVerifyCfg( IN PVOID Handle, IN WCHAR *Buffer ) /*++ Routine Description: This routine verifys that a given parameter list is complete and correct for the adapter associated with the handle. Arguments: Handle - The handle. Buffer - The parameter list. Return Value: 0 if nothing went wrong, else the appropriate WINERROR.H value. --*/ { PADAPTER_HANDLE Adapter = (PADAPTER_HANDLE)(Handle); LONG ReturnValue; ReturnValue = (*(DetectAdapters[Adapter->DriverNumber].NcDetectVerifyCfgHandler))( Adapter->Handle, Buffer); return(ReturnValue); } LONG NcDetectQueryMask( IN LONG NetcardId, OUT WCHAR *Buffer, IN LONG BuffSize ) /*++ Routine Description: This routine returns the parameter list information for a specific network card. Arguments: NetcardId - The id of the desired netcard. Buffer - The buffer for storing the parameter information. BuffSize - Length of Buffer in WCHARs. Return Value: 0 if nothing went wrong, else the appropriate WINERROR.H value. --*/ { LONG SupportedDrivers; LONG CurrentDriver; LONG ReturnValue; LONG AdapterNumber = (NetcardId / 100) - 10; if (AdapterNumber < 0) { return(ERROR_INVALID_PARAMETER); } if ((NetcardId % 100) != 0) { return(ERROR_INVALID_PARAMETER); } // // Now we find the number of drivers this DLL is supporting. // SupportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER); // // Iterate through index until we find the the adapter indicated above. // CurrentDriver = 0; for (; CurrentDriver < SupportedDrivers ; CurrentDriver++) { // // See if the one we want is in here // if (AdapterNumber < DetectAdapters[CurrentDriver].SupportedAdapters) { // // Yes, so call to get the right one. // ReturnValue = (*(DetectAdapters[CurrentDriver].NcDetectQueryMaskHandler))( ((AdapterNumber + 10) * 100), Buffer, BuffSize); return(ReturnValue); } else { // // No, move on to next driver. // AdapterNumber -= DetectAdapters[CurrentDriver].SupportedAdapters; } } return(ERROR_INVALID_PARAMETER); } LONG NcDetectParamRange( IN LONG NetcardId, IN WCHAR *Param, OUT LONG *Values, OUT LONG *BuffSize ) /*++ Routine Description: This routine returns a list of valid values for a given parameter name for a given card. Arguments: NetcardId - The Id of the card desired. Param - A WCHAR string of the parameter name to query the values of. Values - A pointer to a list of LONGs into which we store valid values for the parameter. BuffSize - At entry, the length of plValues in LONGs. At exit, the number of LONGs stored in plValues. Return Value: 0 if nothing went wrong, else the appropriate WINERROR.H value. --*/ { LONG SupportedDrivers; LONG CurrentDriver; LONG ReturnValue; LONG AdapterNumber = (NetcardId / 100) - 10; if (AdapterNumber < 0) { return(ERROR_INVALID_PARAMETER); } if ((NetcardId % 100) != 0) { return(ERROR_INVALID_PARAMETER); } // // Now we find the number of drivers this DLL is supporting. // SupportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER); // // Iterate through index until we find the the adapter indicated above. // CurrentDriver = 0; for (; CurrentDriver < SupportedDrivers ; CurrentDriver++) { // // See if the one we want is in here // if (AdapterNumber < DetectAdapters[CurrentDriver].SupportedAdapters) { // // Yes, so call to get the right one. // ReturnValue = (*(DetectAdapters[CurrentDriver].NcDetectParamRangeHandler))( ((AdapterNumber + 10) * 100), Param, Values, BuffSize); return(ReturnValue); } else { // // No, move on to next driver. // AdapterNumber -= DetectAdapters[CurrentDriver].SupportedAdapters; } } return(ERROR_INVALID_PARAMETER); } LONG NcDetectQueryParameterName( IN WCHAR *Param, OUT WCHAR *Buffer, IN LONG BufferSize ) /*++ Routine Description: Returns a localized, displayable name for a specific parameter. Arguments: Param - The parameter to be queried. Buffer - The buffer to store the result into. BufferSize - The length of Buffer in WCHARs. Return Value: 0 if nothing went wrong, else the appropriate WINERROR.H value. --*/ { LONG SupportedDrivers; LONG CurrentDriver; LONG ReturnValue; // // Now we find the number of drivers this DLL is supporting. // SupportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER); // // Iterate through index until we find the the adapter indicated above. // CurrentDriver = 0; for (; CurrentDriver < SupportedDrivers ; CurrentDriver++) { // // No way to tell where this came from -- guess until success. // ReturnValue = (*(DetectAdapters[CurrentDriver].NcDetectQueryParameterNameHandler))( Param, Buffer, BufferSize); if (ReturnValue == 0) { return(0); } } return(ERROR_INVALID_PARAMETER); } LONG NcDetectResourceClaim( IN INTERFACE_TYPE InterfaceType, IN ULONG BusNumber, IN ULONG Type, IN ULONG Value, IN ULONG Length, IN ULONG Flags, IN BOOL Claim ) /*++ Routine Description: Attempts to claim a resources, failing if there is a conflict. Arguments: InterfaceType - Any type. BusNumber - The bus number of the bus to search. Type - The type of resource, Irq, Memory, Port, Dma Value - The starting value Length - The Length of the resource from starting value to end. Flags - If Type is IRQ, this defines if this is Latched or LevelSensitive. Claim - TRUE if we are to permanently claim the resource, else FALSE. Return Value: 0 if nothing went wrong, else the appropriate WINERROR.H value. --*/ { ULONG i; NTSTATUS NtStatus; return(ERROR_NOT_SUPPORTED); // // Check the resources we've claimed for ourselves // for (i = 0; i < NumberOfResources; i++) { if ((ResourceList[i].InterfaceType == InterfaceType) && (ResourceList[i].BusNumber == BusNumber) && (ResourceList[i].Type == Type)) { if (Value < ResourceList[i].Value) { if ((Value + Length) > ResourceList[i].Value) { return(ERROR_SHARING_VIOLATION); } } else if (Value == ResourceList[i].Value) { return(ERROR_SHARING_VIOLATION); } else if (Value < (ResourceList[i].Value + ResourceList[i].Length)) { return(ERROR_SHARING_VIOLATION); } } } // // Make sure resource list has space for this one. // if (NumberOfResources == NumberOfAllocatedResourceSlots) { PVOID TmpList; // // Get more space // TmpList = DetectAllocateHeap((NumberOfAllocatedResourceSlots + 32) * sizeof(NETDTECT_RESOURCE)); // // Copy data // memcpy(TmpList, ResourceList, (NumberOfAllocatedResourceSlots * sizeof(NETDTECT_RESOURCE))); // // Update counter // NumberOfAllocatedResourceSlots += 32; // // Free old space // DetectFreeHeap(ResourceList); ResourceList = (PNETDTECT_RESOURCE)TmpList; } // // Add it to the list // ResourceList[NumberOfResources].InterfaceType = InterfaceType; ResourceList[NumberOfResources].BusNumber = BusNumber; ResourceList[NumberOfResources].Type = Type; ResourceList[NumberOfResources].Value = Value; ResourceList[NumberOfResources].Length = Length; ResourceList[NumberOfResources].Flags = Flags; // // Try to claim the resource // NtStatus = DetectClaimResource(NumberOfResources + 1, (PVOID)ResourceList); // // If failed, exit // if (NtStatus == STATUS_CONFLICTING_ADDRESSES) { // // Undo the claim // DetectClaimResource(NumberOfResources, (PVOID)ResourceList); return(ERROR_SHARING_VIOLATION); } if (!NT_SUCCESS(NtStatus)) { return(ERROR_NOT_ENOUGH_MEMORY); } if (!Claim) { // // Undo the claim // DetectClaimResource(NumberOfResources, (PVOID)ResourceList); } else { // // Adjust total count only if this is permanent // NumberOfResources++; } // // no error // return(0); } // // Support routines. // // These routines are common routines used within each detection module. // ULONG UnicodeStrLen( IN WCHAR *String ) /*++ Routine Description: This routine returns the number of Unicode characters in a NULL terminated Unicode string. Arguments: String - The string. Return Value: The length in number of unicode characters --*/ { ULONG Length; for (Length=0; ; Length++) { if (String[Length] == L'\0') { return Length; } } } WCHAR * FindParameterString( IN WCHAR *String1, IN WCHAR *String2 ) /*++ Routine Description: This routine returns a pointer to the first instance of String2 in String1. It assumes that String1 is a parameter list where each parameter name is terminated with a NULL and the entire string terminated by two consecutive NULLs. Arguments: String1 -- String to search. String2 -- Substring to search for. Return Value: Pointer to place in String1 of first character of String2 if it exists, else NULL. --*/ { ULONG Length1; ULONG Length2; WCHAR *Place = String1; Length2 = UnicodeStrLen(String2) + 1; Length1 = UnicodeStrLen(String1) + 1; // // While not the NULL only // while (Length1 != 1) { // // Are these the same? // if (memcmp(Place, String2, Length2 * sizeof(WCHAR)) == 0) { // // Yes. // return(Place); } Place = (WCHAR *)(Place + Length1); Length1 = UnicodeStrLen(Place) + 1; } return(NULL); } VOID ScanForNumber( IN WCHAR *Place, OUT ULONG *Value, OUT BOOLEAN *Found ) /*++ Routine Description: This routine does a sscanf(Place, "%d", Value) on a unicode string. Arguments: Place - String to read from Value - Pointer to place to store the result. Found - Pointer to tell if the routine failed to find an integer. Return Value: None. --*/ { ULONG Tmp; *Value = 0; *Found = FALSE; // // Skip leading blanks // while (*Place == L' ') { Place++; } // // Is this a hex number? // if ((Place[0] == L'0') && (Place[1] == L'x')) { // // Yes, parse it as a hex number // *Found = TRUE; // // Skip leading '0x' // Place += 2; // // Convert a hex number // while (TRUE) { if ((*Place >= L'0') && (*Place <= L'9')) { Tmp = ((ULONG)*Place) - ((ULONG)L'0'); } else { switch (*Place) { case L'a': case L'A': Tmp = 10; break; case L'b': case L'B': Tmp = 11; break; case L'c': case L'C': Tmp = 12; break; case L'd': case L'D': Tmp = 13; break; case L'e': case L'E': Tmp = 14; break; case L'f': case L'F': Tmp = 15; break; default: return; } } (*Value) *= 16; (*Value) += Tmp; Place++; } } else if ((*Place >= L'0') && (*Place <= L'9')) { // // Parse it as an int // *Found = TRUE; // // Convert a base 10 number // while (TRUE) { if ((*Place >= L'0') && (*Place <= L'9')) { Tmp = ((ULONG)*Place) - ((ULONG)L'0'); } else { return; } (*Value) *= 10; (*Value) += Tmp; Place++; } } } BOOLEAN CheckFor8390( IN INTERFACE_TYPE InterfaceType, IN ULONG BusNumber, IN ULONG IoBaseAddress ) /*++ Routine Description: This routine checks for the existence of an 8390 NIC. Arguments: InterfaceType - Any bus type. BusNumber - The bus number of the bus in the system. IoBaseAddress - The IoBaseAddress to check. Return Value: None. --*/ { UCHAR Value; UCHAR IMRValue; NTSTATUS NtStatus; UCHAR SavedOffset0; UCHAR SavedOffset3; UCHAR SavedOffsetF; BOOLEAN Status = TRUE; // // If the IoBaseAddress is the address of the DMA register on the NE2000 // adapter, then this routine will hang the card and the machine. To avoid // this, we first write to the Ne2000's reset port. // NtStatus = DetectReadPortUchar(InterfaceType, BusNumber, IoBaseAddress + 0xF, &SavedOffsetF); if (NtStatus != STATUS_SUCCESS) { Status = FALSE; goto Fail; } NtStatus = DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress + 0xF, 0xFF); if (NtStatus != STATUS_SUCCESS) { Status = FALSE; goto Fail; } // // Write STOP bit // NtStatus = DetectReadPortUchar(InterfaceType, BusNumber, IoBaseAddress, &SavedOffset0); if (NtStatus != STATUS_SUCCESS) { Status = FALSE; goto Restore1; } NtStatus = DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress, 0x21); if (NtStatus != STATUS_SUCCESS) { Status = FALSE; goto Restore1; } // // Read boundary // NtStatus = DetectReadPortUchar(InterfaceType, BusNumber, IoBaseAddress + 0x3, &Value); if (NtStatus != STATUS_SUCCESS) { Status = FALSE; goto Restore2; } SavedOffset3 = Value; // // Write a different boundary // NtStatus = DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress + 0x3, (UCHAR)(Value + 1)); if (NtStatus != STATUS_SUCCESS) { Status = FALSE; goto Restore2; } // // Did it stick? // NtStatus = DetectReadPortUchar(InterfaceType, BusNumber, IoBaseAddress + 0x3, &IMRValue); if (NtStatus != STATUS_SUCCESS) { Status = FALSE; goto Restore3; } if (IMRValue != (UCHAR)(Value + 1)) { Status = FALSE; goto Restore3; } // // Write IMR // NtStatus = DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress + 0xF, 0x3F); if (NtStatus != STATUS_SUCCESS) { Status = FALSE; goto Restore3; } // // switch to page 2 // NtStatus = DetectWritePortUchar( InterfaceType, BusNumber, IoBaseAddress, 0xA1); if (NtStatus != STATUS_SUCCESS) { // // Change to page 0 // DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress, 0x21); Status = FALSE; goto Restore3; } // // Read the IMR // NtStatus = DetectReadPortUchar(InterfaceType, BusNumber, IoBaseAddress + 0xF, &IMRValue); if (NtStatus != STATUS_SUCCESS) { // // Change to page 0 // DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress, 0x21); Status = FALSE; goto Restore3; } // // Remove bits added by NIC // IMRValue &= 0x3F; // // switch to page 0 // NtStatus = DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress, 0x21); if (NtStatus != STATUS_SUCCESS) { Status = FALSE; goto Restore3; } // // Write IMR // NtStatus = DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress + 0xF, (UCHAR)(IMRValue)); if (NtStatus != STATUS_SUCCESS) { Status = FALSE; goto Restore3; } // // switch to page 1 // NtStatus = DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress, 0x61); if (NtStatus != STATUS_SUCCESS) { // // Change to page 0 // DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress, 0x21); Status = FALSE; goto Restore3; } // // Write ~IMR // NtStatus = DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress + 0xF, (UCHAR)(~IMRValue)); if (NtStatus != STATUS_SUCCESS) { // // Change to page 0 // DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress, 0x21); Status = FALSE; goto Restore3; } // // switch to page 2 // NtStatus = DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress, 0xA1); if (NtStatus != STATUS_SUCCESS) { // // Change to page 0 // DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress, 0x21); Status = FALSE; goto Restore3; } // // Read IMR // NtStatus = DetectReadPortUchar(InterfaceType, BusNumber, IoBaseAddress + 0xF, &Value); if (NtStatus != STATUS_SUCCESS) { // // Change to page 0 // DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress, 0x21); Status = FALSE; goto Restore3; } // // Are they the same? // if ((UCHAR)(Value & 0x3F) != (UCHAR)(IMRValue)) { Status = FALSE; } // // Change to page 0 // DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress, 0x21); Restore3: DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress + 0x3, SavedOffset3); Restore2: DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress, SavedOffset0); Restore1: DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress + 0xF, SavedOffsetF); Fail: return(Status); } VOID Send8390Packet( IN INTERFACE_TYPE InterfaceType, IN ULONG BusNumber, IN ULONG IoBaseAddress, IN ULONG MemoryBaseAddress, IN COPY_ROUTINE CardCopyDownBuffer, IN UCHAR *NetworkAddress ) /*++ Routine Description: This routine creates an interrupt on an 8390 chip. The only way to do this is to actually transmit a packet. So, we put the card in loopback mode and let 'er rip. Arguments: InterfaceType - Any bus type. BusNumber - The bus number of the bus in the system. IoBaseAddress - The IoBaseAddress to check. MemoryBaseAddress - The MemoryBaseAddress (if applicable) to copy a p packet to for transmission. CardCopyDownBuffer - A routine for copying a packet onto a card. NetworkAddress - The network address of the machine. Return Value: None. --*/ { #define TEST_LEN 60 #define MAGIC_NUM 0x92 NTSTATUS NtStatus; UCHAR TestPacket[TEST_LEN] = {0}; // a dummy packet. memcpy(TestPacket, NetworkAddress, 6); memcpy(TestPacket+6, NetworkAddress, 6); TestPacket[12] = 0x00; TestPacket[13] = 0x00; TestPacket[TEST_LEN-1] = MAGIC_NUM; // // First construct TestPacket. // TestPacket[TEST_LEN-1] = MAGIC_NUM; // // Now copy down TestPacket and start the transmission. // (*CardCopyDownBuffer)(InterfaceType, BusNumber, IoBaseAddress, MemoryBaseAddress, TestPacket, TEST_LEN); NtStatus = DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress + 0x4, (UCHAR)(MemoryBaseAddress >> 8)); if (NtStatus != STATUS_SUCCESS) { return; } NtStatus = DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress + 0x6, 0x0); if (NtStatus != STATUS_SUCCESS) { return; } NtStatus = DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress + 0x5, (UCHAR)(TEST_LEN)); if (NtStatus != STATUS_SUCCESS) { return; } NtStatus = DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress, 0x26); if (NtStatus != STATUS_SUCCESS) { return; } // // We pause here to allow the xmit to complete so that we can ACK // it below - leaving the card in a valid state. // { UCHAR i; UCHAR RegValue; for (i = 0; i != 0xFF; i++) { // // check for send completion // NtStatus = DetectReadPortUchar(InterfaceType, BusNumber, IoBaseAddress + 0x7, &RegValue); if (NtStatus != STATUS_SUCCESS) { return; } if (RegValue & 0xA) { break; } } } // // Turn off any interrupts // NtStatus = DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress + 0xF, 0x00); if (NtStatus != STATUS_SUCCESS) { return; } // // Acknowledge any interrupts that are floating around. // NtStatus = DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress + 0xE, 0xFF); if (NtStatus != STATUS_SUCCESS) { return; } return; } BOOLEAN GetMcaKey( IN ULONG BusNumber, OUT PVOID *InfoHandle ) /*++ Routine Description: This routine finds the Microchannel bus with BusNumber in the registry and returns a handle for the config information. Arguments: BusNumber - The bus number of the bus to search for. InfoHandle - The resulting root in the registry. Return Value: TRUE if nothing went wrong, else FALSE. --*/ { OBJECT_ATTRIBUTES ObjectAttributes; OBJECT_ATTRIBUTES BusObjectAttributes; PWSTR McaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter"; PWSTR ConfigData = L"Configuration Data"; UNICODE_STRING RootName; UNICODE_STRING BusName; UNICODE_STRING ConfigDataName; NTSTATUS NtStatus; PKEY_BASIC_INFORMATION BasicInformation; PKEY_VALUE_FULL_INFORMATION ValueInformation; PUCHAR BufferPointer; PCM_FULL_RESOURCE_DESCRIPTOR FullResource; HANDLE McaHandle, BusHandle; ULONG BytesWritten, BytesNeeded; ULONG Index; *InfoHandle = NULL; if (BusNumber > 98) { return FALSE; } RtlInitUnicodeString(&RootName, McaPath); InitializeObjectAttributes( &ObjectAttributes, &RootName, OBJ_CASE_INSENSITIVE, (HANDLE)NULL, NULL); // // Open the root. // NtStatus = NtOpenKey(&McaHandle, KEY_READ, &ObjectAttributes); if (!NT_SUCCESS(NtStatus)) { return FALSE; } Index = 0; while (TRUE) { // // Enumerate through keys, searching for the proper bus number // NtStatus = NtEnumerateKey( McaHandle, Index, KeyBasicInformation, NULL, 0, &BytesNeeded); // // That should fail! // if (BytesNeeded == 0) { Index++; continue; } BasicInformation = (PKEY_BASIC_INFORMATION)DetectAllocateHeap(BytesNeeded); if (BasicInformation == NULL) { NtClose(McaHandle); return FALSE; } NtStatus = NtEnumerateKey( McaHandle, Index, KeyBasicInformation, BasicInformation, BytesNeeded, &BytesWritten); if (!NT_SUCCESS(NtStatus)) { DetectFreeHeap(BasicInformation); NtClose(McaHandle); return FALSE; } // // Init the BusName String // BusName.MaximumLength = (USHORT)(BasicInformation->NameLength); BusName.Length = (USHORT)(BasicInformation->NameLength); BusName.Buffer = BasicInformation->Name; // // Now try to find Configuration Data within this Key // InitializeObjectAttributes( &BusObjectAttributes, &BusName, OBJ_CASE_INSENSITIVE, (HANDLE)McaHandle, NULL); // // Open the MCA root + Bus Number // NtStatus = NtOpenKey( &BusHandle, KEY_READ, &BusObjectAttributes); DetectFreeHeap(BasicInformation); if (!NT_SUCCESS(NtStatus)) { Index++; continue; } // // opening the configuration data. This first call tells us how // much memory we need to allocate // RtlInitUnicodeString(&ConfigDataName, ConfigData); // // This should fail // NtStatus = NtQueryValueKey( BusHandle, &ConfigDataName, KeyValueFullInformation, NULL, 0, &BytesNeeded); ValueInformation = (PKEY_VALUE_FULL_INFORMATION)DetectAllocateHeap(BytesNeeded); if (ValueInformation == NULL) { Index++; NtClose(BusHandle); continue; } NtStatus = NtQueryValueKey( BusHandle, &ConfigDataName, KeyValueFullInformation, ValueInformation, BytesNeeded, &BytesWritten); if (!NT_SUCCESS(NtStatus)) { Index++; DetectFreeHeap(ValueInformation); NtClose(BusHandle); continue; } // // Search for our bus number and type // // // What we got back from the registry is actually a blob of data that // looks like this // // ------------------------------------------ // |FULL |PAR |PAR |MCA |MCA |MCA | // |RES. |RES |RES |POS |POS |POS | . . . // |DESC |LIST|DESC|DATA|DATA|DATA| // ------------------------------------------ // slot 0 1 2 . . . // // Out of this mess we need to grovel a pointer to the first block // of MCA_POS_DATA, then we can just index by slot number. // if (ValueInformation->DataLength == 0) { // // Get next key // DetectFreeHeap(ValueInformation); Index++; NtClose(BusHandle); continue; } BufferPointer = ((PUCHAR)ValueInformation) + ValueInformation->DataOffset; FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR) BufferPointer; if (FullResource->InterfaceType != MicroChannel) { // // Get next key // DetectFreeHeap(ValueInformation); Index++; NtClose(BusHandle); continue; } if (FullResource->BusNumber != BusNumber) { // // Get next key // DetectFreeHeap(ValueInformation); Index++; NtClose(BusHandle); continue; } // // Found it!! // *InfoHandle = ValueInformation; NtClose(McaHandle); return(TRUE); } } BOOLEAN GetMcaPosId( IN PVOID BusHandle, IN ULONG SlotNumber, OUT PULONG PosId ) /*++ Routine Description: This routine returns the PosId of an adapter in SlotNumber of an MCA bus. Arguments: BusHandle - Handle returned by GetMcaKey(). SlotNumber - the desired slot number PosId - the PosId. Return Value: TRUE if nothing went wrong, else FALSE. --*/ { PKEY_VALUE_FULL_INFORMATION ValueInformation = (PKEY_VALUE_FULL_INFORMATION)(BusHandle); PCM_FULL_RESOURCE_DESCRIPTOR FullResource; PUCHAR BufferPointer; PCM_PARTIAL_RESOURCE_LIST ResourceList; ULONG i; ULONG TotalSlots; PCM_MCA_POS_DATA PosData; BufferPointer = ((PUCHAR)ValueInformation) + ValueInformation->DataOffset; FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR) BufferPointer; ResourceList = &FullResource->PartialResourceList; // // Find the device-specific information, which is where the POS data is. // for (i = 0; i < ResourceList->Count; i++) { if (ResourceList->PartialDescriptors[i].Type == CmResourceTypeDeviceSpecific) { break; } } if (i == ResourceList->Count) { // // Couldn't find device-specific information. // return FALSE; } TotalSlots = ResourceList->PartialDescriptors[i].u.DeviceSpecificData.DataSize; TotalSlots = TotalSlots / sizeof(CM_MCA_POS_DATA); if (SlotNumber <= TotalSlots) { PosData = (PCM_MCA_POS_DATA)(&ResourceList->PartialDescriptors[i+1]); PosData += (SlotNumber - 1); *PosId = PosData->AdapterId; return(TRUE); } return(FALSE); } VOID DeleteMcaKey( IN PVOID BusHandle ) /*++ Routine Description: This routine frees resources associated with an MCA handle. Arguments: BusHandle - Handle returned by GetMcaKey(). Return Value: None. --*/ { DetectFreeHeap(BusHandle); } BOOLEAN GetEisaKey( IN ULONG BusNumber, OUT PVOID *InfoHandle ) /*++ Routine Description: This routine finds the Eisa bus with BusNumber in the registry and returns a handle for the config information. Arguments: BusNumber - The bus number of the bus to search for. InfoHandle - The resulting root in the registry. Return Value: TRUE if nothing went wrong, else FALSE. --*/ { OBJECT_ATTRIBUTES ObjectAttributes; OBJECT_ATTRIBUTES BusObjectAttributes; PWSTR EisaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\EisaAdapter"; PWSTR ConfigData = L"Configuration Data"; UNICODE_STRING RootName; UNICODE_STRING BusName; UNICODE_STRING ConfigDataName; NTSTATUS NtStatus; PKEY_BASIC_INFORMATION BasicInformation; PKEY_VALUE_FULL_INFORMATION ValueInformation; PUCHAR BufferPointer; PCM_FULL_RESOURCE_DESCRIPTOR FullResource; HANDLE EisaHandle, BusHandle; ULONG BytesWritten, BytesNeeded; ULONG Index; *InfoHandle = NULL; if (BusNumber > 98) { return FALSE; } RtlInitUnicodeString(&RootName, EisaPath); InitializeObjectAttributes( &ObjectAttributes, &RootName, OBJ_CASE_INSENSITIVE, (HANDLE)NULL, NULL); // // Open the root. // NtStatus = NtOpenKey(&EisaHandle, KEY_READ, &ObjectAttributes); if (!NT_SUCCESS(NtStatus)) { return FALSE; } Index = 0; while (TRUE) { // // Enumerate through keys, searching for the proper bus number // NtStatus = NtEnumerateKey( EisaHandle, Index, KeyBasicInformation, NULL, 0, &BytesNeeded); // // That should fail! // if (BytesNeeded == 0) { Index++; continue; } BasicInformation = (PKEY_BASIC_INFORMATION)DetectAllocateHeap(BytesNeeded); if (BasicInformation == NULL) { NtClose(EisaHandle); return FALSE; } NtStatus = NtEnumerateKey( EisaHandle, Index, KeyBasicInformation, BasicInformation, BytesNeeded, &BytesWritten); if (!NT_SUCCESS(NtStatus)) { DetectFreeHeap(BasicInformation); NtClose(EisaHandle); return FALSE; } // // Init the BusName String // BusName.MaximumLength = (USHORT)(BasicInformation->NameLength); BusName.Length = (USHORT)(BasicInformation->NameLength); BusName.Buffer = BasicInformation->Name; // // Now try to find Configuration Data within this Key // InitializeObjectAttributes( &BusObjectAttributes, &BusName, OBJ_CASE_INSENSITIVE, (HANDLE)EisaHandle, NULL); // // Open the EISA root + Bus Number // NtStatus = NtOpenKey(&BusHandle, KEY_READ, &BusObjectAttributes); DetectFreeHeap(BasicInformation); if (!NT_SUCCESS(NtStatus)) { Index++; continue; } // // opening the configuration data. This first call tells us how // much memory we need to allocate // RtlInitUnicodeString(&ConfigDataName, ConfigData); // // This should fail // NtStatus = NtQueryValueKey( BusHandle, &ConfigDataName, KeyValueFullInformation, NULL, 0, &BytesNeeded); ValueInformation = (PKEY_VALUE_FULL_INFORMATION)DetectAllocateHeap(BytesNeeded); if (ValueInformation == NULL) { Index++; NtClose(BusHandle); continue; } NtStatus = NtQueryValueKey( BusHandle, &ConfigDataName, KeyValueFullInformation, ValueInformation, BytesNeeded, &BytesWritten); if (!NT_SUCCESS(NtStatus)) { Index++; DetectFreeHeap(ValueInformation); NtClose(BusHandle); continue; } if (ValueInformation->DataLength == 0) { Index++; NtClose(BusHandle); continue; } // // Search for our bus number and type // BufferPointer = ((PUCHAR)ValueInformation) + ValueInformation->DataOffset; FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR) BufferPointer; if (FullResource->InterfaceType != Eisa) { // // Get next key // DetectFreeHeap(ValueInformation); Index++; NtClose(BusHandle); continue; } if (FullResource->BusNumber != BusNumber) { // // Get next key // DetectFreeHeap(ValueInformation); Index++; NtClose(BusHandle); continue; } // // Found it!! // *InfoHandle = ValueInformation; NtClose(EisaHandle); return(TRUE); } } BOOLEAN GetEisaCompressedId( IN PVOID BusHandle, IN ULONG SlotNumber, OUT PULONG CompressedId, IN ULONG Mask ) /*++ Routine Description: This routine returns the PosId of an adapter in SlotNumber of an Eisa bus. Arguments: BusHandle - Handle returned by GetEisaKey(). SlotNumber - the desired slot number CompressedId - EISA Id in the slot desired. Mask - Mask to apply to the ID. Return Value: TRUE if nothing went wrong, else FALSE. --*/ { PKEY_VALUE_FULL_INFORMATION ValueInformation = (PKEY_VALUE_FULL_INFORMATION)(BusHandle); PCM_FULL_RESOURCE_DESCRIPTOR FullResource; PUCHAR BufferPointer; PCM_PARTIAL_RESOURCE_LIST ResourceList; PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor; ULONG i; ULONG TotalDataSize; ULONG SlotDataSize; PCM_EISA_SLOT_INFORMATION SlotInformation; BufferPointer = ((PUCHAR)ValueInformation) + ValueInformation->DataOffset; FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR) BufferPointer; ResourceList = &FullResource->PartialResourceList; // // Find the device-specific information, which is where the POS data is. // for (i = 0; i < ResourceList->Count; i++) { if (ResourceList->PartialDescriptors[i].Type == CmResourceTypeDeviceSpecific) { break; } } if (i == ResourceList->Count) { // // Couldn't find device-specific information. // return FALSE; } // // Bingo! // ResourceDescriptor = &(ResourceList->PartialDescriptors[i]); TotalDataSize = ResourceDescriptor->u.DeviceSpecificData.DataSize; SlotInformation = (PCM_EISA_SLOT_INFORMATION) ((PUCHAR)ResourceDescriptor + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); while (((LONG)TotalDataSize) > 0) { if (SlotInformation->ReturnCode == EISA_EMPTY_SLOT) { SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION); } else { SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION) + SlotInformation->NumberFunctions * sizeof(CM_EISA_FUNCTION_INFORMATION); } if (SlotDataSize > TotalDataSize) { // // Something is wrong again // return FALSE; } if (SlotNumber != 0) { SlotNumber--; SlotInformation = (PCM_EISA_SLOT_INFORMATION) ((PUCHAR)SlotInformation + SlotDataSize); TotalDataSize -= SlotDataSize; continue; } // // This is our slot // break; } if ((SlotNumber != 0) || (TotalDataSize == 0)) { // // No such slot number // return(FALSE); } // // End loop // *CompressedId = SlotInformation->CompressedId & Mask; return(TRUE); } VOID DeleteEisaKey( IN PVOID BusHandle ) /*++ Routine Description: This routine frees resources associated with an EISA handle. Arguments: BusHandle - Handle returned by GetEisaKey(). Return Value: None. --*/ { DetectFreeHeap(BusHandle); } BOOLEAN PcmciaGetCardInfo( OUT PHANDLE phCardInfo, IN PWSTR pCardName ) /*+++ Description: This routine takes a card name and finds the information for it in the registry. Returns: BOOLEAN - TRUE if phCardInfo is a valid handle to the card. Histroy: 1/4/95 [kyleb] created. ---*/ { OBJECT_ATTRIBUTES ObjectAttributes; PWSTR PcmciaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\PCMCIA PCCARDs"; UNICODE_STRING RootName; NTSTATUS Status; HANDLE hPcmcia; ULONG c; ULONG cbNeeded; ULONG cbRead; UNICODE_STRING CardName; UNICODE_STRING ValueName; PKEY_VALUE_BASIC_INFORMATION pValueInfo1; PKEY_VALUE_FULL_INFORMATION pValueInfo2; // // Initialize the card information handle. // *phCardInfo = NULL; // // Turn our card name into a UNICODE_STRING. // RtlInitUnicodeString(&CardName, pCardName); // // Initialize the root name with the path to // the pcmcia card information. // RtlInitUnicodeString(&RootName, PcmciaPath); // // Initialize the attributes for the root. // InitializeObjectAttributes( &ObjectAttributes, &RootName, OBJ_CASE_INSENSITIVE, (HANDLE)NULL, NULL); // // Open the root. // Status = NtOpenKey(&hPcmcia, KEY_READ, &ObjectAttributes); if (!NT_SUCCESS(Status)) return(FALSE); // // Now enumerate the adapter type passed us. // for (c = 0, pValueInfo1 = NULL; ; c++) { // // Determine the amount of buffer space needed. // Status = NtEnumerateValueKey( hPcmcia, c, KeyValueBasicInformation, NULL, 0, &cbNeeded); if (0 == cbNeeded) continue; // // Get the name of the value. // pValueInfo1 = (PKEY_VALUE_BASIC_INFORMATION)DetectAllocateHeap(cbNeeded); if (NULL == pValueInfo1) { // // BUGBUG // Return that out of memory status code (i'm lazy). // return(FALSE); } // // Read in the basic information on the value entry; // this includes the type of the value and the name. // Status = NtEnumerateValueKey( hPcmcia, c, KeyValueBasicInformation, pValueInfo1, cbNeeded, &cbRead); if (!NT_SUCCESS(Status)) { DetectFreeHeap(pValueInfo1); break; } // // Turn the value name into a UNICODE_STRING. // ValueName.Buffer = DetectAllocateHeap(pValueInfo1->NameLength + sizeof(WCHAR)); if (NULL == ValueName.Buffer) { DetectFreeHeap(pValueInfo1); break; } // // Copy the string data. // RtlMoveMemory(ValueName.Buffer, pValueInfo1->Name, pValueInfo1->NameLength); // // Save the unicode string's length. // ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInfo1->NameLength; // // Place the NULL at the end of the string. // ValueName.Buffer[ValueName.Length / 2] = (WCHAR)'\0'; // // We no longer need the pValueInfo1 pointer. // DetectFreeHeap(pValueInfo1); // // Is this the value that we are looking for? // if (RtlEqualUnicodeString(&ValueName, &CardName, TRUE)) { // // We have a match! // Get the resource information and return a pointer to it. // // // First query the value to determine the amount of // resource data. // NtQueryValueKey( hPcmcia, &ValueName, KeyValueFullInformation, NULL, 0, &cbNeeded); // // Allocate a buffer for the information. // pValueInfo2 = (PKEY_VALUE_FULL_INFORMATION)DetectAllocateHeap(cbNeeded); if (NULL == pValueInfo2) { DetectFreeHeap(ValueName.Buffer); break; } // // Read in the full value information. // Status = NtQueryValueKey( hPcmcia, &ValueName, KeyValueFullInformation, pValueInfo2, cbNeeded, &cbRead); if (!NT_SUCCESS(Status)) { // // Free the value information. // DetectFreeHeap(ValueName.Buffer); DetectFreeHeap(pValueInfo2); break; } // // We've now got what we need! // *phCardInfo = (HANDLE)pValueInfo2; // // Free up value information. // DetectFreeHeap(ValueName.Buffer); break; } // // Free the value information. // DetectFreeHeap(ValueName.Buffer); } // // Close the PCMCIA registry handle. // NtClose(hPcmcia); // // Do we have any data to return? // if (NULL == *phCardInfo) { // // We don't have any data to return to the caller. // return(FALSE); } return(TRUE); } //** PcmciaGetCardInfo() VOID PcmciaFreeCardInfo( HANDLE hCardInfo ) /*+++ Description: This routine will free the card information that was allocated by PcmciaGetCardInfo(). Returns: VOID Histroy: 1/4/95 [kyleb] created. ---*/ { DetectFreeHeap((PVOID)hCardInfo); } //** PcmciaFreeCardInfo() BOOLEAN PcmciaQueryCardResource( OUT PVOID *ppvValue, IN HANDLE hCardInfo, IN ULONG ulResource ) /*+++ Description: This routine will find the resource for the card described by the card information handle and return it in the location passed in. NOTE: THE VALUES THAT ARE RETURNED FROM THIS STRUCTURE ARE VALID ONLY AS LONG AS THE hCardInfo PARAMETER IS!!!!!! ONCE PcmciaFreeCardInfo() IS CALLED ON THIS HANDLE THESE VALUES ARE TOAST. Returns: BOOLEAN - TRUE if the resource was successfully returned. Histroy: 1/4/95 [kyleb] created. ---*/ { PCM_FULL_RESOURCE_DESCRIPTOR pFullDesc; PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialDesc; ULONG c; // // Validate the handle (somewhat). // if (NULL == hCardInfo) return(FALSE); // // Get a pointer to the resource data. // pFullDesc = (PVOID)((PUCHAR)hCardInfo + ((PKEY_VALUE_FULL_INFORMATION)hCardInfo)->DataOffset); // // Find the resource needed. // for (c = 0; c < pFullDesc->PartialResourceList.Count; c++) { // // Get a pointer to the current resource list entry. // pPartialDesc = &pFullDesc->PartialResourceList.PartialDescriptors[c]; // // Is this the one we are looking for? // if (pPartialDesc->Type == (UCHAR)ulResource) { // // Return a pointer to the resource descriptor. // *ppvValue = pPartialDesc; return(TRUE); } } return(FALSE); } //** PcmciaQueryCardResource() VOID NcDetectFindOtherHardware( INTERFACE_TYPE InterfaceType, ULONG BusNumber ) /*++ Routine Description: This routine will search for non-network hardware which will cause this DLL to hang. If it finds one, it will grab those resources so that when a Check for resource free is done it will fail. Arguments: InterfaceType - Any bus type. BusNumber - The bus number of the bus in the system. Return Value: None. --*/ { SoundBlaster(InterfaceType, BusNumber); } NTSTATUS NcDetectTemporaryClaimResource( IN PNETDTECT_RESOURCE Resource ) { Resource->InterfaceType = Isa; Resource->BusNumber = 0; #if _DBG DbgPrint( "NcDetectTemporaryClaimResource()\n" " Interface: %x\n" " BusNumber: %x\n" " Type : %s\n" " Value : %x\n" " Length : %x\n" " Flags : %x\n", Resource->InterfaceType, Resource->BusNumber, (Resource->Type == 1) ? "IRQ" : (Resource->Type == 2) ? "MEMORY" : (Resource->Type == 3) ? "PORT" : "DMA", Resource->Value, Resource->Length, Resource->Flags ); #endif return(DetectTemporaryClaimResource(Resource)); } NTSTATUS NcDetectFreeSpecificTemporaryResource( IN PNETDTECT_RESOURCE Resource ) /*++ Routine Description: Arguments: Return Value: --*/ { return(DetectFreeSpecificTemporaryResource(Resource)); } NTSTATUS NcDetectFreeTemporaryResource( VOID ) { #if _DBG DbgPrint("NcDetectFreeTemporaryResource()\n"); #endif return(DetectFreeTemporaryResources()); } BOOLEAN QueryAdapterInformation( IN HANDLE AdapterHandle, OUT PCOMMON_ADAPTER_INFO Adapter ) /*++ Routine Description: Arguments: Return Value: --*/ { UNICODE_STRING NetDetectKeyValue; UINT BytesNeeded; NTSTATUS NtStatus; PKEY_VALUE_PARTIAL_INFORMATION pValueInfo; PWSTR Id = L"Id"; PWSTR Mask = L"Mask"; PWSTR Token = L"token"; // // Build a unicode string to query the eisa token. // RtlInitUnicodeString(&NetDetectKeyValue, Token); // // Determine how much memory we need to get the value. // BytesNeeded = 0; NtQueryValueKey( AdapterHandle, &NetDetectKeyValue, KeyValuePartialInformation, NULL, 0, &BytesNeeded); if (0 == BytesNeeded) { #if _DBG DbgPrint("Unable to get the size of the value information for token\n"); #endif return(FALSE); } // // Allocate space to hold the partial value information. // pValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)DetectAllocateHeap(BytesNeeded); if (NULL == pValueInfo) { #if _DBG DbgPrint("Unable to allocate memory for the value information for the token\n"); #endif return(FALSE); } // // Get the value information for the id. // NtStatus = NtQueryValueKey( AdapterHandle, &NetDetectKeyValue, KeyValuePartialInformation, pValueInfo, BytesNeeded, &BytesNeeded); if (!NT_SUCCESS(NtStatus)) { #if _DBG DbgPrint("Failed to query the value for key index\n"); #endif DetectFreeHeap(pValueInfo); return(FALSE); } // // Allocate memory for the token. // Adapter->InfId = DetectAllocateHeap(pValueInfo->DataLength + sizeof(WCHAR)); if (NULL == Adapter->InfId) { DetectFreeHeap(pValueInfo); return(FALSE); } RtlZeroMemory(Adapter->InfId, pValueInfo->DataLength + sizeof(WCHAR)); RtlCopyMemory(Adapter->InfId, pValueInfo->Data, pValueInfo->DataLength); // // Free the value information pointer. // DetectFreeHeap(pValueInfo); // // Build a unicode string to query the id. // RtlInitUnicodeString(&NetDetectKeyValue, Id); // // Determine how much memory we need to get the value. // BytesNeeded = 0; NtQueryValueKey( AdapterHandle, &NetDetectKeyValue, KeyValuePartialInformation, NULL, 0, &BytesNeeded); if (0 == BytesNeeded) { #if _DBG DbgPrint("Unable to get the size of the value information for id\n"); #endif return(FALSE); } // // Allocate space to hold the partial value information. // pValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)DetectAllocateHeap(BytesNeeded); if (NULL == pValueInfo) { #if _DBG DbgPrint("Unable to allocate memory for the value information for the id\n"); #endif return(FALSE); } // // Get the value information for the id. // NtStatus = NtQueryValueKey( AdapterHandle, &NetDetectKeyValue, KeyValuePartialInformation, pValueInfo, BytesNeeded, &BytesNeeded); if (!NT_SUCCESS(NtStatus)) { #if _DBG DbgPrint("Failed to query the value for key index\n"); #endif DetectFreeHeap(pValueInfo); return(FALSE); } // // Save the value. // Adapter->Id = *((PULONG)(pValueInfo->Data)); // // Free the value information pointer. // DetectFreeHeap(pValueInfo); // // Build a unicode string to query the mask. // RtlInitUnicodeString(&NetDetectKeyValue, Mask); // // Determine how much memory we need to get the value. // BytesNeeded = 0; NtStatus = NtQueryValueKey( AdapterHandle, &NetDetectKeyValue, KeyValuePartialInformation, NULL, 0, &BytesNeeded); if (STATUS_OBJECT_NAME_NOT_FOUND == NtStatus) { // // If there is no mask value then assume it's the whole id // and get out. // Adapter->Mask = 0xffffffff; return(TRUE); } if (0 == BytesNeeded) { #if _DBG DbgPrint("Unable to get the size of the value information for mask\n"); #endif return(FALSE); } // // Allocate space to hold the partial value information. // pValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)DetectAllocateHeap(BytesNeeded); if (NULL == pValueInfo) { #if _DBG DbgPrint("Unable to allocate memory for the value information for the mask\n"); #endif return(FALSE); } // // Get the value information for the mask. // NtStatus = NtQueryValueKey( AdapterHandle, &NetDetectKeyValue, KeyValuePartialInformation, pValueInfo, BytesNeeded, &BytesNeeded); if (!NT_SUCCESS(NtStatus)) { #if _DBG DbgPrint("Failed to query the value for key index\n"); #endif DetectFreeHeap(pValueInfo); return(FALSE); } // // Save the value. // Adapter->Mask = *((PULONG)(pValueInfo->Data)); // // Free the value information pointer. // DetectFreeHeap(pValueInfo); return(TRUE); } BOOLEAN GetAdapterBasicInformation( IN HANDLE BusHandle, IN UINT Count, IN PKEY_BASIC_INFORMATION *pBasicInformation ) /*++ Routine Description: Arguments: Return Value: --*/ { NTSTATUS NtStatus; UINT BytesNeeded; PKEY_BASIC_INFORMATION BasicInfo; // // Determine how big an information buffer is needed. // NtStatus = NtEnumerateKey( BusHandle, Count, KeyBasicInformation, NULL, 0, &BytesNeeded); // // allocate a buffer // BasicInfo = (PKEY_BASIC_INFORMATION)DetectAllocateHeap(BytesNeeded); if (NULL == BasicInfo) { #if _DBG DbgPrint("Failed to get basic information size for key\n"); #endif *pBasicInformation = NULL; return(FALSE); } // // Get the basic information for the key. // NtStatus = NtEnumerateKey( BusHandle, Count, KeyBasicInformation, BasicInfo, BytesNeeded, &BytesNeeded); if (NtStatus != STATUS_SUCCESS) { #if _DBG DbgPrint("Failed to get basic information for key\n"); #endif DetectFreeHeap(BasicInfo); *pBasicInformation = NULL; return(FALSE); } *pBasicInformation = BasicInfo; return(TRUE); } BOOLEAN GetNumberOfAdaptersSupported( IN HANDLE BusHandle, OUT PUINT NumberOfAdapters, OUT PUINT MaxSubKeyLength ) /*++ Routine Description: Arguments: Return Value: --*/ { PKEY_FULL_INFORMATION pFullKeyInformation; NTSTATUS NtStatus; UINT BytesNeeded; // // We need to get the number of sub-keys under the bus specific // section. To do this we need to read in the full key information. // NtStatus = NtQueryKey( BusHandle, KeyFullInformation, NULL, 0, &BytesNeeded); if (NtStatus != STATUS_BUFFER_TOO_SMALL) { #if _DBG DbgPrint("Failed to get the size of the full key information for the bus\n"); #endif return(FALSE); } // // Allocate a buffer for this information. // pFullKeyInformation = (PKEY_FULL_INFORMATION)DetectAllocateHeap(BytesNeeded); if (NULL == pFullKeyInformation) { #if _DBG DbgPrint("Failed to query the number of subkeys under bus key\n"); #endif return(FALSE); } // // Get the actual key information. // NtStatus = NtQueryKey( BusHandle, KeyFullInformation, pFullKeyInformation, BytesNeeded, &BytesNeeded); if (NtStatus != STATUS_SUCCESS) { #if _DBG DbgPrint("Failed to read the full key information for the bus\n"); #endif return(FALSE); } // // Get the number of sub-keys, this is the number of adapters for the // bus. // *NumberOfAdapters = pFullKeyInformation->SubKeys; *MaxSubKeyLength = pFullKeyInformation->MaxNameLen; // // We are done with the key information. // DetectFreeHeap(pFullKeyInformation); return(TRUE); } VOID CloseBusSpecificRegistryKey( IN HANDLE BusHandle, IN UNICODE_STRING *NetDetectRootName ) /*++ Routine Description: Arguments: Return Value: --*/ { if (NetDetectRootName->Buffer != NULL) { DetectFreeHeap(NetDetectRootName->Buffer); } if (BusHandle != NULL) { NtClose(BusHandle); } } BOOLEAN OpenBusSpecificRegistryKey( IN PWSTR DetectPath, IN PWSTR BusName, OUT UNICODE_STRING *NetDetectRootName, OUT HANDLE *BusHandle ) /*++ Routine Description: Arguments: Return Value: --*/ { UNICODE_STRING TempString; OBJECT_ATTRIBUTES ObjectAttributes; PWSTR FullDetectPath; NTSTATUS NtStatus; UINT FullDetectPathLength; // // Determine the length of the string that we need to allocate. // FullDetectPathLength = (wcslen(DetectPath) * sizeof(WCHAR)) + (wcslen(BusName) * sizeof(WCHAR)) + sizeof(WCHAR); // // Allocate memory for the string buffer. // FullDetectPath = (PWSTR)DetectAllocateHeap(FullDetectPathLength); if (NULL == FullDetectPath) { #if _DBG DbgPrint("Failed to allocate memory for the full detection path\n"); #endif *BusHandle = NULL; return(FALSE); } // // Initialize the unicode string. // RtlCopyMemory(FullDetectPath, DetectPath, (wcslen(DetectPath) * sizeof(WCHAR))); NetDetectRootName->Buffer = FullDetectPath; NetDetectRootName->Length = (wcslen(DetectPath) * sizeof(WCHAR)); NetDetectRootName->MaximumLength = FullDetectPathLength; // // Append the bus name to the end of the detection path. // NtStatus = RtlAppendUnicodeToString( NetDetectRootName, BusName); if (NtStatus != STATUS_SUCCESS) { #if _DBG DbgPrint("Unable to append the bus name to the registry path!\n"); #endif *BusHandle = NULL; DetectFreeHeap(FullDetectPath); return(FALSE); } // // Initialize the attributes of the registry key. // InitializeObjectAttributes( &ObjectAttributes, NetDetectRootName, OBJ_CASE_INSENSITIVE, (HANDLE)NULL, NULL); // // Open the key for the eisa information. // NtStatus = NtOpenKey(BusHandle, KEY_READ, &ObjectAttributes); if (!NT_SUCCESS(NtStatus)) { #if _DBG DbgPrint("Failed to open bus key\n"); #endif *BusHandle = NULL; return(FALSE); } return(TRUE); } BOOLEAN LoadAdapterInformation( IN PWSTR BusName, IN UINT AdapterEntrySize, OUT PVOID *AdapterList, OUT UINT *CountOfAdapters ) /*++ Routine Description: Arguments: Return Value: --*/ { UNICODE_STRING NetDetectKeyName; UNICODE_STRING NetDetectRootName; OBJECT_ATTRIBUTES ObjectAttributes; PWSTR DetectPath = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\NDIS\\NetDetect\\"; PWSTR CurrentKeyPath; NTSTATUS NtStatus; HANDLE BusHandle; HANDLE AdapterHandle; HANDLE CurrentAdapterHandle; ULONG Count; PKEY_BASIC_INFORMATION pBasicKeyInformation; ULONG BytesNeeded; BOOLEAN fStatus; PWSTR AdapterName; UINT MaxSubKeyLength; PCOMMON_ADAPTER_INFO pAdapterList; UINT NumberOfAdapters; BOOLEAN fBusHandleOpened = FALSE; BOOLEAN fAllocatedAdapterList = FALSE; BOOLEAN fAllocatedCurrentKeyPath = FALSE; BOOLEAN fAllocatedBasicInformation = FALSE; BOOLEAN fOpenedSubKey = FALSE; BOOLEAN fAllocatedAdapterName = FALSE; do { // // Open the bus specific detection information. // fStatus = OpenBusSpecificRegistryKey( DetectPath, BusName, &NetDetectRootName, &BusHandle); if (!fStatus) { break; } fBusHandleOpened = TRUE; // // Get the number of sub-keys under the bus key. // this is the number of adapters that we will be attempting to // detect. // fStatus = GetNumberOfAdaptersSupported( BusHandle, &NumberOfAdapters, &MaxSubKeyLength); if (!fStatus) { break; } // // Allocate memory for the adapter array. // We also need to allocate memory for the InfId or Option name. // This extra memory is allocated at the end of the array and the // pointers to the name are fixed up. // pAdapterList = (PCOMMON_ADAPTER_INFO)DetectAllocateHeap( NumberOfAdapters * AdapterEntrySize); if (NULL == pAdapterList) { #if _DBG DbgPrint("Unable to allocate memory for the adapter information array\n"); #endif break; } fAllocatedAdapterList = TRUE; // // Zero out the adapter list contents. // RtlZeroMemory(pAdapterList, NumberOfAdapters * AdapterEntrySize); // // Add the terminating NULL... // MaxSubKeyLength += sizeof(WCHAR); // // Build the unicode name for the adapter. // AdapterName = (PWSTR)DetectAllocateHeap(MaxSubKeyLength); if (NULL == AdapterName) { #if _DBG DbgPrint("Failed to allocate memory for the adapter name\n"); #endif continue; } fAllocatedAdapterName = TRUE; // // Read in the information for each adapter. // for (Count = 0, fStatus = TRUE; (Count < NumberOfAdapters) && fStatus; Count++) { // // Initialize the adapter information entry. // pAdapterList[Count].Index = (Count * 100) + 1000; // // Get an adapters basic information. // fStatus = GetAdapterBasicInformation( BusHandle, Count, &pBasicKeyInformation); if (!fStatus) { #if _DBG DbgPrint("Failed to get the basic information for sub-key\n"); #endif continue; } fAllocatedBasicInformation = TRUE; RtlZeroMemory(AdapterName, MaxSubKeyLength); RtlCopyMemory( AdapterName, pBasicKeyInformation->Name, pBasicKeyInformation->NameLength); // // Construct a unicode string from the buffer that was stored // with the adapter list. We know this will stick around for // a while so it's cool. // RtlInitUnicodeString(&NetDetectKeyName, AdapterName); // // Initialize the attributes for the registry sub-key. // InitializeObjectAttributes( &ObjectAttributes, &NetDetectKeyName, OBJ_CASE_INSENSITIVE, BusHandle, NULL); // // Open the sub-key so we can query it. // NtStatus = NtOpenKey( &AdapterHandle, KEY_READ, &ObjectAttributes); if (!NT_SUCCESS(NtStatus)) { #if _DBG DbgPrint("Failed to open the sub-key index[%u]\n", Count); #endif fStatus = FALSE; continue; } fOpenedSubKey = TRUE; // // Query the adapter information. // fStatus = QueryAdapterInformation(AdapterHandle, &pAdapterList[Count]); if (!fStatus) { #if _DBG DbgPrint("Unable to query the id for the adapter\n"); #endif continue; } NtClose(AdapterHandle); fOpenedSubKey = FALSE; // // Free the buffer for the basic key information. // DetectFreeHeap(pBasicKeyInformation); fAllocatedBasicInformation = FALSE; } } while (FALSE); if (fOpenedSubKey) { NtClose(AdapterHandle); } if (fAllocatedAdapterName) { DetectFreeHeap(AdapterName); } if (fAllocatedCurrentKeyPath) { DetectFreeHeap(CurrentKeyPath); } if (fBusHandleOpened) { CloseBusSpecificRegistryKey(BusHandle, &NetDetectRootName); } if ((Count != NumberOfAdapters) || !fStatus) { if (fAllocatedBasicInformation); { DetectFreeHeap(pBasicKeyInformation); } FreeAdapterInformation(pAdapterList, Count); return(FALSE); } // // Save the pointer to the adapter list. // *AdapterList = pAdapterList; *CountOfAdapters = NumberOfAdapters; return(TRUE); } VOID FreeAdapterInformation( IN PVOID AdapterList, IN UINT NumberOfAdapters ) /*++ Routine Description: Arguments: Return Value: --*/ { PCOMMON_ADAPTER_INFO pAdapterList = AdapterList; UINT Count; if (NULL == pAdapterList) { return; } for (Count = 0; Count < NumberOfAdapters; Count++) { if (NULL != pAdapterList[Count].InfId) { DetectFreeHeap(pAdapterList[Count].InfId); } } DetectFreeHeap(pAdapterList); } VOID AcquireAllPcmciaResources( VOID ) /*++ Routine Description: Arguments: Return Value: --*/ { OBJECT_ATTRIBUTES ObjectAttributes; PWSTR PcmciaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\PCMCIA PCCARDs"; UNICODE_STRING RootName; NTSTATUS Status; HANDLE hPcmcia = NULL; ULONG c; ULONG cResource; ULONG cbNeeded; ULONG cbRead; UNICODE_STRING CardName; UNICODE_STRING ValueName; PKEY_FULL_INFORMATION pKeyInfo; PKEY_VALUE_BASIC_INFORMATION pValueInfo1; PKEY_VALUE_FULL_INFORMATION pValueInfo2; PCM_FULL_RESOURCE_DESCRIPTOR pFullResource; PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialResource; NETDTECT_RESOURCE Resource; // // Initialize the root name with the path to // the pcmcia card information. // RtlInitUnicodeString(&RootName, PcmciaPath); // // Initialize the attributes for the root. // InitializeObjectAttributes( &ObjectAttributes, &RootName, OBJ_CASE_INSENSITIVE, (HANDLE)NULL, NULL); // // Open the root. // Status = NtOpenKey(&hPcmcia, KEY_READ, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DBGPRINT(("Failed to open the PCMCIA PCCARDs registry key\n")); DBGPRINT(("<==AcquireAllPcmciaResources\n")); return; } // // Get the number of keys // NtQueryKey(hPcmcia, KeyFullInformation, NULL, 0, &cbNeeded); pKeyInfo = (PKEY_FULL_INFORMATION)DetectAllocateHeap(cbNeeded); if (NULL == pKeyInfo) { DBGPRINT(("Failed to allocate a buffer for the full key information\n")); return; } Status = NtQueryKey( hPcmcia, KeyFullInformation, pKeyInfo, sizeof(KEY_FULL_INFORMATION), &cbRead); if (!NT_SUCCESS(Status)) { DBGPRINT(("Failed to read the full key information. Status 0x%x\n", Status)); DetectFreeHeap(pKeyInfo); return; } pValueInfo1 = NULL; ValueName.Buffer = NULL; // // Now enumerate the adapter type passed us. // for (c = 0, pValueInfo1 = NULL; c < pKeyInfo->Values; c++) { // // Determine the amount of buffer space needed. // NtEnumerateValueKey( hPcmcia, c, KeyValueBasicInformation, NULL, 0, &cbNeeded); // // Get the name of the value. // pValueInfo1 = (PKEY_VALUE_BASIC_INFORMATION)DetectAllocateHeap(cbNeeded); if (NULL == pValueInfo1) { DBGPRINT(("Failed to allocate space for basic value information\n")); break; } // // Read in the basic information on the value entry; // this includes the type of the value and the name. // Status = NtEnumerateValueKey( hPcmcia, c, KeyValueBasicInformation, pValueInfo1, cbNeeded, &cbRead); if (!NT_SUCCESS(Status)) { DBGPRINT(("Failed to read in the basic information. Status 0x%x\n", Status)); break; } // // Turn the value name into a UNICODE_STRING. // ValueName.Buffer = DetectAllocateHeap(pValueInfo1->NameLength + sizeof(WCHAR)); if (NULL == ValueName.Buffer) { DBGPRINT(("Failed to allocate buffer for the value name\n")); break; } // // Copy the string data. // RtlMoveMemory(ValueName.Buffer, pValueInfo1->Name, pValueInfo1->NameLength); // // Save the unicode string's length. // ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInfo1->NameLength; // // Place the NULL at the end of the string. // ValueName.Buffer[ValueName.Length / 2] = (WCHAR)'\0'; // // We no longer need the pValueInfo1 pointer. // DetectFreeHeap(pValueInfo1); pValueInfo1 = NULL; // // First query the value to determine the amount of resource data. // NtQueryValueKey( hPcmcia, &ValueName, KeyValueFullInformation, NULL, 0, &cbNeeded); // // Allocate a buffer for the information. // pValueInfo2 = (PKEY_VALUE_FULL_INFORMATION)DetectAllocateHeap(cbNeeded); if (NULL == pValueInfo2) { DBGPRINT(("Failed to allocate memory for te full value information\n")); break; } // // Read in the full value information. // Status = NtQueryValueKey( hPcmcia, &ValueName, KeyValueFullInformation, pValueInfo2, cbNeeded, &cbRead); if (!NT_SUCCESS(Status)) { DBGPRINT(("Failed to query the full value information. Status 0x%x\n", Status)); break; } // // Go through the resources and acquire them. // we will ignore any conflicts to acquire. // pFullResource = (PCM_FULL_RESOURCE_DESCRIPTOR) ((PUCHAR)pValueInfo2 + pValueInfo2->DataOffset); for (cResource = 0; cResource < pFullResource->PartialResourceList.Count; cResource++) { // // Get a pointer to the current resource. // pPartialResource = &pFullResource->PartialResourceList.PartialDescriptors[cResource]; // // Acquire the resource. // RtlZeroMemory(&Resource, sizeof(NETDTECT_RESOURCE)); Resource.InterfaceType = Isa; Resource.BusNumber = 0; Resource.Flags = 0; switch (pPartialResource->Type) { case CmResourceTypePort: Resource.Type = NETDTECT_PORT_RESOURCE; Resource.Value = pPartialResource->u.Port.Start.LowPart; Resource.Length = pPartialResource->u.Port.Length; break; case CmResourceTypeInterrupt: Resource.Type = NETDTECT_IRQ_RESOURCE; Resource.Value = pPartialResource->u.Interrupt.Level; Resource.Length = 0; break; case CmResourceTypeMemory: Resource.Type = NETDTECT_MEMORY_RESOURCE; Resource.Value = pPartialResource->u.Memory.Start.LowPart; Resource.Length = pPartialResource->u.Memory.Length; break; case CmResourceTypeDma: Resource.Type = NETDTECT_DMA_RESOURCE; Resource.Value = pPartialResource->u.Dma.Channel; Resource.Length = 0; break; } DetectTemporaryClaimResource(&Resource); } // // Free up value information. // DetectFreeHeap(ValueName.Buffer); ValueName.Buffer = NULL; // // Free the value information. // DetectFreeHeap(pValueInfo2); pValueInfo2 = NULL; } // // Free any allocated memory. // if (NULL != ValueName.Buffer) { DetectFreeHeap(ValueName.Buffer); } if (NULL != pValueInfo1) { DetectFreeHeap(pValueInfo1); } if (NULL != pValueInfo2) { DetectFreeHeap(pValueInfo2); } // // Free the PCMCIA PCCARDs full key information. // if (NULL != pKeyInfo) { DetectFreeHeap(pKeyInfo); } // // Close the PCMCIA registry handle. // if (hPcmcia != NULL) { NtClose(hPcmcia); } }