网络设备的初始化:
通过模块的加载函数看出DM9000A的驱动是以平台驱动的形式注册进内核的,下边是模块的加载函数:
1.static int __init
2.dm9000_init(void)
2.{
3. printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION); 4.
5. return platform_driver_register(&dm9000_driver); 6.}
下边是平台驱动结构体:
1.static struct platform_driver dm9000_driver = {
2. .driver = {
3. .name = "dm9000",
2. .owner = THIS_MODULE,
3. },
4. .probe = dm9000_probe,
5. .remove = __devexit_p(dm9000_drv_remove),
6. .suspend = dm9000_drv_suspend,
7. .resume = dm9000_drv_resume,
8.};
下面来分析probe函数,用来执行分配的内核函数是alloc_netdev,函数原型是:
1.struct net_device *alloc_netdev(int sizeof_priv, const char *name, void (*setup)(struct net_device*));
这里的sizeof_priv是驱动程序私有数据区的大小;这个区成员和net_device结构一同分配给网络设备。实际上,他们都处于一大块内存中,但是驱动程序不需要知道这些。name是接口的名字,其在用户空间可见;这个名字可以使用类似printf中%d的格式,内核将用下一个可用的接口号替代%d,最后,setup是一个初始化函数,用来设置net_device结构剩余的部分。网络子系统对alloc_netdev,为不同种类的接口封装了许多函数。最常用的是alloc_etherdev,它定义在linux/etherdevice.h中:
1.struct net_device *alloc_etherdev(int sizeof_priv);
该函数使用eth%d的形式指定分配给网络设备的名字。它提供了自己的初始化函数(ether_setup),用正确的值为以太网设备设置net_device中的许多成员。那么在DM9000A中这个私有数据成员是什么呢,看下边的结构:
1./* Structure/enum declaration ------------------------------- */
2.typedef struct board_info {
2.
3. void __iomem *io_addr; /* Register I/O base address */ 4. void __iomem *io_data; /* Data I/O address */ 5. u16 irq; /* IRQ */ 6.
7. u16 tx_pkt_cnt;
8. u16 queue_pkt_len;
9. u16 queue_start_addr;
10. u16 dbug_cnt;
11. u8 io_mode; /* 0:word, 2:byte */ 12. u8 phy_addr;
13. u8 imr_all;
14.
15. unsigned int flags; 16. unsigned int in_suspend :1; 17. int debug_level; 18.
19. enum dm9000_type type; 20.
21. void (*inblk)(void __iomem *port, void *data, int length); 22. void (*outblk)(void __iomem *port, void *data, int length); 23. void (*dumpblk)(void __iomem *port, int length); 24.
25. struct device *dev; /* parent device */ 26.
27. struct resource *addr_res; /* resources found */ 28. struct resource *data_res; 29. struct resource *addr_req; /* resources requested */ 30. struct resource *data_req; 31. struct resource *irq_res; 32.
33. struct mutex addr_lock; /* phy and eeprom access lock */ 34.
35. struct delayed_work phy_poll; 36. struct net_device *ndev; 37.
38. spinlock_t lock; 39.
40. struct mii_if_info mii; 41. u32 msg_enable;
42.} board_info_t;
这个struct board_info就是那个私有数据,用来保存芯片相关的一些私有信息。
下面是probe函数的实现:
1./*
2. * Search DM9000 board, allocate space and register it
3. */
4.static int __devinit
2.dm9000_probe(struct platform_device *pdev) 3.{
4. /*获得平台数据,这个应该在platform_device那边指定了*/ 5. struct dm9000_plat_data *pdata = pdev->dev.platform_data; 6. struct board_info *db; /* Point a board information structure */ 7. struct net_device *ndev; 8. const unsigned char *mac_src; 9. int ret = 0; 10. int iosize; 11. int i; 12. u32 id_val;
13.
14. /*分配以太网的网络设备*/ 15. ndev = alloc_etherdev(sizeof(struct board_info)); 16. if (!ndev) { 17. dev_err(&pdev->dev, "could not allocate device.\n"); 18. return -ENOMEM; 19. }
20. /*#define SET_NETDEV_DEV(net, pdev) ((net)->dev.parent = (pdev))*/ 21. SET_NETDEV_DEV(ndev, &pdev->dev);
22.
23. dev_dbg(&pdev->dev, "dm9000_probe()\n"); 24.
25. /*设置struct board_info为ndev的私有数据*/ 26. db = netdev_priv(ndev);
27. memset(db, 0, sizeof(*db)); 28.
29. db->dev = &pdev->dev;
30. db->ndev = ndev;
31.
32. spin_lock_init(&db->lock); 33. mutex_init(&db->addr_lock);
34. /*提交一个任务给一个工作队列,你需要填充一个work_struct结构db->phy_poll*/ 35. INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);
36. /*获取IO内存和中断资源*/ 37. db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
38. db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
39. db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
40.
41. if (db->addr_res == NULL || db->data_res == NULL || 42. db->irq_res == NULL) {
43. dev_err(db->dev, "insufficient resources\n"); 44. ret = -ENOENT;
45. goto out; 46. }
47. /*映射到内核,并获得IO内存的虚拟地址,ioremap完成页表的建立,不同于vmalloc,但是,它实际上不分配内存*/ 48. iosize = res_size(db->addr_res);
49. db->addr_req = request_mem_region(db->addr_res->start, iosize,
50. pdev->name);
51.
52. if (db->addr_req == NULL) { 53. dev_err(db->dev, "cannot claim address reg area\n"); 54. ret = -EIO;
55. goto out; 56. }
57.
58. db->io_addr = ioremap(db->addr_res->start, iosize);
59.
60. if (db->io_addr == NULL) { 61. dev_err(db->dev, "failed to ioremap address reg\n"); 62. ret = -EINVAL;
63. goto out; 64. }
65.
66. iosize = res_size(db->data_res);
67. db->data_req = request_mem_region(db->data_res->start, iosize,
68. pdev->name);
69.
70. if (db->data_req == NULL) { 71. dev_err(db->dev, "cannot claim data reg area\n"); 72. ret = -EIO;
73. goto out; 74. }
75.
76. db->io_data = ioremap(db->data_res->start, iosize);
77.
78. if (db->io_data == NULL) { 79. dev_err(db->dev, "failed to ioremap data reg\n"); 80. ret = -EINVAL;
81. goto out; 82. }
83.
84. /*获得网络设备的基地址*/ 85. ndev->base_addr = (unsigned long)db->io_addr; 86. /*获得网络设备的中断号*/ 87. ndev->irq = db->irq_res->start;
88.
89. /*设置默认的IO函数*/ 90. dm9000_set_io(db, iosize);
91.
92. /*如果平台数据不为空*/ 93. if (pdata != NULL) { 94. /* check to see if the driver wants to over-ride the 95. * default IO width */
96.
97. if (pdata->flags & DM9000_PLATF_8BITONLY) 98. dm9000_set_io(db, 1);
99.
100. if (pdata->flags & DM9000_PLATF_16BITONLY) 101. dm9000_set_io(db, 2);
102.
103. if (pdata->flags & DM9000_PLATF_32BITONLY) 104. dm9000_set_io(db, 4);
105.
106. /* check to see if there are any IO routine 107. * over-rides */
108.
109. if (pdata->inblk != NULL) 110. db->inblk = pdata->inblk;
111.
112. if (pdata->outblk != NULL) 113. db->outblk = pdata->outblk;
114.
115. if (pdata->dumpblk != NULL) 116. db->dumpblk = pdata->dumpblk;
117.
118. db->flags = pdata->flags;
119. } 120.
121.#ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL
122. db->flags |= DM9000_PLATF_SIMPLE_PHY; 123.#endif
124. /*dm9000复位*/ 125. dm9000_reset(db);
126. /*读取Vendor ID Register,Product ID Register中的值,与0x90000A46比较,如果相等,则说明是DM9000*/ 127. /* try multiple times, DM9000 sometimes gets the read wrong */ 128. for (i = 0; i < 8; i++) { 129. id_val = ior(db, DM9000_VIDL);
130. id_val |= (u32)ior(db, DM9000_VIDH) << 8;
131. id_val |= (u32)ior(db, DM9000_PIDL) << 16;
132. id_val |= (u32)ior(db, DM9000_PIDH) << 24;
133.
134. if (id_val == DM9000_ID) 135. break; 136. dev_err(db->dev, "read wrong id 0x%08x\n", id_val); 137. }
138.
139. if (id_val != DM9000_ID) { 140. dev_err(db->dev, "wrong id: 0x%08x\n", id_val); 141. ret = -ENODEV;
142. goto out; 143. }
144.
145. /* Identify what type of DM9000 we are working on */ 146. /*读取Chip Revision Register中的值*/ 147. id_val = ior(db, DM9000_CHIPR);
148. dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val); 149.
150. switch (id_val) { 151. case CHIPR_DM9000A: 152. db->type = TYPE_DM9000A;
153. break; 154. case CHIPR_DM9000B: 155. db->type = TYPE_DM9000B;
156. break; 157. default: 158. dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val); 159. db->type = TYPE_DM9000E;
160. }
161.
162. /* from this point we assume that we have found a DM9000 */ 163.
164. /* driver system function */ 165. /*设置部分net_device字段*/ 166. ether_setup(ndev);
167.
168. ndev->open = &dm9000_open;
169. ndev->hard_start_xmit = &dm9000_start_xmit;
170. ndev->tx_timeout = &dm9000_timeout;
171. ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
172. ndev->stop = &dm9000_stop;
173. ndev->set_multicast_list = &dm9000_hash_table;
174. /*对ethtool支持的相关声明可在<linux/ethtool.h>中找到。它的核心是一个ethtool_ops类型的结构,里边包含一个全部的24个不同的方法来支持ethtool*/ 175. ndev->ethtool_ops = &dm9000_ethtool_ops;
176. ndev->do_ioctl = &dm9000_ioctl; 177.
178.#ifdef CONFIG_NET_POLL_CONTROLLER
179. ndev->poll_controller = &dm9000_poll_controller; 180.#endif
181.
182. db->msg_enable = NETIF_MSG_LINK;
183. db->mii.phy_id_mask = 0x1f;
184. db->mii.reg_num_mask = 0x1f;
185. db->mii.force_media = 0;
186. db->mii.full_duplex = 0;
187. db->mii.dev = ndev;
188. db->mii.mdio_read = dm9000_phy_read;
189. db->mii.mdio_write = dm9000_phy_write;
190. /*MAC地址的源是eeprom*/ 191. mac_src = "eeprom"; 192.
193. /* try reading the node address from the attached EEPROM */ 194. for (i = 0; i < 6; i += 2) 195. dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);
196. /*如果从eeprom中读取的地址无效,并且私有数据不为空,从platform_device的私有数据中获取dev_addr*/ 197. if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) { 198. mac_src = "platform data"; 199. memcpy(ndev->dev_addr, pdata->dev_addr, 6);
200. }
201. /*如果地址依然无效,从PAR:物理地址(MAC)寄存器(Physical Address Register)中读取*/ 202. if (!is_valid_ether_addr(ndev->dev_addr)) { 203. /* try reading from mac */ 204.
205. mac_src = "chip"; 206. for (i = 0; i < 6; i++) 207. ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
208. }
209. /*查看以太网网卡设备地址是否有效*/ 210. if (!is_valid_ether_addr(ndev->dev_addr)) 211. dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please " 212. "set using ifconfig\n", ndev->name); 213. /*将ndev保存到pdev->dev->driver_data中*/ 214. platform_set_drvdata(pdev, ndev);
215. /*一切都初始化好后,注册网络设备*/ 216. ret = register_netdev(ndev);
217.
218. if (ret == 0) 219. printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n", 220. ndev->name, dm9000_type_to_char(db->type),
221. db->io_addr, db->io_data, ndev->irq,
222. ndev->dev_addr, mac_src);
223. return 0; 224.
225.out: 226. dev_err(db->dev, "not found (%d).\n", ret); 227.
228. dm9000_release_board(pdev, db);
229. free_netdev(ndev);
230.
231. return ret; 232.}
下边看看挂起和唤醒函数:
挂起函数完成了设置挂起标志,并没有真正把设备移除而只是设置了移除标志,复位PHY,停止PHY,禁止所有中断,禁止接受引脚。
1.static int
2.dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
2.{
3. struct net_device *ndev = platform_get_drvdata(dev); 4. board_info_t *db;
5.
6. if (ndev) { 7. db = netdev_priv(ndev);
8. db->in_suspend = 1;
9.
10. if (netif_running(ndev)) { 11. netif_device_detach(ndev);
12. dm9000_shutdown(ndev);
13. }
14. }
15. return 0; 16.}
唤醒函数完成了复位dm9000,初始化dm9000,标记设备为attached,清除挂起标志。
1.static int
2.dm9000_drv_resume(struct platform_device *dev)
2.{
3. struct net_device *ndev = platform_get_drvdata(dev); 4. board_info_t *db = netdev_priv(ndev);
5.
6. if (ndev) { 7.
8. if (netif_running(ndev)) { 9. dm9000_reset(db);
10. dm9000_init_dm9000(ndev);
11. netif_device_attach(ndev);
12. }
13. db->in_suspend = 0;
14. }
15. return 0; 16.}
网络设备的打开与释放:
首先来看这个open函数:
1.static int
2.dm9000_open(struct net_device *dev)
2.{
3. board_info_t *db = netdev_priv(dev);
4. unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;
2.
3. if (netif_msg_ifup(db)) 4. dev_dbg(db->dev, "enabling %s\n", dev->name); 5.
6. /* If there is no IRQ type specified, default to something that 7. * may work, and tell the user that this is a problem */
8.
9. if (irqflags == IRQF_TRIGGER_NONE) 10. dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n"); 11.
12. irqflags |= IRQF_SHARED;
13. /*注册中断处理函数*/ 14. if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev)) 15. return -EAGAIN; 16.
17. /* Initialize DM9000 board */ 18. /*复位DM9000*/ 19. dm9000_reset(db);
20. /*初始化DM9000的寄存器*/ 21. dm9000_init_dm9000(dev);
22.
23. /* Init driver variable */ 24. db->dbug_cnt = 0;
25. /*检查链路载波状况*/ 26. mii_check_media(&db->mii, netif_msg_link(db), 1);
27. /*启动发送队列*/ 28. netif_start_queue(dev);
29. /*之前在probe函数中调用 INIT_DELAYED_WORK初始化了工作队列,并关联了一个操作函数dm9000_poll_work(),此时运行dm9000_schedule_poll来调用这个函数*/ 30. dm9000_schedule_poll(db);
31.
32. return 0; 33.}
然后是stop函数:
1.static int
2.dm9000_stop(struct net_device *ndev)
2.{
3. board_info_t *db = netdev_priv(ndev);
4.
5. if (netif_msg_ifdown(db))
2. dev_dbg(db->dev, "shutting down %s\n", ndev->name);
2. /*杀死延时工作队列phy_poll*/
2. cancel_delayed_work_sync(&db->phy_poll);
3. /*停止发送队列*/ 4. netif_stop_queue(ndev);
5. /*通知内核链路失去连接*/ 6. netif_carrier_off(ndev);
7. /* free interrupt */ 8. free_irq(ndev->irq, ndev);
9. /*关闭DM9000*/ 10. dm9000_shutdown(ndev);
11. return 0; 12.}
复位PHY,停止PHY,禁止所有中断,禁止接收引脚。
1.static void
2.dm9000_shutdown(struct net_device *dev)
2.{
3. board_info_t *db = netdev_priv(dev);
4.
5. /* RESET device */
2. dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET */
2. iow(db, DM9000_GPR, 0x01); /* Power-Down PHY */
2. iow(db, DM9000_IMR, IMR_PAR); /* Disable all interrupt */ 3. iow(db, DM9000_RCR, 0x00); /* Disable RX */ 4.}
本篇文章来源于 Linux公社网站(www.linuxidc.com) 原文链接:http://www.linuxidc.com/Linux/2011-06/37493p2.htm