歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Linux設備驅動工程師之路——DM9000網卡驅動程序分析

Linux設備驅動工程師之路——DM9000網卡驅動程序分析

日期:2017/3/1 11:16:32   编辑:Linux編程
DM9000是開發板經采用的網絡芯片,是一種高度集成而且功耗很低的高速網絡控制器,可以和CPU直連,支持10/100M以太網連接,芯片內部自帶16K SARM(3KB用來發送,13KB用來接收).

1.模塊初始化

  1. static struct platform_driver dm9000_driver = {
  2. .driver = {
  3. .name = "dm9000",
  4. .owner = THIS_MODULE,
  5. },
  6. .probe = dm9000_probe,
  7. .remove = __devexit_p(dm9000_drv_remove),
  8. .suspend = dm9000_drv_suspend,
  9. .resume = dm9000_drv_resume,
  10. };
  11. static int __init
  12. dm9000_init(void)
  13. {
  14. printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION);
  15. return platform_driver_register(&dm9000_driver);
  16. }

模塊初始化完成了基於platfrom平台的DM9000網卡驅動的注冊,當DM9000網卡找到其對應的能處理的platform設備後調用probe函數。

2.DM9000網卡初始化

在probe函數中完成了對DM9000網卡的初始化

DM9000的特性:DM9000地址信號和數據信號復用使用CMD引腳區分它們(CMD為低是讀寫DM900地址寄存器,CMD為高時讀寫DM9000數據寄存器),訪問DM9000內部寄存器時,先將CMD置低,寫DM900地址寄存器,然後將CMD置高,讀寫DM9000數據寄存器。

  1. static int __devinit
  2. dm9000_probe(struct platform_device *pdev)
  3. {
  4. struct dm9000_plat_data *pdata = pdev->dev.platform_data;
  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結構
  14. ndev = alloc_etherdev(sizeof(struct board_info));
  15. if (!ndev) {
  16. dev_err(&pdev->dev, "could not allocate device.\n");
  17. return -ENOMEM;
  18. }
  19. //將net_device的parent指針指向platform_device對象,表示該設備掛載platform設備上。
  20. SET_NETDEV_DEV(ndev, &pdev->dev);
  21. dev_dbg(&pdev->dev, "dm9000_probe()\n");
  22. /* setup board info structure */
  23. //獲取net_device私有數據結構指針
  24. db = netdev_priv(ndev);
  25. memset(db, 0, sizeof(*db));
  26. //設置相關設備
  27. db->dev = &pdev->dev;
  28. db->ndevndev = ndev;
  29. spin_lock_init(&db->lock);
  30. mutex_init(&db->addr_lock);
  31. INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);
  32. //獲取平台設備資源。包括DM9000地址寄存器地址,DM9000數據寄存器地址,和DM900所占用的中斷號
  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. if (db->addr_res == NULL || db->data_res == NULL ||
  37. db->irq_res == NULL) {
  38. dev_err(db->dev, "insufficient resources\n");
  39. ret = -ENOENT;
  40. goto out;
  41. }
  42. //申請地址寄存器IO內存區域並映射
  43. iosize = res_size(db->addr_res);
  44. db->addr_req = request_mem_region(db->addr_res->start, iosize,
  45. pdev->name);
  46. if (db->addr_req == NULL) {
  47. dev_err(db->dev, "cannot claim address reg area\n");
  48. ret = -EIO;
  49. goto out;
  50. }
  51. db->io_addr = ioremap(db->addr_res->start, iosize);
  52. if (db->io_addr == NULL) {
  53. dev_err(db->dev, "failed to ioremap address reg\n");
  54. ret = -EINVAL;
  55. goto out;
  56. }
  57. //申請數據寄存器IO內存區域並映射
  58. iosize = res_size(db->data_res);
  59. db->data_req = request_mem_region(db->data_res->start, iosize,
  60. pdev->name);
  61. if (db->data_req == NULL) {
  62. dev_err(db->dev, "cannot claim data reg area\n");
  63. ret = -EIO;
  64. goto out;
  65. }
  66. db->io_data = ioremap(db->data_res->start, iosize);
  67. if (db->io_data == NULL) {
  68. dev_err(db->dev, "failed to ioremap data reg\n");
  69. ret = -EINVAL;
  70. goto out;
  71. }
  72. /* fill in parameters for net-dev structure */
  73. ndev->base_addr = (unsigned long)db->io_addr;
  74. ndev->irq = db->irq_res->start;
  75. //設置數據位寬
  76. /* ensure at least we have a default set of IO routines */
  77. dm9000_set_io(db, iosize);
  78. /* check to see if anything is being over-ridden */
  79. if (pdata != NULL) {
  80. /* check to see if the driver wants to over-ride the
  81. * default IO width */
  82. if (pdata->flags & DM9000_PLATF_8BITONLY)
  83. dm9000_set_io(db, 1);
  84. if (pdata->flags & DM9000_PLATF_16BITONLY)
  85. dm9000_set_io(db, 2);
  86. if (pdata->flags & DM9000_PLATF_32BITONLY)
  87. dm9000_set_io(db, 4);
  88. /* check to see if there are any IO routine
  89. * over-rides */
  90. if (pdata->inblk != NULL)
  91. db->inblk = pdata->inblk;
  92. if (pdata->outblk != NULL)
  93. db->outblk = pdata->outblk;
  94. if (pdata->dumpblk != NULL)
  95. db->dumpblk = pdata->dumpblk;
  96. db->flags = pdata->flags;
  97. }
  98. #ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL
  99. db->flags |= DM9000_PLATF_SIMPLE_PHY;
  100. #endif
  101. //復位網卡芯片
  102. dm9000_reset(db);
  103. //讀取設備ID,判斷是否是驅動能夠處理的網卡芯片
  104. /* try multiple times, DM9000 sometimes gets the read wrong */
  105. for (i = 0; i < 8; i++) {
  106. id_val = ior(db, DM9000_VIDL);
  107. id_val |= (u32)ior(db, DM9000_VIDH) << 8;
  108. id_val |= (u32)ior(db, DM9000_PIDL) << 16;
  109. id_val |= (u32)ior(db, DM9000_PIDH) << 24;
  110. if (id_val == DM9000_ID)
  111. break;
  112. dev_err(db->dev, "read wrong id 0x%08x\n", id_val);
  113. }
  114. if (id_val != DM9000_ID) {
  115. dev_err(db->dev, "wrong id: 0x%08x\n", id_val);
  116. ret = -ENODEV;
  117. goto out;
  118. }
  119. /* Identify what type of DM9000 we are working on */
  120. id_val = ior(db, DM9000_CHIPR);
  121. dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val);
  122. switch (id_val) {
  123. case CHIPR_DM9000A:
  124. db->type = TYPE_DM9000A;
  125. break;
  126. case CHIPR_DM9000B:
  127. db->type = TYPE_DM9000B;
  128. break;
  129. default:
  130. dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val);
  131. db->type = TYPE_DM9000E;
  132. }
  133. /* from this point we assume that we have found a DM9000 */
  134. /* driver system function */
  135. ether_setup(ndev);
  136. //設置網卡芯片的接口函數
  137. ndev->open = &dm9000_open;
  138. ndev->hard_start_xmit = &dm9000_start_xmit;
  139. ndev->tx_timeout = &dm9000_timeout;
  140. ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
  141. ndev->stop = &dm9000_stop;
  142. ndev->set_multicast_list = &dm9000_hash_table;
  143. ndev->ethtool_ops = &dm9000_ethtool_ops;
  144. ndev->do_ioctl = &dm9000_ioctl;
  145. #ifdef CONFIG_NET_POLL_CONTROLLER
  146. ndev->poll_controller = &dm9000_poll_controller;
  147. #endif
  148. db->msg_enable = NETIF_MSG_LINK;
  149. db->mii.phy_id_mask = 0x1f;
  150. db->mii.reg_num_mask = 0x1f;
  151. db->mii.force_media = 0;
  152. db->mii.full_duplex = 0;
  153. db->mii.dev = ndev;
  154. db->mii.mdio_read = dm9000_phy_read;
  155. db->mii.mdio_write = dm9000_phy_write;
  156. mac_src = "eeprom";
  157. //從EEPROM中讀取MAC地址填充dev_addr
  158. /* try reading the node address from the attached EEPROM */
  159. for (i = 0; i < 6; i += 2)
  160. dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);
  161. if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {
  162. mac_src = "platform data";
  163. memcpy(ndev->dev_addr, pdata->dev_addr, 6);
  164. }
  165. if (!is_valid_ether_addr(ndev->dev_addr)) {
  166. /* try reading from mac */
  167. mac_src = "chip";
  168. for (i = 0; i < 6; i++)
  169. ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
  170. }
  171. if (!is_valid_ether_addr(ndev->dev_addr))
  172. dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "
  173. "set using ifconfig\n", ndev->name);
  174. //設置平台設備驅動的dev成員為ndev。
  175. platform_set_drvdata(pdev, ndev);
  176. //注冊網絡設備驅動
  177. ret = register_netdev(ndev);
  178. if (ret == 0)
  179. printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n",
  180. ndev->name, dm9000_type_to_char(db->type),
  181. db->io_addr, db->io_data, ndev->irq,
  182. ndev->dev_addr, mac_src);
  183. return 0;
  184. out:
  185. dev_err(db->dev, "not found (%d).\n", ret);
  186. dm9000_release_board(pdev, db);
  187. free_netdev(ndev);
  188. return ret;
  189. }

我們在來看看讀寫網卡寄存器所用的ior和iow

  1. static u8
  2. ior(board_info_t * db, int reg)
  3. {
  4. writeb(reg, db->io_addr);
  5. return readb(db->io_data);
  6. }
  7. static void
  8. iow(board_info_t * db, int reg, int value)
  9. {
  10. writeb(reg, db->io_addr);
  11. writeb(value, db->io_data);
  12. }

可以看得出是先將要訪問的寄存器地址寫入到地址寄存器,然後在將數據寫入到數據寄存器。地址。

Copyright © Linux教程網 All Rights Reserved