当前位置:嗨网首页>书籍在线阅读

16-DM9000网卡驱动设计分析

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

16.9.2 DM9000网卡驱动设计分析

DM9000网卡驱动位于内核源代码的drivers/net/dm9000.c,它基于平台驱动架构,代码清单16.19抽取了它的主干。其核心工作是实现了前文所述net_device结构体中的hard_start_xmit、open、stop、set_multicast_list、do_ioctl、tx_timeout等成员函数并借助中断辅助进行网络数据包的收发,另外它也实现了ethtool_ops中的成员函数。

代码清单16.19 DM9000网卡驱动

1 / Structure/enum 定义 ------------------------------- /

2 typedef struct board_info {

3

4 void __iomem io_addr; / 寄存器I/O基地址*/

5 void __iomem io_data; / 数据I/O基地址 */

6 u16 irq; / IRQ /

7

8 u16 tx_pkt_cnt;

9 ...

10 } board_info_t;

11

12 static int dm9000_ioctl(struct net_device dev, struct ifreq req, int cmd){...}

13

14 static const struct ethtool_ops dm9000_ethtool_ops = {

15 .get_drvinfo = dm9000_get_drvinfo,

16 .get_settings = dm9000_get_settings,

17 .set_settings = dm9000_set_settings,

18 .get_msglevel = dm9000_get_msglevel,

19 .set_msglevel = dm9000_set_msglevel,

20 .nway_reset = dm9000_nway_reset,

21 .get_link = dm9000_get_link,

22 .get_eeprom_len = dm9000_get_eeprom_len,

23 .get_eeprom = dm9000_get_eeprom,

24 .set_eeprom = dm9000_set_eeprom,

25 };

26

27 / 设置DM9000多播地址 /

28 static void dm9000_hash_table(struct net_device *dev)

29

30 / 看门狗超时,网络层将调用该函数 /

31 static void dm9000_timeout(struct net_device *dev)

32 {

33 ...

34 netif_stop_queue(dev);

35 netif_wake_queue(dev);

36 ...

37 }

38

39 static int dm9000_start_xmit(struct sk_buff skb, struct net_device dev)

40 {

41 ...

42 / 将发送数据包移至DM9000的TX RAM /

43 writeb(DM9000_MWCMD, db->io_addr);

44

45 (db->outblk)(db->io_data, skb->data, skb->len);

46 dev->stats.tx_bytes += skb->len;

47 ...

48 }

49

50 / 数据发送完成 /

51 static void dm9000_tx_done(struct net_device dev, board_info_t db)

52 {

53 ...

54 netif_wake_queue(dev);

55 }

56

57 / 接收数据并传递给上层 /

58 static void

59 dm9000_rx(struct net_device *dev)

60 {

61 ...

62 netif_rx(skb);

63 dev->stats.rx_packets++;

64 ...

65 }

66

67 static irqreturn_t dm9000_interrupt(int irq, void *dev_id)

68 {

69 ...

70 return IRQ_HANDLED;

71 }

72

73 / 打开网卡接口 /

74 static int dm9000_open(struct net_device *dev)

75 {

76 ..

77 netif_start_queue(dev);

78 ...

79 return 0;

80 }

81 / 从phyxcer读一个word /

82 static int dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg){...};

83 / 向phyxcer写一个word /

84 static void

85 dm9000_phy_write(struct net_device *dev,

86 int phyaddr_unused, int reg, int value){...}

87

88 static int __devinit

89 dm9000_probe(struct platform_device *pdev)

90 {

91 ...

92

93 / Init network device /

94 ndev = alloc_etherdev(sizeof(struct board_info));

95

96 SET_NETDEV_DEV(ndev, &pdev->dev);

97

98 ether_setup(ndev);

99

100 ndev->open = &dm9000_open;

101 ndev->hard_start_xmit = &dm9000_start_xmit;

102 ndev->tx_timeout = &dm9000_timeout;

103 ndev->stop = &dm9000_stop;

104 ndev->set_multicast_list = &dm9000_hash_table;

105 ndev->ethtool_ops = &dm9000_ethtool_ops;

106 ndev->do_ioctl = &dm9000_ioctl;

107

108 #ifdef CONFIG_NET_POLL_CONTROLLER

109 ndev->poll_controller = &dm9000_poll_controller;

110 #endif

111

112 db->msg_enable = NETIF_MSG_LINK;

113 ...

114 db->mii.mdio_read = dm9000_phy_read;

115 db->mii.mdio_write = dm9000_phy_write;

116

117 platform_set_drvdata(pdev, ndev);

118 ret = register_netdev(ndev);

119

120 ...

121 }

122

123 static int __devexit

124 dm9000_drv_remove(struct platform_device *pdev)

125 {

126 struct net_device *ndev = platform_get_drvdata(pdev);

127

128 platform_set_drvdata(pdev, NULL);

129

130 unregister_netdev(ndev);

131 free_netdev(ndev); / free device structure /

132

133 return 0;

134 }

135

136 static struct platform_driver dm9000_driver = {

137 .driver = {

138 .name = "dm9000",

139 .owner = THIS_MODULE,

140 },

141 .probe = dm9000_probe,

142 .remove = __devexit_p(dm9000_drv_remove),

143 };

144

145 static int __init dm9000_init(void)

146 {

147 return platform_driver_register(&dm9000_driver);

148 }

149

150 static void __exit dm9000_cleanup(void)

151 {

152 platform_driver_unregister(&dm9000_driver);

153 }

154

155 module_init(dm9000_init);

156 module_exit(dm9000_cleanup);

DM9000驱动的实现与具体CPU无关,在将该驱动移植到特定电路板时,只需要在板文件中为板上DM9000对应平台设备的寄存器和数据基地址进行赋值,并指定正确的IRQ资源,代码16.20给出了LDD6410开发板的板文件中对DM9000添加的内容。

代码清单16.20 LDD6410板文件中的DM9000的平台设备

1 static struct resource ldd6410_dm9000_resource[] = {

2 [0] = {

3 .start = 0x18000000,

4 .end = 0x18000000 + 3,

5 .flags = IORESOURCE_MEM

6 },

7 [1] = {

8 .start = 0x18000000 + 0x4,

9 .end = 0x18000000 + 0x7,

10 .flags = IORESOURCE_MEM

11 },

12 [2] = {

13 .start = IRQ_EINT(7),

14 .end = IRQ_EINT(7),

15 .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,

16 }

17

18 };

19

20 static struct dm9000_plat_data ldd6410_dm9000__platdata = {

21 .flags = DM9000_PLATF_16BITONLY | DM9000_PLATF_NO__EEPROM,

22 .dev_addr = { 0x0, 0x16, 0xd4, 0x9f, 0xed, 0xa4 },

23 };

24

25 static struct platform__device ldd6410_dm9000 = {

26 .name = "dm9000",

27 .id = 0,

28 .num_resources = ARRAY_SIZE(ldd6410_dm9000_resource),

29 .resource = ldd6410_dm9000_resource,

30 .dev = {

31 .platform_data = &ldd6410_dm9000_platdata,

32 }

33 };

另外,LDD6410开发板的U-BOOT也全面支持DM9000,这使得我们可以在U-BOOT中运行网络命令或通过tftp下载Linux内核运行,例如:

执行ping:

LDD6410 # ping 192.168.1.111

dm9000 i/o: 0x18000300, id: 0x90000a46

MAC: 00:40:5c:26:0a:5b

operating at 100M full duplex mode host 192.168.1.111 is alive

LDD6410 #

下载zImage:

LDD6410 # tftp 0xc0008000 zImage

dm9000 i/o: 0x18000300, id: 0x90000a46

MAC: 00:40:5c:26:0a:5b

operating at 100M full duplex mode

TFTP from server 192.168.1.111; our IP address is 192.168.1.20

Filename 'zImage'.

Load address: 0xc0008000

Loading: #################################################################

#################################################################

#################################################################

#################################################################

#################################################################

#################################################################

########################################################

done

Bytes transferred = 2279916 (22c9ec hex)

启动内核:

LDD6410 # bootm 0xc0008000

Boot with zImage

Starting kernel ...