Linux2.6.39下DM9K驱动源码分析(2)

typedef struct board_info {
   
    void __iomem    *io_addr;    /* Register I/O base address *///虚拟的通过IO映射的
    void __iomem    *io_data;    /* Data I/O address */
    u16         irq;        /* IRQ */
/**********************************都通过映射后的**********************************************************************************************************/
    u16        tx_pkt_cnt;
    u16        queue_pkt_len;
    u16        queue_start_addr;
    u16        queue_ip_summed;
    u16        dbug_cnt;
    u8        io_mode;        /* 0:word, 2:byte */
    u8        phy_addr;
    u8        imr_all;

    unsigned int    flags;
    unsigned int    in_suspend :1;
    unsigned int    wake_supported :1;
    int        debug_level;

    enum dm9000_type type;
    //IO模式
    void (*inblk)(void __iomem *port, void *data, int length);
    void (*outblk)(void __iomem *port, void *data, int length);
    void (*dumpblk)(void __iomem *port, int length);

    struct device    *dev;         /* parent device */
    //平台设备资源
    struct resource    *addr_res;   /* 地址资源resources found */
    struct resource *data_res;   /**IO数据资源**/
    struct resource    *addr_req;   /* 分配后的地址内存资源*/
    struct resource *data_req;  /* 分配后的数据资源*/
    struct resource *irq_res;    /**中断资源***/

    int         irq_wake;

    struct mutex     addr_lock;    /* phy and eeprom access lock */

    struct delayed_work phy_poll;
    struct net_device  *ndev;

    spinlock_t    lock;

    struct mii_if_info mii;
    u32        msg_enable;
    u32        wake_state;

    int        rx_csum;
    int        can_csum;
    int        ip_summed;
} board_info_t;

/**************************************************************************************************************************************************************/

2.1、 注册平台驱动。

将驱动添加到总线上,完成驱动和设备的匹配,并执行驱动的probe函数。

static struct platform_driver dm9000_driver = {
    .driver    = {
        .name    = "dm9000",
        .owner     = THIS_MODULE,
        .pm     = &dm9000_drv_pm_ops,
    },
    .probe   = dm9000_probe,
    .remove  = __devexit_p(dm9000_drv_remove),
};

static int __init dm9000_init(void)
{
    printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION);

    return platform_driver_register(&dm9000_driver);
}

2.2、dm9000_probe探测函数的分析

static int __devinit dm9000_probe(struct platform_device *pdev)
{

//定义局部变量用来保存数据
    struct dm9000_plat_data *pdata = pdev->dev.platform_data;
    struct board_info *db;    /* Point a board information structure */
    struct net_device *ndev;
    const unsigned char *mac_src;
    int ret = 0;
    int iosize;
    int i;
    u32 id_val;
    /**内核用net_device结构来描述一个网络设备并使用alloc_etherdev或者alloc_netdev函数来分配一个net_device结构
    /* Init network device */
    ndev = alloc_etherdev(sizeof(struct board_info));
    if (!ndev) {
        dev_err(&pdev->dev, "could not allocate device.\n");
        return -ENOMEM;
    }
    //platform_device与net_device关联起来
    SET_NETDEV_DEV(ndev, &pdev->dev);//通过这一步网络设备和平台设备即关联起来了

    dev_dbg(&pdev->dev, "dm9000_probe()\n");

    /* setup board info structure */
 
    db = netdev_priv(ndev);/**获取net_device结构的私有成员保存到struct board_info *db中**/
    
    db->dev = &pdev->dev;
    db->ndev = ndev;
     
    spin_lock_init(&db->lock);/**初始化自旋锁**/
    mutex_init(&db->addr_lock);
    //初始化延迟等待队列并传入dm9000_poll_work该函数将在设备被打开的时候被调度
    INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);
    //获取平台资源?从哪里获取?
    db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);//dm9k平台设备所所使用的IO地址资源
    db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);//dm9k平台设备所所使用的IO数据资源
    db->irq_res  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);   //dm9k平台设备所所使用中断资源

    if (db->addr_res == NULL || db->data_res == NULL ||
        db->irq_res == NULL) {
        dev_err(db->dev, "insufficient resources\n");
        ret = -ENOENT;
        goto out;
    }
    //获取dm9k平台设备所使用的中断号
    db->irq_wake = platform_get_irq(pdev, 1);
    if (db->irq_wake >= 0) {
        dev_dbg(db->dev, "wakeup irq %d\n", db->irq_wake);
        //申请中断   
        ret = request_irq(db->irq_wake, dm9000_wol_interrupt,
                  IRQF_SHARED, dev_name(db->dev), ndev);
        if (ret) {
            dev_err(db->dev, "cannot get wakeup irq (%d)\n", ret);
        } else {

            /* test to see if irq is really wakeup capable */
            ret = irq_set_irq_wake(db->irq_wake, 1);
            if (ret) {
                dev_err(db->dev, "irq %d cannot set wakeup (%d)\n",
                    db->irq_wake, ret);
                ret = 0;
            } else {
                irq_set_irq_wake(db->irq_wake, 0);
                db->wake_supported = 1;
            }
        }
    }
    /*计算上面所获取到的IO地址平台资源的大小*/
    iosize = resource_size(db->addr_res);
    //为IO地址空间分配IO内存
    db->addr_req = request_mem_region(db->addr_res->start, iosize,
                      pdev->name);//物理

    if (db->addr_req == NULL) {
        dev_err(db->dev, "cannot claim address reg area\n");
        ret = -EIO;
        goto out;
    }
    //在访问IO内存之前必须映射IO内存
    db->io_addr = ioremap(db->addr_res->start, iosize);//虚拟地址

    if (db->io_addr == NULL) {
        dev_err(db->dev, "failed to ioremap address reg\n");
        ret = -EINVAL;
        goto out;
    }

    iosize = resource_size(db->data_res);
    db->data_req = request_mem_region(db->data_res->start, iosize,
                      pdev->name);

    if (db->data_req == NULL) {
        dev_err(db->dev, "cannot claim data reg area\n");
        ret = -EIO;
        goto out;
    }

    db->io_data = ioremap(db->data_res->start, iosize);

    if (db->io_data == NULL) {
        dev_err(db->dev, "failed to ioremap data reg\n");
        ret = -EINVAL;
        goto out;
    }
    /* fill in parameters for net-dev structure */
    ndev->base_addr = (unsigned long)db->io_addr;//初始化IO基地址
    ndev->irq    = db->irq_res->start;    //初始化irq      

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wyxjyy.html