DM9000驱动分析之初始化
2015-01-21 14:48
405 查看
/*分析DM9000网卡驱动之初始化*/ /*找到DM9000.c 文件路径: linux/drivers/net下 找到模块的入口函数处 */ static int __init dm9000_init(void) { printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION); return platform_driver_register(&dm9000_driver); } /*很明显DM9000是platform驱动。 既然DM9000是平台驱动,那当然也就有平台设备了*/ /*平台驱动结构初始化*/ 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), }; /*平台设备结构初始化: 路径: arch\arm\mach-s3c64xx\Mach-smdk6410*/ static struct platform_device s3c_device_dm9000 = { .name = "dm9000", .id = 0, .num_resources = ARRAY_SIZE(dm9000_resources), .resource = dm9000_resources, .dev = { .platform_data = &dm9000_setup, } }; /*当平台设备与驱动相匹配后,就会调用dm9000_probe函数*/ /* * Search DM9000 board, allocate space and register it * *从注释上可以得出: 这个函数主要是找到DM9000设备,然后分配空间,然后注册 * * 1. 分配 net_device结构 * 2. 初始化board_info结构 * 3. 获得DM9000的资源。包括DM9000的内存和中断资源 * 4. 地址映射 * 5. 初始化net_device的基地址和中断号 * 6. 重启DM9000设备 * 7. 获取DM9000的版本 * 8. 注册net_device结构 */ 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; /* Init network device */ //分配 net_device结构 ndev = alloc_etherdev(sizeof(struct board_info)); if (!ndev) { dev_err(&pdev->dev, "could not allocate device.\n"); return -ENOMEM; } SET_NETDEV_DEV(ndev, &pdev->dev); dev_dbg(&pdev->dev, "dm9000_probe()\n"); /* setup board info structure */ //初始化board_info结构 db = netdev_priv(ndev); db->dev = &pdev->dev; db->ndev = ndev; spin_lock_init(&db->lock); mutex_init(&db->addr_lock); INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work); //获得DM9000的资源。包括DM9000的内存和中断资源 db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (db->addr_res == NULL || db->data_res == NULL || db->irq_res == NULL) { dev_err(db->dev, "insufficient resources\n"); ret = -ENOENT; goto out; } 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; } } } //地址映射 iosize = resource_size(db->addr_res); 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; } 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 */ //初始化net_device的基地址和中断号 ndev->base_addr = (unsigned long)db->io_addr; ndev->irq = db->irq_res->start; /* ensure at least we have a default set of IO routines */ dm9000_set_io(db, iosize); /* check to see if anything is being over-ridden */ if (pdata != NULL) { /* check to see if the driver wants to over-ride the * default IO width */ if (pdata->flags & DM9000_PLATF_8BITONLY) dm9000_set_io(db, 1); if (pdata->flags & DM9000_PLATF_16BITONLY) dm9000_set_io(db, 2); if (pdata->flags & DM9000_PLATF_32BITONLY) dm9000_set_io(db, 4); /* check to see if there are any IO routine * over-rides */ if (pdata->inblk != NULL) db->inblk = pdata->inblk; if (pdata->outblk != NULL) db->outblk = pdata->outblk; if (pdata->dumpblk != NULL) db->dumpblk = pdata->dumpblk; db->flags = pdata->flags; } #ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL db->flags |= DM9000_PLATF_SIMPLE_PHY; #endif //重启DM9000设备 dm9000_reset(db); /* try multiple times, DM9000 sometimes gets the read wrong */ //判断DM9000的id是否正确,如果正确则说明找到了DM9000设备 for (i = 0; i < 8; i++) { id_val = ior(db, DM9000_VIDL); id_val |= (u32)ior(db, DM9000_VIDH) << 8; id_val |= (u32)ior(db, DM9000_PIDL) << 16; id_val |= (u32)ior(db, DM9000_PIDH) << 24; if (id_val == DM9000_ID) break; dev_err(db->dev, "read wrong id 0x%08x\n", id_val); } if (id_val != DM9000_ID) { dev_err(db->dev, "wrong id: 0x%08x\n", id_val); ret = -ENODEV; goto out; } /* Identify what type of DM9000 we are working on */ //获取DM9000的chipID, 判断是那种类型 id_val = ior(db, DM9000_CHIPR); dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val); switch (id_val) { case CHIPR_DM9000A: db->type = TYPE_DM9000A; break; case CHIPR_DM9000B: db->type = TYPE_DM9000B; break; default: dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val); db->type = TYPE_DM9000E; } /* dm9000a/b are capable of hardware checksum offload */ if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) { ndev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM; ndev->features |= ndev->hw_features; } /* from this point we assume that we have found a DM9000 */ /*从这里意味着找到了DM9000设备*/ /* driver system function */ /*初始化ndev结构*/ ether_setup(ndev); ndev->netdev_ops = &dm9000_netdev_ops; ndev->watchdog_timeo = msecs_to_jiffies(watchdog); ndev->ethtool_ops = &dm9000_ethtool_ops; db->msg_enable = NETIF_MSG_LINK; db->mii.phy_id_mask = 0x1f; db->mii.reg_num_mask = 0x1f; db->mii.force_media = 0; db->mii.full_duplex = 0; db->mii.dev = ndev; db->mii.mdio_read = dm9000_phy_read; db->mii.mdio_write = dm9000_phy_write; mac_src = "eeprom"; /* try reading the node address from the attached EEPROM */ for (i = 0; i < 6; i += 2) dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i); if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) { mac_src = "platform data"; memcpy(ndev->dev_addr, pdata->dev_addr, 6); } if (!is_valid_ether_addr(ndev->dev_addr)) { /* try reading from mac */ mac_src = "chip"; for (i = 0; i < 6; i++) ndev->dev_addr[i] = ior(db, i+DM9000_PAR); } if (!is_valid_ether_addr(ndev->dev_addr)) { dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please " "set using ifconfig\n", ndev->name); random_ether_addr(ndev->dev_addr); mac_src = "random"; } /*注册ndev结构*/ platform_set_drvdata(pdev, ndev); ret = register_netdev(ndev); if (ret == 0) printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n", ndev->name, dm9000_type_to_char(db->type), db->io_addr, db->io_data, ndev->irq, ndev->dev_addr, mac_src); return 0; out: dev_err(db->dev, "not found (%d).\n", ret); dm9000_release_board(pdev, db); free_netdev(ndev); return ret; } /*我们似乎发现,和硬件相关的设置很少。难道不用设置硬件? 其实不然 当我们使用ifconfig的时候,会调用ndev->ndev_ops中open函数设置必要的参数 */ /* * Open the interface. * The interface is opened whenever "ifconfig" actives it. * * 从注释中看出当使用ifconfig就会激活网卡设备 * */ static int dm9000_open(struct net_device *dev) { board_info_t *db = netdev_priv(dev); unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK; if (netif_msg_ifup(db)) dev_dbg(db->dev, "enabling %s\n", dev->name); /* If there is no IRQ type specified, default to something that * may work, and tell the user that this is a problem */ if (irqflags == IRQF_TRIGGER_NONE) dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n"); irqflags |= IRQF_SHARED; /* GPIO0 on pre-activate PHY, Reg 1F is not set by reset */ iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */ /*power up PHY*/ mdelay(1); /* delay needs by DM9000B */ /* Initialize DM9000 board */ dm9000_reset(db); //初始化DM9000 dm9000_init_dm9000(dev); //注册Dm9000中断 if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev)) return -EAGAIN; /* Init driver variable */ db->dbug_cnt = 0; mii_check_media(&db->mii, netif_msg_link(db), 1); netif_start_queue(dev); //启动发生队列 dm9000_schedule_poll(db); return 0; } /*分析 DM9000重启函数* 写0到NCR寄存器的第0位就可以重新启动。软件复位 */ static void dm9000_reset(board_info_t * db) { dev_dbg(db->dev, "resetting device\n"); /* RESET device */ writeb(DM9000_NCR, db->io_addr);//告诉DM9000地址端口为Network Control Register这个寄存器 udelay(200); writeb(NCR_RST, db->io_data); //写0到RST位, udelay(200); } /* * Initialize dm9000 board * 这个函数才是真正意义上的硬件初始化 * 这个函数注释很详细,不用解释 */ static void dm9000_init_dm9000(struct net_device *dev) { board_info_t *db = netdev_priv(dev); unsigned int imr; unsigned int ncr; dm9000_dbg(db, 1, "entering %s\n", __func__); /* I/O mode */ db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ /* Checksum mode */ if (dev->hw_features & NETIF_F_RXCSUM) iow(db, DM9000_RCSR, (dev->features & NETIF_F_RXCSUM) ? RCSR_CSUM : 0); iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */ ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0; /* if wol is needed, then always set NCR_WAKEEN otherwise we end * up dumping the wake events if we disable this. There is already * a wake-mask in DM9000_WCR */ if (db->wake_supported) ncr |= NCR_WAKEEN; iow(db, DM9000_NCR, ncr); //设置内部PHY /* Program operating register */ iow(db, DM9000_TCR, 0); /* TX Polling clear */ iow(db, DM9000_BPTR, 0x3f); /* Less 3Kb, 200us */ iow(db, DM9000_FCR, 0xff); /* Flow Control */ iow(db, DM9000_SMCR, 0); /* Special Mode */ /* clear TX status */ iow(db, DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END); iow(db, DM9000_ISR, ISR_CLR_STATUS); /* Clear interrupt status */ /* Set address filter table */ dm9000_hash_table_unlocked(dev); imr = IMR_PAR | IMR_PTM | IMR_PRM; if (db->type != TYPE_DM9000E) imr |= IMR_LNKCHNG; db->imr_all = imr; /* Enable TX/RX interrupt mask */ iow(db, DM9000_IMR, imr); /* Init Driver variable */ db->tx_pkt_cnt = 0; db->queue_pkt_len = 0; dev->trans_start = jiffies; } /* 总结: * 1. 分配 net_device结构 * 2. 初始化board_info结构 * 3. 获得DM9000的资源。包括DM9000的内存和中断资源 * 4. 地址映射 * 5. 初始化net_device的基地址和中断号 * 6. 重启DM9000设备 * 7. 获取DM9000的版本 * 8. 注册net_device结构 * 9. 硬件相关的初始化 * 10. 注册Dm9000中断 * 11. 启动发送队列 */
相关文章推荐
- dm9000驱动代码流程分析
- ARM-Linux驱动--DM9000网卡驱动分析(一)
- usb网卡驱动分析(一)——设备初始化
- dm9000网卡的linux驱动分析
- Nginx源码分析-事件驱动的初始化
- dm9000驱动代码流程分析
- QualComm 8x50 上MMC host controller 驱动的初始化流程分析
- [Linux驱动开发] 网络设备之DM9000驱动架构分析
- Nginx源码分析--事件驱动的初始化
- Mini2440中的DM9000网卡驱动分析
- ARM-Linux驱动--DM9000网卡驱动分析(一)
- ARM-Linux驱动--DM9000网卡驱动分析(四)
- ARM-Linux驱动--DM9000网卡驱动分析(三)
- 网络设备驱动 和 DM9000 驱动程序分析
- ARM-Linux驱动--DM9000网卡驱动分析(三) .
- Nginx源码分析-事件驱动的初始化
- ARM-Linux驱动--DM9000网卡驱动分析(三)
- ARM-Linux驱动--DM9000网卡驱动分析(一) .
- ARM-Linux驱动--DM9000网卡驱动分析(二)
- linux网卡驱动dm9000_poll_work函数分析