📄 tlan.c
字号:
/******************************************************************** * * Linux ThunderLAN Driver * * tlan.c * by James Banks * * (C) 1997-1998 Caldera, Inc. * (C) 1998 James Banks * * This software may be used and distributed according to the terms * of the GNU Public License, incorporated herein by reference. * ** This file is best viewed/edited with columns>=132. * ** Useful (if not required) reading: * * Texas Instruments, ThunderLAN Programmer's Guide, * TI Literature Number SPWU013A * available in PDF format from www.ti.com * Level One, LXT901 and LXT970 Data Sheets * available in PDF format from www.level1.com * National Semiconductor, DP83840A Data Sheet * available in PDF format from www.national.com * Microchip Technology, 24C01A/02A/04A Data Sheet * available in PDF format from www.microchip.com * * Change History * * Tigran Aivazian <tigran@sco.com>: TLan_PciProbe() now uses * new PCI BIOS interface. * Alan Cox <alan@redhat.com>: Fixed the out of memory * handling. * ********************************************************************/#include <linux/module.h>#include "tlan.h"#include <linux/ioport.h>#include <linux/pci.h>#include <linux/etherdevice.h>#include <linux/delay.h>typedef u32 (TLanIntVectorFunc)( struct device *, u16 );#ifdef MODULEstatic struct device *TLanDevices = NULL;static int TLanDevicesInstalled = 0;static int aui = 0;static int sa_int = 0;static int duplex = 0;static int speed = 0;#endifstatic int debug = 0;static int bbuf = 0;static u8 *TLanPadBuffer;static char TLanSignature[] = "TLAN";static int TLanVersionMajor = 1;static int TLanVersionMinor = 0;static TLanAdapterEntry TLanAdapterList[] = { { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10, "Compaq Netelligent 10 T PCI UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100, "Compaq Netelligent 10/100 TX PCI UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED, "Compaq Integrated NetFlex-3/P", TLAN_ADAPTER_NONE, 0x83 }, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETFLEX_3P, "Compaq NetFlex-3/P", TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 }, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETFLEX_3P_BNC, "Compaq NetFlex-3/P", TLAN_ADAPTER_NONE, 0x83 }, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT, "Compaq Netelligent Integrated 10/100 TX UTP", TLAN_ADAPTER_NONE, 0x83 }, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL, "Compaq Netelligent Dual 10/100 TX PCI UTP", TLAN_ADAPTER_NONE, 0x83 }, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_DESKPRO_4000_5233MMX, "Compaq Netelligent 10/100 TX Embedded UTP", TLAN_ADAPTER_NONE, 0x83 }, { PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2183, "Olicom OC-2183/2185", TLAN_ADAPTER_USE_INTERN_10, 0xF8 }, { PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2325, "Olicom OC-2325", TLAN_ADAPTER_UNMANAGED_PHY, 0xF8 }, { PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2326, "Olicom OC-2326", TLAN_ADAPTER_USE_INTERN_10, 0xF8 }, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100_WS_5100, "Compaq Netelligent 10/100 TX UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_T2, "Compaq Netelligent 10 T/2 PCI UTP/Coax", TLAN_ADAPTER_NONE, 0x83 }, { 0, 0, NULL, 0, 0 } /* End of List */};static int TLan_PciProbe( u8 *, u8 *, u8 *, u32 *, u32 * );static int TLan_Init( struct device * );static int TLan_Open(struct device *dev);static int TLan_StartTx(struct sk_buff *, struct device *);static void TLan_HandleInterrupt(int, void *, struct pt_regs *);static int TLan_Close(struct device *);static struct net_device_stats *TLan_GetStats( struct device * );static void TLan_SetMulticastList( struct device * );static u32 TLan_HandleInvalid( struct device *, u16 );static u32 TLan_HandleTxEOF( struct device *, u16 );static u32 TLan_HandleStatOverflow( struct device *, u16 );static u32 TLan_HandleRxEOF( struct device *, u16 );static u32 TLan_HandleDummy( struct device *, u16 );static u32 TLan_HandleTxEOC( struct device *, u16 );static u32 TLan_HandleStatusCheck( struct device *, u16 );static u32 TLan_HandleRxEOC( struct device *, u16 );static void TLan_Timer( unsigned long );static void TLan_ResetLists( struct device * );static void TLan_FreeLists( struct device * );static void TLan_PrintDio( u16 );static void TLan_PrintList( TLanList *, char *, int );static void TLan_ReadAndClearStats( struct device *, int );static void TLan_ResetAdapter( struct device * );static void TLan_FinishReset( struct device * );static void TLan_SetMac( struct device *, int areg, char *mac );static void TLan_PhyPrint( struct device * );static void TLan_PhyDetect( struct device * );static void TLan_PhyPowerDown( struct device * );static void TLan_PhyPowerUp( struct device * );static void TLan_PhyReset( struct device * );static void TLan_PhyStartLink( struct device * );static void TLan_PhyFinishAutoNeg( struct device * );/*static int TLan_PhyNop( struct device * );static int TLan_PhyInternalCheck( struct device * );static int TLan_PhyInternalService( struct device * );static int TLan_PhyDp83840aCheck( struct device * );*/static int TLan_MiiReadReg( struct device *, u16, u16, u16 * );static void TLan_MiiSendData( u16, u32, unsigned );static void TLan_MiiSync( u16 );static void TLan_MiiWriteReg( struct device *, u16, u16, u16 );static void TLan_EeSendStart( u16 );static int TLan_EeSendByte( u16, u8, int );static void TLan_EeReceiveByte( u16, u8 *, int );static int TLan_EeReadByte( struct device *, u8, u8 * );static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = { TLan_HandleInvalid, TLan_HandleTxEOF, TLan_HandleStatOverflow, TLan_HandleRxEOF, TLan_HandleDummy, TLan_HandleTxEOC, TLan_HandleStatusCheck, TLan_HandleRxEOC};static inline voidTLan_SetTimer( struct device *dev, u32 ticks, u32 type ){ TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; cli(); if ( priv->timer.function != NULL ) { return; } priv->timer.function = &TLan_Timer; sti(); priv->timer.data = (unsigned long) dev; priv->timer.expires = jiffies + ticks; priv->timerSetAt = jiffies; priv->timerType = type; add_timer( &priv->timer );} /* TLan_SetTimer *//*********************************************************************************************************************************************************** ThunderLAN Driver Primary Functions These functions are more or less common to all Linux network drivers.***********************************************************************************************************************************************************/#ifdef MODULE /*************************************************************** * init_module * * Returns: * 0 if module installed ok, non-zero if not. * Parms: * None * * This function begins the setup of the driver creating a * pad buffer, finding all TLAN devices (matching * TLanAdapterList entries), and creating and initializing a * device structure for each adapter. * **************************************************************/extern int init_module(void){ TLanPrivateInfo *priv; struct device *dev; size_t dev_size; u8 dfn; u32 index; int failed; int found; u32 io_base; u8 irq; u8 rev; printk( "TLAN driver, v%d.%d, (C) 1997-8 Caldera, Inc.\n", TLanVersionMajor, TLanVersionMinor ); TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE, ( GFP_KERNEL | GFP_DMA ) ); if ( TLanPadBuffer == NULL ) { printk( "TLAN: Could not allocate memory for pad buffer.\n" ); return -ENOMEM; } memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE ); dev_size = sizeof(struct device) + sizeof(TLanPrivateInfo); while ( ( found = TLan_PciProbe( &dfn, &irq, &rev, &io_base, &index ) ) ) { dev = (struct device *) kmalloc( dev_size, GFP_KERNEL ); if ( dev == NULL ) { printk( "TLAN: Could not allocate memory for device.\n" ); continue; } memset( dev, 0, dev_size ); dev->priv = priv = ( (void *) dev ) + sizeof(struct device); dev->name = priv->devName; strcpy( priv->devName, " " ); dev->base_addr = io_base; dev->irq = irq; dev->init = TLan_Init; priv->adapter = &TLanAdapterList[index]; priv->adapterRev = rev; priv->aui = aui; if ( ( duplex != 1 ) && ( duplex != 2 ) ) { duplex = 0; } priv->duplex = duplex; if ( ( speed != 10 ) && ( speed != 100 ) ) { speed = 0; } priv->speed = speed; priv->sa_int = sa_int; priv->debug = debug; ether_setup( dev ); failed = register_netdev( dev ); if ( failed ) { printk( "TLAN: Could not register device.\n" ); kfree( dev ); } else { priv->nextDevice = TLanDevices; TLanDevices = dev; TLanDevicesInstalled++; printk("TLAN: %s irq=%2d io=%04x, %s, Rev. %d\n", dev->name, (int) dev->irq, (int) dev->base_addr, priv->adapter->deviceLabel, priv->adapterRev ); } } /* printk( "TLAN: Found %d device(s).\n", TLanDevicesInstalled ); */ return ( ( TLanDevicesInstalled >= 0 ) ? 0 : -ENODEV );} /* init_module */ /*************************************************************** * cleanup_module * * Returns: * Nothing * Parms: * None * * Goes through the TLanDevices list and frees the device * structs and memory associated with each device (lists * and buffers). It also ureserves the IO port regions * associated with this device. * **************************************************************/extern void cleanup_module(void){ struct device *dev; TLanPrivateInfo *priv; while ( TLanDevicesInstalled ) { dev = TLanDevices; priv = (TLanPrivateInfo *) dev->priv; if ( priv->dmaStorage ) { kfree( priv->dmaStorage ); } release_region( dev->base_addr, 0x10 ); unregister_netdev( dev ); TLanDevices = priv->nextDevice; kfree( dev ); TLanDevicesInstalled--; } kfree( TLanPadBuffer );} /* cleanup_module */#else /* MODULE */ /*************************************************************** * tlan_probe * * Returns: * 0 on success, error code on error * Parms: * dev device struct to use if adapter is * found. * * The name is lower case to fit in with all the rest of * the netcard_probe names. This function looks for a/ * another TLan based adapter, setting it up with the * provided device struct if one is found. * **************************************************************/ extern int tlan_probe( struct device *dev ){ TLanPrivateInfo *priv; static int pad_allocated = 0; int found; u8 dfn, irq, rev; u32 io_base, index; found = TLan_PciProbe( &dfn, &irq, &rev, &io_base, &index ); if ( ! found ) { return -ENODEV; } dev->priv = kmalloc( sizeof(TLanPrivateInfo), GFP_KERNEL ); if ( dev->priv == NULL ) { printk( "TLAN: Could not allocate memory for device.\n" ); return -ENOMEM; } memset( dev->priv, 0, sizeof(TLanPrivateInfo) ); if ( ! pad_allocated ) { TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE, // ( GFP_KERNEL | GFP_DMA ) ( GFP_KERNEL ) ); if ( TLanPadBuffer == NULL ) { printk( "TLAN: Could not allocate memory for padding.\n" ); kfree( dev->priv ); return -ENOMEM; } else { pad_allocated = 1; memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE ); } } priv = (TLanPrivateInfo *) dev->priv; dev->name = priv->devName; strcpy( priv->devName, " " ); dev = init_etherdev( dev, sizeof(TLanPrivateInfo) ); dev->base_addr = io_base; dev->irq = irq; priv->adapter = &TLanAdapterList[index]; priv->adapterRev = rev; priv->aui = dev->mem_start & 0x01; priv->duplex = ( ( dev->mem_start & 0x0C ) == 0x0C ) ? 0 : ( dev->mem_start & 0x0C ) >> 2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -