mirror of https://github.com/lianthony/NT4.0
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.
2182 lines
44 KiB
2182 lines
44 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
detepro.c
|
|
|
|
Abstract:
|
|
|
|
This is the main file for the autodetection DLL for all the EPro.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 "..\ntos\ndis\ieepro\82595.h"
|
|
|
|
static BOOLEAN fPrintDbgInfo = FALSE;
|
|
|
|
#if DBG
|
|
#define DBGPRINT(a) { if(fPrintDbgInfo) { DbgPrint a; }}
|
|
#else
|
|
#define DBGPRINT(a)
|
|
#endif
|
|
|
|
//
|
|
// Structure for holding a particular adapter's complete information
|
|
//
|
|
typedef struct _EPRO_ADAPTER
|
|
{
|
|
LONG CardType;
|
|
INTERFACE_TYPE InterfaceType;
|
|
ULONG BusNumber;
|
|
ULONG IoBaseAddress;
|
|
UCHAR Interrupt;
|
|
USHORT EEProm0;
|
|
USHORT EEProm1; // 2 eeprom config registers
|
|
BOOLEAN BadStep;
|
|
}
|
|
EPRO_ADAPTER,
|
|
*PEPRO_ADAPTER;
|
|
|
|
//
|
|
// Individual card detection routines
|
|
//
|
|
|
|
BOOLEAN
|
|
EProVerifyRoundRobin(
|
|
UCHAR *buf
|
|
);
|
|
|
|
BOOLEAN
|
|
EProCardAt(
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG IoBaseAddress,
|
|
OUT PUCHAR Interrupt,
|
|
OUT PBOOLEAN BadStep
|
|
);
|
|
|
|
ULONG
|
|
EProNextIoBaseAddress(
|
|
IN ULONG IoBaseAddress
|
|
);
|
|
|
|
|
|
VOID
|
|
EProGenerateIdPattern(
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber
|
|
);
|
|
|
|
// EEProm swill:
|
|
VOID
|
|
EProEERead(
|
|
PEPRO_ADAPTER adapter,
|
|
USHORT address,
|
|
PUSHORT data
|
|
);
|
|
|
|
VOID
|
|
EProEEShiftOutBits(
|
|
PEPRO_ADAPTER adapter,
|
|
USHORT data,
|
|
SHORT count
|
|
);
|
|
|
|
VOID EProEEShiftInBits(
|
|
PEPRO_ADAPTER adapter,
|
|
PUSHORT data,
|
|
SHORT count
|
|
);
|
|
|
|
void EProEELowerClock(PEPRO_ADAPTER adapter, PUCHAR result);
|
|
void EProEERaiseClock(PEPRO_ADAPTER adapter, PUCHAR result);
|
|
VOID EProEEWrite(PEPRO_ADAPTER adapter, USHORT address, USHORT data);
|
|
void EProEEReverseShiftInBits(PEPRO_ADAPTER adapter, PUSHORT data, SHORT count);
|
|
|
|
//VOID EProEERaiseClock(
|
|
// PEPRO_ADAPTER adapter
|
|
// );
|
|
|
|
//VOID EProEELowerClock(
|
|
// PEPRO_ADAPTER adapter
|
|
// );
|
|
|
|
UCHAR EProFirstTime = 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
|
|
// EProQueryCfgHandler() and EProVerifyCfgHandler() as well!
|
|
//
|
|
|
|
static ADAPTER_INFO Adapters[] = {
|
|
|
|
{
|
|
1000,
|
|
L"IEEPRO",
|
|
L"IRQ\0"
|
|
L"1\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,
|
|
350
|
|
}
|
|
};
|
|
|
|
//
|
|
// Structure for holding state of a search
|
|
//
|
|
|
|
typedef struct _SEARCH_STATE
|
|
{
|
|
ULONG IoBaseAddress;
|
|
UCHAR Interrupt;
|
|
BOOLEAN BadStep;
|
|
}
|
|
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};
|
|
|
|
extern
|
|
LONG
|
|
EProIdentifyHandler(
|
|
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;
|
|
LONG AdapterNumber = (lIndex / 100) - 10;
|
|
|
|
DBGPRINT(("EProIdentifyHandler\n"));
|
|
|
|
NumberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
|
|
|
|
lIndex = lIndex - Code;
|
|
|
|
if (AdapterNumber >= NumberOfAdapters)
|
|
{
|
|
DBGPRINT(("No more Items\n"));
|
|
|
|
return(ERROR_NO_MORE_ITEMS);
|
|
}
|
|
|
|
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)
|
|
{
|
|
DBGPRINT(("InsufficientBuffer 1\n"));
|
|
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
memcpy(
|
|
(PVOID)pwchBuffer,
|
|
Adapters[i].InfId,
|
|
Length * sizeof(WCHAR));
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
//
|
|
// Maximum value is 1000
|
|
//
|
|
if (cwchBuffSize < 5)
|
|
{
|
|
DBGPRINT(("Insufficient Buffer 2\n"));
|
|
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
wsprintf((PVOID)pwchBuffer, L"%d", Adapters[i].SearchOrder);
|
|
|
|
break;
|
|
|
|
default:
|
|
DBGPRINT(("Invalid parameter\n"));
|
|
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
DBGPRINT(("Found the adapter\n"));
|
|
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
DBGPRINT(("Invalid Parameter 2\n"));
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
|
|
extern
|
|
LONG
|
|
EProFirstNextHandler(
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGPRINT(("looking for EEPro cards!!! yah!!!!\n"));
|
|
|
|
if ((InterfaceType != Isa) && (InterfaceType != Eisa))
|
|
{
|
|
*lConfidence = 0;
|
|
DBGPRINT(("Wrong bus\n"));
|
|
return(0);
|
|
}
|
|
|
|
if (lNetcardId != 1000)
|
|
{
|
|
*lConfidence = 0;
|
|
DBGPRINT(("Bad parameter\n"));
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// If fFirst, reset search state
|
|
//
|
|
if (fFirst)
|
|
{
|
|
SearchStates[0].IoBaseAddress = 0x200;
|
|
}
|
|
else
|
|
{
|
|
SearchStates[0].IoBaseAddress = EProNextIoBaseAddress(
|
|
SearchStates[0].IoBaseAddress);
|
|
}
|
|
|
|
//
|
|
// Find an adapter
|
|
//
|
|
while (SearchStates[0].IoBaseAddress != 0x400)
|
|
{
|
|
if (EProCardAt(
|
|
InterfaceType,
|
|
BusNumber,
|
|
SearchStates[0].IoBaseAddress,
|
|
&SearchStates[0].Interrupt,
|
|
&SearchStates[0].BadStep))
|
|
{
|
|
break;
|
|
}
|
|
|
|
SearchStates[0].IoBaseAddress = EProNextIoBaseAddress(
|
|
SearchStates[0].IoBaseAddress);
|
|
}
|
|
|
|
if (SearchStates[0].IoBaseAddress == 0x400)
|
|
{
|
|
*lConfidence = 0;
|
|
DBGPRINT(("Bad I/O address.\n"));
|
|
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?
|
|
//
|
|
DBGPRINT(("Found an epro...\n"));
|
|
|
|
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;
|
|
DBGPRINT(("card found okay\n"));
|
|
return(0);
|
|
}
|
|
|
|
extern
|
|
LONG
|
|
EProOpenHandleHandler(
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PEPRO_ADAPTER Handle;
|
|
LONG AdapterNumber;
|
|
ULONG BusNumber;
|
|
INTERFACE_TYPE InterfaceType;
|
|
|
|
DBGPRINT(("EProOpenHandleHandler\n"));
|
|
|
|
//
|
|
// 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 = (PEPRO_ADAPTER)DetectAllocateHeap(sizeof(EPRO_ADAPTER));
|
|
|
|
if (Handle == NULL)
|
|
{
|
|
DBGPRINT(("Not enough memory\n"));
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
//
|
|
// Copy across address
|
|
//
|
|
Handle->IoBaseAddress = SearchStates[(ULONG)AdapterNumber].IoBaseAddress;
|
|
Handle->Interrupt = SearchStates[(ULONG)AdapterNumber].Interrupt;
|
|
Handle->BadStep = SearchStates[(ULONG)AdapterNumber].BadStep;
|
|
Handle->CardType = Adapters[AdapterNumber].Index;
|
|
Handle->InterfaceType = InterfaceType;
|
|
Handle->BusNumber = BusNumber;
|
|
|
|
DBGPRINT(("EPro at base address: 0x%x\n", Handle->IoBaseAddress));
|
|
DBGPRINT(("EPro at interrupt: 0x%x\n", Handle->Interrupt));
|
|
DBGPRINT(("Adapter number: %lx\n", AdapterNumber));
|
|
DBGPRINT(("BusNumber: %lx\n", BusNumber));
|
|
|
|
*ppvHandle = (PVOID)Handle;
|
|
|
|
DBGPRINT(("Opened handle OK\n"));
|
|
return(0);
|
|
}
|
|
|
|
extern
|
|
LONG
|
|
EProCreateHandleHandler(
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PEPRO_ADAPTER Handle;
|
|
LONG NumberOfAdapters;
|
|
LONG i;
|
|
NETDTECT_RESOURCE Resource;
|
|
|
|
DBGPRINT(("EProCreateHandleHandler\n"));
|
|
|
|
if ((InterfaceType != Isa) && (InterfaceType != Eisa))
|
|
{
|
|
DBGPRINT(("Wrong bus\n"));
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
NumberOfAdapters = sizeof(Adapters) / sizeof(ADAPTER_INFO);
|
|
|
|
for (i = 0; i < NumberOfAdapters; i++)
|
|
{
|
|
if (Adapters[i].Index == lNetcardId)
|
|
{
|
|
//
|
|
// Store information
|
|
//
|
|
Handle = (PEPRO_ADAPTER)DetectAllocateHeap(sizeof(EPRO_ADAPTER));
|
|
|
|
if (Handle == NULL)
|
|
{
|
|
DBGPRINT(("Handle is null\n"));
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
//
|
|
// Copy across memory address
|
|
//
|
|
Handle->BadStep = TRUE;
|
|
Handle->Interrupt = 5;
|
|
Handle->IoBaseAddress = 0x300;
|
|
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;
|
|
DBGPRINT(("Ok\n"));
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
DBGPRINT(("Invalid Parameter\n"));
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
extern
|
|
LONG
|
|
EProCloseHandleHandler(
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGPRINT(("EProCloseHandleHandler\n"));
|
|
|
|
DetectFreeHeap(pvHandle);
|
|
|
|
return(0);
|
|
}
|
|
|
|
LONG
|
|
EProQueryCfgHandler(
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PEPRO_ADAPTER Adapter = (PEPRO_ADAPTER)(pvHandle);
|
|
NTSTATUS NtStatus;
|
|
LONG OutputLengthLeft = cwchBuffSize;
|
|
LONG CopyLength;
|
|
ULONG TransceiverType;
|
|
ULONG IoChannelReadyType;
|
|
ULONG StartPointer = (ULONG)pwchBuffer;
|
|
NETDTECT_RESOURCE Resource;
|
|
|
|
DBGPRINT(("EProQueryCfgHandler\n"));
|
|
|
|
if ((Adapter->InterfaceType != Isa) && (Adapter->InterfaceType != Eisa))
|
|
{
|
|
DBGPRINT(("Wrong bus\n"));
|
|
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// Now get the Transceiver type
|
|
//
|
|
TransceiverType = 4;
|
|
|
|
// I have no clue how to get the transciever type out of the eeprom.
|
|
// go intel documentation
|
|
|
|
//
|
|
// Now get the IoChannelReady type
|
|
//
|
|
|
|
//
|
|
// Read old IoChannelReady value
|
|
//
|
|
|
|
// Once again, I don't know how to do this. We'll just
|
|
// use the default. We auto-detect this on driver start
|
|
// anyway, so it doesn't matter to us.
|
|
//
|
|
IoChannelReadyType = 4;
|
|
|
|
//
|
|
// Build resulting buffer
|
|
//
|
|
|
|
//
|
|
// Now the IoBaseAddress
|
|
//
|
|
|
|
//
|
|
// Copy in the title string
|
|
//
|
|
CopyLength = UnicodeStrLen(IoAddrString) + 1;
|
|
|
|
if (OutputLengthLeft < CopyLength)
|
|
{
|
|
DBGPRINT(("Insufficient buffer blah\n"));
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
RtlMoveMemory(
|
|
(PVOID)pwchBuffer,
|
|
(PVOID)IoAddrString,
|
|
(CopyLength * sizeof(WCHAR)));
|
|
|
|
pwchBuffer = &(pwchBuffer[CopyLength]);
|
|
OutputLengthLeft -= CopyLength;
|
|
|
|
//
|
|
// Copy in the value
|
|
//
|
|
if (OutputLengthLeft < 6)
|
|
{
|
|
DBGPRINT(("Insufficient buffer 9\n"));
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
CopyLength = wsprintf(pwchBuffer,L"0x%x",Adapter->IoBaseAddress);
|
|
|
|
if (CopyLength < 0)
|
|
{
|
|
DBGPRINT(("Insufficient buffer 8\n"));
|
|
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)
|
|
{
|
|
DBGPRINT(("Insufficient buffer 7\n"));
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
RtlMoveMemory((PVOID)pwchBuffer,
|
|
(PVOID)IoLengthString,
|
|
(CopyLength * sizeof(WCHAR)));
|
|
|
|
pwchBuffer = &(pwchBuffer[CopyLength]);
|
|
OutputLengthLeft -= CopyLength;
|
|
|
|
//
|
|
// Copy in the value
|
|
//
|
|
if (OutputLengthLeft < 5)
|
|
{
|
|
DBGPRINT(("Insufficient buffer 6\n"));
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
CopyLength = wsprintf(pwchBuffer,L"0x10");
|
|
|
|
if (CopyLength < 0)
|
|
{
|
|
DBGPRINT(("Insufficient buffer 5\n"));
|
|
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)
|
|
{
|
|
DBGPRINT(("Insufficient buffer 4\n"));
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
RtlMoveMemory((PVOID)pwchBuffer,
|
|
(PVOID)IrqString,
|
|
(CopyLength * sizeof(WCHAR)));
|
|
|
|
pwchBuffer = &(pwchBuffer[CopyLength]);
|
|
OutputLengthLeft -= CopyLength;
|
|
|
|
//
|
|
// Copy in the value
|
|
//
|
|
if (OutputLengthLeft < 3)
|
|
{
|
|
DBGPRINT(("Insufficient buffer 3\n"));
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
CopyLength = wsprintf(pwchBuffer,L"%d",Adapter->Interrupt);
|
|
|
|
if (CopyLength < 0)
|
|
{
|
|
DBGPRINT(("Insufficient buffer 2\n"));
|
|
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)
|
|
{
|
|
DBGPRINT(("Insufficient buffer 11\n"));
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
RtlMoveMemory((PVOID)pwchBuffer,
|
|
(PVOID)IrqTypeString,
|
|
(CopyLength * sizeof(WCHAR)));
|
|
|
|
pwchBuffer = &(pwchBuffer[CopyLength]);
|
|
OutputLengthLeft -= CopyLength;
|
|
|
|
//
|
|
// Copy in the value
|
|
//
|
|
if (OutputLengthLeft < 2)
|
|
{
|
|
DBGPRINT(("Insufficient buffer 12\n"));
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
CopyLength = wsprintf(pwchBuffer,L"0");
|
|
|
|
if (CopyLength < 0)
|
|
{
|
|
DBGPRINT(("Insufficient buffer 13\n"));
|
|
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)
|
|
{
|
|
DBGPRINT(("Insufficient buffer 14\n"));
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
RtlMoveMemory((PVOID)pwchBuffer,
|
|
(PVOID)TransceiverString,
|
|
(CopyLength * sizeof(WCHAR)));
|
|
|
|
pwchBuffer = &(pwchBuffer[CopyLength]);
|
|
OutputLengthLeft -= CopyLength;
|
|
|
|
//
|
|
// Copy in the value
|
|
//
|
|
if (OutputLengthLeft < 3)
|
|
{
|
|
DBGPRINT(("Insufficient buffer 15\n"));
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
CopyLength = wsprintf(pwchBuffer,L"%d",TransceiverType);
|
|
|
|
if (CopyLength < 0)
|
|
{
|
|
DBGPRINT(("Insufficient buffer 16\n"));
|
|
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)
|
|
{
|
|
DBGPRINT(("Insufficient buffer 17\n"));
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
RtlMoveMemory((PVOID)pwchBuffer,
|
|
(PVOID)IoChannelReadyString,
|
|
(CopyLength * sizeof(WCHAR)));
|
|
|
|
pwchBuffer = &(pwchBuffer[CopyLength]);
|
|
OutputLengthLeft -= CopyLength;
|
|
|
|
//
|
|
// Copy in the value
|
|
//
|
|
if (OutputLengthLeft < 3)
|
|
{
|
|
DBGPRINT(("Insufficient buffer 18\n"));
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
CopyLength = wsprintf(pwchBuffer,L"%d",IoChannelReadyType);
|
|
|
|
if (CopyLength < 0)
|
|
{
|
|
DBGPRINT(("Insufficient buffer 19\n"));
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
CopyLength++; // Add in the \0
|
|
|
|
pwchBuffer = &(pwchBuffer[CopyLength]);
|
|
OutputLengthLeft -= CopyLength;
|
|
|
|
//
|
|
// Copy in final \0
|
|
//
|
|
if (OutputLengthLeft < 1)
|
|
{
|
|
DBGPRINT(("Insufficient buffer 20\n"));
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
DBGPRINT(("Returning: %S\n", StartPointer));
|
|
DBGPRINT(("Returning: %s\n", StartPointer));
|
|
|
|
CopyLength = (ULONG)pwchBuffer - StartPointer;
|
|
((PUCHAR)StartPointer)[CopyLength] = L'\0';
|
|
|
|
DBGPRINT(("Returning: %S\n", StartPointer));
|
|
DBGPRINT(("Returning: %s\n", StartPointer));
|
|
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < CopyLength; i++)
|
|
{
|
|
DBGPRINT(("%c ", *((UCHAR *)(StartPointer + i))));
|
|
}
|
|
}
|
|
|
|
DBGPRINT(("CopyLength is %d\n", CopyLength));
|
|
|
|
DBGPRINT(("Ok.......\n"));
|
|
return(0);
|
|
}
|
|
|
|
extern
|
|
LONG
|
|
EProVerifyCfgHandler(
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PEPRO_ADAPTER Adapter = (PEPRO_ADAPTER)(pvHandle);
|
|
NTSTATUS NtStatus;
|
|
ULONG IoBaseAddress;
|
|
ULONG Interrupt;
|
|
WCHAR *Place;
|
|
BOOLEAN Found;
|
|
ULONG TransceiverType;
|
|
ULONG IoChannelReadyType;
|
|
NETDTECT_RESOURCE Resource;
|
|
|
|
DBGPRINT(("EproVerifyCfgHandler\n"));
|
|
|
|
if ((Adapter->InterfaceType != Isa) && (Adapter->InterfaceType != Eisa))
|
|
{
|
|
DBGPRINT(("WrongBus\n"));
|
|
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
if (Adapter->CardType == 1000)
|
|
{
|
|
//
|
|
// Parse out the parameter.
|
|
//
|
|
|
|
//
|
|
// Get the IoBaseAddress
|
|
//
|
|
DBGPRINT(("The buffer is %S\n", pwchBuffer));
|
|
|
|
Place = FindParameterString(pwchBuffer, IoAddrString);
|
|
|
|
if (Place == NULL)
|
|
{
|
|
DBGPRINT(("Invalid data a\n"));
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
Place += UnicodeStrLen(IoAddrString) + 1;
|
|
|
|
//
|
|
// Now parse the thing.
|
|
//
|
|
ScanForNumber(Place, &IoBaseAddress, &Found);
|
|
|
|
if (Found == FALSE)
|
|
{
|
|
DBGPRINT(("Not found\n"));
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
//
|
|
// Get the Interrupt
|
|
//
|
|
Place = FindParameterString(pwchBuffer, IrqString);
|
|
|
|
if (Place == NULL)
|
|
{
|
|
DBGPRINT(("Invalid Data b\n"));
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
Place += UnicodeStrLen(IrqString) + 1;
|
|
|
|
//
|
|
// Now parse the thing.
|
|
//
|
|
ScanForNumber(Place, &Interrupt, &Found);
|
|
|
|
if (Found == FALSE)
|
|
{
|
|
DBGPRINT(("Failed in Scanfornumber\n"));
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
//
|
|
// Get the TransceiverType
|
|
//
|
|
Place = FindParameterString(pwchBuffer, TransceiverString);
|
|
|
|
if (Place == NULL)
|
|
{
|
|
DBGPRINT(("Failed to find parameterstring\n"));
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
Place += UnicodeStrLen(TransceiverString) + 1;
|
|
|
|
//
|
|
// Now parse the thing.
|
|
//
|
|
ScanForNumber(Place, &TransceiverType, &Found);
|
|
|
|
if (Found == FALSE)
|
|
{
|
|
DBGPRINT(("Couldn't get transcievertype\n"));
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
//
|
|
// Get the IoChannelReadyType
|
|
//
|
|
Place = FindParameterString(pwchBuffer, IoChannelReadyString);
|
|
|
|
if (Place == NULL)
|
|
{
|
|
DBGPRINT(("INvalid data 0\n"));
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
Place += UnicodeStrLen(IoChannelReadyString) + 1;
|
|
|
|
//
|
|
// Now parse the thing.
|
|
//
|
|
ScanForNumber(Place, &IoChannelReadyType, &Found);
|
|
|
|
if (Found == FALSE)
|
|
{
|
|
DBGPRINT(("Invalid Data 1\n"));
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Error!
|
|
//
|
|
DBGPRINT(("Invalid Data 2\n"));
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
//
|
|
// Verify IoAddress
|
|
//
|
|
if ((IoBaseAddress != Adapter->IoBaseAddress) ||
|
|
(Interrupt != Adapter->Interrupt) ||
|
|
(Adapter->BadStep))
|
|
{
|
|
UCHAR TempInterrupt = 0;
|
|
BOOLEAN BadStep = FALSE;
|
|
|
|
//
|
|
// 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 = 0x10;
|
|
Resource.Flags = 0;
|
|
DetectFreeSpecificTemporaryResource(&Resource);
|
|
|
|
//
|
|
// Free up the detected interrupt.
|
|
//
|
|
Resource.Type = NETDTECT_IRQ_RESOURCE;
|
|
Resource.Value = Adapter->Interrupt;
|
|
Resource.Length = 0;
|
|
DetectFreeSpecificTemporaryResource(&Resource);
|
|
|
|
//
|
|
// See if we can find a nic at their resources...
|
|
//
|
|
if (!EProCardAt(Adapter->InterfaceType,
|
|
Adapter->BusNumber,
|
|
IoBaseAddress,
|
|
&TempInterrupt,
|
|
&BadStep))
|
|
{
|
|
DBGPRINT(("Couldn't verify their port\n"));
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
//
|
|
// Acquire the new port.
|
|
//
|
|
Resource.Type = NETDTECT_PORT_RESOURCE;
|
|
Resource.Value = IoBaseAddress;
|
|
Resource.Length = 0x10;
|
|
DetectTemporaryClaimResource(&Resource);
|
|
|
|
Adapter->IoBaseAddress = IoBaseAddress;
|
|
|
|
//
|
|
// Acquire the new interrupt.
|
|
//
|
|
Resource.Type = NETDTECT_IRQ_RESOURCE;
|
|
Resource.Value = Interrupt;
|
|
Resource.Length = 0;
|
|
DetectTemporaryClaimResource(&Resource);
|
|
|
|
Adapter->Interrupt = (UCHAR)Interrupt;
|
|
|
|
//
|
|
// Did we find their interrupt?
|
|
//
|
|
if (Interrupt != TempInterrupt)
|
|
{
|
|
DBGPRINT(("Couldn't verify the interrupt\n"));
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
|
|
Adapter->BadStep = BadStep;
|
|
|
|
if (BadStep)
|
|
{
|
|
DBGPRINT(("Card truly has a bad stepping and we can verify this\n"));
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Do not verify the other parameters since they are set by the
|
|
// driver.
|
|
//
|
|
DBGPRINT(("Okay\n"));
|
|
return(0);
|
|
}
|
|
|
|
extern
|
|
LONG
|
|
EProQueryMaskHandler(
|
|
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;
|
|
|
|
|
|
DBGPRINT(("EProVerifyMaskHandler\n"));
|
|
|
|
//
|
|
// 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)
|
|
{
|
|
DBGPRINT(("Not enough memory\n"));
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
memcpy((PVOID)pwchBuffer, Result, Length * sizeof(WCHAR));
|
|
|
|
DBGPRINT(("Ok\n"));
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
DBGPRINT(("Invalid Parameter\n"));
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
extern
|
|
LONG
|
|
EProParamRangeHandler(
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DBGPRINT(("EProParamRangeHandler\n"));
|
|
|
|
//
|
|
// Do we want the IoBaseAddress
|
|
//
|
|
if (memcmp(pwchParam, IoAddrString, (UnicodeStrLen(IoAddrString) + 1) * sizeof(WCHAR)) == 0)
|
|
{
|
|
//
|
|
// Is there enough space
|
|
//
|
|
if (*plBuffSize < 32)
|
|
{
|
|
*plBuffSize = 0;
|
|
DBGPRINT(("Insufficient buffer\n"));
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
plValues[0] = 0x300;
|
|
plValues[1] = 0x200;
|
|
plValues[2] = 0x210;
|
|
plValues[3] = 0x220;
|
|
plValues[4] = 0x230;
|
|
plValues[5] = 0x240;
|
|
plValues[6] = 0x250;
|
|
plValues[7] = 0x260;
|
|
plValues[8] = 0x270;
|
|
plValues[9] = 0x280;
|
|
plValues[10] = 0x290;
|
|
plValues[11] = 0x2A0;
|
|
plValues[12] = 0x2B0;
|
|
plValues[13] = 0x2C0;
|
|
plValues[14] = 0x2D0;
|
|
plValues[15] = 0x2E0;
|
|
plValues[16] = 0x2F0;
|
|
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;
|
|
DBGPRINT(("Insuff. Buffer\n"));
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
plValues[0] = 5;
|
|
plValues[1] = 9;
|
|
plValues[2] = 3;
|
|
plValues[3] = 10;
|
|
plValues[4] = 11;
|
|
*plBuffSize = 5;
|
|
DBGPRINT(("Ok1\n"));
|
|
|
|
return(0);
|
|
}
|
|
else if (memcmp(pwchParam, TransceiverString, (UnicodeStrLen(TransceiverString) + 1) * sizeof(WCHAR)) == 0)
|
|
{
|
|
//
|
|
// Is there enough space
|
|
//
|
|
if (*plBuffSize < 3)
|
|
{
|
|
*plBuffSize = 0;
|
|
DBGPRINT(("Ok2\n"));
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
plValues[0] = 1;
|
|
plValues[1] = 2;
|
|
plValues[2] = 3;
|
|
*plBuffSize = 3;
|
|
DBGPRINT(("Ok3\n"));
|
|
|
|
return(0);
|
|
}
|
|
else if (memcmp(pwchParam, IoChannelReadyString, (UnicodeStrLen(IoChannelReadyString) + 1) * sizeof(WCHAR)) == 0)
|
|
{
|
|
//
|
|
// Is there enough space
|
|
//
|
|
if (*plBuffSize < 3)
|
|
{
|
|
*plBuffSize = 0;
|
|
DBGPRINT(("Insufficent Buffer\n"));
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
plValues[0] = 2;
|
|
plValues[1] = 1;
|
|
plValues[2] = 3;
|
|
*plBuffSize = 3;
|
|
DBGPRINT(("ok4\n"));
|
|
|
|
return(0);
|
|
}
|
|
|
|
DBGPRINT(("INvalid Parameter\n"));
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
extern
|
|
LONG
|
|
EProQueryParameterNameHandler(
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGPRINT(("QueryParameterNameHandler\n"));
|
|
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
|
|
BOOLEAN EProVerifyRoundRobin(UCHAR *buf)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks to see if the 4 bytes given are a round-robin
|
|
counter in the 7th and 8th bits.
|
|
|
|
Arguments:
|
|
|
|
A 4-byte long buffer of UCHARs which are the result of four consecutive
|
|
reads from a possible EPro's ID register (bank 0, #2);
|
|
|
|
Returns:
|
|
|
|
TRUE if it was an EPro's signature
|
|
FALSE if it wasn't.
|
|
|
|
--*/
|
|
{
|
|
UCHAR ch;
|
|
int i, i1;
|
|
|
|
DBGPRINT(("verify round robin...\n"));
|
|
|
|
// Don't even try to figure this out
|
|
// it works. Take my word for it and deal.
|
|
//
|
|
i1 = buf[0] >> 6;
|
|
|
|
for (i = 1; i < 4; i++)
|
|
{
|
|
i1 = i1 > 2 ? 0 : i1 + 1;
|
|
|
|
if ((buf[i] >> 6) != i1)
|
|
{
|
|
// nope.
|
|
//
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
// yup.
|
|
//
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
EProCardAt(
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG IoBaseAddress,
|
|
OUT PUCHAR Interrupt,
|
|
OUT PBOOLEAN BadStep
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks for the instance of a EPro 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;
|
|
UCHAR IdReg[4];
|
|
UINT i;
|
|
NETDTECT_RESOURCE Resource;
|
|
|
|
DBGPRINT(("Looking for an EPro at 0x%x...\n", IoBaseAddress));
|
|
|
|
//
|
|
// Check for resource conflict
|
|
//
|
|
NtStatus = DetectCheckPortUsage(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress,
|
|
0x10);
|
|
|
|
if (NtStatus != STATUS_SUCCESS)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
// save what used to be at this address, since we are going to write to it.
|
|
NtStatus = DetectReadPortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress,
|
|
&SavedValue);
|
|
|
|
//
|
|
// now, we switch the card into bank 0 by writing
|
|
// 0x00 to its command register.
|
|
//
|
|
DetectWritePortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress,
|
|
I82595_CMD_BANK0);
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
DetectReadPortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + I82595_ID_REG,
|
|
&IdReg[i]);
|
|
}
|
|
|
|
if (EProVerifyRoundRobin(IdReg))
|
|
{
|
|
EPRO_ADAPTER adapter;
|
|
UCHAR InterruptNumber;
|
|
UCHAR EproStepping;
|
|
UCHAR SteppingReg;
|
|
|
|
//
|
|
// Switch to bank 2.
|
|
//
|
|
DetectWritePortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + I82595_CMD_REG,
|
|
I82595_CMD_BANK2);
|
|
|
|
//
|
|
// Verify that this is not a step 0 chip.
|
|
//
|
|
DetectReadPortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + I82595_STEPPING_REG,
|
|
&SteppingReg);
|
|
|
|
EproStepping = (SteppingReg >> I82595_STEPPING_OFFSET);
|
|
|
|
DBGPRINT(("Epro stepping is %x\n", EproStepping));
|
|
|
|
//
|
|
// Make sure that this is not a 0, 1, or 4 step of the card.
|
|
// RM: added step 4
|
|
//
|
|
if (EproStepping > 4)
|
|
{
|
|
DBGPRINT(("Epro has an invalid stepping\n"));
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Grab the io base address.
|
|
//
|
|
Resource.InterfaceType = InterfaceType;
|
|
Resource.BusNumber = BusNumber;
|
|
Resource.Type = NETDTECT_PORT_RESOURCE;
|
|
Resource.Value = IoBaseAddress;
|
|
Resource.Length = 0x10;
|
|
Resource.Flags = 0;
|
|
|
|
DetectTemporaryClaimResource(&Resource);
|
|
|
|
//
|
|
// If this is a cool chip the look for the interrupt.
|
|
// RM: added even cooler step 4
|
|
//
|
|
if ((EproStepping == 2) || (EproStepping == 3) || (EproStepping == 4))
|
|
{
|
|
//
|
|
// Build a fake adapter structure.
|
|
//
|
|
adapter.InterfaceType = InterfaceType;
|
|
adapter.BusNumber = BusNumber;
|
|
adapter.IoBaseAddress = IoBaseAddress;
|
|
|
|
//
|
|
// Read the eeprom to get the interrupt.
|
|
//
|
|
EProEERead(&adapter, 0, &adapter.EEProm0);
|
|
EProEERead(&adapter, 1, &adapter.EEProm1);
|
|
|
|
//
|
|
// Translate Interrupt number from EtherExpress Encode IRQ.
|
|
//
|
|
switch (((USHORT)adapter.EEProm1) & 0x000f)
|
|
{
|
|
case 0:
|
|
DBGPRINT(("Case: 0\n"));
|
|
InterruptNumber = (EproStepping == 4)? 3 : 9;
|
|
break;
|
|
|
|
case 1:
|
|
DBGPRINT(("Case: 1\n"));
|
|
InterruptNumber = (EproStepping == 4)? 4 : 3;
|
|
break;
|
|
|
|
case 2:
|
|
DBGPRINT(("Case: 2\n"));
|
|
InterruptNumber = 5;
|
|
break;
|
|
|
|
case 3:
|
|
DBGPRINT(("Case: 3\n"));
|
|
InterruptNumber = (EproStepping == 4)? 7 : 10;
|
|
break;
|
|
|
|
case 4:
|
|
DBGPRINT(("Case: 4\n"));
|
|
InterruptNumber = (EproStepping == 4)? 9 : 11;
|
|
break;
|
|
|
|
case 6:
|
|
DBGPRINT(("Case: 6\n"));
|
|
InterruptNumber = (EproStepping == 4)? 11 : 5;
|
|
break;
|
|
|
|
case 7:
|
|
DBGPRINT(("Case: 7\n"));
|
|
InterruptNumber = (EproStepping == 4)? 12 : 5;
|
|
break;
|
|
|
|
|
|
default:
|
|
DBGPRINT(("Case: default\n"));
|
|
InterruptNumber = 5;
|
|
break;
|
|
}
|
|
|
|
*BadStep = FALSE;
|
|
}
|
|
else
|
|
{
|
|
*BadStep = TRUE;
|
|
InterruptNumber = 5;
|
|
}
|
|
|
|
DBGPRINT(("The EEPRO is at interrupt number %x\n", InterruptNumber));
|
|
|
|
//
|
|
// Grab the interrupt
|
|
//
|
|
Resource.InterfaceType = InterfaceType;
|
|
Resource.BusNumber = BusNumber;
|
|
Resource.Type = NETDTECT_IRQ_RESOURCE;
|
|
Resource.Value = InterruptNumber;
|
|
Resource.Length = 0;
|
|
Resource.Flags = 0;
|
|
|
|
DetectTemporaryClaimResource(&Resource);
|
|
|
|
*Interrupt = InterruptNumber;
|
|
|
|
DBGPRINT(("FOUND one!\n"));
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
// Nope, we failed...
|
|
|
|
NtStatus = DetectWritePortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xE,
|
|
SavedValue);
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
ULONG
|
|
EProNextIoBaseAddress(
|
|
IN ULONG IoBaseAddress
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the next in a sequence on good IoBaseAddresses for an EPro card.
|
|
|
|
Arguments:
|
|
|
|
IoBaseAddress - Current IO port address.
|
|
|
|
Return Value:
|
|
|
|
Next IoBaseAddress
|
|
|
|
--*/
|
|
|
|
{
|
|
IoBaseAddress += 0x10;
|
|
|
|
if (IoBaseAddress > 0x3F0)
|
|
{
|
|
DBGPRINT(("DONE in nextioaddress\n"));
|
|
return(0x400);
|
|
}
|
|
|
|
return(IoBaseAddress);
|
|
}
|
|
|
|
|
|
// byte and word accesses to I/O ports
|
|
|
|
#define EPRO_RD_PORT_UCHAR(_Adapter, _Offset, _pValue) \
|
|
DetectReadPortUchar( \
|
|
_Adapter->InterfaceType,\
|
|
_Adapter->BusNumber,\
|
|
_Adapter->IoBaseAddress + (_Offset),\
|
|
(PUCHAR)(_pValue) \
|
|
)
|
|
|
|
#define EPRO_WR_PORT_UCHAR(_Adapter, _Offset, _Value) \
|
|
DetectWritePortUchar( \
|
|
_Adapter->InterfaceType,\
|
|
_Adapter->BusNumber,\
|
|
_Adapter->IoBaseAddress + (_Offset),\
|
|
(UCHAR)(_Value) \
|
|
)
|
|
|
|
#define EPRO_SWITCH_BANK_0(_adapter) \
|
|
EPRO_WR_PORT_UCHAR(_adapter, I82595_CMD_REG, I82595_CMD_BANK0)
|
|
|
|
#define EPRO_SWITCH_BANK_1(_adapter) \
|
|
EPRO_WR_PORT_UCHAR(_adapter, I82595_CMD_REG, I82595_CMD_BANK1)
|
|
|
|
#define EPRO_SWITCH_BANK_2(_adapter) \
|
|
EPRO_WR_PORT_UCHAR(_adapter, I82595_CMD_REG, I82595_CMD_BANK2)
|
|
|
|
#define EPRO_STALL_EXECUTION Sleep
|
|
#define EPRO_SK_STALL_TIME 1
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// EPro eeprom helper routines
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
VOID EProEECleanup(PEPRO_ADAPTER adapter)
|
|
{
|
|
UCHAR result;
|
|
|
|
EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result);
|
|
result &= ~(I82595_EECS_MASK | I82595_EEDI_MASK);
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
|
|
EProEERaiseClock(adapter, &result);
|
|
EProEELowerClock(adapter, &result);
|
|
}
|
|
|
|
|
|
VOID EProEEUpdateChecksum(PEPRO_ADAPTER adapter)
|
|
{
|
|
USHORT chkSum = 0, result, i;
|
|
|
|
for (i=0;i<0x3f;i++) {
|
|
EProEERead(adapter, i, &result);
|
|
chkSum+=result;
|
|
}
|
|
|
|
chkSum = (USHORT)0xBABA - chkSum;
|
|
EProEEWrite(adapter, 0x3f, chkSum);
|
|
}
|
|
|
|
|
|
VOID EProEEStandBy(PEPRO_ADAPTER adapter)
|
|
{
|
|
UCHAR result;
|
|
|
|
EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result);
|
|
result &= ~(I82595_EECS_MASK | I82595_EESK_MASK);
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
|
|
Sleep(0);
|
|
result |= I82595_EECS_MASK;
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
|
|
}
|
|
|
|
|
|
VOID EProEERead(PEPRO_ADAPTER adapter, USHORT address, PUSHORT data)
|
|
{
|
|
UCHAR result;
|
|
UCHAR opcode;
|
|
|
|
// siwtch to bank2
|
|
EPRO_SWITCH_BANK_2(adapter);
|
|
|
|
// Get the value from the register, so we can flip the eecs bit
|
|
EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result);
|
|
|
|
// turn the eecs bit on.. (1)
|
|
result |= I82595_EECS_MASK;
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
|
|
|
|
// Write the read opcode to the eeprom (2)
|
|
opcode = I82595_EEPROM_READ;
|
|
EProEEShiftOutBits(adapter, opcode, 3);
|
|
|
|
// Write the address to read to the eeprom
|
|
EProEEShiftOutBits(adapter, address, 6);
|
|
|
|
// Read the result
|
|
EProEEShiftInBits(adapter, data, 16);
|
|
|
|
// Turn off EEPROM
|
|
// EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result);
|
|
// result &= (~I82595_EECS_MASK);
|
|
// EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
|
|
|
|
EProEECleanup(adapter);
|
|
|
|
EPRO_SWITCH_BANK_0(adapter);
|
|
}
|
|
|
|
BOOLEAN EProEEWaitCmdDone(PEPRO_ADAPTER adapter)
|
|
{
|
|
USHORT i;
|
|
UCHAR result;
|
|
|
|
EProEEStandBy(adapter);
|
|
|
|
for (i=0; i<200;i++) {
|
|
EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result);
|
|
if (result & I82595_EEDO_MASK) {
|
|
return(TRUE);
|
|
}
|
|
Sleep(10);
|
|
}
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
|
|
VOID EProEEWrite(PEPRO_ADAPTER adapter, USHORT address, USHORT data)
|
|
{
|
|
UCHAR result;
|
|
|
|
EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result);
|
|
result &= ~(I82595_EEDI_MASK | I82595_EEDO_MASK | I82595_EESK_MASK);
|
|
result |= I82595_EECS_MASK;
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
|
|
|
|
// write the read opcode and register number
|
|
EProEEShiftOutBits(adapter, I82595_EEPROM_EWEN, 5);
|
|
EProEEShiftOutBits(adapter, address, 4);
|
|
|
|
EProEEStandBy(adapter);
|
|
|
|
EProEEShiftOutBits(adapter, I82595_EEPROM_WRITE, 3);
|
|
EProEEShiftOutBits(adapter, address, 6);
|
|
|
|
if (EProEEWaitCmdDone(adapter) == FALSE) {
|
|
DBGPRINT(("Failed EEPROM erase!\n"));
|
|
return;
|
|
}
|
|
|
|
EProEEStandBy(adapter);
|
|
|
|
EProEEShiftOutBits(adapter, I82595_EEPROM_WRITE, 3);
|
|
EProEEShiftOutBits(adapter, address, 6);
|
|
EProEEShiftOutBits(adapter, data, 16);
|
|
|
|
if (EProEEWaitCmdDone(adapter) == FALSE) {
|
|
DBGPRINT(("Failed EEPROM write!\n"));
|
|
return;
|
|
}
|
|
|
|
EProEEStandBy(adapter);
|
|
|
|
EProEEShiftOutBits(adapter, I82595_EEPROM_EWDS, 5);
|
|
EProEEShiftOutBits(adapter, address, 4);
|
|
|
|
EProEECleanup(adapter);
|
|
}
|
|
|
|
void EProEEReverseRead(PEPRO_ADAPTER adapter, USHORT address, PUSHORT data)
|
|
{
|
|
UCHAR result, opcode;
|
|
UINT i;
|
|
|
|
// siwtch to bank2
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_CMD_BANK2);
|
|
|
|
// Get the value from the register, so we can flip the eecs bit
|
|
EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result);
|
|
|
|
// turn the eecs bit on.. (1)
|
|
result |= I82595_EECS_MASK;
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
|
|
|
|
// Write the read opcode to the eeprom (2)
|
|
opcode = I82595_EEPROM_READ;
|
|
EProEEShiftOutBits(adapter, opcode, 3);
|
|
|
|
// Write the address to read to the eeprom
|
|
EProEEShiftOutBits(adapter, address, 6);
|
|
|
|
// Read the result
|
|
EProEEReverseShiftInBits(adapter, data, 16);
|
|
|
|
// Turn off EEPROM
|
|
EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result);
|
|
result &= (~I82595_EECS_MASK);
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
|
|
|
|
EPRO_SWITCH_BANK_0(adapter);
|
|
}
|
|
|
|
void EProEEShiftOutBits(PEPRO_ADAPTER adapter, USHORT data, SHORT count)
|
|
{
|
|
UCHAR result;
|
|
USHORT mask;
|
|
|
|
mask = 0x1 << (count - 1);
|
|
EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result);
|
|
result &= ~(I82595_EEDO_MASK | I82595_EEDI_MASK);
|
|
|
|
do {
|
|
result &= ~I82595_EEDI_MASK;
|
|
if (data & mask) {
|
|
result |= I82595_EEDI_MASK;
|
|
}
|
|
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
|
|
Sleep(10);
|
|
EProEERaiseClock(adapter, &result);
|
|
EProEELowerClock(adapter, &result);
|
|
mask = mask >> 1;
|
|
} while(mask);
|
|
|
|
result &= ~I82595_EEDI_MASK;
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
|
|
}
|
|
|
|
void EProEEShiftInBits(PEPRO_ADAPTER adapter, PUSHORT data, SHORT count)
|
|
{
|
|
UCHAR result;
|
|
USHORT i;
|
|
|
|
EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result);
|
|
result &= ~(I82595_EEDO_MASK | I82595_EEDI_MASK);
|
|
*data = 0;
|
|
|
|
for (i=0;i<16;i++)
|
|
{
|
|
*data = *data << 1;
|
|
EProEERaiseClock(adapter, &result); // 4.1
|
|
EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result); // 4.2
|
|
result &= ~I82595_EEDI_MASK;
|
|
if (result & I82595_EEDO_MASK) {
|
|
*data |= 1;
|
|
}
|
|
EProEELowerClock(adapter, &result);
|
|
}
|
|
}
|
|
|
|
void EProEEReverseShiftInBits(PEPRO_ADAPTER adapter, PUSHORT data, SHORT count)
|
|
{
|
|
UCHAR result;
|
|
SHORT count1;
|
|
|
|
*data = 0;
|
|
|
|
// for (--count;count>=0;count--) {
|
|
for (count1=0;count1<=count;count1++) {
|
|
// EProEERaiseClock(adapter); // 4.1
|
|
|
|
EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result); // 4.2
|
|
|
|
result &= I82595_EEDO_MASK; // turn off everything but the EEDO bit
|
|
|
|
// according to docs we get MSB out first...
|
|
// this is a REVERSE read - get LSB first
|
|
*data |= ((result >> I82595_EEDO_OFFSET) << count1);
|
|
// EProEELowerClock(adapter); // 4.3
|
|
}
|
|
}
|
|
|
|
void EProEERaiseClock(PEPRO_ADAPTER adapter, PUCHAR result)
|
|
{
|
|
// UCHAR result;
|
|
|
|
// turn EESK bit high
|
|
*result = *result | I82595_EESK_MASK;
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, *result);
|
|
Sleep(1);
|
|
}
|
|
|
|
void EProEELowerClock(PEPRO_ADAPTER adapter, PUCHAR result)
|
|
{
|
|
// UCHAR result;
|
|
|
|
// EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, result);
|
|
|
|
// turn EESK bit low...
|
|
*result = *result & ~I82595_EESK_MASK;
|
|
EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, *result);
|
|
|
|
EPRO_STALL_EXECUTION(EPRO_SK_STALL_TIME);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|