Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2836 lines
74 KiB

/**********************************************************************/
/** Microsoft Windows NT **/
/** Copyright(c) Microsoft Corp., 1991 **/
/**********************************************************************/
/*
NCPADTCT.CXX: Netcard detection interface.
FILE HISTORY:
DavidHov 10/31/92 Created
*/
#include "pch.hxx" // Precompiled header
#pragma hdrstop
#if defined(DEBUG) && defined(TRACE)
// #define DBGDETAILS TRUE
#endif
#define NCDT_SETUP_KEY_NAME SZ("System\\Setup")
#define NCDT_SETUP_VALUE_NAME SZ("NetcardDlls")
#define NCDT_HWARE_KEY_NAME SZ("Hardware\\Description\\System")
#define NCDT_HWARE_VALUE_CFG_DATA SZ("Configuration Data")
#define NCDT_MSNCDET_DLL_NAME SZ("MSNCDET.DLL")
#define PNAME_SIZE_MAX 400
#define PBUFF_SIZE_MAX 4000
#define PARAM_RANGE_MAX 1000
#define CONFIDENCE_MINIMUM 70
static const TCHAR chSpOpenList = TCH('(') ;
static const TCHAR chSpCloseList = TCH(')') ;
static const TCHAR chSpSep = TCH(' ') ;
// These tables must be in the same order as NETDTECT_XXX_RESOURCE
// definitions.
#define UPPER_BOUND(a) (sizeof(a)/sizeof(a[0]))
// The following are separate arrays because CFRONT insisted.
// (SZ() macro expansion caused an error in the structure
// initializer).
#define MAX_RESOURCE 5
// Names of claimable parameters
static TCHAR * apszClaimNames [] =
{
NULL,
SZ("IRQ"),
SZ("MEMADDR"),
SZ("IOADDR"),
SZ("DMACHANNEL")
};
// Name of associated range parameter, or NULL if n/a
static TCHAR * apszClaimRangeNames [] =
{
NULL,
NULL,
SZ("MEMLENGTH"),
SZ("IOADDRLENGTH"),
NULL
};
// Error to return when conflict occurs.
static APIERR amsgidClaimErrors [] =
{
NO_ERROR,
IDS_NCPA_CONFLICT_IRQ,
IDS_NCPA_CONFLICT_MEMADDR,
IDS_NCPA_CONFLICT_IOADDR,
IDS_NCPA_CONFLICT_DMA,
NO_ERROR
};
// BUGBUG: this global allows me to turn resource claiming off and on
// from within the debugger.
BOOL fClaimingActive = FALSE ;
BOOL fFreeingActive = FALSE ;
/*******************************************************************
NAME: queryValueBuffer
SYNOPSIS: Read a binary Registry value into a BUFFER object,
expanding the buffer size as required up to a
maximum limit.
ENTRY: REG_KEY * pRegKey the key to query
const TCHAR * pszValueName the value to find
BUFFER * pBuff the container for the data
LONG cbMaximum optional upper bound on size
EXIT: BUFFER updated if successful; contents indeterminate
if unsuccessful.
RETURNS: APIERR
NOTES:
HISTORY:
********************************************************************/
APIERR queryValueBuffer (
REG_KEY * pRegKey,
const TCHAR * pszValueName,
BUFFER * pBuff,
LONG cbMaximum = -1 )
{
APIERR err = 0 ;
REG_VALUE_INFO_STRUCT rvInfo ;
UINT cb ;
do
{
cb = pBuff->QuerySize() ;
// If err != 0, this is not first cycle;
// expand buffer and try again.
if ( err )
{
cb += cb / 2 ;
if ( cbMaximum >= 0 && cb > (UINT)cbMaximum )
{
err = ERROR_MORE_DATA ;
}
else
{
err = pBuff->Resize( cb + cb / 2 ) ;
}
}
else
{
// First cycle: check construction.
err = rvInfo.QueryError() ;
}
if ( err )
break ;
if ( err = rvInfo.nlsValueName.CopyFrom( pszValueName ) )
break ;
rvInfo.pwcData = pBuff->QueryPtr() ;
rvInfo.ulDataLength = cb ;
err = pRegKey->QueryValue( & rvInfo ) ;
}
while ( err == ERROR_MORE_DATA
|| err == ERROR_INSUFFICIENT_BUFFER ) ;
return err ;
}
/*******************************************************************
NAME: convertParseTreeToParameterString
SYNOPSIS: Given a parsed CFG_RULE_SET, convert it to a
packed string of UNICODE characters as used
by the netcard detection DLLs.
ENTRY: CFG_RULE_SET * pointer to parse tree
EXIT: TCHAR * * dynamically allocated
result for use in calling
VerifyCfg().
RETURNS: LONG if failure
NOTES: In SProlog form, the tree must be:
( (PARAM_1_NAME <param 1 value>)
(PARAM_2_NAME,<param 2 value>}
...
)
The result is simply each of the imbedded strings
delimited by a UNICODE NUL, with an additional
NUL at the end of all the strings.
HISTORY:
********************************************************************/
LONG convertParseTreeToParameterString (
CFG_RULE_SET * pcrnList,
TCHAR * * ppszResult )
{
LONG err = 0 ;
TCHAR * pszResult,
* pszResultBase = NULL,
* pszResultEnd ;
const TCHAR * pszTemp ;
INT i, cch ;
const INT cchHexMax = 20 ;
CFG_RULE_NODE_TYPE crnt ;
CFG_RULE_NODE * pcrnTop,
* pcrnParam ;
do
{
// Allocate the return result buffer
pszResultBase = new TCHAR [ PBUFF_SIZE_MAX ] ;
if ( pszResultBase == NULL )
{
err = ERROR_NOT_ENOUGH_MEMORY ;
break ;
}
// Set the limit point, allowing for double NUL terminator
pszResult = pszResultBase ;
pszResultEnd = pszResult + PBUFF_SIZE_MAX - 2 ;
// Walk the parse tree, extracting the information
// necessary. Parse tree looks like this:
//
// ( ) enclosing list (CFG_RULE_SET)
// |
// ( ) enclosing list from text
// |
// ( ) ( ) ( ) ( ) one list per parameter
// |
// name value... name and value pairs
//
// Walk the tree down to the top-level list of lists
if ( (pcrnTop = pcrnList->QueryList()) == NULL
|| pcrnTop->QueryType() != CRN_NIL
|| (pcrnTop = pcrnTop->QueryNext()) == NULL
|| pcrnTop->QueryType() != CRN_LIST
|| (pcrnTop = pcrnTop->QueryList()) == NULL )
{
err = ERROR_GEN_FAILURE ;
break ;
}
err = 0 ;
for ( ; err == 0 && (pcrnTop = pcrnTop->QueryNext()) ; )
{
crnt = pcrnTop->QueryType() ;
if ( crnt != CRN_LIST )
break ;
pcrnParam = pcrnTop->QueryList() ;
for ( i = 0 ;
err == 0 && (pcrnParam = pcrnParam->QueryNext()) ;
i++ )
{
crnt = pcrnParam->QueryType() ;
switch ( crnt )
{
case CRN_VAR:
case CRN_STR:
case CRN_ATOM:
cch = ::strlenf( pszTemp = pcrnParam->QueryAtom().QueryText() ) ;
if ( cch + pszResult >= pszResultEnd )
{
err = ERROR_BUFFER_OVERFLOW ;
break ;
}
#if defined(DBGDETAILS)
TRACEEOL( SZ("NCPA/DTCT: Inf list string: ")
<< pszTemp );
#endif
::strcpyf( pszResult, pszTemp );
pszResult += cch ;
break ;
case CRN_NUM:
if ( pszResult + cchHexMax >= pszResultEnd )
{
err = ERROR_BUFFER_OVERFLOW ;
break ;
}
#if defined(DBGDETAILS)
TRACEEOL( SZ("NCPA/DTCT: Inf list number: ")
<< pcrnParam->QueryNumber() );
#endif
pszResult = IntToStr( pcrnParam->QueryNumber(),
pszResult,
16 ) ;
break ;
default:
TRACEEOL( SZ("NCPA/DTCT: Inf list bad token: ")
<< (INT) crnt ) ;
break ;
}
// Delimit each string with NUL
*pszResult++ = 0 ;
}
}
if ( err )
break ;
// Delimit the whole shebang
*pszResult++ = 0 ;
} while ( FALSE ) ;
if ( err )
{
delete pszResultBase ;
pszResultBase = NULL ;
}
*ppszResult = pszResultBase ;
return err ;
}
/*******************************************************************
NAME: convertSpListToParameterString
SYNOPSIS: Given a SProlog-style list, convert it to a
packed string of UNICODE characters as used
by the netcard detection DLLs.
ENTRY: const TCHAR * pointer to INF string
EXIT: TCHAR * * dynamically allocated
result for use in calling
VerifyCfg().
RETURNS: LONG err if failure
NOTES: The input must be of the form:
( (PARAM_1_NAME <param 1 value>)
(PARAM_2_NAME,<param 2 value>}
...
)
The result is simply each of the imbedded strings
delimited by a UNICODE NUL, with an additional
NUL at the end of all the strings.
HISTORY:
********************************************************************/
LONG convertSpListToParameterString (
const TCHAR * pszList,
TCHAR * * ppszResult )
{
LONG err = 0 ;
TCHAR * pszResult = NULL ;
CFG_RULE_SET crnList ;
do
{
#if defined(DBGDETAILS)
TRACEEOL( SZ("NCPA/DTCT: SP list to be parsed: ")
<< pszList );
#endif
// Parse it using "full syntax"; this allows atoms which
// begin with an upper case letter (Prolog variables).
if ( err = crnList.Parse( pszList, PARSE_CTL_FULL_SYNTAX ) )
break ;
err = convertParseTreeToParameterString( & crnList, & pszResult ) ;
} while ( FALSE ) ;
if ( err )
{
delete pszResult ;
pszResult = NULL ;
}
*ppszResult = pszResult ;
return err ;
}
/*******************************************************************
NAME: DLL::DLL
SYNOPSIS: Constructor of base wrapper for a dynamically bound
Dynamic Link Library.
ENTRY: const TCHAR * pszDllName path\name of DLL
EXIT: nothing
RETURNS: standard constructor interface
NOTES:
HISTORY:
********************************************************************/
DLL :: DLL ( const TCHAR * pszDllName )
: _hDll( NULL ),
_nlsDllName( pszDllName )
{
if ( _nlsDllName.QueryError() )
{
ReportError( _nlsDllName.QueryError() ) ;
return ;
}
if ( (_hDll = ::LoadLibrary( pszDllName )) == NULL )
{
ReportError( ::GetLastError() ) ;
}
}
DLL :: ~ DLL ()
{
if ( _hDll )
{
::FreeLibrary( _hDll ) ;
}
}
/*******************************************************************
NAME: DETECT_DLL::DETECT_DLL
SYNOPSIS: Constructor of a netcard detection DLL object
ENTRY: const TCHAR * pszDllName name of DLL
EXIT: standard for constructor
RETURNS:
NOTES: Performs GetProcAddress() for all possible exports;
reports error only if a required export is missing.
HISTORY:
********************************************************************/
DETECT_DLL :: DETECT_DLL ( const TCHAR * pszDllName )
: DLL( pszDllName )
{
static CHAR * apszExports [ DDVI_Maximum ] =
{
// Required exports
NC_DETECT_IDENTIFY,
NC_DETECT_QUERY_MASK,
NC_DETECT_FIRST_NEXT,
NC_DETECT_OPEN_HANDLE,
NC_DETECT_CREATE_HANDLE,
NC_DETECT_CLOSE_HANDLE,
NC_DETECT_QUERY_CFG,
NC_DETECT_VERIFY_CFG,
NC_DETECT_QUERY_PARAM_RANGE,
// Optional exports
NC_DETECT_PARAM_NAME,
// Exported by MSNCDET.DLL only
NC_DETECT_RESOURCE_CLAIM,
NC_DETECT_RESOURCE_FREE,
NC_DETECT_TEMPORARY_RESOURCE_CLAIM,
NC_DETECT_TEMPORARY_RESOURCE_FREE
};
INT i,
cFound = 0 ;
if ( QueryError() )
return ;
ASSERT( UPPER_BOUND(apszExports) == DDVI_Maximum );
TRACEEOL( SZ("NCPA/DTCT: load and validate detection library: ")
<< pszDllName ) ;
for ( i = 0 ; i < DDVI_Maximum ; i++ )
{
_pFarRtn[i] = ::GetProcAddress( _hDll, apszExports[i] ) ;
if ( _pFarRtn[i] )
{
if ( i < DDVI_MinimumRequired )
cFound++ ;
}
#ifdef TRACE
else
if ( i < DDVI_MinimumRequired )
{
TRACEEOL( SZ("NCPA/DTCT: error-- Dll ")
<< pszDllName
<< SZ(" lacks export ")
<< apszExports[i] );
}
#endif
}
if ( cFound < DDVI_MinimumRequired )
{
ReportError( IDS_NCPA_DETECT_EXPORT_MISSING ) ;
}
}
DETECT_DLL :: ~ DETECT_DLL ()
{
}
// Macro to check that unexported functions are never called.
#define FAR_RTN_CHECK(f) { \
ASSERT( f != NULL ); \
if ( f == NULL ) \
return ERROR_INVALID_FUNCTION ; \
}
/*******************************************************************
NAME: DETECT_DLL::Identify
SYNOPSIS: Return standard string data from DLL
ENTRY: LONG lIndex the string index
WCHAR * pwcBuffer output buffer
LONG cwchBuffSize buffer capacity
EXIT: output buffer updated
RETURNS: LONG (APIERR): 0 if success; error code if otherwise.
NOTES:
HISTORY:
********************************************************************/
LONG DETECT_DLL :: Identify ( LONG lIndex,
WCHAR * pwcBuffer,
LONG cwchBuffSize )
{
FARPROC pFarRtn = _pFarRtn[DDVI_DetectIdentify] ;
FAR_RTN_CHECK( pFarRtn ) ;
return (*(pNcDetectIdentify)pFarRtn)( lIndex,
pwcBuffer,
cwchBuffSize );
}
/*******************************************************************
NAME: DETECT_DLL::QueryMask
SYNOPSIS: LONG lIndex numeric netcard ID
WCHAR * pwcBuffer output buffer for parameter data
LONG cwchBuffSize buffer capacity
ENTRY:
EXIT:
RETURNS: LONG (APIERR): 0 if success; error code if otherwise.
NOTES:
HISTORY:
********************************************************************/
LONG DETECT_DLL :: QueryMask ( LONG lIndex,
WCHAR * pwcBuffer,
LONG cwchBuffSize )
{
FARPROC pFarRtn = _pFarRtn[DDVI_QueryMask] ;
FAR_RTN_CHECK( pFarRtn ) ;
return (*(pNcQueryMask)pFarRtn)( lIndex,
pwcBuffer,
cwchBuffSize );
}
/*******************************************************************
NAME: DETECT_DLL::FirstNext
SYNOPSIS: Attempt to detect a given type of netcard on a specific
bus type and bus number.
ENTRY: LONG lNetcardId card type number
LONG itBusType bus interface type
LONG lBusNumber bus index
BOOL fFirst TRUE if initial detection
EXIT: PVOID * ppvToken output storage for opaque token
if successful
LONG * lConfidence confidence level [0..100]
RETURNS: LONG (APIERR): 0 if success; error code if otherwise.
NOTES:
HISTORY:
********************************************************************/
LONG DETECT_DLL :: FirstNext ( LONG lNetcardId,
LONG itBusType,
LONG lBusNumber,
BOOL fFirst,
PVOID * ppvToken,
LONG * lConfidence )
{
FARPROC pFarRtn = _pFarRtn[DDVI_DetectFirstNext] ;
FAR_RTN_CHECK( pFarRtn ) ;
return (*(pNcDetectFirstNext)pFarRtn)(
lNetcardId,
itBusType,
lBusNumber,
fFirst,
ppvToken,
lConfidence );
}
/*******************************************************************
NAME: DETECT_DLL::OpenHandle
SYNOPSIS: Given the opaque reference token for a detected
card, return a handle usable for parameter querying
and verification.
ENTRY: PVOID pvToken token from FIrstNext()
EXIT: PVOID * ppvHandle location to store handle
RETURNS: LONG (APIERR): 0 if success; error code if otherwise.
NOTES:
HISTORY:
********************************************************************/
LONG DETECT_DLL :: OpenHandle ( PVOID pvToken,
PVOID * ppvHandle )
{
FARPROC pFarRtn = _pFarRtn[DDVI_DetectOpenHandle] ;
FAR_RTN_CHECK( pFarRtn ) ;
return (*(pNcDetectOpenHandle)pFarRtn)(
pvToken,
ppvHandle );
}
/*******************************************************************
NAME: DETECT_DLL::CreateHandle
SYNOPSIS: Allow the user interface to force a DLL to create
a valid handle for a card which the user insists
is present.
ENTRY: LONG lNetcardId
LONG itBusType
LONG lBusNumber
EXIT: PVOID * ppvToken
RETURNS: LONG (APIERR): 0 if success; error code if otherwise.
NOTES:
HISTORY:
********************************************************************/
LONG DETECT_DLL :: CreateHandle ( LONG lNetcardId,
LONG itBusType,
LONG lBusNumber,
PVOID * ppvToken )
{
FARPROC pFarRtn = _pFarRtn[DDVI_DetectCreateHandle] ;
FAR_RTN_CHECK( pFarRtn ) ;
TRACEEOL( SZ("NCPA/DTCT: WARNING! CreateHandle called for ID ")
<< lNetcardId );
return (*(pNcDetectCreateHandle)pFarRtn)( lNetcardId,
itBusType,
lBusNumber,
ppvToken );
}
/*******************************************************************
NAME: DETECT_DLL::CloseHandle
SYNOPSIS: Self-explanatory
ENTRY:
EXIT:
RETURNS: LONG (APIERR): 0 if success; error code if otherwise.
NOTES:
HISTORY:
********************************************************************/
LONG DETECT_DLL :: CloseHandle ( PVOID pvHandle )
{
FARPROC pFarRtn = _pFarRtn[DDVI_DetectCloseHandle] ;
FAR_RTN_CHECK( pFarRtn ) ;
return (*(pNcDetectCloseHandle)pFarRtn)( pvHandle );
}
/*******************************************************************
NAME: DETECT_DLL::QueryCfg
SYNOPSIS: Obtain the probably parameter settings for a particular
detected netcard.
ENTRY: PVOID pvHandle from OpenHandle()
WCHAR * pwcBuffer output buffer
LONG cwchBuffSize buffer capacity
EXIT:
RETURNS: LONG (APIERR): 0 if success; error code if otherwise.
NOTES:
HISTORY:
********************************************************************/
LONG DETECT_DLL :: QueryCfg ( PVOID pvHandle,
WCHAR * pwcBuffer,
LONG cwchBuffSize )
{
LONG lResult ;
FARPROC pFarRtn = _pFarRtn[DDVI_DetectQueryCfg] ;
FAR_RTN_CHECK( pFarRtn ) ;
lResult = (*(pNcQueryCfg)pFarRtn)( pvHandle,
pwcBuffer,
cwchBuffSize ) ;
#if defined(DBGDETAILS)
for ( WCHAR * pwch = pwcBuffer ; *pwch ; )
{
TRACEEOL( SZ("NCPA/DTCT: QueryCfg returned [")
<< pwch
<< SZ("]") ) ;
pwch += ::strlenf( pwch ) + 1 ;
}
#endif
return lResult ;
}
/*******************************************************************
NAME: DETECT_DLL::VerifyCfg
SYNOPSIS: Verify a set of netcard parameters provided by
the user interface.
ENTRY: PVOID pvHandle
const WCHAR * pwcBuffer the parameters
EXIT:
RETURNS: LONG (APIERR): 0 if success; error code if otherwise.
NOTES:
HISTORY:
********************************************************************/
LONG DETECT_DLL :: VerifyCfg ( PVOID pvHandle,
const WCHAR * pwcBuffer )
{
FARPROC pFarRtn = _pFarRtn[DDVI_DetectVerifyCfg] ;
FAR_RTN_CHECK( pFarRtn ) ;
return (*(pNcVerifyCfg)pFarRtn)( pvHandle,
(WCHAR * ) pwcBuffer ) ;
}
/*******************************************************************
NAME: DETECT_DLL::QueryParamName
SYNOPSIS: Return the displayable name of a parameter based
upon its internal string name.
ENTRY:
EXIT:
RETURNS: LONG (APIERR): 0 if success; error code if otherwise.
NOTES:
HISTORY:
********************************************************************/
LONG DETECT_DLL :: QueryParamName ( const WCHAR * pwcParamName,
WCHAR * pwcBuffer,
LONG cwchBuffSize )
{
FARPROC pFarRtn = _pFarRtn[DDVI_QueryParamName] ;
FAR_RTN_CHECK( pFarRtn ) ;
return (*(pNcQueryParamName)pFarRtn)( (WCHAR *) pwcParamName,
pwcBuffer,
cwchBuffSize );
}
/*******************************************************************
NAME: DETECT_DLL::QueryParamRange
SYNOPSIS: For a given card type and parameter name, return
a complete list of all possible numeric settings.
ENTRY:
EXIT:
RETURNS: LONG (APIERR): 0 if success; error code if otherwise.
NOTES:
HISTORY:
********************************************************************/
LONG DETECT_DLL :: QueryParamRange ( LONG lIndex,
const WCHAR * pwcParamName,
LONG * plValues,
LONG * plValueCount )
{
FARPROC pFarRtn = _pFarRtn[DDVI_QueryParamRange] ;
FAR_RTN_CHECK( pFarRtn ) ;
return (*(pNcQueryParamRange)pFarRtn)( lIndex,
(WCHAR *) pwcParamName,
plValues,
plValueCount );
}
/*******************************************************************
NAME: DETECT_DLL::ClaimResource
SYNOPSIS: Use the NETDTECT.SYS driver to claim system-level
hardware interface resources.
ENTRY:
EXIT:
RETURNS: LONG (APIERR): 0 if success; error code if otherwise.
NOTES:
HISTORY:
********************************************************************/
LONG DETECT_DLL :: ClaimResource (
INTERFACE_TYPE itBusType,
LONG lBusNumber,
LONG lType,
LONG lValue,
LONG lRange,
LONG lFlags,
BOOL fClaim )
{
LONG lResult ;
FARPROC pFarRtn = _pFarRtn[DDVI_ResourceClaim] ;
FAR_RTN_CHECK( pFarRtn ) ;
lResult = (*(pNcDetectResourceClaim)pFarRtn)(
itBusType,
lBusNumber,
lType,
lValue,
lRange,
lFlags,
fClaim );
TRACEEOL( SZ("NCPA/DTCT: ClaimResource(), type ")
<< lType
<< SZ(", value ")
<< lValue
<< SZ(", bus ")
<< (LONG)itBusType
<< SZ("/")
<< lBusNumber
<< SZ(", result = ")
<< lResult );
return lResult ;
}
/*******************************************************************
NAME: DETECT_DLL::FreeResource
SYNOPSIS: Release a resource reserved by ClaimResource.
ENTRY:
EXIT:
RETURNS: LONG (APIERR): 0 if success; error code if otherwise.
NOTES:
HISTORY:
********************************************************************/
LONG DETECT_DLL :: FreeResource (
INTERFACE_TYPE itBusType,
LONG lBusNumber,
LONG lType,
LONG lValue,
LONG lRange,
LONG lFlags )
{
FARPROC pFarRtn = _pFarRtn[DDVI_ResourceFree] ;
FAR_RTN_CHECK( pFarRtn ) ;
return (*(pNcDetectResourceFree)pFarRtn)(
itBusType,
lBusNumber,
lType,
lValue,
lRange,
lFlags );
}
/*******************************************************************
NAME: DETECT_DLL::TemporaryClaimResource
SYNOPSIS: Use the NETDTECT.SYS driver to claim system-level
hardware interface resources.
ENTRY:
EXIT:
RETURNS: LONG (APIERR): 0 if success; error code if otherwise.
NOTES:
HISTORY:
********************************************************************/
LONG DETECT_DLL :: TemporaryClaimResource (
INTERFACE_TYPE itBusType,
LONG lBusNumber,
LONG lType,
LONG lValue,
LONG lRange,
LONG lFlags,
BOOL fClaim )
{
LONG lResult ;
FARPROC pFarRtn = _pFarRtn[DDVI_TemporaryResourceClaim] ;
FAR_RTN_CHECK( pFarRtn ) ;
NETDTECT_RESOURCE ClaimedResource;
ClaimedResource.InterfaceType = itBusType;
ClaimedResource.BusNumber = lBusNumber;
ClaimedResource.Type = lType;
ClaimedResource.Flags = lFlags;
ClaimedResource.Value = lValue;
ClaimedResource.Length = lRange;
lResult = (*(pNcDetectTemporaryResourceClaim)pFarRtn)( &ClaimedResource );
TRACEEOL( SZ("NCPA/DTCT: ClaimResource(), type ")
<< lType
<< SZ(", value ")
<< lValue
<< SZ(", bus ")
<< (LONG)itBusType
<< SZ("/")
<< lBusNumber
<< SZ(", result = ")
<< lResult );
return lResult ;
}
/*******************************************************************
NAME: DETECT_DLL::TemporaryFreeResource
SYNOPSIS: Release a resource reserved by ClaimResource.
ENTRY:
EXIT:
RETURNS: LONG (APIERR): 0 if success; error code if otherwise.
NOTES:
HISTORY:
********************************************************************/
LONG DETECT_DLL :: TemporaryFreeResource ()
{
FARPROC pFarRtn = _pFarRtn[DDVI_TemporaryResourceFree] ;
FAR_RTN_CHECK( pFarRtn ) ;
return (*(pNcDetectTemporaryResourceFree)pFarRtn)();
}
// Define the support routines for an SLIST of DETECT_DLLs
DEFINE_SLIST_OF(DETECT_DLL)
// Define the support routines for an SLIST of CARDTYPE_REFERENCE
DEFINE_SLIST_OF(CARDTYPE_REFERENCE)
// Define the support routines for an SLIST of CARD_REFERENCE
DEFINE_SLIST_OF(CARD_REFERENCE)
/*******************************************************************
NAME: CARDTYPE_REFERENCE::CARDTYPE_REFERENCE
SYNOPSIS: Constructor of object describing a single type
of netcard supported by its parent DLL.
ENTRY: DETECT_DLL & dll the supporting DLL
LONG lCardType the netcard index
EXIT:
RETURNS:
NOTES:
HISTORY:
********************************************************************/
CARDTYPE_REFERENCE :: CARDTYPE_REFERENCE (
DETECT_DLL & dll,
LONG lCardType )
: _dll( dll ),
_lCardType( lCardType ),
_lSortOrder( SORTORDER_DEFAULT ),
_pszParamMask( NULL )
{
APIERR err = 0 ;
TCHAR chTitle [PNAME_SIZE_MAX] ;
// Get the card's option name
if ( (err = dll.Identify( _lCardType + CD_ID_OPTION,
chTitle,
sizeof chTitle )) == 0 )
{
err = _nlsOptionName.CopyFrom( chTitle ) ;
}
if ( err == 0 )
{
_pszParamMask = QueryMask() ;
if ( _pszParamMask == NULL )
{
err = ERROR_NOT_ENOUGH_MEMORY ;
}
if ( dll.Identify( _lCardType + CD_ID_SORTORD,
chTitle,
sizeof chTitle ) == 0 )
{
_lSortOrder = CFG_RULE_NODE::cfAtoL( chTitle ) ;
if ( _lSortOrder < 0 || _lSortOrder > SORTORDER_MAXIMUM )
_lSortOrder = SORTORDER_DEFAULT ;
}
#if defined(DBGDETAILS)
TRACEEOL( SZ("NCPA/DTCT: construct option ")
<< _nlsOptionName.QueryPch()
<< SZ(" in DLL ")
<< _dll.Name().QueryPch()
<< SZ(" sort order ")
<< _lSortOrder ) ;
#endif
}
if ( err )
{
ReportError( err ) ;
}
}
CARDTYPE_REFERENCE :: ~ CARDTYPE_REFERENCE ()
{
delete _pszParamMask ;
}
/*******************************************************************
NAME: CARDTYPE_REFERENCE::QueryMask
SYNOPSIS: Return the packed array of strings describing
the netcard's parameters and their usage.
ENTRY:
EXIT:
RETURNS:
NOTES:
HISTORY:
********************************************************************/
TCHAR * CARDTYPE_REFERENCE :: QueryMask ()
{
TCHAR tchParams [PBUFF_SIZE_MAX],
* pszResult = NULL ;
if ( _dll.QueryMask( _lCardType, tchParams, sizeof tchParams ) == 0 )
{
LONG cch = ParamBufferSize( tchParams ) ;
if ( pszResult = new TCHAR [ cch ] )
{
::memcpyf( pszResult, tchParams, cch * sizeof (TCHAR) ) ;
}
}
return pszResult ;
}
/*******************************************************************
NAME: CARDTYPE_REFERENCE::QueryConfigurationOptions
SYNOPSIS: Produce a SProlog-style nested list describing
the configuration options pertaining to this
card type.
ENTRY: nothing
EXIT: TCHAR * pointing at resulting list
RETURNS:
NOTES: Calling a DLL's NcDetectQueryMask() export
produces a buffer of WCHAR string triples:
"PARAMNAME" name of option
[0|1|2] type of option
[0..100] confidence factor
Calling a DLL's NcDetectParamRange() export
produces an array of LONGs. These are converted
to decimal. The final list appears as:
(
("PARAM1" <type> <confidence> (3 4 5))
("PARAM2" <type> <confidence> (3 4 5))
)
where (3 4 5) is the range of settings possible
for the option.
HISTORY:
********************************************************************/
TCHAR * CARDTYPE_REFERENCE :: QueryConfigurationOptions ()
{
NLS_STR nlsList ;
WCHAR * pwchBuffer,
* pwchBufferStart ;
TCHAR * pchResult = NULL ;
TCHAR * pchParam = NULL ;
APIERR err ;
LONG lValues [ PARAM_RANGE_MAX ] ;
LONG lValueCount ;
LONG i, cParams ;
if ( nlsList.QueryError() )
return NULL ;
if ( (pwchBufferStart = QueryMask()) == NULL )
return NULL ;
pwchBuffer = pwchBufferStart ;
do
{
// Open the overall list
if ( err = nlsList.AppendChar( chSpOpenList ) )
break ;
// Once for each parameter
for ( cParams = 0 ; err == 0 && *pwchBuffer ; cParams++ )
{
// Delimit the last parameter sub-list if necessary
if ( cParams && (err = nlsList.AppendChar( chSpSep )) )
break ;
// Guarantee that the next parameter name is alphabetic
// BUGBUG: SeanSe must fix his code so this isn't necessary!
if ( ! CFG_RULE_NODE::cfIsAlpha( *pwchBuffer ) )
break ;
// Open the parameter-level list
if ( err = nlsList.AppendChar( chSpOpenList ) )
break ;
pchParam = pwchBuffer ; // Save ptr to parameter name
for ( i = 0 ; i <= 2 ; i++ )
{
if ( err = nlsList.Append( pwchBuffer ) )
break ;
pwchBuffer += ::strlenf( pwchBuffer ) + 1 ;
if ( err = nlsList.AppendChar( chSpSep ) )
break ;
}
if ( err )
break ;
// Query the range information
lValueCount = PARAM_RANGE_MAX ;
err = Dll()->QueryParamRange( _lCardType,
pchParam,
lValues,
& lValueCount ) ;
if ( err )
{
lValueCount = 0 ;
TRACEEOL( SZ("NCPA/DTCT: parameter ")
<< pchParam
<< SZ(" for card type ")
<< _lCardType
<< SZ(" failed on query range") ) ;
}
// Open the parameter-range-level list
if ( err = nlsList.AppendChar( chSpOpenList ) )
break ;
// Convert the param ranges to decimal and append
for ( i = 0 ; i < lValueCount ; i++ )
{
DEC_STR decStr( lValues[i] ) ;
if ( err = nlsList.Append( decStr ) )
break ;
if ( i + 1 < lValueCount )
{
if ( err = nlsList.AppendChar( chSpSep ) )
break ;
}
}
if ( err )
break ;
// Close the parameter-range-level list
if ( err = nlsList.AppendChar( chSpCloseList ) )
break ;
// Close the parameter-level list
if ( err = nlsList.AppendChar( chSpCloseList ) )
break ;
}
if ( err )
break ;
if ( err = nlsList.AppendChar( chSpCloseList ) )
break ;
} while ( FALSE ) ;
// Delete the temporary buffer
delete pwchBufferStart ;
// If successful, create a simple text string
if ( err == 0 )
{
UINT cchResult = nlsList.QueryTextLength() + 1 ;
if ( pchResult = new TCHAR[ cchResult ] )
{
::memcpyf( pchResult, nlsList.QueryPch(), cchResult * sizeof (TCHAR) ) ;
}
}
return pchResult ;
}
/*******************************************************************
NAME: DETECT_DLL::AddCardTypesToList
SYNOPSIS: Enumerate all supported card types. Create a
CARDTYPE_REFERENCE for each and append it to
the given SLIST_OF_CARDTYPE_REFERENCE.
ENTRY:
EXIT:
RETURNS:
NOTES:
HISTORY:
********************************************************************/
APIERR DETECT_DLL :: AddCardTypesToList ( SLIST_OF_CARDTYPE_REFERENCE * pslCtype )
{
APIERR err = 0 ;
LONG cNextType ;
TCHAR chTitle [PNAME_SIZE_MAX] ;
CARDTYPE_REFERENCE * pCardType = NULL ;
for ( cNextType = CD_ID_BASE ;
Identify( cNextType, chTitle, sizeof chTitle ) == 0 ;
cNextType += CD_ID_INCR )
{
// Create and validate the new card type reference
pCardType = new CARDTYPE_REFERENCE( *this, cNextType ) ;
if ( pCardType == NULL )
{
err = ERROR_NOT_ENOUGH_MEMORY ;
break ;
}
if ( err = pCardType->QueryError() )
break ;
// Append this card type onto the pointed list
pslCtype->Append( pCardType ) ;
}
return err ;
}
/*******************************************************************
NAME: CARD_REFERENCE::CARD_REFERENCE
SYNOPSIS: Constructor for wrapper structure for a detected
network card.
ENTRY: BUS_ELEMENT & bus where card lives
CARDTYPE_REFERENCE * type of card
CARD_TOKEN PVOID token referencing card
LONG lConfidence confidence factor for card
EXIT:
RETURNS:
NOTES:
HISTORY:
********************************************************************/
CARD_REFERENCE :: CARD_REFERENCE (
const BUS_ELEMENT & busElem,
CARDTYPE_REFERENCE * pCardTypeRef,
CARD_TOKEN tkCard,
LONG lConfidence )
: _busElem( busElem ),
_pCardTypeRef( pCardTypeRef ),
_tkCard( tkCard ),
_lConfidence( lConfidence ),
_hCard( NULL )
{
}
CARD_REFERENCE :: CARD_REFERENCE (
const BUS_ELEMENT & busElem,
CARDTYPE_REFERENCE * pCardTypeRef )
: _busElem( busElem ),
_pCardTypeRef( pCardTypeRef ),
_tkCard( NULL ),
_lConfidence( 0 ),
_hCard( NULL )
{
}
CARD_REFERENCE :: ~ CARD_REFERENCE ()
{
Close() ;
}
APIERR CARD_REFERENCE :: Open ()
{
APIERR err = 0 ;
if ( _hCard )
Close() ;
// If we have a detection token, use it; otherwise, force
// the DLL to create a handle for the card.
if ( _tkCard )
{
err = _pCardTypeRef->Dll()->OpenHandle( _tkCard, & _hCard ) ;
}
else
{
err = _pCardTypeRef->Dll()->CreateHandle( _pCardTypeRef->QueryType(),
QueryIfType(),
QueryBus(),
& _hCard ) ;
}
return err ;
}
VOID CARD_REFERENCE :: Close ()
{
if ( _hCard )
{
_pCardTypeRef->Dll()->CloseHandle( _hCard ) ;
_hCard = NULL ;
}
}
/*******************************************************************
NAME: CARD_REFERENCE::QueryConfiguration
SYNOPSIS: Returns a SETUP INF list representing the
detected configuration settings of the
given netcard.
ENTRY: Nothing
EXIT: See notes
RETURNS: See notes
NOTES: The result of this function is a dynamically
allocated INF list of parameters and their settings.
The list is nested; e.g.,
{
{IRQ,5}, // IRQ = 0x5
{IOADDR,784} // IOADDR = 0x310
}
The result is NULL if any error occurs.
HISTORY:
********************************************************************/
TCHAR * CARD_REFERENCE :: QueryConfiguration ()
{
WCHAR chBuffer [PBUFF_SIZE_MAX] ;
NLS_STR nlsList ;
WCHAR * pwchBuffer ;
TCHAR * pchResult = NULL ;
TCHAR * pchParam = NULL ;
INT cParam ;
UINT uValue ;
LONG err ;
memset( chBuffer, 0, sizeof( chBuffer ));
if ( nlsList.QueryError() )
return NULL ;
// Guarantee that the card is "open"
if ( _hCard == NULL )
{
if ( err = Open() )
return NULL ;
}
if ( err = _pCardTypeRef->Dll()->QueryCfg( _hCard,
chBuffer,
sizeof chBuffer ) )
return NULL ;
pwchBuffer = chBuffer ;
do
{
// Open the overall list
if ( err = nlsList.AppendChar( chSpOpenList ) )
break ;
// Once for each parameter
for ( cParam = 0 ; err == 0 && *pwchBuffer ; cParam++ )
{
// Delimit the last parameter sub-list if necessary
if ( cParam && (err = nlsList.AppendChar( chSpSep )) )
break ;
// Open the parameter-level list
if ( err = nlsList.AppendChar( chSpOpenList ) )
break ;
// Append the parameter name and the separator
if ( err = nlsList.Append( pwchBuffer ) )
break ;
if ( err = nlsList.AppendChar( chSpSep ) )
break ;
// Append a decimal version of the UNICODE Hex string
pwchBuffer += ::strlenf( pwchBuffer ) + 1 ;
uValue = CvtDecOrHex( pwchBuffer ) ;
pwchBuffer += ::strlenf( pwchBuffer ) + 1 ;
{
if ( err = nlsList.Append( DEC_STR( uValue ) ) )
break ;
}
if ( err = nlsList.AppendChar( chSpCloseList ) )
break ;
}
if ( err )
break ;
if ( err = nlsList.AppendChar( chSpCloseList ) )
break ;
} while ( FALSE ) ;
// If successful, create a simple text string
if ( err == 0 )
{
UINT cchResult = nlsList.QueryTextLength() + 1 ;
if ( pchResult = new TCHAR[ cchResult ] )
{
::memcpyf( pchResult, nlsList.QueryPch(), cchResult * sizeof(TCHAR) ) ;
}
}
return pchResult ;
}
/*******************************************************************
NAME: CARD_REFERENCE::VerifyConfiguration
SYNOPSIS: Verify a packed buffer of Unicode parameter
name/value pairs.
ENTRY: const TCHAR * pszParmList buffer
EXIT: LONG
RETURNS:
NOTES:
HISTORY:
********************************************************************/
LONG CARD_REFERENCE :: VerifyConfiguration ( const TCHAR * pszParamList )
{
LONG err = 0 ;
// Guarantee that the card is "open"; open it if not.
if ( _hCard == NULL )
{
err = Open() ;
}
if ( err == 0 )
{
err = _pCardTypeRef->Dll()->VerifyCfg( _hCard, pszParamList ) ;
}
return err ;
}
/*******************************************************************
NAME: DETECTION_MANAGER::DETECTION_MANAGER
SYNOPSIS: Constructor of overall detection handler
ENTRY:
EXIT:
RETURNS:
NOTES:
HISTORY:
********************************************************************/
DETECTION_MANAGER :: DETECTION_MANAGER ()
: _cBuses(0),
_pDtDllMsncdet( NULL ),
_cIterBus( -1 ),
_cIterCardType( MAXLONG - 1 )
{
APIERR err ;
do
{
if ( err = EnumerateBuses() )
break ;
TRACEEOL( SZ("NCPA/DTCT: DETECTION_MANAGER: ")
<< SZ("EnumerateBuses() found ")
<< _cBuses
<< SZ(" buses ") ) ;
if ( err = EnumerateDlls() )
break ;
TRACEEOL( SZ("NCPA/DTCT: DETECTION_MANAGER: ")
<< SZ("EnumerateDlls() found ")
<< _slDlls.QueryNumElem()
<< SZ(" DLLs ") ) ;
if ( err = SortCardRefList() )
break ;
TRACEEOL( SZ("NCPA/DTCT: DETECTION_MANAGER: ")
<< SZ("SortCardRefList() returned ")
<< _slCtypes.QueryNumElem()
<< SZ(" different types of cards ") ) ;
}
while ( FALSE ) ;
ResetIteration() ;
if ( err )
{
ReportError( err ) ;
}
}
DETECTION_MANAGER :: ~ DETECTION_MANAGER ()
{
}
/*******************************************************************
NAME: DETECTION_MANAGHER::EnumerateDlls
SYNOPSIS: Get the REG_MULTI_SZ from the SETUP key in the
Registry and create a DETECT_DLL object for each
DLL therein.
ENTRY: Nothing
EXIT: _slDlls contains DLL objects successfully created
RETURNS: APIERR if failure
NOTES:
HISTORY:
********************************************************************/
APIERR DETECTION_MANAGER :: EnumerateDlls ()
{
APIERR err = 0 ;
STRLIST * pSlDlls = NULL ;
NLS_STR nlsSetupKeyName ( NCDT_SETUP_KEY_NAME ) ;
REG_KEY rkMachine ( HKEY_LOCAL_MACHINE ) ;
if ( nlsSetupKeyName.QueryError() )
{
return nlsSetupKeyName.QueryError() ;
}
if ( rkMachine.QueryError() )
{
return rkMachine.QueryError() ;
}
REG_KEY rkNetcardDlls ( rkMachine, nlsSetupKeyName ) ;
if ( rkNetcardDlls.QueryError() )
{
return rkNetcardDlls.QueryError() ;
}
if ( (err = rkNetcardDlls.QueryValue( NCDT_SETUP_VALUE_NAME,
& pSlDlls )) == 0 )
{
ITER_STRLIST islDllNames( *pSlDlls ) ;
const NLS_STR * pnlsName ;
DETECT_DLL * pDll = NULL ;
INT cDlls = 0 ;
while ( pnlsName = islDllNames.Next() )
{
pDll = new DETECT_DLL( pnlsName->QueryPch() ) ;
if ( pDll != NULL && pDll->QueryError() == 0 )
{
_slDlls.Append( pDll ) ;
cDlls++ ;
pDll->AddCardTypesToList( & _slCtypes ) ;
// See if this is MSNCDET.DLL; save ptr if so.
if ( pnlsName->_stricmp( NCDT_MSNCDET_DLL_NAME ) == 0 )
{
_pDtDllMsncdet = pDll ;
}
}
else
{
delete pDll ;
}
}
if ( cDlls == 0 )
{
err = IDS_NCPA_DETECT_NO_DLLS ;
}
}
delete pSlDlls ;
// Guarantee that MSNCDET.DLL was found.
if ( err == 0 && _pDtDllMsncdet == NULL )
{
err = ERROR_FILE_NOT_FOUND ;
}
return err ;
}
/*******************************************************************
NAME: DETECTION_MANAGER::EnumerateBuses
SYNOPSIS: Walk the HARDWARE Registry hive; build an array
of the buses found and their types.
ENTRY:
EXIT:
RETURNS:
NOTES:
HISTORY:
********************************************************************/
APIERR DETECTION_MANAGER :: EnumerateBuses ()
{
static const TCHAR * pszKeyNames [] =
{
SZ("MultifunctionAdapter"),
SZ("EisaAdapter"),
SZ("DtiAdapter"),
SZ("TcAdapter"),
NULL
};
APIERR err = 0 ;
NLS_STR nlsHardKeyName ( NCDT_HWARE_KEY_NAME ) ;
NLS_STR nlsBusName ;
BUFFER buff( 1000 ) ;
REG_KEY rkMachine ( HKEY_LOCAL_MACHINE ) ;
do
{
if ( err = nlsHardKeyName.QueryError() )
break ;
if ( err = rkMachine.QueryError() )
break ;
} while ( FALSE ) ;
if ( err )
return err ;
// Open HKEY_LOCAL_MACHINE\Hardware\Description\System
REG_KEY rkHardKey ( rkMachine, nlsHardKeyName ) ;
if ( rkHardKey.QueryError() )
{
return rkHardKey.QueryError() ;
}
// Open each possible bus type sub-key...
_cBuses = 0 ;
// hack - if PCMCIA bus exist, put it in the first place
ALIAS_STR nlsPcmcia=SZ("PCMCIA PCCARDs");
REG_KEY rkPcmciaBus( rkHardKey, nlsPcmcia);
if ( rkPcmciaBus.QueryError() == 0 )
{
// yes, pcmcia exist, put it in the first place
_bus[_cBuses].ifType = PCMCIABus;
_bus[_cBuses].iBus = 0;
_cBuses++;
}
for ( INT cBus = 0 ; pszKeyNames[cBus] ; cBus++ )
{
NLS_STR nlsBusName( pszKeyNames[cBus] ) ;
REG_KEY rkBusType( rkHardKey, nlsBusName ) ;
// If string failure, quit.
if ( nlsBusName.QueryError() )
break ;
// If key not found, continue with next bus type.
if ( rkBusType.QueryError() )
continue ;
REG_ENUM enumBus( rkBusType );
REG_KEY_INFO_STRUCT KeyInfo;
if ( enumBus.QueryError())
continue;
while ( enumBus.NextSubKey( &KeyInfo ) == NERR_Success )
{
NLS_STR nlsInstance = KeyInfo.nlsName;
REG_KEY rkInstance( rkBusType, nlsInstance ) ;
CM_FULL_RESOURCE_DESCRIPTOR * pcfResDesc ;
if ( rkInstance.QueryError() )
{
break ; // No more buses of this type
}
// Get the "Configuration Data" value. Check
// that the length makes sense.
if ( queryValueBuffer( & rkInstance,
NCDT_HWARE_VALUE_CFG_DATA,
& buff,
200000 ) )
{
TRACEEOL( SZ("NCPA/DTCT: bus: ")
<< nlsBusName.QueryPch()
<< SZ(", failed to query Configuration Data value") );
continue ;
}
pcfResDesc = (CM_FULL_RESOURCE_DESCRIPTOR *) buff.QueryPtr() ;
// Store info into the bus information array
_bus[_cBuses].ifType = pcfResDesc->InterfaceType ;
_bus[_cBuses].iBus = pcfResDesc->BusNumber ;
TRACEEOL( SZ("NCPA/DTCT: found bus: ")
<< nlsBusName.QueryPch()
<< SZ("/")
<< KeyInfo.nlsName.QueryPch()
<< SZ(", type ")
<< (INT) _bus[_cBuses].ifType
<< SZ("/")
<< (INT) _bus[_cBuses].iBus );
if ( ++_cBuses >= MAX_BUSES_ALLOWED )
break ;
}
if ( _cBuses >= MAX_BUSES_ALLOWED )
break ;
}
if ( err == 0 && _cBuses < 1 )
{
err = IDS_NCPA_DETECT_BUS_ENUM_FAILED ;
}
return err ;
}
/*******************************************************************
NAME: DETECTION_MANAGER::SortCardRefList
SYNOPSIS: Given the SLIST of CARDTYPE_REFERENCE,
sort it into SORTORDER sequence.
ENTRY:
EXIT:
RETURNS:
NOTES:
HISTORY:
********************************************************************/
APIERR DETECTION_MANAGER :: SortCardRefList ()
{
UINT cCardRef = _slCtypes.QueryNumElem(),
cCard ;
CARDTYPE_REFERENCE * * ppCardTypeRef = NULL ;
if ( cCardRef == 0 )
return NO_ERROR ;
ppCardTypeRef = new CARDTYPE_REFERENCE * [ cCardRef ] ;
if ( ppCardTypeRef == NULL )
return ERROR_NOT_ENOUGH_MEMORY ;
ITER_SL_OF(CARDTYPE_REFERENCE) islCards( _slCtypes ) ;
CARDTYPE_REFERENCE * pCard ;
// Drain the SLIST entirely, building the sortable array
for ( cCard = 0 ;
pCard = _slCtypes.Remove( islCards ) ;
cCard++ )
{
if ( cCard >= cCardRef )
return ERROR_INTERNAL_ERROR ;
ppCardTypeRef[cCard] = pCard ;
}
// Sort the array
::qsort( (PVOID) ppCardTypeRef,
cCardRef,
sizeof (CARDTYPE_REFERENCE *),
& DETECTION_MANAGER::CardCompareFunc ) ;
// Reload the SLIST from the sorted array
for ( cCard = 0 ; cCard < cCardRef ; cCard++ )
{
_slCtypes.Append( ppCardTypeRef[ cCard ] ) ;
}
// Delete the array
delete [] ppCardTypeRef ;
// Return an error if the numbers don't match
return _slCtypes.QueryNumElem() == cCardRef
? NO_ERROR
: ERROR_GEN_FAILURE ;
}
// Qsort() worker function:
// Compare SORTORDER for CARDTYPE_REFERENCEs
//
// BUGBUG: for now, invert the sense of the sort;
// i.e., do a descending sort.
INT _CRTAPI1 DETECTION_MANAGER :: CardCompareFunc ( const VOID * a, const VOID * b )
{
CARDTYPE_REFERENCE * * ppCard1 = (CARDTYPE_REFERENCE * *) a ;
CARDTYPE_REFERENCE * * ppCard2 = (CARDTYPE_REFERENCE * *) b ;
if ( (*ppCard1)->QuerySortOrder() > (*ppCard2)->QuerySortOrder() )
return -1 ;
return (*ppCard1)->QuerySortOrder() < (*ppCard2)->QuerySortOrder() ;
}
// Reset the iteraction counters
VOID DETECTION_MANAGER :: ResetIteration ()
{
_cIterBus = -1 ;
_cIterCardType = MAXLONG - 1 ;
}
// Increment the iteration counters.
// Return TRUE if iteration is to continue.
BOOL DETECTION_MANAGER :: BumpIteration ()
{
INT cTypes = QueryMaxCardType() ;
if ( cTypes == 0 )
return FALSE ;
if ( ++_cIterCardType >= cTypes )
{
_cIterCardType = 0 ;
if ( ++_cIterBus >= QueryMaxBus() )
{
ResetIteration() ;
return FALSE ;
}
}
return TRUE ;
}
BOOL DETECTION_MANAGER :: QueryBusInfo (
INT iBus,
INTERFACE_TYPE * pIfType,
INT * pBusIndex )
{
if ( iBus > _cBuses )
return FALSE ;
*pIfType = _bus[iBus].ifType ;
*pBusIndex = _bus[iBus].iBus ;
return TRUE ;
}
/*******************************************************************
NAME: DETECTION_MANAGER::DetectNext
SYNOPSIS: Find the next card.
ENTRY: CARD_REFERENCE * * location to store
detection result
BOOL fFirst TRUE if detect first
card
BOOL fSingleStep TRUE if looping is not
desired
EXIT: PCARD_REFERENCE --> newly constructed CARD_REFERENCE
CARD_REFERENCE::Open()
has already been called.
RETURNS: APIERR --- ERROR_NO_MORE_ITEMS if there is
no next card; other error as
necessary.
NOTES: Iteration is bus-major, card-minor. Slist of card types
is sorted by SORTORDER parameter.
NOTE: this routine currently only supports first card
detection; see NCDETECT.DOC for details.
HISTORY:
********************************************************************/
APIERR DETECTION_MANAGER :: DetectCard (
PCARD_REFERENCE * ppCardRef,
BOOL fFirst,
BOOL fSingleStep )
{
CARDTYPE_REFERENCE * pCardType ;
CARD_TOKEN tkCard ;
LONG lConfidence ;
APIERR err ;
BOOL fFound = FALSE ;
while ( BumpIteration() )
{
// Get the CARDTYPE_REFERENCE pointer
pCardType = NthCardType( _cIterCardType ) ;
ASSERT( pCardType != NULL ) ;
// Perform the detection
TRACEEOL( SZ("NCPA/DTCT: attempting card detection on bus ")
<< (INT) _bus[_cIterBus].ifType
<< SZ("/")
<< (INT) _bus[_cIterBus].iBus
<< SZ(", type ")
<< pCardType->QueryOptionName() ) ;
err = pCardType->Dll()->FirstNext( pCardType->QueryType(),
_bus[_cIterBus].ifType,
_bus[_cIterBus].iBus,
fFirst,
& tkCard,
& lConfidence ) ;
if ( err == 0
&& lConfidence >= CONFIDENCE_MINIMUM )
{
fFound = TRUE ;
break ; // Found a card!
}
// If the caller is single-stepping, exit.
if ( fSingleStep )
break ;
}
// If we found a card, create and open a corresponding CARD_REFERENCE.
if ( fFound )
{
CARD_REFERENCE * pCard ;
pCard = new CARD_REFERENCE( _bus[_cIterBus],
pCardType,
tkCard,
lConfidence ) ;
if ( pCard )
{
if ( err = pCard->Open() )
{
delete pCard ;
}
else
{
*ppCardRef = pCard ;
}
}
else
{
err = ERROR_NOT_ENOUGH_MEMORY ;
}
}
else
{
err = ERROR_NO_MORE_ITEMS ;
}
return err ;
}
CARDTYPE_REFERENCE * DETECTION_MANAGER :: NthCardType ( INT iIndex )
{
ITER_SL_OF(CARDTYPE_REFERENCE) islCardType( _slCtypes ) ;
CARDTYPE_REFERENCE * pResult = NULL ;
for ( INT i = 0 ;
(pResult = islCardType.Next()) && i < iIndex ;
i++ ) ;
return pResult ;
}
/*******************************************************************
NAME: DETECTION_MANAGER::ReleaseCard
SYNOPSIS: Destroy the pointed CARD_REFERENCE create earlier
ENTRY:
EXIT:
RETURNS:
NOTES:
HISTORY:
********************************************************************/
VOID DETECTION_MANAGER :: ReleaseCard ( PCARD_REFERENCE pCardRef )
{
delete pCardRef ;
}
/*******************************************************************
NAME: DETECTION_MANAGER::FindOptionName
SYNOPSIS: Return a pointer to the CARDTYPE_REFERENCE whose
name is provided.
ENTRY:
EXIT:
RETURNS: NULL if not found.
NOTES:
HISTORY:
********************************************************************/
CARDTYPE_REFERENCE * DETECTION_MANAGER :: FindOptionName (
const TCHAR * pszOption )
{
ITER_SL_OF(CARDTYPE_REFERENCE) islCardType( _slCtypes ) ;
CARDTYPE_REFERENCE * pResult = NULL ;
while ( pResult = islCardType.Next() )
{
if ( ::stricmpf( pszOption, pResult->QueryOptionName()) == 0 )
break ;
}
return pResult ;
}
/*******************************************************************
NAME: DETECTION_MANAGER::FindOptionValue
SYNOPSIS: Given a list of parameter name and value Unicode
string pairs, return the corresponding numeric
value of the named option.
ENTRY: const TCHAR * pszOption name of the parameter
const TCHAR * pszOptionList buffer of string pairs
EXIT: nothing
RETURNS: LONG value or -1 if not found.
NOTES:
HISTORY:
********************************************************************/
LONG DETECTION_MANAGER :: FindOptionValue (
const TCHAR * pszOption,
const TCHAR * pszOptionList )
{
LONG lResult = -1 ;
const TCHAR * pszNext = pszOptionList ;
for ( ; *pszNext ; )
{
INT cchThis = ::strlenf( pszNext ) ;
INT cchNext = ::strlenf( pszNext + cchThis + 1 ) ;
if ( cchThis == 0 || cchNext == 0 )
break ;
if ( ::stricmpf( pszOption, pszNext ) == 0 )
{
lResult = ::CvtDecOrHex( pszNext + cchThis + 1 ) ;
break ;
}
pszNext += cchThis + cchNext + 2 ;
}
return lResult ;
}
/*******************************************************************
NAME: DETECTION_MANAGER::ClaimOrFreeParameterSet
SYNOPSIS: Claim or free a set of parameters.
ENTRY: LONG itBusType bus interface type
LONG lBusNumber bus instance number
const TCHAR * pszParamList ptr to packed list of
UNICODE parameter strings
BOOL fClaim TRUE if claim; otherwise
just check for availablity
ignored if "fFree".
BOOL fFree TRUE if freeing (! claiming)
EXIT: Nothing
RETURNS: APIERR if failure
NOTES: List is formatted as for DETECT_DLL::VerifyCfg(); i.e.,
PARAM_NAME_1\0<numeric value>\0PARAM_NAME_2\0<num value>,
etc.
HISTORY:
********************************************************************/
APIERR DETECTION_MANAGER :: ClaimOrFreeParameterSet (
INTERFACE_TYPE itBusType,
LONG lBusNumber,
const TCHAR * pszParamList,
BOOL fClaim,
BOOL fFree,
BOOL fTemporary )
{
APIERR err = 0 ;
// Check that the DLL was bound successfully.
if ( _pDtDllMsncdet == NULL )
return ERROR_FILE_NOT_FOUND ;
// Check that the DLL exported the function.
if ( ! _pDtDllMsncdet->QueryRtnAvail(fTemporary?
( fFree
? DDVI_TemporaryResourceFree
: DDVI_TemporaryResourceClaim ) :
( fFree
? DDVI_ResourceFree
: DDVI_ResourceClaim )))
{
return ERROR_INVALID_FUNCTION ;
}
if ( fTemporary && fFree )
{
_pDtDllMsncdet->TemporaryFreeResource( );
return err;
}
// Iterate the resource name table, claiming or freeing as we go.
for ( INT iParam = 0 ;
err == 0 && iParam < MAX_RESOURCE ;
iParam++ )
{
LONG lValue,
lRange = 0,
lFlags ;
// Check if this entry is valid
if ( apszClaimNames[ iParam ] == NULL )
continue ;
// See if it's being claimed
lValue = FindOptionValue( apszClaimNames[ iParam ],
pszParamList ) ;
if ( lValue < 0 )
continue ;
// See if it requires a corresponding length
if ( apszClaimRangeNames[ iParam ] )
{
lRange = FindOptionValue( apszClaimRangeNames[ iParam ],
pszParamList ) ;
if ( lRange < 0 )
{
// Required parameter range value MISSING!
err = ERROR_INVALID_PARAMETER ;
break ;
}
}
// Claim it: THIS IS DEPENDENT UPON THE DEFINITIONS
// in NNDDNETD.H (NETDTECT_IRQ_RESOURCE, et al.).
lFlags = iParam == NETDTECT_IRQ_RESOURCE
? NETDTECT_IRQ_RESOURCE_LATCHED
: 0 ;
// Claim or free the resource.
if ( fTemporary )
{
if ( !fFree )
{
err = _pDtDllMsncdet->TemporaryClaimResource( itBusType,
lBusNumber,
iParam,
lValue,
lRange,
lFlags,
fClaim ) ;
if ( err )
{
err = amsgidClaimErrors[ iParam ] ;
}
}
} else {
if ( fFree )
{
// Freeing errors are ignored. What's to do?
_pDtDllMsncdet->FreeResource( itBusType,
lBusNumber,
iParam,
lValue,
lRange,
lFlags ) ;
}
else
{
err = _pDtDllMsncdet->ClaimResource( itBusType,
lBusNumber,
iParam,
lValue,
lRange,
lFlags,
fClaim ) ;
if ( err )
{
err = amsgidClaimErrors[ iParam ] ;
}
}
}
}
return err ;
}
/*******************************************************************
NAME: DETECTION_MANAGER::ClaimParameterSet
SYNOPSIS: Claim or verify the availablilty of a set of parameters.
ENTRY: LONG itBusType bus interface type
LONG lBusNumber bus instance number
const TCHAR * pszParamList ptr to packed list of
UNICODE parameter strings
BOOL fClaim TRUE if claim; otherwise
just check for availablity
EXIT: Nothing
RETURNS: APIERR if failure (ERROR_INVALID_PARAMETER)
NOTES: List is formatted as for DETECT_DLL::VerifyCfg(); i.e.,
PARAM_NAME_1\0<numeric value>\0PARAM_NAME_2\0<num value>,
etc.
HISTORY:
********************************************************************/
APIERR DETECTION_MANAGER :: ClaimParameterSet (
INTERFACE_TYPE itBusType,
LONG lBusNumber,
const TCHAR * pszParamList,
BOOL fClaim,
BOOL fTemporary )
{
if (( ! fClaimingActive ) && ( !fTemporary ))
return NO_ERROR ;
return ClaimOrFreeParameterSet( itBusType,
lBusNumber,
pszParamList,
fClaim,
FALSE,
fTemporary ) ;
}
/*******************************************************************
NAME: DETECTION_MANAGER::FreeParameterSet
SYNOPSIS: Release a set of claimed parameters.
ENTRY: LONG itBusType bus interface type
LONG lBusNumber bus instance number
const TCHAR * pszParamList ptr to packed list of
UNICODE parameter strings
EXIT: Nothing
RETURNS: APIERR if failure (ERROR_INVALID_PARAMETER)
NOTES: List is formatted as for DETECT_DLL::VerifyCfg(); i.e.,
PARAM_NAME_1\0<numeric value>\0PARAM_NAME_2\0<num value>,
etc.
HISTORY: CODEWORK: There is NO EXPORT FROM MSNDCDET.DLL for
this yet. SeanSe and I are still discussing
the need for it. I'm providing it here for
symmmetry.
********************************************************************/
APIERR DETECTION_MANAGER :: FreeParameterSet (
INTERFACE_TYPE itBusType,
LONG lBusNumber,
const TCHAR * pszParamList,
BOOL fTemporary )
{
if (( ! fFreeingActive ) && ( !fTemporary ))
return NO_ERROR ;
return ClaimOrFreeParameterSet( itBusType,
lBusNumber,
pszParamList,
FALSE,
TRUE,
fTemporary ) ;
}
/*******************************************************************
NAME: DETECTION_MANAGER::VerifyCfg
SYNOPSIS: Helper function for overloaded VerifyConfiguration().
ENTRY: CARD_REFERENCE * pCardRef reference to detected card.
If NULL, just claim resources.
const TCHAR * pszCfgString the parameters to verify
BOOL fClaim TRUE if parameters are to remain
claimed.
EXIT: nothing
RETURNS: APIERR or 0 if successful
NOTES: The basic problem with this code is that we really should
know the bus type and number of the card in question. The
problem is that this would entail talking to the user in
truly cryptic terms. Fortunately, the actual number
of times when the bus problem arises is small, since most
machines have only one bus, and NOBODY has a machine with
multiple ISA buses.
So, the solution adopted here is as follows:
if we know the bus info, use it (detected card);
if not, and the machine has only one (non-internal)
bus, assume that it must be the bus in question;
otherwise, fail (ERROR_GEN_FAILURE);
if the single known bus is not ISA or EISA,
assume the card is OK, because "smart" buses do
not have the problems ISA buses do. EISA
is "smart" as well, but we cannot know whether
the card in an EISA slot is EISA or ISA.
HISTORY:
********************************************************************/
APIERR DETECTION_MANAGER :: VerifyCfg (
PCARD_REFERENCE pCardRef,
const TCHAR * pszCfgString,
BOOL fClaim )
{
APIERR err ;
INTERFACE_TYPE itBusType ;
INT lBusNumber ;
//
// BUGBUG: If we're given a specfic netcard, use it; otherwise,
// default to the zeroth bus. We REALLY need to store
// the bus info with the card and return it when needed.
//
if ( pCardRef )
{
itBusType = pCardRef->QueryIfType() ;
lBusNumber = pCardRef->QueryBus() ;
}
else
{
// We don't have all the data we need; however, if there's
// only one (dumb) bus, we can guess what bus this card is on.
INT iBus ;
// There must be exactly one non-internal bus
for ( iBus = 0 ; iBus < _cBuses ; iBus++ )
{
if ( _bus[iBus].ifType != Internal )
break ;
}
if ( iBus + 1 != _cBuses )
return ERROR_GEN_FAILURE ;
// Get bus type and number
QueryBusInfo( iBus, & itBusType, & lBusNumber );
// If the bus is smart, return NO_ERROR.
// Treat EISA as "dumb", since ISA cards can be used.
if ( itBusType != Eisa && itBusType != Isa )
return NO_ERROR ;
}
// If we have a detected card handle, verify the parameters
// with the netcard's DLL. In any case, claim the parameters
// as required.
do
{
if ( pCardRef != NULL
&& (err = pCardRef->VerifyConfiguration( pszCfgString )) )
break ;
if ( err = ClaimParameterSet( itBusType,
lBusNumber,
pszCfgString,
fClaim ) )
break ;
} while ( FALSE ) ;
return err ;
}
/*******************************************************************
NAME: DETECTION_MANAGER::VerifyConfiguration
SYNOPSIS: Given a CARD_REFERENCE and a set of parameters,
verify the card's configuration. If successful,
guarantee that there are no NT-level resource conflicts
by claiming all the parameters.
ENTRY: CARD_REFERENCE * pCardRef reference to detected card.
If NULL, just claim resources.
const TCHAR * pszSpList the parameters to verify
- or - CFG_RULE_SET * pcrsList
BOOL fClaim TRUE if parameters are to remain
claimed.
EXIT: nothing
RETURNS: APIERR or 0 if successful
NOTES:
HISTORY:
********************************************************************/
APIERR DETECTION_MANAGER :: VerifyConfiguration (
PCARD_REFERENCE pCardRef,
const TCHAR * pszSpList,
BOOL fClaim )
{
APIERR err ;
TCHAR * pszCfgString = NULL ;
// Convert the SProlog-style data to UNICODE string buffer format.
// Verify them with the netcard's DLL.
// Claim the parameters as required.
do
{
if ( err = convertSpListToParameterString( pszSpList,
& pszCfgString ) )
break ;
err = VerifyCfg( pCardRef, pszCfgString, fClaim ) ;
} while ( FALSE ) ;
delete pszCfgString ;
return err ;
}
APIERR DETECTION_MANAGER :: VerifyConfiguration (
PCARD_REFERENCE pCardRef,
CFG_RULE_SET * pcrsList,
BOOL fClaim )
{
APIERR err ;
TCHAR * pszCfgString = NULL ;
// Convert the CFG_RULE_SET to UNICODE string buffer format.
// Verify them with the netcard's DLL.
// Claim the parameters as required.
do
{
if ( err = convertParseTreeToParameterString( pcrsList,
& pszCfgString ) )
break ;
err = VerifyCfg( pCardRef, pszCfgString, fClaim ) ;
} while ( FALSE ) ;
delete pszCfgString ;
return err ;
}
/*******************************************************************
NAME: DETECTION_MANAGER::OpenCard
SYNOPSIS: Return a pointer to a CARD_REFERENCE for
an existing (previously installed) card.
ENTRY: const TCHAR * name of card option
INT iBus bus number
INTERFACE_TYPE bus type
EXIT:
RETURNS:
NOTES:
HISTORY:
********************************************************************/
CARD_REFERENCE * DETECTION_MANAGER :: OpenCard (
const TCHAR * pszOptionName,
INT iBus,
INTERFACE_TYPE ifType )
{
BUS_ELEMENT be ;
CARD_REFERENCE * pCard = NULL ;
CARDTYPE_REFERENCE * pcrf = FindOptionName( pszOptionName ) ;
be.ifType = ifType ;
be.iBus = iBus ;
// Find the option, create a card ref, open it.
if ( pcrf )
{
pCard = new CARD_REFERENCE( be, pcrf ) ;
if ( pCard->Open() )
{
delete pCard ;
pCard = NULL ;
}
}
return pCard ;
}
// End of NCPADTCT.CXX