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.
2827 lines
58 KiB
2827 lines
58 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
det1000.c
|
|
|
|
Abstract:
|
|
|
|
This is the main file for the autodetection DLL for all the ne1000.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
|
|
//
|
|
|
|
|
|
//
|
|
// Helper functions
|
|
//
|
|
|
|
BOOLEAN
|
|
Ne1000CardAt(
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG IoBaseAddress,
|
|
OUT PUCHAR Interrupt
|
|
);
|
|
|
|
VOID
|
|
Ne1000CardCopyDownBuffer(
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG IoBaseAddress,
|
|
IN ULONG MemoryBaseAddress,
|
|
IN PUCHAR Buffer,
|
|
IN ULONG Length
|
|
);
|
|
|
|
ULONG
|
|
Ne1000NextIoAddr(
|
|
IN ULONG IoBaseAddress
|
|
);
|
|
|
|
VOID
|
|
Ne1000CardSetup(
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG IoBaseAddress,
|
|
OUT PULONG MemoryBaseAddress,
|
|
IN BOOLEAN EightBitSlot
|
|
);
|
|
|
|
BOOLEAN
|
|
Ne1000CardSlotTest(
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG IoBaseAddress,
|
|
OUT PBOOLEAN EightBitSlot
|
|
);
|
|
|
|
BOOLEAN
|
|
Ne1000CheckForNovellAddress(
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG IoBaseAddress
|
|
);
|
|
|
|
#ifdef WORKAROUND
|
|
|
|
UCHAR Ne1000FirstTime = 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
|
|
// Ne1000QueryCfgHandler() and Ne1000VerifyCfgHandler() as well!
|
|
//
|
|
|
|
static ADAPTER_INFO Adapters[] = {
|
|
|
|
{
|
|
1000,
|
|
L"NE1000",
|
|
L"IRQ 1 80 IRQTYPE 2 100 IOADDR 1 100 IOADDRLENGTH 2 100 ",
|
|
NULL,
|
|
502
|
|
|
|
}
|
|
|
|
};
|
|
|
|
#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
|
|
// Ne1000QueryCfgHandler() and Ne1000VerifyCfgHandler() as well!
|
|
//
|
|
|
|
static ADAPTER_INFO Adapters[] = {
|
|
|
|
{
|
|
1000,
|
|
L"NE1000",
|
|
L"IRQ\0"
|
|
L"1\0"
|
|
L"80\0"
|
|
L"IRQTYPE\0"
|
|
L"2\0"
|
|
L"100\0"
|
|
L"IOADDR\0"
|
|
L"1\0"
|
|
L"100\0"
|
|
L"IOADDRLENGTH\0"
|
|
L"2\0"
|
|
L"100\0",
|
|
NULL,
|
|
502
|
|
}
|
|
};
|
|
|
|
#endif
|
|
|
|
//
|
|
// Structure for holding state of a search
|
|
//
|
|
|
|
typedef struct _SEARCH_STATE
|
|
{
|
|
ULONG IoBaseAddress;
|
|
UCHAR Interrupt;
|
|
}
|
|
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 _NE1000_ADAPTER
|
|
{
|
|
LONG CardType;
|
|
INTERFACE_TYPE InterfaceType;
|
|
ULONG BusNumber;
|
|
ULONG IoBaseAddress;
|
|
UCHAR Interrupt;
|
|
}
|
|
NE1000_ADAPTER,
|
|
*PNE1000_ADAPTER;
|
|
|
|
|
|
extern
|
|
LONG
|
|
Ne1000IdentifyHandler(
|
|
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 (Ne1000FirstTime) {
|
|
|
|
Ne1000FirstTime = 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 Ne1000FirstNextHandler(
|
|
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.
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
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 = 0x300;
|
|
}
|
|
else if (SearchStates[0].IoBaseAddress < 0x400)
|
|
{
|
|
SearchStates[0].IoBaseAddress = Ne1000NextIoAddr(SearchStates[0].IoBaseAddress);
|
|
}
|
|
|
|
while (SearchStates[0].IoBaseAddress < 0x400)
|
|
{
|
|
if (Ne1000CardAt(
|
|
InterfaceType,
|
|
BusNumber,
|
|
SearchStates[0].IoBaseAddress,
|
|
&SearchStates[0].Interrupt))
|
|
{
|
|
break;
|
|
}
|
|
|
|
SearchStates[0].IoBaseAddress = Ne1000NextIoAddr(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
|
|
Ne1000OpenHandleHandler(
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNE1000_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 = (PNE1000_ADAPTER)DetectAllocateHeap(sizeof(NE1000_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->CardType = Adapters[AdapterNumber].Index;
|
|
Handle->InterfaceType = InterfaceType;
|
|
Handle->BusNumber = BusNumber;
|
|
|
|
*ppvHandle = (PVOID)Handle;
|
|
|
|
return(0);
|
|
}
|
|
|
|
LONG
|
|
Ne1000CreateHandleHandler(
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNE1000_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 = (PNE1000_ADAPTER)DetectAllocateHeap(sizeof(NE1000_ADAPTER));
|
|
if (Handle == NULL)
|
|
{
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
//
|
|
// Copy across memory address
|
|
//
|
|
Handle->IoBaseAddress = 0x300;
|
|
Handle->CardType = lNetcardId;
|
|
Handle->InterfaceType = InterfaceType;
|
|
Handle->BusNumber = BusNumber;
|
|
Handle->Interrupt = 3;
|
|
|
|
//
|
|
// 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 = 0x20;
|
|
|
|
DetectTemporaryClaimResource(&Resource);
|
|
|
|
Resource.Type = NETDTECT_IRQ_RESOURCE;
|
|
Resource.Value = 3;
|
|
Resource.Length = 0;
|
|
|
|
DetectTemporaryClaimResource(&Resource);
|
|
|
|
*ppvHandle = (PVOID)Handle;
|
|
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
extern
|
|
LONG
|
|
Ne1000CloseHandleHandler(
|
|
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
|
|
Ne1000QueryCfgHandler(
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNE1000_ADAPTER Adapter = (PNE1000_ADAPTER)(pvHandle);
|
|
LONG OutputLengthLeft = cwchBuffSize;
|
|
LONG CopyLength;
|
|
ULONG StartPointer = (ULONG)pwchBuffer;
|
|
|
|
if ((Adapter->InterfaceType != Isa) && (Adapter->InterfaceType != Eisa))
|
|
{
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (Adapter->Interrupt != 0)
|
|
{
|
|
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 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);
|
|
}
|
|
|
|
//
|
|
// LATCHED (0 == latched)
|
|
//
|
|
CopyLength = wsprintf(pwchBuffer,L"0");
|
|
|
|
if (CopyLength < 0)
|
|
{
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
CopyLength++; // Add in the \0
|
|
|
|
pwchBuffer = &(pwchBuffer[CopyLength]);
|
|
OutputLengthLeft -= CopyLength;
|
|
}
|
|
|
|
//
|
|
// Now the IoBaseAddress
|
|
//
|
|
|
|
//
|
|
// 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;
|
|
|
|
//
|
|
// 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"0x20");
|
|
|
|
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
|
|
Ne1000VerifyCfgHandler(
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNE1000_ADAPTER Adapter = (PNE1000_ADAPTER)(pvHandle);
|
|
ULONG IoBaseAddress;
|
|
WCHAR *Place;
|
|
ULONG Interrupt;
|
|
BOOLEAN Found;
|
|
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 Interrupt number
|
|
//
|
|
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);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Error!
|
|
//
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
//
|
|
// Verify IoAddress
|
|
//
|
|
if ((IoBaseAddress != Adapter->IoBaseAddress) ||
|
|
(Interrupt != Adapter->Interrupt))
|
|
{
|
|
UCHAR TempInterrupt = 0;
|
|
|
|
//
|
|
// See if we can find a nic at their resources...
|
|
//
|
|
if (!Ne1000CardAt(Adapter->InterfaceType,
|
|
Adapter->BusNumber,
|
|
IoBaseAddress,
|
|
&TempInterrupt))
|
|
{
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
//
|
|
// Did we find their interrupt?
|
|
//
|
|
if (Interrupt != TempInterrupt)
|
|
{
|
|
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;
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
extern
|
|
LONG Ne1000QueryMaskHandler(
|
|
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
|
|
Ne1000ParamRangeHandler(
|
|
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 < 4) {
|
|
|
|
*plBuffSize = 0;
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
}
|
|
|
|
plValues[0] = 0x300;
|
|
plValues[1] = 0x320;
|
|
plValues[2] = 0x340;
|
|
plValues[3] = 0x360;
|
|
*plBuffSize = 4;
|
|
return(0);
|
|
|
|
} else if (memcmp(pwchParam, IrqString, (UnicodeStrLen(IrqString) + 1) * sizeof(WCHAR)) == 0) {
|
|
|
|
//
|
|
// Is there enough space
|
|
//
|
|
|
|
if (*plBuffSize < 13) {
|
|
|
|
*plBuffSize = 0;
|
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
}
|
|
|
|
plValues[0] = 2;
|
|
plValues[1] = 3;
|
|
plValues[2] = 4;
|
|
plValues[3] = 5;
|
|
plValues[4] = 7;
|
|
plValues[5] = 10;
|
|
plValues[6] = 11;
|
|
plValues[7] = 13;
|
|
plValues[8] = 14;
|
|
plValues[9] = 15;
|
|
|
|
*plBuffSize = 10;
|
|
return(0);
|
|
|
|
}
|
|
|
|
return(ERROR_INVALID_PARAMETER);
|
|
|
|
}
|
|
|
|
extern
|
|
LONG Ne1000QueryParameterNameHandler(
|
|
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
|
|
Ne1000CardAt(
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG IoBaseAddress,
|
|
OUT PUCHAR Interrupt
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks for the instance of an Ne1000 card at the Io
|
|
location given.
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
NETDTECT_RESOURCE Resource;
|
|
UCHAR Value;
|
|
UCHAR TempInterrupt = 0;
|
|
ULONG RamAddr = 0;
|
|
HANDLE TrapHandle;
|
|
UCHAR InterruptList[13];
|
|
UCHAR ResultList[13] = {0};
|
|
NTSTATUS NtStatus;
|
|
UINT i;
|
|
|
|
if (DetectCheckPortUsage(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress,
|
|
0x20) != STATUS_SUCCESS)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
if (!CheckFor8390(InterfaceType, BusNumber, IoBaseAddress))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
if (!Ne1000CheckForNovellAddress(InterfaceType, BusNumber, IoBaseAddress))
|
|
{
|
|
//
|
|
// Stop the 8390
|
|
//
|
|
DetectReadPortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x1F, // RESET
|
|
&Value);
|
|
|
|
DetectWritePortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x1F, // RESET
|
|
0xFF);
|
|
|
|
DetectWritePortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress, // COMMAND
|
|
0x21);
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
DetectReadPortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x1F, // RESET
|
|
&Value);
|
|
|
|
DetectWritePortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x1F, // RESET
|
|
0xFF);
|
|
|
|
DetectWritePortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress, // COMMAND
|
|
0x21);
|
|
|
|
//
|
|
// Acquire the resource
|
|
//
|
|
Resource.InterfaceType = InterfaceType;
|
|
Resource.BusNumber = BusNumber;
|
|
Resource.Type = NETDTECT_PORT_RESOURCE;
|
|
Resource.Value = SearchStates[0].IoBaseAddress;
|
|
Resource.Length = 0x20;
|
|
|
|
DetectTemporaryClaimResource(&Resource);
|
|
|
|
//
|
|
// Find the interrupt
|
|
//
|
|
InterruptList[0] = 2;
|
|
InterruptList[1] = 3;
|
|
InterruptList[2] = 4;
|
|
InterruptList[3] = 5;
|
|
InterruptList[4] = 7;
|
|
InterruptList[5] = 10;
|
|
InterruptList[6] = 11;
|
|
InterruptList[7] = 13;
|
|
InterruptList[8] = 14;
|
|
InterruptList[9] = 15;
|
|
|
|
//
|
|
// Set the interrupt trap -- we are checking the interrupt number now
|
|
//
|
|
NtStatus = DetectSetInterruptTrap(
|
|
InterfaceType,
|
|
BusNumber,
|
|
&TrapHandle,
|
|
InterruptList,
|
|
10);
|
|
|
|
if (NtStatus == STATUS_SUCCESS)
|
|
{
|
|
Ne1000CardSlotTest(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress,
|
|
&Value);
|
|
|
|
//
|
|
// CardSetup
|
|
//
|
|
Ne1000CardSetup(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress,
|
|
&RamAddr,
|
|
Value);
|
|
|
|
//
|
|
// Check for interrupt
|
|
//
|
|
DetectQueryInterruptTrap(TrapHandle, ResultList, 13);
|
|
|
|
//
|
|
// Stop the chip
|
|
//
|
|
DetectReadPortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x1F, // RESET
|
|
&Value);
|
|
|
|
DetectWritePortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x1F, // RESET
|
|
0xFF);
|
|
|
|
DetectWritePortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress, // COMMAND
|
|
0x21);
|
|
|
|
//
|
|
// Remove interrupt trap
|
|
//
|
|
DetectRemoveInterruptTrap(TrapHandle);
|
|
|
|
//
|
|
// Search resulting buffer to find the right interrupt
|
|
//
|
|
for (i = 0; i < 10; i++)
|
|
{
|
|
if ((ResultList[i] == 1) || (ResultList[i] == 2))
|
|
{
|
|
if (TempInterrupt != 0)
|
|
{
|
|
//
|
|
// Uh-oh, looks like interrupts on two different IRQs.
|
|
//
|
|
TempInterrupt = 0;
|
|
break;
|
|
}
|
|
|
|
TempInterrupt = InterruptList[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (TempInterrupt != 0)
|
|
{
|
|
Resource.Type = NETDTECT_IRQ_RESOURCE;
|
|
Resource.Value = TempInterrupt;
|
|
Resource.Length = 0;
|
|
|
|
DetectTemporaryClaimResource(&Resource);
|
|
|
|
*Interrupt = TempInterrupt;
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
Ne1000CheckForNovellAddress(
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG IoBaseAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will determine if the network address of the card is
|
|
(indeed) the Novell prefix (or compatible from another company).
|
|
|
|
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:
|
|
|
|
TRUE if it is an NE1000 identification, else FALSE.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR Value;
|
|
NTSTATUS NtStatus;
|
|
ULONG RamAddr;
|
|
BOOLEAN Result;
|
|
|
|
if (!Ne1000CardSlotTest(InterfaceType, BusNumber, IoBaseAddress, &Result))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
Ne1000CardSetup(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress,
|
|
&RamAddr,
|
|
Result);
|
|
|
|
Result = TRUE;
|
|
|
|
//
|
|
// Read in the station address. (We have to read words -- 2 * 3 -- bytes)
|
|
//
|
|
NtStatus = DetectWritePortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xA, // RBC0
|
|
6);
|
|
|
|
if (NtStatus != STATUS_SUCCESS)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xB, // RBC1
|
|
0);
|
|
|
|
if (NtStatus != STATUS_SUCCESS)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x8, // RADDR0
|
|
0);
|
|
|
|
if (NtStatus != STATUS_SUCCESS)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x9, // RADDR1
|
|
0);
|
|
|
|
if (NtStatus != STATUS_SUCCESS)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress, // START | DMA_READ
|
|
0xA);
|
|
|
|
if (NtStatus != STATUS_SUCCESS)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
NtStatus = DetectReadPortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x10, // RACK_NIC
|
|
&Value);
|
|
|
|
if (NtStatus != STATUS_SUCCESS)
|
|
{
|
|
Result = FALSE;
|
|
}
|
|
|
|
if (Value != 0x00)
|
|
{
|
|
Result = FALSE;
|
|
}
|
|
|
|
NtStatus = DetectReadPortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x10, // RACK_NIC
|
|
&Value);
|
|
|
|
if (NtStatus != STATUS_SUCCESS)
|
|
{
|
|
Result = FALSE;
|
|
}
|
|
|
|
if (Value != 0x00)
|
|
{
|
|
Result = FALSE;
|
|
}
|
|
|
|
NtStatus = DetectReadPortUchar(
|
|
InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x10, // RACK_NIC
|
|
&Value);
|
|
|
|
if (NtStatus != STATUS_SUCCESS)
|
|
{
|
|
Result = FALSE;
|
|
}
|
|
|
|
if (Value == 0x1D)
|
|
{
|
|
//
|
|
// Here we are checking for the IEEE address of Cabletron. Turns out
|
|
// that there are many many companies that make Ne1000 compatible
|
|
// cards and checking for Novell only would be a small subset of
|
|
// the market. The only known card that detects just like an Ne1000
|
|
// but is not an Ne1000 compatible card is the Cabletron card.
|
|
//
|
|
Result = FALSE;
|
|
}
|
|
|
|
return(Result);
|
|
}
|
|
|
|
VOID
|
|
Ne1000CardCopyDownBuffer(
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG IoBaseAddress,
|
|
IN ULONG MemoryBaseAddress,
|
|
IN PUCHAR Buffer,
|
|
IN ULONG Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will copy down a buffer to the address given on the card.
|
|
|
|
Arguments:
|
|
|
|
InterfaceType - The type of bus, ISA or EISA.
|
|
|
|
BusNumber - The bus number in the system.
|
|
|
|
IoBaseAddress - The IO port address of the card.
|
|
|
|
MemoryBaseAddress - The destination of the buffer, if in memory mapped mode,
|
|
else it is the value to be stored in the Gate Array Control Register
|
|
when doing Programmed I/O.
|
|
|
|
Buffer - The buffer to copy
|
|
|
|
Length - Number of bytes to copy to the card.
|
|
|
|
Return:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
UCHAR Tmp;
|
|
USHORT OldAddr, NewAddr, Count;
|
|
PUCHAR ReadBuffer;
|
|
|
|
//
|
|
// Do Write errata as described on pages 1-143 and 1-144 of the 1992
|
|
// LAN databook
|
|
//
|
|
|
|
//
|
|
// Set Count and destination address
|
|
//
|
|
|
|
ReadBuffer = ((PUCHAR)(MemoryBaseAddress + (MemoryBaseAddress & 1)));
|
|
|
|
OldAddr = NewAddr = (USHORT)(ReadBuffer);
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress,
|
|
0x00 // PAGE0
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x8, // NIC_RMT_ADDR_LSB
|
|
(UCHAR)ReadBuffer
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x9, // NIC_RMT_ADDR_MSB
|
|
(UCHAR)((ULONG)ReadBuffer >> 8)
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xA, //NIC_RMT_COUNT_LSB
|
|
0x2
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xB, // NIC_RMT_COUNT_MSB
|
|
0x0
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Set direction (Read)
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress,
|
|
0x2A // CR_START | CR_PAGE0 | CR_DMA_READ
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Read from port
|
|
//
|
|
|
|
NtStatus = DetectReadPortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x10, // RACK_NIC
|
|
&Tmp
|
|
);
|
|
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
NtStatus = DetectReadPortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x10, // NIC_RACK_NIC
|
|
&Tmp
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Wait for addr to change
|
|
//
|
|
|
|
Count = 0xFF;
|
|
|
|
while (Count != 0) {
|
|
|
|
NtStatus = DetectReadPortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x1, // NIC_CRDA_LSB
|
|
&Tmp
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
NewAddr = Tmp;
|
|
|
|
NtStatus = DetectReadPortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x2, // NIC_CRDA_MSB
|
|
&Tmp
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
NewAddr |= (Tmp << 8);
|
|
|
|
if (NewAddr != OldAddr) {
|
|
|
|
break;
|
|
}
|
|
|
|
Count--;
|
|
|
|
}
|
|
|
|
if (NewAddr == OldAddr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Now we can do write
|
|
//
|
|
|
|
//
|
|
// Set Count and destination address
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress,
|
|
0x0 // PAGE0
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x8, // NIC_RMT_ADDR_LSB
|
|
(UCHAR)MemoryBaseAddress
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x9, // NIC_RMT_ADDR_MSB
|
|
(UCHAR)(MemoryBaseAddress >> 8)
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xA, // NIC_RMT_COUNT_LSB
|
|
(UCHAR)Length
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xB, // NIC_RMT_COUNT_MSB
|
|
(UCHAR)(Length >> 8)
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Set direction (Write)
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress,
|
|
0x32 // CR_START | CR_PAGE0 | CR_DMA_WRITE
|
|
);
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Repeatedly write to out port
|
|
//
|
|
|
|
for (; Length > 0; Length--) {
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x10, // NIC_RACK_NIC
|
|
*Buffer
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Buffer++;
|
|
|
|
}
|
|
|
|
//
|
|
// Wait for DMA to complete
|
|
//
|
|
|
|
Count = 10;
|
|
|
|
while (Count) {
|
|
|
|
NtStatus = DetectReadPortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x7, // NIC_INTR_STATUS
|
|
&Tmp
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (Tmp & 0x40) { // ISR_DMA_DONE
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
Count--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
VOID
|
|
Ne1000CardSetup(
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG IoBaseAddress,
|
|
OUT PULONG MemoryBaseAddress,
|
|
IN BOOLEAN EightBitSlot
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets up the card, using the sequence given in the Etherlink II
|
|
technical reference.
|
|
|
|
Arguments:
|
|
|
|
InterfaceType - The type of bus, ISA or EISA.
|
|
|
|
BusNumber - The bus number in the system.
|
|
|
|
IoBaseAddress - The IO port address of the card.
|
|
|
|
MemoryBaseAddress - Pointer to store the base address of card memory.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT i;
|
|
UCHAR Tmp;
|
|
NTSTATUS NtStatus;
|
|
LARGE_INTEGER Delay;
|
|
|
|
//
|
|
// Stop the card.
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress,
|
|
0x21 // STOP | ABORT_DMA
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Initialize the Data Configuration register.
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xE, // NIC_DATA_CONFIG
|
|
0x50 // DCR_AUTO_INIT | DCR_FIFO_8_BYTE
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Set Xmit start location
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x4, // NIC_XMIT_START
|
|
0xA0
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Set Xmit configuration
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xD, // NIC_XMIT_CONFIG
|
|
0x0
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Set Receive configuration
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xC, // NIC_RCV_CONFIG
|
|
0
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Set Receive start
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x1, // NIC_PAGE_START
|
|
0x4
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Set Receive end
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x2, // NIC_PAGE_STOP
|
|
0xFF
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Set Receive boundary
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x3, // NIC_BOUNDARY
|
|
0x4
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Set Xmit bytes
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x5, // NIC_XMIT_COUNT_LSB
|
|
0x3C
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x6, // NIC_XMIT_COUNT_MSB
|
|
0x0
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Pause
|
|
//
|
|
|
|
//
|
|
// Wait for reset to complete. (100 ms)
|
|
//
|
|
|
|
Delay.LowPart = 100000;
|
|
Delay.HighPart = 0;
|
|
|
|
NtDelayExecution(
|
|
FALSE,
|
|
&Delay
|
|
);
|
|
|
|
//
|
|
// Ack all interrupts that we might have produced
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x7, // NIC_INTR_STATUS
|
|
0xFF
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Change to page 1
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress,
|
|
0x61 // CR_PAGE1 | CR_STOP
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Set current
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x7, // NIC_CURRENT
|
|
0x4
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Back to page 0
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress,
|
|
0x21 // CR_PAGE0 | CR_STOP
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Pause
|
|
//
|
|
|
|
Delay.LowPart = 1000;
|
|
Delay.HighPart = 0;
|
|
|
|
NtDelayExecution(
|
|
FALSE,
|
|
&Delay
|
|
);
|
|
|
|
|
|
//
|
|
// Do initialization errata
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xA, // NIC_RMT_COUNT_LSB
|
|
55
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Reset the chip
|
|
//
|
|
|
|
NtStatus = DetectReadPortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x1F, // NIC_RESET
|
|
&Tmp
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x1F, // NIC_RESET
|
|
0xFF
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Start the chip
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress,
|
|
0x22
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Mask Interrupts
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xF, // NIC_INTR_MASK
|
|
0xFF
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
if (EightBitSlot) {
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xE, // NIC_DATA_CONFIG
|
|
0x48 // DCR_FIFO_8_BYTE | DCR_NORMAL | DCR_BYTE_WIDE
|
|
);
|
|
|
|
} else {
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xE, // NIC_DATA_CONFIG
|
|
0x49 // DCR_FIFO_8_BYTE | DCR_NORMAL | DCR_WORD_WIDE
|
|
);
|
|
|
|
}
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xD, // NIC_XMIT_CONFIG
|
|
0
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xC, // NIC_RCV_CONFIG
|
|
0
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x7, // NIC_INTR_STATUS
|
|
0xFF
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress,
|
|
0x21 // CR_NO_DMA | CR_STOP
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xA, // NIC_RMT_COUNT_LSB
|
|
0
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xB, // NIC_RMT_COUNT_MSB
|
|
0
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Wait for STOP to complete
|
|
//
|
|
|
|
i = 0xFF;
|
|
|
|
while (--i) {
|
|
|
|
NtStatus = DetectReadPortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x7, // NIC_INTR_STATUS
|
|
&Tmp
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
if (Tmp & 0x80) { // ISR_RESET
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Put card in loopback mode
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xD, // NIC_XMIT_CONFIG
|
|
0x2 // TCR_LOOPBACK
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress,
|
|
0x22 // CR_NO_DMA | CR_START
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
*MemoryBaseAddress = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// ... but it is still in loopback mode.
|
|
//
|
|
|
|
return;
|
|
}
|
|
|
|
ULONG
|
|
Ne1000NextIoAddr(
|
|
IN ULONG IoBaseAddress
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets the next IoBaseAddress.
|
|
|
|
Arguments:
|
|
|
|
IoBaseAddress - The IO port address of the card.
|
|
|
|
Return Value:
|
|
|
|
BaseAddress
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
IoBaseAddress += 0x20;
|
|
|
|
if (IoBaseAddress > 0x380) {
|
|
|
|
IoBaseAddress = 0x400;
|
|
|
|
}
|
|
|
|
return(IoBaseAddress);
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
Ne1000CardSlotTest(
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG IoBaseAddress,
|
|
OUT PBOOLEAN EightBitSlot
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks if the card is in an 8 or 16 bit slot and sets a flag in the
|
|
adapter structure.
|
|
|
|
Arguments:
|
|
|
|
|
|
InterfaceType - The type of bus, ISA or EISA.
|
|
|
|
BusNumber - The bus number in the system.
|
|
|
|
IoBaseAddress - The IO port address of the card.
|
|
|
|
EightBitSlot - Result of test.
|
|
|
|
Return Value:
|
|
|
|
TRUE, if all goes well, else FALSE.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR Tmp;
|
|
UCHAR RomCopy[32];
|
|
UCHAR i;
|
|
NTSTATUS NtStatus;
|
|
LARGE_INTEGER Delay;
|
|
|
|
//
|
|
// Reset the chip
|
|
//
|
|
|
|
NtStatus = DetectReadPortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x1F, // NIC_RESET
|
|
&Tmp
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x1F, // NIC_RESET
|
|
0xFF
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
//
|
|
// Go to page 0 and stop
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress,
|
|
0x21 // CR_STOP | CR_NO_DMA
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
//
|
|
// Pause
|
|
//
|
|
|
|
Delay.LowPart = 1000;
|
|
Delay.HighPart = 0;
|
|
|
|
NtDelayExecution(
|
|
FALSE,
|
|
&Delay
|
|
);
|
|
|
|
//
|
|
// Setup to read from ROM
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xE, // NIC_DATA_CONFIG
|
|
0x48 // DCR_BYTE_WIDE | DCR_FIFO_8_BYTE | DCR_NORMAL
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xF, // NIC_INTR_MASK
|
|
0x0
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
//
|
|
// Ack any interrupts that may be hanging around
|
|
//
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x7, // NIC_INTR_STATUS
|
|
0xFF
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x8, // NIC_RMT_ADDR_LSB
|
|
0x0
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x9, // NIC_RMT_ADDR_MSB,
|
|
0x0
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xA, // NIC_RMT_COUNT_LSB
|
|
32
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0xB, // NIC_RMT_COUNT_MSB
|
|
0x0
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress,
|
|
0xA // CR_DMA_READ | CR_START
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
//
|
|
// Read first 32 bytes in 16 bit mode
|
|
//
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
|
|
NtStatus = DetectReadPortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x10, // NIC_RACK_NIC
|
|
RomCopy + i
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Reset the chip
|
|
//
|
|
|
|
NtStatus = DetectReadPortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x1F, // NIC_RESET
|
|
&Tmp
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
NtStatus = DetectWritePortUchar(InterfaceType,
|
|
BusNumber,
|
|
IoBaseAddress + 0x1F, // NIC_RESET
|
|
0xFF
|
|
);
|
|
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
//
|
|
// Check address being singular
|
|
//
|
|
|
|
for (i = 6; i < 31; i++) {
|
|
|
|
if ((RomCopy[i] != 'B') && (RomCopy[i+1] == 'B')) {
|
|
|
|
//
|
|
// Now check that the address is singular. On an Ne1000 the
|
|
// ethernet address is store in offsets 0 thru 5. On the Ne2000
|
|
// the address is stored in offsets 0 thru 11, where each byte
|
|
// is duplicated.
|
|
//
|
|
// Here we only check the first two bytes because some of the
|
|
// other bytes may be accidentally equal.
|
|
//
|
|
|
|
if ((RomCopy[0] != RomCopy[1]) ||
|
|
(RomCopy[2] != RomCopy[3]) ||
|
|
(RomCopy[4] != RomCopy[5])) {
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// If no 'B' found, then not an NE1000.
|
|
//
|
|
|
|
return(FALSE);
|
|
}
|