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.
 
 
 
 
 
 

2029 lines
40 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
detee16.c
Abstract:
This is the main file for the autodetection DLL for all the ee16.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"
//
// Individual card detection routines
//
BOOLEAN
Ee16CardAt(
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber,
IN ULONG IoBaseAddress,
OUT PUCHAR Interrupt,
OUT PULONG Transceiver,
OUT PULONG IoChannelReady
);
ULONG
Ee16NextIoBaseAddress(
IN ULONG IoBaseAddress
);
VOID
Ee16GenerateIdPattern(
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber
);
USHORT
read_eeprom(
INTERFACE_TYPE InterfaceType,
ULONG BusNumber,
ULONG IoBaseAddress,
ULONG reg
);
void
shift_out_bits(
INTERFACE_TYPE InterfaceType,
ULONG BusNumber,
ULONG IoBaseAddress,
USHORT data,
USHORT count
);
void
raise_clock(
INTERFACE_TYPE InterfaceType,
ULONG BusNumber,
ULONG IoBaseAddress,
USHORT *x
);
void
lower_clock(
INTERFACE_TYPE InterfaceType,
ULONG BusNumber,
ULONG IoBaseAddress,
USHORT *x
);
USHORT
shift_in_bits(
INTERFACE_TYPE InterfaceType,
ULONG BusNumber,
ULONG IoBaseAddress
);
void
eeprom_cleanup(
INTERFACE_TYPE InterfaceType,
ULONG BusNumber,
ULONG IoBaseAddress
);
UCHAR Ee16FirstTime = 1;
#ifdef WORKAROUND
//
// 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
// Ee16QueryCfgHandler() and Ee16VerifyCfgHandler() as well!
//
static ADAPTER_INFO Adapters[] = {
{
1000,
L"EE16",
L"IRQ 0 100 IRQTYPE 2 100 IOADDR 0 100 IOADDRLENGTH 2 100 IOCHANNELREADY 0 100 TRANSCEIVER 0 100 ",
NULL,
600
}
};
#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
// Ee16QueryCfgHandler() and Ee16VerifyCfgHandler() as well!
//
static ADAPTER_INFO Adapters[] = {
{
1000,
L"EE16",
L"IRQ\0"
L"0\0"
L"100\0"
L"IRQTYPE\0"
L"2\0"
L"100\0"
L"IOADDR\0"
L"0\0"
L"100\0"
L"IOADDRLENGTH\0"
L"2\0"
L"100\0"
L"IOCHANNELREADY\0"
L"0\0"
L"100\0"
L"TRANSCEIVER\0"
L"0\0"
L"100\0",
NULL,
600
}
};
#endif
//
// Structure for holding state of a search
//
typedef struct _SEARCH_STATE
{
ULONG IoBaseAddress;
UCHAR Interrupt;
ULONG Transceiver;
ULONG IoChannelReady;
}
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 _EE16_ADAPTER
{
LONG CardType;
INTERFACE_TYPE InterfaceType;
ULONG BusNumber;
ULONG IoBaseAddress;
UCHAR Interrupt;
ULONG Transceiver;
ULONG IoChannelReady;
}
EE16_ADAPTER,
*PEE16_ADAPTER;
extern
LONG
Ee16IdentifyHandler(
IN LONG lIndex,
IN WCHAR * pwchBuffer,
IN LONG cwchBuffSize
)
/*++
Routine Description:
This routine returns information about the netcards supported by
this file.
Arguments:
lIndex - The index of the netcard being address. The first
cards information is at index 1000, the second at 1100, etc.
pwchBuffer - Buffer to store the result into.
cwchBuffSize - Number of bytes in pwchBuffer
Return Value:
0 if nothing went wrong, else the appropriate WINERROR.H value.
--*/
{
LONG NumberOfAdapters;
LONG Code = lIndex % 100;
LONG Length;
LONG i;
NumberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
#ifdef WORKAROUND
if (Ee16FirstTime) {
Ee16FirstTime = 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
lIndex = lIndex - Code;
if (((lIndex / 100) - 10) < NumberOfAdapters) {
for (i=0; i < NumberOfAdapters; i++) {
if (Adapters[i].Index == lIndex) {
switch (Code) {
case 0:
//
// Find the string length
//
Length = UnicodeStrLen(Adapters[i].InfId);
Length ++;
if (cwchBuffSize < Length) {
return(ERROR_INSUFFICIENT_BUFFER);
}
memcpy((PVOID)pwchBuffer, Adapters[i].InfId, Length * sizeof(WCHAR));
break;
case 3:
//
// Maximum value is 1000
//
if (cwchBuffSize < 5) {
return(ERROR_INSUFFICIENT_BUFFER);
}
wsprintf((PVOID)pwchBuffer, L"%d", Adapters[i].SearchOrder);
break;
default:
return(ERROR_INVALID_PARAMETER);
}
return(0);
}
}
return(ERROR_INVALID_PARAMETER);
}
return(ERROR_NO_MORE_ITEMS);
}
extern
LONG
Ee16FirstNextHandler(
IN LONG lNetcardId,
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber,
IN BOOL fFirst,
OUT PVOID *ppvToken,
OUT LONG *lConfidence
)
/*++
Routine Description:
This routine finds the instances of a physical adapter identified
by the NetcardId.
NOTE: That for now there is only one card supported by this file,
so we ignore the specific FirstNext handler in Adapters to save
some processing time.
Arguments:
lNetcardId - 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.
fFirst - 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.
ppvToken - A pointer to a handle to return to identify the found
instance
lConfidence - 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;
if ((InterfaceType != Isa) && (InterfaceType != Eisa))
{
*lConfidence = 0;
return(0);
}
if (lNetcardId != 1000)
{
*lConfidence = 0;
return(ERROR_INVALID_PARAMETER);
}
//
// If fFirst, reset search state
//
if (fFirst)
{
SearchStates[0].IoBaseAddress = 0x200;
}
else
{
SearchStates[0].IoBaseAddress = Ee16NextIoBaseAddress(
SearchStates[0].IoBaseAddress);
}
//
// Find an adapter
//
while (SearchStates[0].IoBaseAddress != 0x400)
{
if (Ee16CardAt(
InterfaceType,
BusNumber,
SearchStates[0].IoBaseAddress,
&SearchStates[0].Interrupt,
&SearchStates[0].Transceiver,
&SearchStates[0].IoChannelReady))
{
break;
}
SearchStates[0].IoBaseAddress = Ee16NextIoBaseAddress(
SearchStates[0].IoBaseAddress);
}
if (SearchStates[0].IoBaseAddress == 0x400)
{
*lConfidence = 0;
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
Ee16OpenHandleHandler(
IN PVOID pvToken,
OUT PVOID *ppvHandle
)
/*++
Routine Description:
This routine takes a token returned by FirstNext and converts it
into a permanent handle.
Arguments:
Token - The token.
ppvHandle - 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.
--*/
{
PEE16_ADAPTER Handle;
LONG AdapterNumber;
ULONG BusNumber;
INTERFACE_TYPE InterfaceType;
//
// Get info from the token
//
if (((ULONG)pvToken) & 0x8000)
{
InterfaceType = Isa;
}
else
{
InterfaceType = Eisa;
}
BusNumber = (ULONG)(((ULONG)pvToken >> 8) & 0x7F);
AdapterNumber = ((ULONG)pvToken) & 0xFF;
//
// Store information
//
Handle = (PEE16_ADAPTER)DetectAllocateHeap(sizeof(EE16_ADAPTER));
if (Handle == NULL)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
//
// Copy across address
//
Handle->IoBaseAddress = SearchStates[(ULONG)AdapterNumber].IoBaseAddress;
Handle->Interrupt = SearchStates[(ULONG)AdapterNumber].Interrupt;
Handle->Transceiver = SearchStates[(ULONG)AdapterNumber].Transceiver;
Handle->IoChannelReady = SearchStates[(ULONG)AdapterNumber].IoChannelReady;
Handle->CardType = Adapters[AdapterNumber].Index;
Handle->InterfaceType = InterfaceType;
Handle->BusNumber = BusNumber;
*ppvHandle = (PVOID)Handle;
return(0);
}
extern
LONG
Ee16CreateHandleHandler(
IN LONG lNetcardId,
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber,
OUT PVOID *ppvHandle
)
/*++
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:
lNetcardId - The id of the card to create the handle for.
InterfaceType - Isa or Eisa.
BusNumber - The bus number of the bus in the system.
ppvHandle - A pointer to the handle, for storing the resulting handle.
Return Value:
0 if nothing went wrong, else the appropriate WINERROR.H value.
--*/
{
PEE16_ADAPTER Handle;
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 == lNetcardId)
{
//
// Store information
//
Handle = (PEE16_ADAPTER)DetectAllocateHeap(sizeof(EE16_ADAPTER));
if (Handle == NULL)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
//
// Copy across memory address
//
Handle->IoBaseAddress = 0x300;
Handle->Interrupt = 5;
Handle->Transceiver = 1;
Handle->IoChannelReady = 2;
Handle->CardType = lNetcardId;
Handle->InterfaceType = InterfaceType;
Handle->BusNumber = BusNumber;
//
// We need to claim this port so no one else uses it....
//
Resource.InterfaceType = InterfaceType;
Resource.BusNumber = BusNumber;
Resource.Type = NETDTECT_PORT_RESOURCE;
Resource.Value = 0x300;
Resource.Length = 0x10;
DetectTemporaryClaimResource(&Resource);
Resource.Type = NETDTECT_IRQ_RESOURCE;
Resource.Value = 5;
Resource.Length = 0;
DetectTemporaryClaimResource(&Resource);
*ppvHandle = (PVOID)Handle;
return(0);
}
}
return(ERROR_INVALID_PARAMETER);
}
extern
LONG
Ee16CloseHandleHandler(
IN PVOID pvHandle
)
/*++
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.
--*/
{
DetectFreeHeap(pvHandle);
return(0);
}
LONG
Ee16QueryCfgHandler(
IN PVOID pvHandle,
OUT WCHAR *pwchBuffer,
IN LONG cwchBuffSize
)
/*++
Routine Description:
This routine calls the appropriate driver's query config handler to
get the parameters for the adapter associated with the handle.
Arguments:
pvHandle - The handle.
pwchBuffer - The resulting parameter list.
cwchBuffSize - Length of the given buffer in WCHARs.
Return Value:
0 if nothing went wrong, else the appropriate WINERROR.H value.
--*/
{
PEE16_ADAPTER Adapter = (PEE16_ADAPTER)(pvHandle);
NTSTATUS NtStatus;
LONG OutputLengthLeft = cwchBuffSize;
LONG CopyLength;
ULONG StartPointer = (ULONG)pwchBuffer;
NETDTECT_RESOURCE Resource;
if ((Adapter->InterfaceType != Isa) && (Adapter->InterfaceType != Eisa))
{
return(ERROR_INVALID_PARAMETER);
}
//
// Copy in the title string
//
CopyLength = UnicodeStrLen(IoAddrString) + 1;
if (OutputLengthLeft < CopyLength)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
RtlMoveMemory((PVOID)pwchBuffer,
(PVOID)IoAddrString,
(CopyLength * sizeof(WCHAR)));
pwchBuffer = &(pwchBuffer[CopyLength]);
OutputLengthLeft -= CopyLength;
//
// Copy in the value
//
if (OutputLengthLeft < 6)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
CopyLength = wsprintf(pwchBuffer,L"0x%x",Adapter->IoBaseAddress);
if (CopyLength < 0)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
CopyLength++; // Add in the \0
pwchBuffer = &(pwchBuffer[CopyLength]);
OutputLengthLeft -= CopyLength;
//
// Now the IoAddressLength
//
//
// Copy in the title string
//
CopyLength = UnicodeStrLen(IoLengthString) + 1;
if (OutputLengthLeft < CopyLength)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
RtlMoveMemory((PVOID)pwchBuffer,
(PVOID)IoLengthString,
(CopyLength * sizeof(WCHAR)));
pwchBuffer = &(pwchBuffer[CopyLength]);
OutputLengthLeft -= CopyLength;
//
// Copy in the value
//
if (OutputLengthLeft < 5)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
CopyLength = wsprintf(pwchBuffer,L"0x10");
if (CopyLength < 0)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
CopyLength++; // Add in the \0
pwchBuffer = &(pwchBuffer[CopyLength]);
OutputLengthLeft -= CopyLength;
//
// Now the interrupt number
//
//
// Copy in the title string
//
CopyLength = UnicodeStrLen(IrqString) + 1;
if (OutputLengthLeft < CopyLength)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
RtlMoveMemory((PVOID)pwchBuffer,
(PVOID)IrqString,
(CopyLength * sizeof(WCHAR)));
pwchBuffer = &(pwchBuffer[CopyLength]);
OutputLengthLeft -= CopyLength;
//
// Copy in the value
//
if (OutputLengthLeft < 3)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
CopyLength = wsprintf(pwchBuffer,L"%d", Adapter->Interrupt);
if (CopyLength < 0)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
CopyLength++; // Add in the \0
pwchBuffer = &(pwchBuffer[CopyLength]);
OutputLengthLeft -= CopyLength;
//
// Copy in the title string (IRQTYPE)
//
CopyLength = UnicodeStrLen(IrqTypeString) + 1;
if (OutputLengthLeft < CopyLength)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
RtlMoveMemory((PVOID)pwchBuffer,
(PVOID)IrqTypeString,
(CopyLength * sizeof(WCHAR)));
pwchBuffer = &(pwchBuffer[CopyLength]);
OutputLengthLeft -= CopyLength;
//
// Copy in the value
//
if (OutputLengthLeft < 2)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
CopyLength = wsprintf(pwchBuffer,L"0");
if (CopyLength < 0)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
CopyLength++; // Add in the \0
pwchBuffer = &(pwchBuffer[CopyLength]);
OutputLengthLeft -= CopyLength;
//
// Now the TransceiverType
//
//
// Copy in the title string
//
CopyLength = UnicodeStrLen(TransceiverString) + 1;
if (OutputLengthLeft < CopyLength)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
RtlMoveMemory((PVOID)pwchBuffer,
(PVOID)TransceiverString,
(CopyLength * sizeof(WCHAR)));
pwchBuffer = &(pwchBuffer[CopyLength]);
OutputLengthLeft -= CopyLength;
//
// Copy in the value
//
if (OutputLengthLeft < 3)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
CopyLength = wsprintf(pwchBuffer,L"%d", Adapter->Transceiver);
if (CopyLength < 0)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
CopyLength++; // Add in the \0
pwchBuffer = &(pwchBuffer[CopyLength]);
OutputLengthLeft -= CopyLength;
//
// Now the IoChannelReadyType
//
//
// Copy in the title string
//
CopyLength = UnicodeStrLen(IoChannelReadyString) + 1;
if (OutputLengthLeft < CopyLength)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
RtlMoveMemory((PVOID)pwchBuffer,
(PVOID)IoChannelReadyString,
(CopyLength * sizeof(WCHAR)));
pwchBuffer = &(pwchBuffer[CopyLength]);
OutputLengthLeft -= CopyLength;
//
// Copy in the value
//
if (OutputLengthLeft < 3)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
CopyLength = wsprintf(pwchBuffer,L"%d", Adapter->IoChannelReady);
if (CopyLength < 0)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
CopyLength++; // Add in the \0
pwchBuffer = &(pwchBuffer[CopyLength]);
OutputLengthLeft -= CopyLength;
//
// Copy in final \0
//
if (OutputLengthLeft < 1)
{
return(ERROR_INSUFFICIENT_BUFFER);
}
CopyLength = (ULONG)pwchBuffer - StartPointer;
((PUCHAR)StartPointer)[CopyLength] = L'\0';
return(0);
}
extern
LONG
Ee16VerifyCfgHandler(
IN PVOID pvHandle,
IN WCHAR *pwchBuffer
)
/*++
Routine Description:
This routine verifys that a given parameter list is complete and
correct for the adapter associated with the handle.
Arguments:
pvHandle - The handle.
pwchBuffer - The parameter list.
Return Value:
0 if nothing went wrong, else the appropriate WINERROR.H value.
--*/
{
PEE16_ADAPTER Adapter = (PEE16_ADAPTER)(pvHandle);
NTSTATUS NtStatus;
ULONG IoBaseAddress;
ULONG Interrupt;
WCHAR *Place;
BOOLEAN Found;
ULONG TransceiverType;
ULONG IoChannelReadyType;
NETDTECT_RESOURCE Resource;
if ((Adapter->InterfaceType != Isa) && (Adapter->InterfaceType != Eisa))
{
return(ERROR_INVALID_DATA);
}
if (Adapter->CardType == 1000)
{
//
// Parse out the parameter.
//
//
// Get the IoBaseAddress
//
Place = FindParameterString(pwchBuffer, IoAddrString);
if (Place == NULL)
{
return(ERROR_INVALID_DATA);
}
Place += UnicodeStrLen(IoAddrString) + 1;
//
// Now parse the thing.
//
ScanForNumber(Place, &IoBaseAddress, &Found);
if (Found == FALSE)
{
return(ERROR_INVALID_DATA);
}
//
// Get the Interrupt
//
Place = FindParameterString(pwchBuffer, IrqString);
if (Place == NULL)
{
return(ERROR_INVALID_DATA);
}
Place += UnicodeStrLen(IrqString) + 1;
//
// Now parse the thing.
//
ScanForNumber(Place, &Interrupt, &Found);
if (Found == FALSE)
{
return(ERROR_INVALID_DATA);
}
//
// Get the TransceiverType
//
Place = FindParameterString(pwchBuffer, TransceiverString);
if (Place == NULL)
{
return(ERROR_INVALID_DATA);
}
Place += UnicodeStrLen(TransceiverString) + 1;
//
// Now parse the thing.
//
ScanForNumber(Place, &TransceiverType, &Found);
if (Found == FALSE)
{
return(ERROR_INVALID_DATA);
}
//
// Get the IoChannelReadyType
//
Place = FindParameterString(pwchBuffer, IoChannelReadyString);
if (Place == NULL)
{
return(ERROR_INVALID_DATA);
}
Place += UnicodeStrLen(IoChannelReadyString) + 1;
//
// Now parse the thing.
//
ScanForNumber(Place, &IoChannelReadyType, &Found);
if (Found == FALSE)
{
return(ERROR_INVALID_DATA);
}
}
else
{
//
// Error!
//
return(ERROR_INVALID_DATA);
}
if ((IoBaseAddress != Adapter->IoBaseAddress) ||
(Interrupt != Adapter->Interrupt) ||
(TransceiverType != Adapter->Transceiver) ||
(IoChannelReadyType != Adapter->IoChannelReady))
{
UCHAR TempInterrupt = 0;
ULONG TempTransceiver;
ULONG TempIoChannelReady;
//
// See if we can find a nic at their resources...
//
if (!Ee16CardAt(Adapter->InterfaceType,
Adapter->BusNumber,
IoBaseAddress,
&TempInterrupt,
&TempTransceiver,
&TempIoChannelReady))
{
return(ERROR_INVALID_DATA);
}
//
// Did we find their interrupt?
//
if ((Interrupt != TempInterrupt) ||
(TransceiverType != TempTransceiver) ||
(IoChannelReadyType != TempIoChannelReady))
{
return(ERROR_INVALID_DATA);
}
//
// Looks like there is a nic their. Free up the
// resources that we acquired and acquire the new ones.
//
Resource.InterfaceType = Adapter->InterfaceType;
Resource.BusNumber = Adapter->BusNumber;
//
// Free up the detected port.
//
Resource.Type = NETDTECT_PORT_RESOURCE;
Resource.Value = Adapter->IoBaseAddress;
Resource.Length = 0x20;
Resource.Flags = 0;
DetectFreeSpecificTemporaryResource(&Resource);
//
// Acquire the new port.
//
Resource.Value = IoBaseAddress;
DetectTemporaryClaimResource(&Resource);
//
// Free up the detected interrupt.
//
Resource.Type = NETDTECT_IRQ_RESOURCE;
Resource.Value = Adapter->Interrupt;
Resource.Length = 0;
DetectFreeSpecificTemporaryResource(&Resource);
//
// Acquire the new interrupt.
//
Resource.Value = Interrupt;
DetectTemporaryClaimResource(&Resource);
//
// Save the new resources.
//
Adapter->IoBaseAddress = IoBaseAddress;
Adapter->Interrupt = (UCHAR)Interrupt;
Adapter->Transceiver = TransceiverType;
Adapter->IoChannelReady = IoChannelReadyType;
}
//
// Do not verify the other parameters since they are set by the
// driver.
//
return(0);
}
extern
LONG
Ee16QueryMaskHandler(
IN LONG lNetcardId,
OUT WCHAR *pwchBuffer,
IN LONG cwchBuffSize
)
/*++
Routine Description:
This routine returns the parameter list information for a specific
network card.
Arguments:
lNetcardId - The id of the desired netcard.
pwchBuffer - The buffer for storing the parameter information.
cwchBuffSize - Length of pwchBuffer 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 == lNetcardId) {
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 (cwchBuffSize < Length) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
memcpy((PVOID)pwchBuffer, Result, Length * sizeof(WCHAR));
return(0);
}
}
return(ERROR_INVALID_PARAMETER);
}
extern
LONG
Ee16ParamRangeHandler(
IN LONG lNetcardId,
IN WCHAR *pwchParam,
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:
lNetcardId - The Id of the card desired.
pwchParam - 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.
--*/
{
//
// Do we want the IoBaseAddress
//
if (memcmp(pwchParam, IoAddrString, (UnicodeStrLen(IoAddrString) + 1) * sizeof(WCHAR)) == 0) {
//
// Is there enough space
//
if (*plBuffSize < 32) {
*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;
plValues[31] = 0x3F0;
*plBuffSize = 32;
return(0);
} else if (memcmp(pwchParam, IrqString, (UnicodeStrLen(IrqString) + 1) * sizeof(WCHAR)) == 0) {
//
// Is there enough space
//
if (*plBuffSize < 7) {
*plBuffSize = 0;
return(ERROR_INSUFFICIENT_BUFFER);
}
plValues[0] = 3;
plValues[1] = 2;
plValues[2] = 4;
plValues[3] = 5;
plValues[4] = 9;
plValues[5] = 10;
plValues[6] = 11;
*plBuffSize = 7;
return(0);
} else if (memcmp(pwchParam, TransceiverString, (UnicodeStrLen(TransceiverString) + 1) * sizeof(WCHAR)) == 0) {
//
// Is there enough space
//
if (*plBuffSize < 3) {
*plBuffSize = 0;
return(ERROR_INSUFFICIENT_BUFFER);
}
plValues[0] = 1;
plValues[1] = 2;
plValues[2] = 3;
*plBuffSize = 3;
return(0);
} else if (memcmp(pwchParam, IoChannelReadyString, (UnicodeStrLen(IoChannelReadyString) + 1) * sizeof(WCHAR)) == 0) {
//
// Is there enough space
//
if (*plBuffSize < 3) {
*plBuffSize = 0;
return(ERROR_INSUFFICIENT_BUFFER);
}
plValues[0] = 2;
plValues[1] = 1;
plValues[2] = 3;
*plBuffSize = 3;
return(0);
}
return(ERROR_INVALID_PARAMETER);
}
extern
LONG
Ee16QueryParameterNameHandler(
IN WCHAR *pwchParam,
OUT WCHAR *pwchBuffer,
IN LONG cwchBufferSize
)
/*++
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:
pwchParam - The parameter to be queried.
pwchBuffer - The buffer to store the result into.
cwchBufferSize - The length of pwchBuffer in WCHARs.
Return Value:
ERROR_INVALID_PARAMETER -- To indicate that the MS supplied strings
should be used.
--*/
{
return(ERROR_INVALID_PARAMETER);
}
BOOLEAN
Ee16CardAt(
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber,
IN ULONG IoBaseAddress,
OUT PUCHAR Interrupt,
OUT PULONG Transceiver,
OUT PULONG IoChannelReady
)
/*++
Routine Description:
This routine checks for the instance of a Ee16 card at the Io
location given. This is done by checking for the AUTO ID pattern
in the ports
Arguments:
InterfaceType - The type of bus, ISA or EISA.
BusNumber - The bus number in the system.
IoBaseAddress - The IO port address of the card.
Return Value:
TRUE if a card is found, else FALSE.
--*/
{
NTSTATUS NtStatus;
UCHAR SavedValue;
NETDTECT_RESOURCE Resource;
UCHAR InterruptNumber = 0;
USHORT eepromVal;
UCHAR i;
ULONG TransceiverType;
ULONG IoChannelReadyType;
ULONG Ee16InterruptCode = 0;
//
// Check for resource conflict
//
NtStatus = DetectCheckPortUsage(
InterfaceType,
BusNumber,
IoBaseAddress,
0x10);
if (NtStatus != STATUS_SUCCESS)
{
return(FALSE);
}
//
// Reset ASIC on board to read in stored values from EEPROM
//
// EE_CTRL 0x0E
// AUTOID 0x0F
//
// RESET_586 0x80
// GA_RESET 0x40
NtStatus = DetectReadPortUchar(
InterfaceType,
BusNumber,
IoBaseAddress + 0xE,
&SavedValue);
if (NtStatus != STATUS_SUCCESS)
{
return(FALSE);
}
NtStatus = DetectWritePortUchar(
InterfaceType,
BusNumber,
IoBaseAddress + 0xE,
0x80);
if (NtStatus != STATUS_SUCCESS)
{
goto Fail;
}
Sleep(1);
NtStatus = DetectWritePortUchar(
InterfaceType,
BusNumber,
IoBaseAddress + 0xE,
0xC0);
if (NtStatus != STATUS_SUCCESS)
{
goto Fail;
}
Sleep(1);
NtStatus = DetectWritePortUchar(
InterfaceType,
BusNumber,
IoBaseAddress + 0xE,
0x80);
if (NtStatus != STATUS_SUCCESS)
{
goto Fail;
}
//
// Check if card is present
//
{
UCHAR i,j;
//
// get the card into a known state: lower nibble = 0
// In the worst case this should happen in 15 attempts
//
for (i = 0; i < 20; i++)
{
NtStatus = DetectReadPortUchar(
InterfaceType,
BusNumber,
IoBaseAddress + 0xF,
&j);
if (NtStatus != STATUS_SUCCESS)
{
goto Fail;
}
if (!(j & 0x0f))
break;
}
if (i == 20)
{
goto Fail;
}
NtStatus = DetectReadPortUchar(
InterfaceType,
BusNumber,
IoBaseAddress + 0xF,
&j);
if (NtStatus != STATUS_SUCCESS)
{
goto Fail;
}
if (j != 0xb1)
return FALSE;
NtStatus = DetectReadPortUchar(
InterfaceType,
BusNumber,
IoBaseAddress + 0xF,
&j);
if (NtStatus != STATUS_SUCCESS)
{
goto Fail;
}
if (j != 0xa2)
return FALSE;
NtStatus = DetectReadPortUchar(
InterfaceType,
BusNumber,
IoBaseAddress + 0xF,
&j);
if (NtStatus != STATUS_SUCCESS)
{
goto Fail;
}
if (j != 0xb3)
{
goto Fail;
}
}
//
// Acquire the resource
//
Resource.InterfaceType = InterfaceType;
Resource.BusNumber = BusNumber;
Resource.Type = NETDTECT_PORT_RESOURCE;
Resource.Value = SearchStates[0].IoBaseAddress;
Resource.Length = 0x10;
DetectTemporaryClaimResource(&Resource);
//
// Now find the IRQ setting on the card and verify that it is available. If
// it is not available, then we suggest a new IRQ.
//
//
// Get IRQ from EEPROM
//
eepromVal = read_eeprom(InterfaceType, BusNumber, IoBaseAddress, 0);
eepromVal &= 0xE000;
eepromVal >>= 13;
//
// Translate Interrupt number from EtherExpress Encode IRQ.
//
switch ((USHORT) eepromVal)
{
case 1:
InterruptNumber = 2;
break;
case 2:
InterruptNumber = 3;
break;
case 3:
InterruptNumber = 4;
break;
case 4:
InterruptNumber = 5;
break;
case 5:
InterruptNumber = 10;
break;
case 6:
InterruptNumber = 11;
break;
default:
InterruptNumber = 5;
break;
}
Resource.InterfaceType = InterfaceType;
Resource.BusNumber = BusNumber;
Resource.Type = NETDTECT_IRQ_RESOURCE;
Resource.Value = InterruptNumber;
Resource.Length = 0;
Resource.Flags = 0;
DetectTemporaryClaimResource(&Resource);
*Interrupt = InterruptNumber;
//
// Now get the Transceiver type
//
TransceiverType = 1;
eepromVal = read_eeprom(InterfaceType, BusNumber, IoBaseAddress, 0);
if ((eepromVal & 0x1000) != 0)
{
//
// Guess again
//
TransceiverType = 2;
eepromVal = read_eeprom(InterfaceType, BusNumber, IoBaseAddress, 5);
if ((eepromVal & 0x1) == 1)
{
TransceiverType = 3;
}
}
*Transceiver = TransceiverType;
//
// Now get the IoChannelReady type
//
eepromVal = read_eeprom(InterfaceType, BusNumber, IoBaseAddress, 0);
eepromVal &= 0x0C00;
if (eepromVal == 0x0400)
{
// Early
IoChannelReadyType = 1;
}
else if (eepromVal == 0x0C00)
{
// Late
IoChannelReadyType = 2;
}
else
{
IoChannelReadyType = 3;
}
*IoChannelReady = IoChannelReadyType;
return(TRUE);
Fail:
NtStatus = DetectWritePortUchar(
InterfaceType,
BusNumber,
IoBaseAddress + 0xE,
SavedValue);
return(FALSE);
}
ULONG
Ee16NextIoBaseAddress(
IN ULONG IoBaseAddress
)
/*++
Routine Description:
Returns the next in a sequence on good IoBaseAddresses for an Ee16 card.
Arguments:
IoBaseAddress - Current IO port address.
Return Value:
Next IoBaseAddress
--*/
{
IoBaseAddress += 0x10;
if (IoBaseAddress > 0x3F0) {
return(0x400);
}
return(IoBaseAddress);
}
// byte and word accesses to I/O ports
#define EE16_READ_UCHAR(_InterfaceType, _BusNumber, _IoBaseAddress, _Offset, _pValue) \
DetectReadPortUchar( \
_InterfaceType,\
_BusNumber,\
_IoBaseAddress + (_Offset),\
(PUCHAR)(_pValue) \
)
#define EE16_READ_USHORT(_InterfaceType, _BusNumber, _IoBaseAddress, _Offset, _pValue) \
DetectReadPortUshort( \
_InterfaceType,\
_BusNumber,\
_IoBaseAddress + (_Offset),\
(PUSHORT)(_pValue) \
)
#define EE16_WRITE_UCHAR(_InterfaceType, _BusNumber, _IoBaseAddress, _Offset, _pValue) \
DetectWritePortUchar( \
_InterfaceType,\
_BusNumber,\
_IoBaseAddress + (_Offset),\
(UCHAR)(_pValue) \
)
#define EE16_WRITE_USHORT(_InterfaceType, _BusNumber, _IoBaseAddress, _Offset, _pValue) \
DetectWritePortUshort( \
_InterfaceType,\
_BusNumber,\
_IoBaseAddress + (_Offset),\
(USHORT)(_pValue) \
)
//
// EEPROM helper routines
//
#define EE_CTRL 0x0E
// EEPROM control register bits
#define RESET_586 0x80
#define GA_RESET 0x40
#define EEDO 0x08
#define EEDI 0x04
#define EECS 0x02
#define EESK 0x01
// EEPROM opcodes
#define EEPROM_READ_OPCODE 06
#define EEPROM_WRITE_OPCODE 05
#define EEPROM_ERASE_OPCODE 07
#define EEPROM_EWEN_OPCODE 19
#define EEPROM_EWDS_OPCODE 16
USHORT
read_eeprom(
INTERFACE_TYPE InterfaceType,
ULONG BusNumber,
ULONG IoBaseAddress,
ULONG reg
)
{
USHORT x;
USHORT data;
// mask off 586 access
EE16_READ_UCHAR(InterfaceType, BusNumber, IoBaseAddress, EE_CTRL, (char *)&x);
x |= RESET_586;
x &= ~GA_RESET;
EE16_WRITE_UCHAR(InterfaceType, BusNumber, IoBaseAddress, EE_CTRL, x);
// select EEPROM, mask off ASIC and reset bits, set EECS
EE16_READ_UCHAR(InterfaceType, BusNumber, IoBaseAddress, EE_CTRL, (char *)&x);
x &= ~(GA_RESET | EEDI | EEDO | EESK);
x |= EECS;
EE16_WRITE_UCHAR(InterfaceType, BusNumber, IoBaseAddress, EE_CTRL, x);
// write the read opcode and register number in that order
// The opcode is 3bits in length; reg is 6 bits long
shift_out_bits(InterfaceType, BusNumber, IoBaseAddress, EEPROM_READ_OPCODE, 3);
shift_out_bits(InterfaceType, BusNumber, IoBaseAddress, (USHORT)reg, 6);
data = shift_in_bits(InterfaceType, BusNumber, IoBaseAddress);
eeprom_cleanup(InterfaceType, BusNumber, IoBaseAddress);
return data;
}
/*---------------------------------
* shift count bits of data to eeprom
*/
void
shift_out_bits(
INTERFACE_TYPE InterfaceType,
ULONG BusNumber,
ULONG IoBaseAddress,
USHORT data,
USHORT count
)
{
USHORT x,mask;
mask = 0x01 << (count - 1);
EE16_READ_UCHAR(InterfaceType, BusNumber, IoBaseAddress, EE_CTRL, (char *)&x);
x &= ~(GA_RESET | EEDO | EEDI);
do {
x &= ~EEDI;
if (data & mask)
x |= EEDI;
EE16_WRITE_UCHAR(InterfaceType, BusNumber, IoBaseAddress, EE_CTRL, x);
Sleep(1);
raise_clock(InterfaceType, BusNumber, IoBaseAddress, &x);
lower_clock(InterfaceType, BusNumber, IoBaseAddress, &x);
mask = mask >> 1;
} while (mask);
x &= ~EEDI;
EE16_WRITE_UCHAR(InterfaceType, BusNumber, IoBaseAddress, EE_CTRL, x);
}
/*---------------------------------
* raise eeprom clock
*/
void
raise_clock(
INTERFACE_TYPE InterfaceType,
ULONG BusNumber,
ULONG IoBaseAddress,
USHORT *x
)
{
*x = *x | EESK;
EE16_WRITE_UCHAR(InterfaceType, BusNumber, IoBaseAddress, EE_CTRL, *x);
Sleep(1);
}
/*---------------------------------
* lower eeprom clock
*/
void
lower_clock(
INTERFACE_TYPE InterfaceType,
ULONG BusNumber,
ULONG IoBaseAddress,
USHORT *x
)
{
*x = *x & ~EESK;
EE16_WRITE_UCHAR(InterfaceType, BusNumber, IoBaseAddress, EE_CTRL, *x);
Sleep(1);
}
/*---------------------------------
* shift count bits of data in from eeprom
*/
USHORT
shift_in_bits(
INTERFACE_TYPE InterfaceType,
ULONG BusNumber,
ULONG IoBaseAddress
)
{
USHORT x,d,i;
EE16_READ_UCHAR(InterfaceType, BusNumber, IoBaseAddress, EE_CTRL, (char *)&x);
x &= ~(GA_RESET | EEDO | EEDI);
d = 0;
for (i=0; i<16; i++) {
d = d << 1;
raise_clock(InterfaceType, BusNumber, IoBaseAddress, &x);
EE16_READ_UCHAR(InterfaceType, BusNumber, IoBaseAddress, EE_CTRL, (char *)&x);
x &= ~(GA_RESET | EEDI);
if (x & EEDO)
d |= 1;
lower_clock(InterfaceType, BusNumber, IoBaseAddress, &x);
}
return d;
}
/*---------------------------------
*/
void
eeprom_cleanup(
INTERFACE_TYPE InterfaceType,
ULONG BusNumber,
ULONG IoBaseAddress
)
{
USHORT x;
EE16_READ_UCHAR(InterfaceType, BusNumber, IoBaseAddress, EE_CTRL, (char *)&x);
x &= ~GA_RESET;
x &= ~(EECS | EEDI);
EE16_WRITE_UCHAR(InterfaceType, BusNumber, IoBaseAddress, EE_CTRL, x);
raise_clock(InterfaceType, BusNumber, IoBaseAddress, &x);
lower_clock(InterfaceType, BusNumber, IoBaseAddress, &x);
}