dm9000网卡驱动分析(一)

转自http://blog.chinaunix.net/uid-26442066-id-3184195.html

s3c6410自带的DM9000网卡驱动也是基于platform设备模型。

其定义的设备资源在arch/arm/mach-s3c64xx/mach-smdk6410中。有网卡的resource resource dm9000_resources[],还有一些板级信息,dm9000_plat_data dm9000_setup。

1.宏及参数  //板级、系统定义
  1. #define DM9000_PHY        0x40    /* PHY address 0x01 */

  2. #define CARDNAME    "dm9000"
  3. #define DRV_VERSION    "1.31"
  4. /*
  5.  * Transmit timeout, default 5 seconds.
  6.  */
  7. static int watchdog = 5000; //5s的延时时间
  8. module_param(watchdog, int, 0400);
  9. MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
  10. enum dm9000_type {  //开发板定义了三个DM9000类型
  11.     TYPE_DM9000E,    /* original DM9000 */
  12.     TYPE_DM9000A,
  13.     TYPE_DM9000B
  14. };

2.模块注册
此处因为基于platform模型,采用platform_driver_register函数注册内核模块,当设备驱动与设备匹配真确后,转入执行dm9000_probe()函数,该函数包含真正的dm9000网卡驱动注册函数是register_netdev()函数。
  1. static int __init dm9000_init(void)
  2. {
  3.     printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION);

  4.     return platform_driver_register(&dm9000_driver); //platform设备模型注册驱动
  5. }
dm9000的platform设备驱动函数如下
  1. static struct platform_driver dm9000_driver = {
  2.     .driver    = {
  3.         .name = "dm9000",
  4.         .owner     = THIS_MODULE,
  5.         .pm     = &dm9000_drv_pm_ops,
  6.     },
  7.     .probe = dm9000_probe,
  8.     .remove = __devexit_p(dm9000_drv_remove),
  9. };

3.dm9000_probe函数
主要完成网络设备的初始化,以及网卡驱动的注册register_netdev()
  1. static int __devinit  dm9000_probe(struct platform_device *pdev)
  2. {
  3.     struct dm9000_plat_data *pdata = pdev->dev.platform_data;//驱动程序中获得系统定义的网卡板级信息
  4.                                             //定义在/arch/arm/mach-s3c64xx/mach-smdk6410.c中。
  5.     struct board_info *db;    /* Point a board information structure */
  6.     struct net_device *ndev; //定义设备结构体
  7.     const unsigned char *mac_src;
  8.     int ret = 0;
  9.     int iosize;
  10.     int i;
  11.     u32 id_val;

  12.     /* Init network device */
  13. //分配生成net_device结构体  alloc_etherdev是alloc_netdev()针对以太网的快捷操作函数
  14.     ndev = alloc_etherdev(sizeof(struct board_info))

  15. //判断是否分配正确
  16.     if (!ndev) {
  17.         dev_err(&pdev->dev, "could not allocate device.\n");
  18.         return -ENOMEM;
  19.     }
  20. //建立net_device到device的连接
  21.     SET_NETDEV_DEV(ndev, &pdev->dev)
  22. //内核输出信息
  23.     dev_dbg(&pdev->dev, "dm9000_probe()\n");
  24. //函数netdev_priv直接返回了net_device结构末端地址,也就是网卡私有数据结构的起始地址。
  25.     /* setup board info structure */
  26.     db = netdev_priv(ndev);

  27.     db->dev = &pdev->dev;
  28.     db->ndev = ndev;

  29.     spin_lock_init(&db->lock);//初始化自旋锁
  30.     mutex_init(&db->addr_lock);

  31.     INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work); //??
  32. //获取平台设备资源 resource 地址空间、数据空间、中断信号 7号中断
  33.     db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  34.     db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
  35.     db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
  36. //判断资源是否获取成功
  37.     if (db->addr_res == NULL || db->data_res == NULL ||
  38.      db->irq_res == NULL) {
  39.         dev_err(db->dev, "insufficient resources\n");
  40.         ret = -ENOENT;
  41.         goto out;
  42.     }
  43. //platform_get_resource的变体 同  platform_get_resource(pdev, IORESOURCE_IRQ, 1)
  44.     db->irq_wake = platform_get_irq(pdev, 1)
  45.     if (db->irq_wake >= 0) {
  46.         dev_dbg(db->dev, "wakeup irq %d\n", db->irq_wake);
  47.                                                                                           //前面获得中断号  申请中断
  48.         ret = request_irq(db->irq_wake, dm9000_wol_interrupt,
  49.                  IRQF_SHARED, dev_name(db->dev), ndev);
  50.         if (ret) {
  51.             dev_err(db->dev, "cannot get wakeup irq (%d)\n", ret);
  52.         } else {
  53.             /* test to see if irq is really wakeup capable */
  54.             ret = set_irq_wake(db->irq_wake, 1);
  55.             if (ret) {
  56.                 dev_err(db->dev, "irq %d cannot set wakeup (%d)\n",
  57.                     db->irq_wake, ret);
  58.                 ret = 0;
  59.             } else {
  60.                 set_irq_wake(db->irq_wake, 0);
  61.                 db->wake_supported = 1;
  62.             }
  63.         }
  64.     }
  65. //IO资源分配大小  地址  为resource分配内存
  66.     iosize = resource_size(db->addr_res);
  67.     db->addr_req = request_mem_region(db->addr_res->start, iosize,
  68.                      pdev->name); //内存申请

  69.     if (db->addr_req == NULL) {
  70.         dev_err(db->dev, "cannot claim address reg area\n");
  71.         ret = -EIO;
  72.         goto out;
  73.     }

  74.     db->io_addr = ioremap(db->addr_res->start, iosize);

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

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

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

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

  89.     if (db->io_data == NULL) {
  90.         dev_err(db->dev, "failed to ioremap data reg\n");
  91.         ret = -EINVAL;
  92.         goto out;
  93.     }
  94. //初始化net_device中的成员
  95.     /* fill in parameters for net-dev structure */
  96.     ndev->base_addr = (unsigned long)db->io_addr; //网络接口的IO基地址
  97.     ndev->irq    = db->irq_res->start;//中断号  ifconfig时会打印出这个值  也可通过这个修改

  98.     /* ensure at least we have a default set of IO routines */
  99.     dm9000_set_io(db, iosize)

  100.     /* check to see if anything is being over-ridden */
  101.     if (pdata != NULL) {
  102.         /* check to see if the driver wants to over-ride the
  103.          * default IO width */
  104. //检测与板级信息是否相同
  105.         if (pdata->flags & DM9000_PLATF_8BITONLY)
  106.             dm9000_set_io(db, 1);

  107.         if (pdata->flags & DM9000_PLATF_16BITONLY)
  108.             dm9000_set_io(db, 2);

  109.         if (pdata->flags & DM9000_PLATF_32BITONLY)
  110.             dm9000_set_io(db, 4);

  111.         /* check to see if there are any IO routine
  112.          * over-rides */

  113.         if (pdata->inblk != NULL)
  114.             db->inblk = pdata->inblk;

  115.         if (pdata->outblk != NULL)
  116.             db->outblk = pdata->outblk;

  117.         if (pdata->dumpblk != NULL)
  118.             db->dumpblk = pdata->dumpblk;

  119.         db->flags = pdata->flags;
  120.     }

  121. #ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL
  122.     db->flags |= DM9000_PLATF_SIMPLE_PHY;
  123. #endif

  124.     dm9000_reset(db);

  125.     /* try multiple times, DM9000 sometimes gets the read wrong */
  126.     for (= 0; i < 8; i++) {  //宏定义在dm9000.h中
  127.         id_val = ior(db, DM9000_VIDL);
  128.         id_val |= (u32)ior(db, DM9000_VIDH) << 8;
  129.         id_val |= (u32)ior(db, DM9000_PIDL) << 16;
  130.         id_val |= (u32)ior(db, DM9000_PIDH) << 24;

  131.         if (id_val == DM9000_ID)
  132.             break;
  133.         dev_err(db->dev, "read wrong id 0x%08x\n", id_val);
  134.     }

  135.     if (id_val != DM9000_ID) {
  136.         dev_err(db->dev, "wrong id: 0x%08x\n", id_val);
  137.         ret = -ENODEV;
  138.         goto out;
  139.     }

  140.     /* Identify what type of DM9000 we are working on */

  141.     id_val = ior(db, DM9000_CHIPR);
  142.     dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val);

  143.     switch (id_val) {
  144.     case CHIPR_DM9000A:
  145.         db->type = TYPE_DM9000A;
  146.         break;
  147.     case CHIPR_DM9000B:
  148.         db->type = TYPE_DM9000B;
  149.         break;
  150.     default:
  151.         dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val);
  152.         db->type = TYPE_DM9000E;
  153.     }

  154.     /* dm9000a/b are capable of hardware checksum offload */
  155.     if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) {
  156.         db->can_csum = 1;
  157.         db->rx_csum = 1;
  158.         ndev->features |= NETIF_F_IP_CSUM;
  159.     }

  160.     /* from this point we assume that we have found a DM9000 */

  161.     /* driver system function */ //初始化以太网设备的公有成员
  162.     ether_setup(ndev);//在调用register_netdev之前必须初始化完全。该函数中为net_device设置了很多默认值

  163.     ndev->netdev_ops    = &dm9000_netdev_ops;
  164.     ndev->watchdog_timeo    = msecs_to_jiffies(watchdog);
  165.     ndev->ethtool_ops    = &dm9000_ethtool_ops;

  166.     db->msg_enable = NETIF_MSG_LINK;
  167.     db->mii.phy_id_mask = 0x1f;
  168.     db->mii.reg_num_mask = 0x1f;
  169.     db->mii.force_media = 0;
  170.     db->mii.full_duplex = 0;
  171.     db->mii.dev     = ndev;
  172.     db->mii.mdio_read = dm9000_phy_read;
  173.     db->mii.mdio_write = dm9000_phy_write;

  174.     mac_src = "eeprom";

  175.     /* try reading the node address from the attached EEPROM */
  176.     for (= 0; i < 6; i += 2)
  177.         dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);

  178.     if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {
  179.         mac_src = "platform data";
  180.         memcpy(ndev->dev_addr, pdata->dev_addr, 6);
  181.     }

  182.     if (!is_valid_ether_addr(ndev->dev_addr)) {
  183.         /* try reading from mac */
  184.         
  185.         mac_src = "chip";
  186.         for (= 0; i < 6; i++)
  187.             ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
  188.     }

  189.     if (!is_valid_ether_addr(ndev->dev_addr))
  190.         dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "
  191.              "set using ifconfig\n", ndev->name);

  192.     platform_set_drvdata(pdev, ndev);
  193.     ret = register_netdev(ndev); //注册net_device结构体

  194.     if (ret == 0)
  195.         printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n",
  196.          ndev->name, dm9000_type_to_char(db->type),
  197.          db->io_addr, db->io_data, ndev->irq,
  198.          ndev->dev_addr, mac_src);
  199.     return 0;

  200. out:
  201.     dev_err(db->dev, "not found (%d).\n", ret);

  202.     dm9000_release_board(pdev, db);
  203.     free_netdev(ndev); //分配错误则释放net_device结构

  204.     return ret;
  205. }
模块加载后转入probe中执行,在probe中完成了分配net_device、网络设备的初始化,设备驱动的加载。
先是分配获得了net_device结构体等。
网络设备初始化包括:
进行硬件上的准备工作,检查网络设备是否存在,检测所使用的硬件资源,主要是resource;
获得软件接口上的准备工作;
获得私有数据指针,初始化以太网设备公有成员、初始化成员,初始化自旋锁或并发同步机制、申请设备所需的硬件资源 request_region等。

你可能感兴趣的:(dm9000网卡驱动分析(一))