Template Information

Trang

Realtek 8139 programming in Linux

Thứ Bảy, 4 tháng 6, 2011 / 21:35

#include<linux/init.h>
#include<linux/module.h>
#include<linux/pci.h>
#include<linux/netdevice.h>
#include<linux/etherdevice.h>
#include<linux/irq.h>
#include<linux/interrupt.h>

MODULE_LICENSE("Dual BSD/GPL");

static struct pci_device_id rtl8139_table[]=
{
    {
        PCI_VENDOR_ID_REALTEK,
        PCI_DEVICE_ID_REALTEK_8139,
        PCI_ANY_ID,
        PCI_ANY_ID,
        0,
        0,
        0,
    },

    {
        0,
    },
};

MODULE_DEVICE_TABLE(pci,rtl8139_table);

static int rtl8139_probe(struct pci_dev *pdev,const struct pci_device_id *id);
static void rtl8139_remove(struct pci_dev *pdev);

static int rtl8139_open(struct net_device *dev);
static int rtl8139_release(struct net_device *dev);

static int rtl8139_handler(int,void *);

static struct pci_driver rtl8139_driver=
{
    .name = "net_driver",
    .id_table = rtl8139_table,
    .probe = rtl8139_probe,
    .remove = rtl8139_remove,
};

typedef struct priv_device
{
    struct net_device *netdev;
    void *regaddr;
}NSM_CONTEXT;

struct net_device *dev = NULL;
NSM_CONTEXT *adapter;

static int __init rtl8139_init_module(void)
{
    int retval = 0;
    retval = pci_register_driver(&rtl8139_driver);
    if(retval)
    {
        printk(KERN_ALERT "*****\nRegistration failure\n*****\n");
        return retval;
    }
    else
    {
        printk(KERN_ALERT "*****\nModule registered\n******\n");
        return retval;
    }
}

static void __exit rtl8139_exit_module(void)
{
    pci_unregister_driver(&rtl8139_driver);
//    return;
}

module_init(rtl8139_init_module);
module_exit(rtl8139_exit_module);

static int rtl8139_probe(struct pci_dev *pdev,const struct pci_device_id *id)
{
//    struct net_device  *dev = NULL;   
//    NSM_CONTEXT *adapter;

    printk(KERN_ALERT "*********\nrtl8139_probe called\n*******\n");

    if(pci_enable_device(pdev) != 0)
    {
        return -ENODEV;
    }

    pci_set_master(pdev);

    dev = alloc_etherdev(sizeof(NSM_CONTEXT));
    if(dev == NULL)
    {
        return -ENOMEM;
    }

//    adapter = (NSM_CONTEXT *)dev->priv;
    adapter = netdev_priv(dev);

    memset(adapter,0,sizeof(NSM_CONTEXT));

    adapter->netdev = dev;

    pci_set_drvdata(pdev,dev);

    if(pci_request_regions(pdev,"net_driver"))
    {
        rtl8139_remove(pdev);
        return -ENOMEM;
    }

    adapter->regaddr = ioremap(pci_resource_start(pdev,1),
                pci_resource_len(pdev,1));
    if(adapter->regaddr == NULL)
    {
        rtl8139_remove(pdev);
        return -ENOMEM;
    }
    else
    {
        dev->base_addr = pci_resource_start(pdev,1);
    }

    memcpy(dev->dev_addr,adapter->regaddr,ETH_ALEN);
    memcpy(dev->name,"my_ethernet",12);
    dev->mtu = 1000;
    dev->irq = pdev->irq;
    dev->open = &rtl8139_open;
    dev->stop = &rtl8139_release;

//    SET_MODULE_OWNER(dev);

    if(register_netdev(dev))
    {
        rtl8139_remove(pdev);
        return -ENODEV;
    }

    return 0;
}

/*static irqreturn_t rtl8139_handler(int irq,void *dev_id,struct pt_regs *regs)
{
    printk(KERN_ALERT "rtl8139_handler called\n");
    return IRQ_NONE;
}
*/
static int rtl8139_open(struct net_device *dev)
{
      u8 reg;
    u16 reg1;
    int retval;

    printk(KERN_ALERT "******************************\n");

    /*    Reset     */

    reg = ioread8(adapter->regaddr + 0x0037);
    rmb();
    printk(KERN_NOTICE "Before reset: reg = %x\n",reg);
    reg = reg | 0x10;
    iowrite8(reg,adapter->regaddr + 0x0037);
    wmb();
    reg = ioread8(adapter->regaddr + 0x0037);
    rmb();
    printk(KERN_NOTICE "After reset: reg = %x\n\n",reg);

    /*    Auto Negotiation Enable(ANE)        */

    reg1 = ioread16(adapter->regaddr + 0x0062);
    rmb();
    printk(KERN_NOTICE "Before ANE: reg1 = %x\n",reg1);
    reg1 = reg1 | 0x1000;
    iowrite16(reg1,adapter->regaddr + 0x0062);
    wmb();
    reg1 = ioread16(adapter->regaddr + 0x0062);
    rmb();
    printk(KERN_NOTICE "After ANE: reg1 = %x\n\n",reg1);

    /*    Disabling the Interrupts    */

    reg1 = ioread16(adapter->regaddr + 0x003c);
    rmb();
    printk(KERN_NOTICE "Before disabling interrupts: reg1 = %x\n",reg1);
    reg1 = reg1 | 0x00;
    iowrite16(reg1,adapter->regaddr + 0x003c);
    wmb();
    reg1 = ioread16(adapter->regaddr + 0x003c);
    rmb();
    printk(KERN_NOTICE "After disabling interrupts: reg1 = %x\n\n",reg1);

    /*    Registering Interrupt Handler        */   

    retval = request_irq(dev->irq,rtl8139_handler,IRQF_SHARED,dev->name,
                dev);
    if(retval)
    {
        printk(KERN_ALERT "Error\n");
        return retval;
    }

    /*    Receiver Enable        */

    reg = ioread8(adapter->regaddr + 0x0037);
    rmb();
    printk(KERN_NOTICE "Before receiver enable: reg = %x\n",reg);
    reg = reg | 0x08;
    iowrite8(reg,adapter->regaddr + 0x0037);
    wmb();
    reg = ioread8(adapter->regaddr + 0x0037);
    rmb();
    printk(KERN_NOTICE "After receiver enable: reg = %x\n\n",reg);

    /*    Transmitter Enable    */

    reg = ioread8(adapter->regaddr + 0x0037);
    rmb();
    printk(KERN_NOTICE "Before transmitter enable: reg = %x\n",reg);
    reg = reg | 0x04;
    iowrite8(reg,adapter->regaddr + 0x0037);
    wmb();
    reg = ioread8(adapter->regaddr + 0x0037);
    rmb();
    printk(KERN_NOTICE "After transmitter enable: reg = %x\n\n",reg);


    printk(KERN_ALERT "rtl8139_open called\n");
    printk(KERN_ALERT "******************************\n");
       return 0;
}

static int rtl8139_handler(int irq,void *dev_id)
{
    printk(KERN_ALERT "****\nrtl8139_handler called\n****\n");
    return IRQ_NONE;
}

static int rtl8139_release(struct net_device *dev)
{
    printk(KERN_NOTICE "*******\nrtl8139_release called\n********\n");
      return 0;
}

static void rtl8139_remove(struct pci_dev *pdev)
{
   
//    dev = pci_get_drvdata(pdev);

    pci_release_regions(pdev);
    unregister_netdev(dev);
    free_netdev(dev);

    printk(KERN_ALERT "********\nrtl8139_remove called\n********\n");
}

0 nhận xét:

Đăng nhận xét