Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1911814
  • 博文数量: 376
  • 博客积分: 2147
  • 博客等级: 大尉
  • 技术积分: 3642
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-06 10:47
文章分类

全部博文(376)

文章存档

2019年(3)

2017年(28)

2016年(15)

2015年(17)

2014年(182)

2013年(16)

2012年(115)

我的朋友

分类: LINUX

2012-02-07 14:49:14

从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) |
给主人留下些什么吧!~~