📄 3c90x.c
字号:
#include "3c90x.h"
#ifndef NOSTATIC
static
#endif
char *version =
"3Com 3c90x Version 1.0.0i 1999 <linux_drivers@3com.com>\n";
/*
3Com EtherLink 10/100 PCI (3C90x) Linux Network Driver, Copyright (c) 1999
3Com Corporation. All rights reserved.
3Com Linux Network Driver software is distributed as is, without any warranty
of any kind, either express or implied as further specified in the GNU Public
License. This software may be used and distributed according to the terms of
the GNU Public License, located in the file LICENSE.
3Com and EtherLink are registered trademarks of 3Com Corporation. Linux is a
registered trademarks of Linus Torvalds.
Credit
------
Special thanks goes to Donald Becker for providing the skeleton driver outline
used in this driver, and for the hard work he has put into the 3c59x EtherLink
The 3Com 3c90x driver works in cooperatioon with his 3c59x driver.
skeleton.c: A network driver out line for Linux.
Copyright 1993 Uninted States Government as represented by the Director, National
Security Agency.
Donald Becker may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O Center of
Excellence in Space Data and Information Sciences Code 930.5, Goddard Space Flight
Center, Greenbelt MD 20771
http://cesdis.gsfc.nasa.gov/linux/
This is 3Com's EtherLink PCI driver for Linux. It provides support for the
3c90x and 3c980 network adapters listed here:
EtherLink 10/100 PCI NICs
3C905C Family and 3C920 ASICs EtherLink 10/100 PCI including
the -TX and -TX-M
3C905B Family and 3C918 ASICs EtherLink 10/100 PCI including
the -TX -TX-M and -TX-NM
3C905B-COMBO EtherLink 10/100 PCI COMBO
3C905B-T4 EtherLink 10/100 PCI T4
EtherLink Server 10/100 PCI NICs
3C980C-TX EtherLink Server 10/100 PCI
3C980B-TX EtherLink Server 10/100 PCI
3C980-TX EtherLink Server 10/100 PCI
EtherLink 100 PCI NIC
3C905B-FX EtherLink 100 PCI Fiber
EtherLink 10 PCI NICs
3C900B-TPO EtherLink 10 PCI TPO
3C900B-TPC EtherLink 10 PCI TPC
3C900B-COMBO EtherLink 10 PCI COMBO
3C900B-FL EtherLink 10 PCI Fiber
E-mail Support:
- USA or Canada: 3COM_US_NIC_FAMILY@3COM.COM
- Mexico and Latin America: AMI_HD@3com.com
- Brazil: br-nicsupport@3com.com
- Europe, Middle East and Africa: European_Technical_Support@3com.com
- Asia Pacific Rim: apr_technical_support@3com.com
URL: http://support.3com.com/infodeli/tools/nic/linux.htm
Compile command :
gcc -c 3c90x.c -O2 -Wall -Wstrict-prototypes -fomit-frame-pointer \
-fno-strength-reduce -pipe -m486 -malign-loops=2 \
-malign-jumps=2 -malign-functions=2 -DCPU=486 -DMODULE -D__KERNEL__
+ Add -D__SMP__ to the command line for SMP support
+ Add -DMODVERSIONS to the command line if your kernel was built with
symbol versioning (RedHat, etc.)
c-indent-level: 4
c-basic-offset: 4
tab-width: 8
*/
#include <linux/string.h>
#if defined(MODULE) && (LINUX_VERSION_CODE >= 0x20115)
MODULE_AUTHOR("3Com Corporation <linux_drivers@3com.com>");
MODULE_DESCRIPTION("EtherLink PCI Driver");
#ifdef DEBUG
MODULE_PARM(debug, "i");
#endif
MODULE_PARM(switchdelay, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(downpoll, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(flowcontrol, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(media_select, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
#endif // MODULE && LINUX_VERSION_CODE
char kernel_version [] = UTS_RELEASE;
static const INT MTU = 1500;
PCHAR ProductName = "3Com EtherLink PCI NIC\n";
static ULONG tc90x_Index = 0;
#ifndef NOSTATIC
static
#endif
UCHAR BroadcastAddr[] = {0xff,0xff,0xff,0xff,0xff,0xff};
// Global variable for waittimer
TIMER WaitTimer;
BOOLEAN InWaitTimer;
BOOLEAN DCConverterEnabledState_g;
ULONG TimeOutCount = 0;
USHORT MediaStatus_g = 0;
BOOLEAN PhyResponding_g;
USHORT PhyStatus_g;
ULONG DownListPointer_g;
ULONG UpListPointer_g;
ULONG portValue_g;
ULONG dmaControl_g;
PDEVICE RootNICDevice = NULL;
#ifdef MODULE
/*++
Routine Name:
init_module
Routine Description:
This routine finds the adapter using the Linux calls
Arguments:
Device - Pointer to the device structure.
Return Value:
-ENODEV if no adapter found
noAdapterFound if adapter(s) found
--*/
INT
init_module(VOID)
{
NIC_STATUS nicStatus;
DBGPRINT_INIT((KERN_CRIT "init_module: IN\n"));
nicStatus = tc90xbc_ScanDevices(0);
if (NIC_STATUS_SUCCESS == nicStatus) {
DBGPRINT_FUNCTION((KERN_CRIT "init_module: OUT\n"));
printk(version);
return 0;
}
DBGPRINT_ERROR((KERN_CRIT "Scan Devices failed\n"));
DBGPRINT_FUNCTION((KERN_CRIT "init_module: OUT\n"));
return -ENODEV;
}
#else
/*++
Routine Name:
tc90xbc_probe
Routine Description:
This routine finds the adapter using the Linux calls
Arguments:
Device - Pointer to the device structure.
Return Value:
-ENODEV if no adapter found
noAdapterFound if adapter(s) found
--*/
INT
tc90xbc_probe(
IN PDEVICE Device
)
{
static int scanned = 0;
NIC_STATUS nicStatus;
DBGPRINT_INIT((KERN_CRIT "tc90xbc_probe: IN\n"));
if(scanned++)
return -ENODEV;
printk(KERN_INFO "%s", version);
nicStatus = tc90xbc_ScanDevices(Device);
if (NIC_STATUS_SUCCESS == nicStatus) {
DBGPRINT_FUNCTION((
KERN_CRIT"NICScanDevices: OUT-success\n"));
return 0;
}
else {
DBGPRINT_ERROR((
KERN_CRIT "NICScanDevices returned error\n"));
return -ENODEV;
}
}
#endif
NIC_STATUS
tc90xbc_ScanDevices(
IN PDEVICE Device
)
{
PNIC_INFORMATION pAdapter = NULL;
INT ioBaseAddress;
USHORT pciCommand, vendorId, deviceId;
INT interruptVector, noAdapterFound = 0;
UCHAR pciBus, pciDeviceFunction;
static INT pciIndex = 0;
UCHAR cacheLineSize, revisionId;
USHORT powerManagementControl;
DBGPRINT_INIT((KERN_CRIT "tc90xbc_ScanDevices: IN\n"));
for (; pciIndex < 0xff; pciIndex++) {
if (pcibios_find_class(
PCI_CLASS_NETWORK_ETHERNET << 8,
pciIndex,
&pciBus,
&pciDeviceFunction
) != PCIBIOS_SUCCESSFUL)
break;
pcibios_read_config_word(
pciBus,
pciDeviceFunction,
PCI_VENDOR_ID,
&vendorId);
if (vendorId != NIC_VENDOR_ID)
continue;
pcibios_read_config_word(
pciBus,
pciDeviceFunction,
PCI_DEVICE_ID,
&deviceId);
switch (deviceId) {
case NIC_PCI_DEVICE_ID_9055:
DBGPRINT_INIT(("10/100 Base-TX NIC found\n"));
break;
case NIC_PCI_DEVICE_ID_9058:
DBGPRINT_INIT(("10/100 COMBO Deluxe board found\n"));
break;
case NIC_PCI_DEVICE_ID_9004:
DBGPRINT_INIT(("10Base-T TPO NIC found\n"));
break;
case NIC_PCI_DEVICE_ID_9005:
DBGPRINT_INIT(("10Base-T/10Base-2/AUI Combo found\n"));
case NIC_PCI_DEVICE_ID_9006:
DBGPRINT_INIT(("10Base-T/10Base-2/TPC found\n"));
break;
case NIC_PCI_DEVICE_ID_900A:
DBGPRINT_INIT(("10Base-FL NIC found\n"));
break;
case NIC_PCI_DEVICE_ID_905A:
DBGPRINT_INIT(("100Base-Fx NIC found\n"));
break;
case NIC_PCI_DEVICE_ID_9200:
DBGPRINT_INIT(("Tornado NIC found\n"));
break;
case NIC_PCI_DEVICE_ID_9800:
DBGPRINT_INIT(("10/100 Base-TX NIC(Python-H) found\n"));
break;
case NIC_PCI_DEVICE_ID_9805:
DBGPRINT_INIT(("10/100 Base-TX NIC(Python-T) found\n"));
break;
case NIC_PCI_DEVICE_ID_4500:
DBGPRINT_INIT(("10/100 Base-TX NIC(Home Network) found\n"));
break;
case NIC_PCI_DEVICE_ID_7646:
DBGPRINT_INIT(("10/100 Base-TX NIC(SOHO) found\n"));
break;
default:
DBGPRINT_INIT(("UnSupported NIC found\n"));
continue;
}
//
// Initialize the ether device.
//
Device = init_etherdev(Device, 0);
DBGPRINT_INIT((
KERN_CRIT "3Com device %s\n",Device->name));
Device->priv = kmalloc(sizeof(NIC_INFORMATION), GFP_KERNEL);
memset(Device->priv, 0, sizeof(NIC_INFORMATION));
pAdapter = (PNIC_INFORMATION)Device->priv;
pAdapter->Device = Device;
//
// Save the NIC index.
//
pAdapter->Index = tc90x_Index++;
pcibios_read_config_word(
pciBus,
pciDeviceFunction,
PCI_COMMAND,
&pciCommand);
if (!(pciCommand & PCI_COMMAND_MASTER)) {
DBGPRINT_INIT(("Enabling Bus Matering\n"));
pciCommand |= PCI_COMMAND_MASTER;
}
else {
DBGPRINT_INIT(("Bus Mastering enabled by BIOS\n"));
}
{
#if LINUX_VERSION_CODE >= 0x20155
struct pci_dev *pdev = pci_find_slot(
pciBus,
pciDeviceFunction
);
ioBaseAddress = pdev->base_address[0];
interruptVector = pdev->irq;
#else
u32 pciIoAddress;
u8 pciIrqLine;
pcibios_read_config_byte(
pciBus,
pciDeviceFunction,
PCI_INTERRUPT_LINE,
&pciIrqLine);
pcibios_read_config_dword(
pciBus,
pciDeviceFunction,
PCI_BASE_ADDRESS_0,
&pciIoAddress);
ioBaseAddress = pciIoAddress;
interruptVector = pciIrqLine;
#endif
}
ioBaseAddress &= ~1;
//
//Check that IO range is free.
//
if (check_region(ioBaseAddress, 0x40)) {
DBGPRINT_ERROR(("NICScan: check_region failed\n"));
continue;
}
DBGPRINT_INIT(("Irq = %x , IoAddress = %x\n",
interruptVector,
ioBaseAddress));
pcibios_read_config_byte(
pciBus,
pciDeviceFunction,
PCI_REVISION_ID,
&revisionId);
pcibios_read_config_byte(
pciBus,
pciDeviceFunction,
PCI_CACHE_LINE_SIZE,
&cacheLineSize);
powerManagementControl = PCI_PME_STATUS |
PCI_POWER_STATE_D0;
pcibios_write_config_word(
pciBus,
pciDeviceFunction,
PCI_POWER_CONTROL,
powerManagementControl);
pcibios_write_config_dword(
pciBus,
pciDeviceFunction,
PCI_BASE_ADDRESS_0,
ioBaseAddress);
pcibios_write_config_byte(
pciBus,
pciDeviceFunction,
PCI_INTERRUPT_LINE,
interruptVector);
pcibios_write_config_byte(
pciBus,
pciDeviceFunction,
PCI_CACHE_LINE_SIZE,
cacheLineSize);
pcibios_write_config_word(
pciBus,
pciDeviceFunction,
PCI_COMMAND,
pciCommand);
pAdapter->Hardware.CacheLineSize = cacheLineSize * 4;
if ((pAdapter->Hardware.CacheLineSize % 0x10) ||
(!pAdapter->Hardware.CacheLineSize)) {
DBGPRINT_ERROR((
"tc90xbc_Scan: Cacheline size wrong\n"));
pAdapter->Hardware.CacheLineSize = 0x20;
}
//
// Save the variables in adapter structure
//
pAdapter->IoBaseAddress = ioBaseAddress;
pAdapter->PCI.IoBaseAddress = ioBaseAddress;
pAdapter->PCI.InterruptVector = interruptVector;
pAdapter->Hardware.RevisionId = revisionId;
pAdapter->Hardware.DeviceId = deviceId;
#ifdef __SMP__
spin_lock_init(&pAdapter->SpinLock_m); // set multicast
spin_lock_init(&pAdapter->SpinLock_send);
spin_lock_init(&pAdapter->SpinLock_int);
spin_lock_init(&pAdapter->SpinLock_misc); //recv mode/close/timer
#endif
//
// Fill the device structure
//
if (tc90x_FillDeviceStructure(pAdapter) != NIC_STATUS_SUCCESS) {
DBGPRINT_ERROR((
KERN_CRIT "FillDeviceStructure failed\n"));
tc90x_FreeAdapterResources(pAdapter);
continue;
}
if (tc90x_ReadCommandLineChanges(pAdapter) !=
NIC_STATUS_SUCCESS) {
DBGPRINT_ERROR((
KERN_CRIT "ReadCommandLineChanges failed\n"
));
tc90x_FreeAdapterResources(pAdapter);
continue;
}
//
// Allocate Shared memory
//
if (tc90x_AllocateSharedMemory(pAdapter) != NIC_STATUS_SUCCESS) {
DBGPRINT_ERROR((
"tc90x_AllocateSharedMemory failed\n"
));
tc90x_FreeAdapterResources(pAdapter);
continue;
}
//
// Reserve the io range.
//
request_region(
Device->base_addr,
0x80,
ProductName);
pAdapter->ResourcesReserved |= NIC_IO_PORT_REGISTERED;
//
// Set the root device and the next device.
//
((PNIC_INFORMATION)(Device->priv))->NextDevice = RootNICDevice;
((PNIC_INFORMATION)(Device->priv))->Device = Device;
RootNICDevice = Device;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -