从8139too的驱动转换到pcnet32驱动程序,重新开始PCI的初始化过程是一件比较枯燥的事情。由于pcnet32驱动程序提供对非PCI设备
的支持,同时,它需要确定当前系统中的网卡的版本号。而我的调试过程,是在一块已确定版本的网卡(AMD
97C970A)上进行的,所以删去了原驱动程序的非PCI支持部分和对版本号的探测部分。经简化的驱动程序可以在vmwre上正常insmod和
rmmod。源代码如下:
/* pcnet32.h
* helinqiang@hotmail.com
* 2006-04-06
*/
#ifndef PCNET32_H_INCLUDED
#define PCNET32_H_INCLUDED
#include
#define DRV_NAME "pcnet32"
#define DRV_VERSION "1.30j"
#define DRV_RELDATE "29.04.2005"
#define PFX DRV_NAME ": "
static const char *version =
DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " tsbogend@alpha.franken.de\n";
#define PCNET32_WIO_RDP 0x10
#define PCNET32_WIO_RAP 0x12
#define PCNET32_WIO_RESET 0x14
#define PCNET32_WIO_BDP 0x16
#define PCNET32_DWIO_RDP 0x10
#define PCNET32_DWIO_RAP 0x14
#define PCNET32_DWIO_RESET 0x18
#define PCNET32_DWIO_BDP 0x1c
#define PCNET32_TOTAL_SIZE 0x20
struct pcnet32_access{
u16 (*read_csr)(unsigned long, int);
void (*write_csr)(unsigned long, int, u16);
u16 (*read_bcr)(unsigned long, int);
void (*write_bcr)(unsigned long, int, u16);
u16 (*read_rap)(unsigned long);
void (*write_rap)(unsigned long, u16);
void (*reset)(unsigned long);
};
static u16 pcnet32_wio_read_csr( unsigned long addr, int index )
{
outw( index, addr + PCNET32_WIO_RAP );
return inw( addr + PCNET32_WIO_RDP );
}
static void pcnet32_wio_write_csr( unsigned long addr, int index, u16 val )
{
outw( index, addr + PCNET32_WIO_RAP );
outw( val, addr + PCNET32_WIO_RDP );
}
static u16 pcnet32_wio_read_bcr( unsigned long addr, int index )
{
outw( index, addr + PCNET32_WIO_RAP );
return inw( addr + PCNET32_WIO_BDP );
}
static void pcnet32_wio_write_bcr( unsigned long addr, int index, u16 val )
{
outw( index, addr + PCNET32_WIO_RAP );
outw( val, addr + PCNET32_WIO_BDP );
}
static u16 pcnet32_wio_read_rap( unsigned long addr )
{
return inw( addr + PCNET32_WIO_RAP );
}
static void pcnet32_wio_write_rap( unsigned long addr, u16 val )
{
outw( val, addr + PCNET32_WIO_RAP );
}
static void pcnet32_wio_reset( unsigned long addr )
{
inw( addr + PCNET32_WIO_RESET );
}
static int pcnet32_wio_check( unsigned long addr )
{
outw( 88, addr + PCNET32_WIO_RAP );
return ( inw(addr + PCNET32_WIO_RAP) == 88 );
}
static struct pcnet32_access pcnet32_wio = {
.read_csr = pcnet32_wio_read_csr,
.write_csr = pcnet32_wio_write_csr,
.read_bcr = pcnet32_wio_read_bcr,
.write_bcr = pcnet32_wio_write_bcr,
.read_rap = pcnet32_wio_read_rap,
.write_rap = pcnet32_wio_write_rap,
.reset = pcnet32_wio_reset
};
static u16 pcnet32_dwio_read_csr( unsigned long addr, int index )
{
outl( index, addr + PCNET32_DWIO_RAP );
return ( inl(addr + PCNET32_DWIO_RDP) & 0xffff );
}
static void pcnet32_dwio_write_csr( unsigned long addr, int index, u16 val )
{
outl( index, addr + PCNET32_DWIO_RAP );
outl( val, addr + PCNET32_DWIO_RDP );
}
static u16 pcnet32_dwio_read_bcr( unsigned long addr, int index )
{
outl( index, addr + PCNET32_DWIO_RAP );
return( inl(addr + PCNET32_DWIO_BDP) & 0xffff);
}
static void pcnet32_dwio_write_bcr( unsigned long addr, int index, u16 val )
{
outl( index, addr + PCNET32_DWIO_RAP );
outl( val, addr + PCNET32_DWIO_BDP );
}
static u16 pcnet32_dwio_read_rap( unsigned long addr )
{
return ( inl(addr + PCNET32_DWIO_RAP) & 0xffff );
}
static void pcnet32_dwio_write_rap( unsigned long addr, u16 val )
{
outl( val, addr + PCNET32_DWIO_RAP );
}
static void pcnet32_dwio_reset( unsigned long addr )
{
inl( addr + PCNET32_DWIO_RESET );
}
static int pcnet32_dwio_check( unsigned long addr )
{
outl( 88, addr + PCNET32_DWIO_RAP );
return ( (inl(addr + PCNET32_DWIO_RAP) & 0xffff ) == 88 );
}
static struct pcnet32_access pcnet32_dwio = {
.read_csr = pcnet32_dwio_read_csr,
.write_csr = pcnet32_dwio_write_csr,
.read_bcr = pcnet32_dwio_read_bcr,
.write_bcr = pcnet32_dwio_write_bcr,
.read_rap = pcnet32_dwio_read_rap,
.write_rap = pcnet32_dwio_write_rap,
.reset = pcnet32_dwio_reset
};
#define PCNET32_DMA_MASK 0xffffffff
#define PCNET32_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
static int __devinit pcnet32_probe_pci(struct pci_dev *pdev,
const struct pci_device_id *ent);
static void __devexit pcnet32_remove_one(struct pci_dev *pdev);
static int __devinit pcnet32_probe1( unsigned long ioaddr, int shared,
struct pci_dev *pdev );
static int pcnet32_open( struct net_device * );
static int pcnet32_start_xmit( struct sk_buff *, struct net_device * );
static struct net_device_stats *pcnet32_get_stats(struct net_device * );
struct pcnet32_private{
//struct pcnet32_rx_head rx_ring[RX_RING_SIZE];
//struct pcnet32_tx_head tx_ring[TX_RING_SIZE];
//struct pcnet32_init_block init_block;
dma_addr_t dma_addr;
struct pci_dev *pci_dev;
const char *name;
//struct sk_buff *tx_skbuff[TX_RING_SIZE];
//struct sk_buff *rx_skbuff[RX_RING_SIZE];
//dma_addr_t tx_dma_addr[TX_RING_SIZE];
//dma_addr_t rx_dma_addr[RX_RING_SIZE];
struct pcnet32_access a;
spinlock_t lock;
unsigned int cur_rx, cur_tx;
unsigned int dirty_rx, dirty_tx;
struct net_device_stats stats;
char tx_full;
int options;
unsigned int shared_irq:1,
dxsuflo:1,
mii:1;
struct net_device *next;
//struct mii_if_info mii_if;
//struct timer_list watchdog_timer;
//struct timer_list blink_timer;
u32 msg_enable;
};
#endif //PCNET32_H_INCLUDED
/* pcnet32.c
* helinqiang@hotmail.com
* 2006-04-06
*/
#include
#include
#include
#include "pcnet32.h"
static int cards_found = 0;
static int pcnet32_debug = 0;
static int tx_start = 1;
static int debug = -1;
static int tx_start_pt = -1;
static struct pci_device_id pcnet32_pci_tbl[] = {
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE,
PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET<<8, 0xffff00, 0 },
{ 0, }
};
static struct pci_driver pcnet32_driver = {
.name = DRV_NAME,
.probe = pcnet32_probe_pci,
.remove = __devexit_p(pcnet32_remove_one),
.id_table = pcnet32_pci_tbl,
};
static int __devinit pcnet32_probe_pci(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
unsigned long ioaddr;
int err;
err = pci_enable_device( pdev );
if( err < 0 ){
if( pcnet32_debug & NETIF_MSG_PROBE )
printk(KERN_ERR PFX "failed to enable device --err=%d\n", err);
return err;
}
pci_set_master( pdev );
ioaddr = pci_resource_start(pdev, 0);
if( !ioaddr ){
if( pcnet32_debug & NETIF_MSG_PROBE )
printk(KERN_ERR PFX "card has no PCI IO resource, aborting\n");
return -ENODEV;
}
if( !pci_dma_supported(pdev, PCNET32_DMA_MASK) ){
if( pcnet32_debug & NETIF_MSG_PROBE )
printk(KERN_ERR PFX "architecture dos not"
"support 32bit PCI busmaster DMA\n");
return -ENODEV;
}
if( request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_pci")
== NULL ){
if( pcnet32_debug & NETIF_MSG_PROBE )
printk(KERN_ERR PFX "io address range already allocated\n");
return -EBUSY;
}
err = pcnet32_probe1( ioaddr, 1, pdev );
if( err < 0 )
pci_disable_device( pdev );
return err;
}
static int __devinit pcnet32_probe1( unsigned long ioaddr, int shared,
struct pci_dev *pdev )
{
struct pcnet32_private *lp;
dma_addr_t lp_dma_addr;
struct pcnet32_access *a = NULL;
int i;
int fdx, mii, fset, dxsuflo;
int chip_version;
struct net_device *dev;
char *chipname;
u8 promaddr[6];
int ret = -ENODEV;
pcnet32_wio_reset( ioaddr );
if( pcnet32_wio_read_csr(ioaddr, 0)==4 && pcnet32_wio_check(ioaddr) )
a = &pcnet32_wio;
else{
pcnet32_dwio_reset( ioaddr );
if( pcnet32_dwio_read_csr(ioaddr, 0)==4 && pcnet32_dwio_check(ioaddr) )
a = &pcnet32_dwio;
else
goto err_release_region;
}
chip_version = a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr, 89) << 16);
printk(KERN_INFO " PCnet chip version is %#x.\n", chip_version);
fdx = mii = fset = dxsuflo = 0;
chip_version = ( chip_version >> 12 ) & 0xffff;
chipname = "PCnet/PCI II 79C970A";
fdx = 1;
dev = alloc_etherdev(0);
if(!dev){
if( pcnet32_debug & NETIF_MSG_PROBE )
printk(KERN_ERR PFX "Memory allocation failed.\n");
ret = -ENOMEM;
goto err_release_region;
}
SET_NETDEV_DEV( dev, &pdev->dev );
for( i = 0; i < 3; i ++ ){
unsigned int val;
val = a->read_csr( ioaddr, i+12 ) & 0xffff;
dev->dev_addr[2*i] = val &0x0ff;
dev->dev_addr[2*i+1] = (val >> 8) & 0x0ff;
}
for( i = 0; i < 6; i ++ )
promaddr[i] = inb( ioaddr + i );
if( pcnet32_debug & NETIF_MSG_PROBE )
printk( KERN_INFO PFX "%s at %#3lx,", chipname, ioaddr );
if( pcnet32_debug & NETIF_MSG_PROBE )
for( i = 0; i < 6; i ++ )
printk( KERN_INFO " %2.2x", dev->dev_addr[i] );
dev->base_addr = ioaddr;
if( (lp = pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL ){
if( pcnet32_debug & NETIF_MSG_PROBE )
printk(KERN_ERR PFX "Consistent memory allocation failed.\n");
ret = -ENOMEM;
goto err_free_netdev;
}
memset( lp, 0, sizeof(*lp) );
lp->dma_addr = lp_dma_addr;
lp->pci_dev = pdev;
spin_lock_init( &lp->lock );
SET_MODULE_OWNER( dev );
SET_NETDEV_DEV( dev, &pdev->dev );
dev->priv = lp;
lp->name = chipname;
lp->shared_irq = shared;
lp->dxsuflo = dxsuflo;
lp->mii = mii;
lp->msg_enable = pcnet32_debug;
lp->a = *a;
dev->irq = pdev->irq;
if( pcnet32_debug & NETIF_MSG_PROBE )
printk(" assigned IRQ %d. \n", dev->irq );
dev->open = &pcnet32_open;
dev->hard_start_xmit = &pcnet32_start_xmit;
//dev->stop = &pcnet32_close;
dev->get_stats = &pcnet32_get_stats;
//dev->set_multicast_list = &pcnet32_set_multicast_list;
//dev->do_ioctl = &pcnet32_ioctl;
//dev->ethtool_ops = &pcnet32_ethtool_ops;
//dev->tx_timeout = pcnet32_tx_timeout;
//dev->watchdog_timeo = (5*HZ);
register_netdev( dev );
pci_set_drvdata( pdev, dev );
if( pcnet32_debug & NETIF_MSG_PROBE )
printk(KERN_INFO "%s: registered as %s\n", dev->name, lp->name );
cards_found ++;
return 0;
err_free_netdev:
free_netdev( dev );
err_release_region:
release_region( ioaddr, PCNET32_TOTAL_SIZE );
return ret;
}
static void __devexit pcnet32_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct pcnet32_private *lp = dev->priv;
unregister_netdev( dev );
release_region( dev->base_addr, PCNET32_TOTAL_SIZE );
pci_free_consistent( lp->pci_dev, sizeof(*lp), lp, lp->dma_addr );
free_netdev( dev );
pci_disable_device( pdev );
pci_set_drvdata(pdev, NULL );
}
static int pcnet32_open( struct net_device *dev )
{
return 0;
}
static int pcnet32_start_xmit( struct sk_buff *skb, struct net_device *dev )
{
struct pcnet32_private *lp = dev->priv;
dev_kfree_skb( skb );
lp->stats.tx_dropped ++;
return 0;
}
static struct net_device_stats *pcnet32_get_stats( struct net_device *dev )
{
struct pcnet32_private *lp = dev->priv;
return &lp->stats;
}
static int __init pcnet32_init_module(void)
{
printk(KERN_INFO "%s", version);
pcnet32_debug = netif_msg_init(debug, PCNET32_MSG_DEFAULT);
if( (tx_start_pt >= 0) && (tx_start_pt <= 3) )
tx_start= tx_start_pt;
return pci_module_init(&pcnet32_driver);
}
static void __exit pcnet32_cleanup_module(void)
{
pci_unregister_driver(&pcnet32_driver);
}
module_init(pcnet32_init_module);
module_exit(pcnet32_cleanup_module);
阅读(1749) | 评论(0) | 转发(0) |