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.
 
 
 
 
 
 

1485 lines
29 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
detElnk3.c
Abstract:
This is the main file for the autodetection DLL for all the Elnk3.sys
which MS is shipping with Windows NT.
Author:
Sean Selitrennikoff (SeanSe) October 1992.
Environment:
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ntddnetd.h"
#include "detect.h"
#include "detElnk3.h"
//
// Individual card detection routines
//
#ifdef WORKAROUND
UCHAR Elnk3FirstTime = 1;
//
// List of all the adapters supported in this file, this cannot be > 256
// because of the way tokens are generated.
//
//
// NOTE : If you change the index of an adapter, be sure the change it in
// Elnk3QueryCfgHandler() and Elnk3VerifyCfgHandler() as well!
//
static ADAPTER_INFO Adapters[] = {
{
1000,
L"ELNK3ISA509",
L"IOADDR 1 100 IRQ 1 100 TRANSCEIVER 1 100 PCMCIA 1 100 CARDTYPE 1 100",
NULL,
700
}
};
#else
//
// List of all the adapters supported in this file, this cannot be > 256
// because of the way tokens are generated.
//
//
// NOTE : If you change the index of an adapter, be sure the change it in
// Elnk3QueryCfgHandler() and Elnk3VerifyCfgHandler() as well!
//
static ADAPTER_INFO Adapters[] = {
{
1000,
L"ELNK3ISA509",
L"IOADDR\0"
L"1\0"
L"100\0"
L"IRQ\0"
L"1\0"
L"100\0"
L"TRANSCEIVER\0"
L"1\0"
L"100\0"
L"PCMCIA\0"
L"1\0"
L"100\0"
L"CARDTYPE\0"
L"1\0"
L"100\0",
NULL,
700
}
};
#endif
//
// Structure for holding state of a search
//
typedef struct _SEARCH_STATE
{
ULONG NumberOfAdapters;
ULONG CurrentAdapter;
USHORT IoBases[7];
UCHAR Irq[7];
UCHAR Transceiver[7];
}
SEARCH_STATE,
*PSEARCH_STATE;
//
// This is an array of search states. We need one state for each type
// of adapter supported.
//
static SEARCH_STATE SearchStates[sizeof(Adapters) / sizeof(ADAPTER_INFO)] = {0};
//
// Structure for holding a particular adapter's complete information
//
typedef struct _ELNK3_ADAPTER
{
INTERFACE_TYPE InterfaceType;
ULONG BusNumber;
USHORT IoBaseAddr;
UCHAR Irq;
UCHAR Transceiver;
}
ELNK3_ADAPTER,
*PELNK3_ADAPTER;
//
// Constant strings for parameters
//
static CHAR Elnk3String[] = "3C509";
USHORT
ELNK3ContentionTest(
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber,
IN ULONG IdPort,
IN UCHAR EEPromWord
);
VOID
ELNK3WriteIDSequence(
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber,
IN ULONG IdPort
);
UINT
Elnk3FindCards(
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber,
IN PSEARCH_STATE SearchState
);
VOID
Stall(
VOID
);
extern
LONG
Elnk3IdentifyHandler(
IN LONG Index,
IN WCHAR * Buffer,
IN LONG BuffSize
)
/*++
Routine Description:
This routine returns information about the netcards supported by
this file.
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 Buffer
Return Value:
0 if nothing went wrong, else the appropriate WINERROR.H value.
--*/
{
LONG NumberOfAdapters;
LONG Code = Index % 100;
LONG Length;
LONG i;
NumberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
#ifdef WORKAROUND
if (Elnk3FirstTime) {
Elnk3FirstTime = 0;
for (i = 0; i < NumberOfAdapters; i++) {
Length = UnicodeStrLen(Adapters[i].Parameters);
for (; Length > 0; Length--) {
if (Adapters[i].Parameters[Length] == L' ') {
Adapters[i].Parameters[Length] = UNICODE_NULL;
}
}
}
}
#endif
Index = Index - Code;
if (((Index / 100) - 10) < NumberOfAdapters) {
//
// Find the adapter
//
for (i=0; i < NumberOfAdapters; i++) {
if (Adapters[i].Index == Index) {
switch (Code) {
case 0:
//
// Find the string length
//
Length = UnicodeStrLen(Adapters[i].InfId);
Length ++;
if (BuffSize < Length) {
return(ERROR_INSUFFICIENT_BUFFER);
}
memcpy((PVOID)Buffer, Adapters[i].InfId, Length * sizeof(WCHAR));
break;
case 3:
//
// Maximum value is 1000
//
if (BuffSize < 5) {
return(ERROR_INSUFFICIENT_BUFFER);
}
wsprintf((PVOID)Buffer, L"%d", Adapters[i].SearchOrder);
break;
default:
return(ERROR_INVALID_PARAMETER);
}
return(0);
}
}
return(ERROR_INVALID_PARAMETER);
}
return(ERROR_NO_MORE_ITEMS);
}
extern
LONG Elnk3FirstNextHandler(
IN LONG NetcardId,
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber,
IN BOOL First,
OUT PVOID *ppvToken,
OUT LONG *lConfidence
)
/*++
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 - Either Isa, or Eisa.
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.
--*/
{
NETDTECT_RESOURCE Resource;
*lConfidence = 0;
*ppvToken = 0;
if ((InterfaceType != Isa) && (InterfaceType != Eisa))
{
return(0);
}
if (First)
{
SearchStates[0].CurrentAdapter = 0;
Elnk3FindCards(
InterfaceType,
BusNumber,
SearchStates);
}
else
{
if (++SearchStates[0].CurrentAdapter > 7)
{
return(0);
}
}
while (SearchStates[0].CurrentAdapter < 7)
{
if ((SearchStates[0].IoBases[SearchStates[0].CurrentAdapter] != 0) &&
(SearchStates[0].IoBases[SearchStates[0].CurrentAdapter] != 0x3f0))
{
//
// Acquire the resources.
//
Resource.InterfaceType = InterfaceType;
Resource.BusNumber = BusNumber;
Resource.Type = NETDTECT_PORT_RESOURCE;
Resource.Value = SearchStates[0].IoBases[SearchStates[0].CurrentAdapter];
Resource.Length = 0x10;
Resource.Flags = 0;
DetectTemporaryClaimResource(&Resource);
Resource.Type = NETDTECT_IRQ_RESOURCE;
Resource.Value = SearchStates[0].Irq[SearchStates[0].CurrentAdapter];
Resource.Length = 0;
DetectTemporaryClaimResource(&Resource);
break;
}
SearchStates[0].CurrentAdapter++;
}
if (SearchStates[0].CurrentAdapter == 7)
{
return(0);
}
//
// In this module I use the token as follows: Remember that
// the token can only be 2 bytes long (the low 2) because of
// the interface to the upper part of this DLL.
//
// The high bit of the short is boolean for ISA (else, EISA).
// The rest of the high byte is the the bus number.
// The low byte is the driver index number into Adapters.
//
// NOTE: This presumes that there are < 129 buses in the
// system. Is this reasonable?
//
if (InterfaceType == Isa)
{
*ppvToken = (PVOID)0x8000;
}
else
{
*ppvToken = (PVOID)0x0;
}
*ppvToken = (PVOID)(((ULONG)*ppvToken) | ((BusNumber & 0x7F) << 8));
*ppvToken = (PVOID)(((ULONG)*ppvToken) | 0); // index
*lConfidence = 100;
return(0);
}
extern
LONG
Elnk3OpenHandleHandler(
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.
--*/
{
PELNK3_ADAPTER Adapter;
LONG AdapterNumber;
ULONG BusNumber;
INTERFACE_TYPE InterfaceType;
//
// Get info from the token
//
if (((ULONG)Token) & 0x8000)
{
InterfaceType = Isa;
}
else
{
InterfaceType = Eisa;
}
BusNumber = (ULONG)(((ULONG)Token >> 8) & 0x7F);
AdapterNumber = ((ULONG)Token) & 0xFF;
//
// Store information
//
Adapter = (PELNK3_ADAPTER)DetectAllocateHeap(sizeof(ELNK3_ADAPTER));
if (Adapter == NULL)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
//
// Copy across memory address
//
Adapter->IoBaseAddr = SearchStates[(ULONG)AdapterNumber].IoBases[SearchStates[(ULONG)AdapterNumber].CurrentAdapter];
Adapter->Irq = SearchStates[(ULONG)AdapterNumber].Irq[SearchStates[(ULONG)AdapterNumber].CurrentAdapter];
Adapter->Transceiver= SearchStates[(ULONG)AdapterNumber].Transceiver[SearchStates[(ULONG)AdapterNumber].CurrentAdapter];
Adapter->InterfaceType = InterfaceType;
Adapter->BusNumber = BusNumber;
*Handle = (PVOID)Adapter;
return(0);
}
extern
LONG Elnk3CreateHandleHandler(
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 - Isa or Eisa.
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.
--*/
{
PELNK3_ADAPTER Adapter;
LONG NumberOfAdapters;
LONG i;
NETDTECT_RESOURCE Resource;
if ((InterfaceType != Isa) && (InterfaceType != Eisa))
{
return(ERROR_INVALID_PARAMETER);
}
NumberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
for (i = 0; i < NumberOfAdapters; i++)
{
if (Adapters[i].Index == NetcardId)
{
//
// Store information
//
Adapter = (PELNK3_ADAPTER)DetectAllocateHeap(sizeof(ELNK3_ADAPTER));
if (Adapter == NULL)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
//
// Copy across memory address
//
Adapter->IoBaseAddr = 0x300;
Adapter->Irq = 10;
Adapter->Transceiver = 0;
Adapter->InterfaceType = InterfaceType;
Adapter->BusNumber = BusNumber;
//
// Acquire the resources.
//
Resource.InterfaceType = InterfaceType;
Resource.BusNumber = BusNumber;
Resource.Type = NETDTECT_PORT_RESOURCE;
Resource.Value = 0x300;
Resource.Length = 0x10;
Resource.Flags = 0;
DetectTemporaryClaimResource(&Resource);
Resource.Type = NETDTECT_IRQ_RESOURCE;
Resource.Value = 10;
Resource.Length = 0;
DetectTemporaryClaimResource(&Resource);
*Handle = (PVOID)Adapter;
return(0);
}
}
return(ERROR_INVALID_PARAMETER);
}
extern
LONG
Elnk3CloseHandleHandler(
IN PVOID Handle
)
/*++
Routine Description:
This frees any resources associated with a handle.
Arguments:
Handle - The handle.
Return Value:
0 if nothing went wrong, else the appropriate WINERROR.H value.
--*/
{
DetectFreeHeap(Handle);
return(0);
}
LONG
Elnk3QueryCfgHandler(
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.
--*/
{
PELNK3_ADAPTER Adapter = (PELNK3_ADAPTER)(Handle);
ULONG ParameterValue = 0;
LONG OutputLengthLeft = BuffSize;
LONG CopyLength;
ULONG StartPointer = (ULONG)Buffer;
if ((Adapter->InterfaceType != Isa) && (Adapter->InterfaceType != Eisa))
{
return(ERROR_INVALID_PARAMETER);
}
//
// Now the IoBaseAddress
//
ParameterValue = Adapter->IoBaseAddr;
//
// Copy in the title string
//
CopyLength = UnicodeStrLen(IoAddrString) + 1;
if (OutputLengthLeft < CopyLength)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
RtlMoveMemory((PVOID)Buffer,
(PVOID)IoAddrString,
(CopyLength * sizeof(WCHAR)));
Buffer = &(Buffer[CopyLength]);
OutputLengthLeft -= CopyLength;
//
// Copy in the value
//
if (OutputLengthLeft < 6)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
CopyLength = wsprintf(Buffer,L"0x%x",ParameterValue);
if (CopyLength < 0)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
CopyLength++; // Add in the \0
Buffer = &(Buffer[CopyLength]);
//
// Now the IRQ
//
ParameterValue = Adapter->Irq;
//
// Copy in the title string
//
CopyLength = UnicodeStrLen(IrqString) + 1;
if (OutputLengthLeft < CopyLength)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
RtlMoveMemory((PVOID)Buffer,
(PVOID)IrqString,
(CopyLength * sizeof(WCHAR)));
Buffer = &(Buffer[CopyLength]);
OutputLengthLeft -= CopyLength;
//
// Copy in the value
//
if (OutputLengthLeft < 6)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
CopyLength = wsprintf(Buffer,L"0x%x",ParameterValue);
if (CopyLength < 0)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
CopyLength++; // Add in the \0
Buffer = &(Buffer[CopyLength]);
//
// Now the transceiver
//
ParameterValue=Adapter->Transceiver;
//
// Copy in the title string
//
CopyLength = UnicodeStrLen(TransceiverString) + 1;
if (OutputLengthLeft < CopyLength)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
RtlMoveMemory((PVOID)Buffer,
(PVOID)TransceiverString,
(CopyLength * sizeof(WCHAR)));
Buffer = &(Buffer[CopyLength]);
OutputLengthLeft -= CopyLength;
//
// Copy in the value
//
if (OutputLengthLeft < 6)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
CopyLength = wsprintf(Buffer,L"0x%x",ParameterValue);
if (CopyLength < 0)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
CopyLength++; // Add in the \0
Buffer = &(Buffer[CopyLength]);
OutputLengthLeft -= CopyLength;
//
// Add the PCMCIA parameter.
//
CopyLength = UnicodeStrLen(PcmciaString) + 1;
if (OutputLengthLeft < CopyLength)
return(ERROR_INSUFFICIENT_BUFFER);
RtlMoveMemory(Buffer, PcmciaString, CopyLength * sizeof(WCHAR));
Buffer = &(Buffer[CopyLength]);
OutputLengthLeft -= CopyLength;
if (OutputLengthLeft < 2)
return(ERROR_INSUFFICIENT_BUFFER);
CopyLength = wsprintf(Buffer, L"%d", 0);
if (CopyLength < 0)
return(ERROR_INSUFFICIENT_BUFFER);
CopyLength++;
Buffer = &(Buffer[CopyLength]);
OutputLengthLeft -= CopyLength;
//
// Add the CARDTYPE parameter.
//
CopyLength = UnicodeStrLen(CardTypeString) + 1;
if (OutputLengthLeft < CopyLength)
return(ERROR_INSUFFICIENT_BUFFER);
RtlMoveMemory(Buffer, CardTypeString, CopyLength * sizeof(WCHAR));
Buffer = &(Buffer[CopyLength]);
OutputLengthLeft -= CopyLength;
if (OutputLengthLeft < 2)
return(ERROR_INSUFFICIENT_BUFFER);
CopyLength = wsprintf(Buffer, L"%d", 0);
if (CopyLength < 0)
return(ERROR_INSUFFICIENT_BUFFER);
CopyLength++;
Buffer[CopyLength] = L'\0';
return(0);
}
BOOLEAN
TestParameter(
PWCHAR Buffer,
PWCHAR SearchString,
ULONG Value
)
{
BOOLEAN Found;
PWCHAR Place;
ULONG Parameter;
//
// Get the IoBaseAddress
//
Place = FindParameterString(Buffer, SearchString);
if (Place == NULL)
{
return(ERROR_INVALID_DATA);
}
Place += UnicodeStrLen(SearchString) + 1;
//
// Now parse the thing.
//
ScanForNumber(Place, &Parameter, &Found);
if (Found == FALSE)
{
return FALSE;
}
if (Parameter != Value)
{
return FALSE;
}
return TRUE;
}
extern
LONG
Elnk3VerifyCfgHandler(
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.
--*/
{
PELNK3_ADAPTER Adapter = (PELNK3_ADAPTER)(Handle);
BOOLEAN Found = FALSE;
if ((Adapter->InterfaceType != Isa) && (Adapter->InterfaceType != Eisa))
{
return(ERROR_INVALID_DATA);
}
Found = TestParameter(
Buffer,
IoAddrString,
Adapter->IoBaseAddr);
if (Found == FALSE)
{
return(ERROR_INVALID_DATA);
}
Found=TestParameter(
Buffer,
IrqString,
Adapter->Irq);
if (Found == FALSE)
{
return(ERROR_INVALID_DATA);
}
Found=TestParameter(
Buffer,
TransceiverString,
Adapter->Transceiver);
if (Found == FALSE)
{
return(ERROR_INVALID_DATA);
}
Found = TestParameter(Buffer, PcmciaString, 0);
if (!Found)
return(ERROR_INVALID_DATA);
Found = TestParameter(Buffer, CardTypeString, 1);
if (!Found)
return(ERROR_INVALID_DATA);
return(NO_ERROR);
}
extern
LONG Elnk3QueryMaskHandler(
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.
--*/
{
WCHAR *Result;
LONG Length;
LONG NumberOfAdapters;
LONG i;
//
// Find the adapter
//
NumberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
for (i=0; i < NumberOfAdapters; i++)
{
if (Adapters[i].Index == NetcardId)
{
Result = Adapters[i].Parameters;
//
// Find the string length (Ends with 2 NULLs)
//
for (Length=0; ; Length++)
{
if (Result[Length] == L'\0')
{
++Length;
if (Result[Length] == L'\0')
{
break;
}
}
}
Length++;
if (BuffSize < Length)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
memcpy((PVOID)Buffer, Result, Length * sizeof(WCHAR));
return(0);
}
}
return(ERROR_INVALID_PARAMETER);
}
extern
LONG
Elnk3ParamRangeHandler(
IN LONG NetcardId,
IN WCHAR *Param,
OUT LONG *plValues,
OUT LONG *plBuffSize
)
/*++
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.
plValues - A pointer to a list of LONGs into which we store valid values
for the parameter.
plBuffSize - 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.
--*/
{
//
// Verify that the caller is looking for us.
//
if (1000 != NetcardId)
{
*plBuffSize = 0;
return(ERROR_INVALID_PARAMETER);
}
//
// Do we want the IoBaseAddress
//
if (memcmp(Param, IoAddrString, (UnicodeStrLen(IoAddrString) + 1) * sizeof(WCHAR)) == 0) {
//
// Is there enough space
//
if (*plBuffSize < 31) {
*plBuffSize = 0;
return(ERROR_INSUFFICIENT_BUFFER);
}
plValues[0] = 0x200;
plValues[1] = 0x210;
plValues[2] = 0x220;
plValues[3] = 0x230;
plValues[4] = 0x240;
plValues[5] = 0x250;
plValues[6] = 0x260;
plValues[7] = 0x270;
plValues[8] = 0x280;
plValues[9] = 0x290;
plValues[10] = 0x2a0;
plValues[11] = 0x2b0;
plValues[12] = 0x2c0;
plValues[13] = 0x2d0;
plValues[14] = 0x2e0;
plValues[15] = 0x2f0;
plValues[16] = 0x300;
plValues[17] = 0x310;
plValues[18] = 0x320;
plValues[19] = 0x330;
plValues[20] = 0x340;
plValues[21] = 0x350;
plValues[22] = 0x360;
plValues[23] = 0x370;
plValues[24] = 0x380;
plValues[25] = 0x390;
plValues[26] = 0x3a0;
plValues[27] = 0x3b0;
plValues[28] = 0x3c0;
plValues[29] = 0x3d0;
plValues[30] = 0x3e0;
*plBuffSize = 31;
return(0);
}
//
// Do we want the Irq
//
if (memcmp(Param, IrqString, (UnicodeStrLen(IrqString) + 1) * sizeof(WCHAR)) == 0) {
//
// Is there enough space
//
if (*plBuffSize < 8) {
*plBuffSize = 0;
return(ERROR_INSUFFICIENT_BUFFER);
}
plValues[0] = 3;
plValues[1] = 5;
plValues[2] = 7;
plValues[3] = 9;
plValues[4] = 10;
plValues[5] = 11;
plValues[6] = 12;
plValues[7] = 15;
*plBuffSize = 8;
return(0);
}
//
// Do we want the Transceiver
//
if (memcmp(Param, TransceiverString, (UnicodeStrLen(TransceiverString) + 1) * sizeof(WCHAR)) == 0) {
//
// Is there enough space
//
if (*plBuffSize < 3) {
*plBuffSize = 0;
return(ERROR_INSUFFICIENT_BUFFER);
}
plValues[0] = 0;
plValues[1] = 1;
plValues[2] = 3;
*plBuffSize = 3;
return(0);
}
return(ERROR_INVALID_PARAMETER);
}
extern
LONG Elnk3QueryParameterNameHandler(
IN WCHAR *Param,
OUT WCHAR *Buffer,
IN LONG BufferSize
)
/*++
Routine Description:
Returns a localized, displayable name for a specific parameter. All the
parameters that this file uses are define by MS, so no strings are
needed here.
Arguments:
Param - The parameter to be queried.
Buffer - The buffer to store the result into.
BufferSize - The length of Buffer in WCHARs.
Return Value:
ERROR_INVALID_PARAMETER -- To indicate that the MS supplied strings
should be used.
--*/
{
return(ERROR_INVALID_PARAMETER);
}
UINT
Elnk3FindCards(
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber,
IN PSEARCH_STATE SearchState
)
{
NTSTATUS NtStatus;
ULONG IdPort;
USHORT AddressConfigRegister;
USHORT ResourceConfigRegister;
USHORT ProductId;
UINT i;
SearchStates->NumberOfAdapters = 0;
for (i = 0; i < 16; i++)
{
NtStatus = DetectCheckPortUsage(
InterfaceType,
BusNumber,
0x100 + (i << 4),
1);
if (NtStatus == STATUS_SUCCESS)
{
break;
}
}
if (NtStatus != STATUS_SUCCESS)
{
return(0);
}
IdPort = 0x100 + (i << 4);
ELNK3WriteIDSequence(InterfaceType, BusNumber, IdPort);
NtStatus = DetectWritePortUchar(
InterfaceType,
BusNumber,
IdPort,
IDCMD_SET_TAG + 0);
SearchStates->NumberOfAdapters = 0;
for (i = 1; i < 8 ; i++)
{
//
// Get the cards' attention
//
ELNK3WriteIDSequence( InterfaceType, BusNumber, IdPort );
//
// See if there any cards out there
//
if (ELNK3ContentionTest( InterfaceType, BusNumber,IdPort, EE_MANUFACTURER_CODE ) == EISA_MANUFACTURER_ID)
{
ELNK3ContentionTest(InterfaceType, BusNumber, IdPort, EE_TCOM_NODE_ADDR_WORD0);
ELNK3ContentionTest(InterfaceType, BusNumber, IdPort, EE_TCOM_NODE_ADDR_WORD1);
ELNK3ContentionTest(InterfaceType, BusNumber, IdPort, EE_TCOM_NODE_ADDR_WORD2);
ProductId = ELNK3ContentionTest(InterfaceType, BusNumber, IdPort, EE_VULCAN_PROD_ID );
ProductId &= 0xf0ff;
if (ProductId == 0x9050)
{
//
// This one is a elnk3 adapter
//
//
// This one won the contention battle
// Get it's i/o base and irq from the eeprom
//
AddressConfigRegister = ELNK3ContentionTest(InterfaceType, BusNumber, IdPort, EE_ADDR_CONFIGURATION );
SearchStates->IoBases[i-1] = 0x200 + ((AddressConfigRegister & 0x1f) << 4);
SearchStates->Transceiver[i-1] = AddressConfigRegister >> 14;
ResourceConfigRegister = ELNK3ContentionTest(InterfaceType, BusNumber, IdPort, EE_RESOURCE_CONFIGURATION );
SearchStates->Irq[i-1] = ResourceConfigRegister >> 12;
}
else
{
//
// it's a 3com card but not an elnk3
// set the iobase so that it looks like and eisa
// which will be ignored
//
SearchStates->IoBases[i-1]=0x3f0;
}
//
// Tag it so it don't bother us again
//
NtStatus = DetectWritePortUchar(
InterfaceType,
BusNumber,
IdPort,
(UCHAR)(IDCMD_SET_TAG+(i)));
//
// One more found
//
SearchStates->NumberOfAdapters++;
}
else
{
//
// No more elnk3 cards
//
break;
}
}
return 0;
}
VOID
ELNK3WriteIDSequence(
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber,
IN ULONG IdPort
)
/*++
Routine Description:
Writes the magic EtherLink III wake up sequence to a port.
This puts all uninitialized EtherLink III cards on the bus in the ID_CMD
state.
Must be called with exclusive access to all 1x0h ports, where x is any
hex digit.
Arguments:
Return Value:
--*/
{
NTSTATUS NtStatus;
USHORT outval;
UINT i;
NtStatus = DetectWritePortUchar(InterfaceType, BusNumber, IdPort, 0);
NtStatus = DetectWritePortUchar(InterfaceType, BusNumber, IdPort, 0);
for ( outval = 0xff, i = 255 ; i-- ; )
{
NtStatus = DetectWritePortUchar(
InterfaceType,
BusNumber,
IdPort,
(UCHAR)outval);
outval <<= 1;
if (( outval & 0x0100 ) != 0 )
{
outval ^= 0xCF;
}
}
}
USHORT
ELNK3ContentionTest(
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber,
IN ULONG IdPort,
IN UCHAR EEPromWord
)
{
UCHAR data;
USHORT result;
UINT i;
NTSTATUS NtStatus;
NtStatus = DetectWritePortUchar(
InterfaceType,
BusNumber,
IdPort,
(UCHAR)(IDCMD_READ_PROM + EEPromWord));
/*
3COM's detection code has a 400 microsecond delay here.
*/
Sleep(20);
for ( i = 16, result = 0 ; i-- ; )
{
result <<= 1;
NtStatus = DetectReadPortUchar(
InterfaceType,
BusNumber,
IdPort,
&data);
result += (data & 1);
}
return (result);
}