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
3 #define CARDNAME "dm9000"
4 #define DRV_VERSION "1.31"
5 /*
6 * Transmit timeout, default 5 seconds.
7 */
8 static int watchdog = 5000; //5s的延时时间
9 module_param(watchdog, int, 0400);
10 MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
11 enum dm9000_type { //开发板定义了三个DM9000类型
12 TYPE_DM9000E, /* original DM9000 */
13 TYPE_DM9000A,
14 TYPE_DM9000B
15 };
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
5 return platform_driver_register(&dm9000_driver); //platform设备模型注册驱动
6 }

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
13 /* Init network device */
14 //分配生成net_device结构体 alloc_etherdev是alloc_netdev()针对以太网的快捷操作函数
15 ndev = alloc_etherdev(sizeof(struct board_info));
16
17 //判断是否分配正确
18 if (!ndev) {
19 dev_err(&pdev->dev, "could not allocate device.\n");
20 return -ENOMEM;
21 }
22 //建立net_device到device的连接
23 SET_NETDEV_DEV(ndev, &pdev->dev);
24 //内核输出信息
25 dev_dbg(&pdev->dev, "dm9000_probe()\n");
26 //函数netdev_priv直接返回了net_device结构末端地址,也就是网卡私有数据结构的起始地址。
27 /* setup board info structure */
28 db = netdev_priv(ndev);
29
30 db->dev = &pdev->dev;
31 db->ndev = ndev;
32
33 spin_lock_init(&db->lock);//初始化自旋锁
34 mutex_init(&db->addr_lock);
35
36 INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work); //??
37 //获取平台设备资源 resource 地址空间、数据空间、中断信号 7号中断
38 db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
39 db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
40 db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
41 //判断资源是否获取成功
42 if (db->addr_res == NULL || db->data_res == NULL ||
43 db->irq_res == NULL) {
44 dev_err(db->dev, "insufficient resources\n");
45 ret = -ENOENT;
46 goto out;
47 }
48 //platform_get_resource的变体 同 platform_get_resource(pdev, IORESOURCE_IRQ, 1)
49 db->irq_wake = platform_get_irq(pdev, 1);
50 if (db->irq_wake >= 0) {
51 dev_dbg(db->dev, "wakeup irq %d\n", db->irq_wake);
52 //前面获得中断号 申请中断
53 ret = request_irq(db->irq_wake, dm9000_wol_interrupt,
54 IRQF_SHARED, dev_name(db->dev), ndev);
55 if (ret) {
56 dev_err(db->dev, "cannot get wakeup irq (%d)\n", ret);
57 } else {
58 /* test to see if irq is really wakeup capable */
59 ret = set_irq_wake(db->irq_wake, 1);
60 if (ret) {
61 dev_err(db->dev, "irq %d cannot set wakeup (%d)\n",
62 db->irq_wake, ret);
63 ret = 0;
64 } else {
65 set_irq_wake(db->irq_wake, 0);
66 db->wake_supported = 1;
67 }
68 }
69 }
70 //IO资源分配大小 地址 为resource分配内存
71 iosize = resource_size(db->addr_res);
72 db->addr_req = request_mem_region(db->addr_res->start, iosize,
73 pdev->name); //内存申请
74
75 if (db->addr_req == NULL) {
76 dev_err(db->dev, "cannot claim address reg area\n");
77 ret = -EIO;
78 goto out;
79 }
80
81 db->io_addr = ioremap(db->addr_res->start, iosize);
82
83 if (db->io_addr == NULL) {
84 dev_err(db->dev, "failed to ioremap address reg\n");
85 ret = -EINVAL;
86 goto out;
87 }
88
89 iosize = resource_size(db->data_res);
90 db->data_req = request_mem_region(db->data_res->start, iosize,
91 pdev->name);
92
93 if (db->data_req == NULL) {
94 dev_err(db->dev, "cannot claim data reg area\n");
95 ret = -EIO;
96 goto out;
97 }
98
99 db->io_data = ioremap(db->data_res->start, iosize);
100
101 if (db->io_data == NULL) {
102 dev_err(db->dev, "failed to ioremap data reg\n");
103 ret = -EINVAL;
104 goto out;
105 }
106 //初始化net_device中的成员
107 /* fill in parameters for net-dev structure */
108 ndev->base_addr = (unsigned long)db->io_addr; //网络接口的IO基地址
109 ndev->irq = db->irq_res->start;//中断号 ifconfig时会打印出这个值 也可通过这个修改
110
111 /* ensure at least we have a default set of IO routines */
112 dm9000_set_io(db, iosize);
113
114 /* check to see if anything is being over-ridden */
115 if (pdata != NULL) {
116 /* check to see if the driver wants to over-ride the
117 * default IO width */
118 //检测与板级信息是否相同
119 if (pdata->flags & DM9000_PLATF_8BITONLY)
120 dm9000_set_io(db, 1);
121
122 if (pdata->flags & DM9000_PLATF_16BITONLY)
123 dm9000_set_io(db, 2);
124
125 if (pdata->flags & DM9000_PLATF_32BITONLY)
126 dm9000_set_io(db, 4);
127
128 /* check to see if there are any IO routine
129 * over-rides */
130
131 if (pdata->inblk != NULL)
132 db->inblk = pdata->inblk;
133
134 if (pdata->outblk != NULL)
135 db->outblk = pdata->outblk;
136
137 if (pdata->dumpblk != NULL)
138 db->dumpblk = pdata->dumpblk;
139
140 db->flags = pdata->flags;
141 }
142
143 #ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL
144 db->flags |= DM9000_PLATF_SIMPLE_PHY;
145 #endif
146
147 dm9000_reset(db);
148
149 /* try multiple times, DM9000 sometimes gets the read wrong */
150 for (i = 0; i < 8; i++) { //宏定义在dm9000.h中
151 id_val = ior(db, DM9000_VIDL);
152 id_val |= (u32)ior(db, DM9000_VIDH) << 8;
153 id_val |= (u32)ior(db, DM9000_PIDL) << 16;
154 id_val |= (u32)ior(db, DM9000_PIDH) << 24;
155
156 if (id_val == DM9000_ID)
157 break;
158 dev_err(db->dev, "read wrong id 0x%08x\n", id_val);
159 }
160
161 if (id_val != DM9000_ID) {
162 dev_err(db->dev, "wrong id: 0x%08x\n", id_val);
163 ret = -ENODEV;
164 goto out;
165 }
166
167 /* Identify what type of DM9000 we are working on */
168
169 id_val = ior(db, DM9000_CHIPR);
170 dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val);
171
172 switch (id_val) {
173 case CHIPR_DM9000A:
174 db->type = TYPE_DM9000A;
175 break;
176 case CHIPR_DM9000B:
177 db->type = TYPE_DM9000B;
178 break;
179 default:
180 dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val);
181 db->type = TYPE_DM9000E;
182 }
183
184 /* dm9000a/b are capable of hardware checksum offload */
185 if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) {
186 db->can_csum = 1;
187 db->rx_csum = 1;
188 ndev->features |= NETIF_F_IP_CSUM;
189 }
190
191 /* from this point we assume that we have found a DM9000 */
192
193 /* driver system function */ //初始化以太网设备的公有成员
194 ether_setup(ndev);//在调用register_netdev之前必须初始化完全。该函数中为net_device设置了很多默认值
195
196 ndev->netdev_ops = &dm9000_netdev_ops;
197 ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
198 ndev->ethtool_ops = &dm9000_ethtool_ops;
199
200 db->msg_enable = NETIF_MSG_LINK;
201 db->mii.phy_id_mask = 0x1f;
202 db->mii.reg_num_mask = 0x1f;
203 db->mii.force_media = 0;
204 db->mii.full_duplex = 0;
205 db->mii.dev = ndev;
206 db->mii.mdio_read = dm9000_phy_read;
207 db->mii.mdio_write = dm9000_phy_write;
208
209 mac_src = "eeprom";
210
211 /* try reading the node address from the attached EEPROM */
212 for (i = 0; i < 6; i += 2)
213 dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);
214
215 if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {
216 mac_src = "platform data";
217 memcpy(ndev->dev_addr, pdata->dev_addr, 6);
218 }
219
220 if (!is_valid_ether_addr(ndev->dev_addr)) {
221 /* try reading from mac */
222
223 mac_src = "chip";
224 for (i = 0; i < 6; i++)
225 ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
226 }
227
228 if (!is_valid_ether_addr(ndev->dev_addr))
229 dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "
230 "set using ifconfig\n", ndev->name);
231
232 platform_set_drvdata(pdev, ndev);
233 ret = register_netdev(ndev); //注册net_device结构体
234
235 if (ret == 0)
236 printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n",
237 ndev->name, dm9000_type_to_char(db->type),
238 db->io_addr, db->io_data, ndev->irq,
239 ndev->dev_addr, mac_src);
240 return 0;
241
242 out:
243 dev_err(db->dev, "not found (%d).\n", ret);
244
245 dm9000_release_board(pdev, db);
246 free_netdev(ndev); //分配错误则释放net_device结构
247
248 return ret;
249 }
模块加载后转入probe中执行,在probe中完成了分配net_device、网络设备的初始化,设备驱动的加载。
先是分配获得了net_device结构体等。
网络设备初始化包括:
进行硬件上的准备工作,检查网络设备是否存在,检测所使用的硬件资源。主要是resource
获得软件接口上的准备工作。
获得私有数据指针,初始化以太网设备公有成员、初始化成员,初始化自旋锁或并发同步机制、申请设备所需的硬件资源 request_region等。
 
在网络设备驱动程序完成模块注册时,会调用dm9000_probe()函数进行初始化,分配并初始化net_device结构体。其中有些成员在dm9000_probe()中已经完成初始化,还有一些函数指针例如(*open)()、(*release)()等函数,也是在驱动程序中进行定义。
 
4.dm9000_open()
open函数在执行ifconfig命令时会被激活。主要作用是打开网络设备,获得设备所需的IO地址,IRQ、DMA通道等。注册中断、设置寄存器、启动发送队列。
在字符设备驱动中是把中断注册放在模块初始化函数中,而网卡驱动则放在open函数中。原因是网卡有禁用操作,当被禁用的时候,要把占用的中断号释放。
 1 m9000_open(struct net_device *dev)
2 {
3 board_info_t *db = netdev_priv(dev);//获取设备私有数据 返回board_info_t的地址
4 unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;
5
6 if (netif_msg_ifup(db))
7 dev_dbg(db->dev, "enabling %s\n", dev->name);
8
9 /* If there is no IRQ type specified, default to something that
10 * may work, and tell the user that this is a problem */
11
12 if (irqflags == IRQF_TRIGGER_NONE)
13 dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");
14
15 irqflags |= IRQF_SHARED;
16 //注册中断
17 if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
18 return -EAGAIN;
19
20 /* Initialize DM9000 board */
21 dm9000_reset(db); //复位DM9000
22 dm9000_init_dm9000(dev); //初始化dm9000中net_device结构中的成员
23
24 /* Init driver variable */
25 db->dbug_cnt = 0;
26
27 mii_check_media(&db->mii, netif_msg_link(db), 1);//检测mii接口状态
28 netif_start_queue(dev); //启动发送队列 协议栈向网卡发送
29
30 dm9000_schedule_poll(db);
31
32 return 0;
33 }
5.stop()
设备关闭函数
tatic int dm9000_stop(struct net_device *ndev)
{
board_info_t *db = netdev_priv(ndev); if (netif_msg_ifdown(db))
dev_dbg(db->dev, "shutting down %s\n", ndev->name); cancel_delayed_work_sync(&db->phy_poll); /* 终止phy_poll队列中被延迟的任务 */ netif_stop_queue(ndev); /* 关闭发送队列 */
netif_carrier_off(ndev); /* free interrupt */
free_irq(ndev->irq, ndev); /* 释放中断 */ dm9000_shutdown(ndev); /* 关闭DM9000网卡 */ return 0;
}
6.dm9000_shutdown()
下面是调用的dm9000_shutdown(ndev)函数,该函数的功能是复位phy,配置寄存器GPR位0为1,关闭dm9000电源,配置寄存器IMR位7为1,disable中断,配置寄存器RCR,disable接收.
 1 static void dm9000_shutdown(struct net_device *dev)
2 {
3 board_info_t *db = netdev_priv(dev);
4
5 /* RESET device */
6 dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET ,复位PHY*/
7 iow(db, DM9000_GPR, 0x01); /* Power-Down PHY */
8 iow(db, DM9000_IMR, IMR_PAR); /* Disable all interrupt ,关闭所有的中断*/
9 iow(db, DM9000_RCR, 0x00); /* Disable RX ,不再接受数据*/
10 }
7.数据发送函数
数据包发送流程:
1)设备驱动程序从上层协议传递过来的sk_buff参数获得数据包的有效数据和长度,将有效数据放入临时缓冲区中。
2)设置硬件寄存器,驱动网络设备进行数据发送操作。
 1 static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
2 {
3 unsigned long flags;
4 board_info_t *db = netdev_priv(dev);
5
6 dm9000_dbg(db, 3, "%s:\n", __func__);
7
8 if (db->tx_pkt_cnt > 1)
9 return NETDEV_TX_BUSY;
10
11 spin_lock_irqsave(&db->lock, flags); //获得自旋锁
12
13 /* Move data to DM9000 TX RAM */
14 writeb(DM9000_MWCMD, db->io_addr); //根据 IO 操作模式(8-bit or 16-bit)来增加写指针 1 或 2
15
16 (db->outblk)(db->io_data, skb->data, skb->len); //将数据从sk_buff中copy到网卡的TX SRAM中
17 dev->stats.tx_bytes += skb->len; //统计发送的字节数
18
19 db->tx_pkt_cnt++; //待发送计数
20 /* TX control: First packet immediately send, second packet queue */
21 if (db->tx_pkt_cnt == 1) { //如果计数为1,直接发送
22 dm9000_send_packet(dev, skb->ip_summed, skb->len);
23 } else {
24 /* Second packet */
25 db->queue_pkt_len = skb->len;
26 db->queue_ip_summed = skb->ip_summed;
27 netif_stop_queue(dev); //告诉上层停止发送
28 }
29
30 spin_unlock_irqrestore(&db->lock, flags);//解锁
31
32 /* free this SKB */
33 dev_kfree_skb(skb); //释放SKB
34
35 return NETDEV_TX_OK;
36 }

dm9000_start_xmit通过调用dm9000_send_packet来发送数据。

8.发送数据
dm9000_start_xmit函数中获得要发送的数据字节数,并调用dm9000_send_packet来发送数据。
 1 static void dm9000_send_packet(struct net_device *dev,
2 int ip_summed,
3 u16 pkt_len)
4 {
5 board_info_t *dm = to_dm9000_board(dev);
6
7 /* The DM9000 is not smart enough to leave fragmented packets alone. */
8 if (dm->ip_summed != ip_summed) {
9 if (ip_summed == CHECKSUM_NONE)
10 iow(dm, DM9000_TCCR, 0);
11 else
12 iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP);
13 dm->ip_summed = ip_summed;
14 }
15
16 /* Set TX length to DM9000 *///设置发送数据的长度到TXPLL\TXPLH中
17 iow(dm, DM9000_TXPLL, pkt_len);
18 iow(dm, DM9000_TXPLH, pkt_len >> 8);
19
20 /* Issue TX polling command *///设置发送寄存器的发送控制位,启动发送数据
21 iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
22 }
9.发送超时函数
发送数据时并不一定会成功,系统会调用dm9000_timeout函数。当传输数据超时时,意味发送操作失败或硬件进入未知状态。在超时函数中会调用netif_wake_queue()函数来重新启动设备发送队列。
 1 static void dm9000_timeout(struct net_device *dev)
2 {
3 board_info_t *db = netdev_priv(dev);
4 u8 reg_save;
5 unsigned long flags;
6
7 /* Save previous register address */
8 reg_save = readb(db->io_addr);
9 spin_lock_irqsave(&db->lock, flags);
10
11 netif_stop_queue(dev);
12 dm9000_reset(db);
13 dm9000_init_dm9000(dev);
14 /* We can accept TX packets again */
15 dev->trans_start = jiffies; /* prevent tx timeout */
16 netif_wake_queue(dev); //重启发送队列
17
18 /* Restore previous register address */
19 writeb(reg_save, db->io_addr);
20 spin_unlock_irqrestore(&db->lock, flags);
21 }
由此,netif_wake_queue()函数与netif_stop_queue()是数据发送流程中要调用的两个重要的函数,分别用于唤醒和阻止上层向下层传送数据包。原型定义于include/linux/netdevice.h中。
 
10.发送中断处理函数
当一个数据包发送完成后会产生一个中断,进入中断处理函数。
 1 static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
2 {
3 int tx_status = ior(db, DM9000_NSR); /* Got TX status */
4
5 if (tx_status & (NSR_TX2END | NSR_TX1END)) { //检测一个数据包发送完毕
6 /* One packet sent complete */
7 db->tx_pkt_cnt--; //待发送的数据包数减1
8 dev->stats.tx_packets++;//已发送数据包加1
9
10 if (netif_msg_tx_done(db))
11 dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status);
12
13 /* Queue packet check & send */
14 if (db->tx_pkt_cnt > 0) //如果还有数据包,则继续发送
15 dm9000_send_packet(dev, db->queue_ip_summed,
16 db->queue_pkt_len);
17 netif_wake_queue(dev); //启动发送队列
18 }
19 }

11.中断处理函数

网络设备接收数据的主要方法是有中断引发设备的中断处理函数,中断处理函数判断中断的类型,如果为接收中断,则读取接收到的数据,分配sk_buff数据结构和数据缓冲区,将接收到的数据复制到数据缓冲区中,并调用netif_rx()函数将sk_buff传递给上层协议。
 1 static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
2 {
3 struct net_device *dev = dev_id;
4 board_info_t *db = netdev_priv(dev);
5 int int_status;
6 unsigned long flags;
7 u8 reg_save;
8
9 dm9000_dbg(db, 3, "entering %s\n", __func__);
10
11 /* A real interrupt coming */
12
13 /* holders of db->lock must always block IRQs */
14 spin_lock_irqsave(&db->lock, flags);
15
16 /* Save previous register address */
17 reg_save = readb(db->io_addr);
18
19 /* Disable all interrupts */
20 iow(db, DM9000_IMR, IMR_PAR);
21
22 /* Got DM9000 interrupt status */ //获取中断类型
23 int_status = ior(db, DM9000_ISR); /* Got ISR */
24 iow(db, DM9000_ISR, int_status); /* Clear ISR status */
25
26 if (netif_msg_intr(db))
27 dev_dbg(db->dev, "interrupt status %02x\n", int_status);
28
29 /* Received the coming packet */ //接收到一个数据包
30 if (int_status & ISR_PRS)
31 dm9000_rx(dev); //调用数据接收函数
32
33 /* Trnasmit Interrupt check */ //发送一个数据包
34 if (int_status & ISR_PTS)
35 dm9000_tx_done(dev, db); //调用数据发送函数
36
37 if (db->type != TYPE_DM9000E) {
38 if (int_status & ISR_LNKCHNG) {
39 /* fire a link-change request */
40 schedule_delayed_work(&db->phy_poll, 1);
41 }
42 }
43
44 /* Re-enable interrupt mask */
45 iow(db, DM9000_IMR, db->imr_all);
46
47 /* Restore previous register address */
48 writeb(reg_save, db->io_addr);
49
50 spin_unlock_irqrestore(&db->lock, flags);
51
52 return IRQ_HANDLED;
53 }
12.接收数据
接收数据函数主要将接收到的数据包传递给上层。
  1 dm9000_rx(struct net_device *dev)
2 {
3 board_info_t *db = netdev_priv(dev); //获得网卡私有数据首地址
4 struct dm9000_rxhdr rxhdr;
5 struct sk_buff *skb;
6 u8 rxbyte, *rdptr;
7 bool GoodPacket;
8 int RxLen;
9
10 /* Check packet ready or not */
11 do {//存储器地址不变的读数据
12 ior(db, DM9000_MRCMDX); /* Dummy read */ //MRCMDX是内存数据预取读命令
13
14 /* Get most updated data */
15 rxbyte = readb(db->io_data);
16
17 /* Status check: this byte must be 0 or 1 */ //0、1为正确,2表示接收出错
18 if (rxbyte & DM9000_PKT_ERR) {
19 dev_warn(db->dev, "status check fail: %d\n", rxbyte);
20 iow(db, DM9000_RCR, 0x00); /* Stop Device */ //关闭设备 并停止中断请求
21 iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */
22 return;
23 }
24
25 if (!(rxbyte & DM9000_PKT_RDY)) // 0x01没准备好,直接返回
26 return;
27
28 /* A packet ready now & Get status/length */
29 GoodPacket = true;
30 writeb(DM9000_MRCMD, db->io_addr);
31 //读取数据,从RX_SRAM读取到rxhdr中
32 (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));
33
34 RxLen = le16_to_cpu(rxhdr.RxLen);
35
36 if (netif_msg_rx_status(db))
37 dev_dbg(db->dev, "RX: status %02x, length %04x\n",
38 rxhdr.RxStatus, RxLen);
39
40 /* Packet Status check */ //检查包得完整性
41 if (RxLen < 0x40) {
42 GoodPacket = false;
43 if (netif_msg_rx_err(db))
44 dev_dbg(db->dev, "RX: Bad Packet (runt)\n");
45 }
46
47 if (RxLen > DM9000_PKT_MAX) {
48 dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen);
49 }
50
51 /* rxhdr.RxStatus is identical to RSR register. */
52 if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |
53 RSR_PLE | RSR_RWTO |
54 RSR_LCS | RSR_RF)) {
55 GoodPacket = false;
56 if (rxhdr.RxStatus & RSR_FOE) {
57 if (netif_msg_rx_err(db))
58 dev_dbg(db->dev, "fifo error\n");
59 dev->stats.rx_fifo_errors++;
60 }
61 if (rxhdr.RxStatus & RSR_CE) {
62 if (netif_msg_rx_err(db))
63 dev_dbg(db->dev, "crc error\n");
64 dev->stats.rx_crc_errors++;
65 }
66 if (rxhdr.RxStatus & RSR_RF) {
67 if (netif_msg_rx_err(db))
68 dev_dbg(db->dev, "length error\n");
69 dev->stats.rx_length_errors++;
70 }
71 }
72
73 /* Move data from DM9000 */ //从DM9000获取数据
74 if (GoodPacket && //分配SKB
75 ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) { //+4是因为除了数据包前面还有空读一字节、读状态一字节、读长度低位和高位各一个字节
76 skb_reserve(skb, 2); //定位data指针 DA(6)+SA(6)+type(2)+IP包+CFS(校验码4字节) IP包要求四字节对齐
77 rdptr = (u8 *) skb_put(skb, RxLen - 4); //定位tail指针 -4是减去校验码
78
79 /* Read received packet from RX SRAM */
80 //读取数据 从RX SRAM 到sk_buff中
81 (db->inblk)(db->io_data, rdptr, RxLen);
82 dev->stats.rx_bytes += RxLen;
83
84 /* Pass to upper layer */ //获取上层协议类型
85 skb->protocol = eth_type_trans(skb, dev);
86 if (db->rx_csum) {
87 if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0)
88 skb->ip_summed = CHECKSUM_UNNECESSARY;
89 else
90 skb->ip_summed = CHECKSUM_NONE;
91 }
92 netif_rx(skb); //把数据包交给上层
93 dev->stats.rx_packets++;
94
95 } else {
96 /* need to dump the packet's data */
97
98 (db->dumpblk)(db->io_data, RxLen);
99 }
100 } while (rxbyte & DM9000_PKT_RDY);
101 }
可以看出接收数据主要包括:
判断为接收数据中断----dm9000_rx()完成更深入的数据包接收工作[获取数据包长度,分配sk_buff和数据段缓冲区,读取硬件接收的数据放入缓冲区中,解析上层协议类型,将数据包交给上层]

DM9000网卡驱动分析(转)的更多相关文章

  1. Linux网卡驱动移植--Dm9000网卡驱动分析

    1. Linux网络体系结构由以下5部分组成 ① 系统调用接口: 位于Linux网络子系统的顶部,为应用程序提供访问内核网络子系统的方法,主要指socket系统调用. ② 协议无关接口: 实现一组基于 ...

  2. 【驱动】DM9000网卡驱动分析

    Preface    内核源码版本:linux-2.6.18    网卡驱动·linux内核网络分层结构:http://infohacker.blog.51cto.com/6751239/122114 ...

  3. Xilinx Uboot网卡驱动分析

    1.MAC控制器.网卡.PHY.MDIO.mii.gmii.rgmii概念扫盲 网卡在功能上包含OSI模型的两个层,数据链路层和物理层.物理层定义了数据传送与接收所需要的电与光信号.线路状态.时钟基准 ...

  4. DM9000网卡驱动深度分析

    一.dm9000_porbe函数分析 不同于u-boot代码,tq2440中的DM9000更加复杂,需要分析的点也很多: /* * Search DM9000 board, allocate spac ...

  5. [国嵌攻略][136][DM9000网卡驱动深度分析]

    网卡初始化 1.分配描述结构,alloc_etherdev 2.获取平台资源,platform_get_resource 2.1.在s3c_dm9k_resource中有相关的资源 2.2.add地址 ...

  6. mini2440移植uboot-2008.10 (二) DM9000网卡驱动移植

    还是利用 mini2440移植uboot-2008.10 (一)  修改好的代码 通过观察可以发现,mini2400使用的网卡芯片是DM9000,在uboot-2008.10源码中已经支持该芯片的驱动 ...

  7. Linux网卡驱动分析

    以太网(Ethernet)是一种计算机局域网组网技术,基于IEEE 802.3标准,它规定了包括物理层的连线.电信号和介质访问层协议. Ethernet接口的实质是MAC通过MII总线控制PHY的过程 ...

  8. DM9000网卡驱动接受数据从中断方式改成NAPI方式小记

    平台是最最经典的s3c2440了,说了要做这件事情很久了,就是改几行代码,一直没有做.前几天逼了自己一下,终于给做了,拖延症患者伤不起. 以下是需要读者对napi机制有所熟悉: step1:在boar ...

  9. [国嵌攻略][137][DM9000网卡驱动编程]

    DM9000数据发送 DM9000数据发送函数是在/drivers/net/dm9000.c中的dm9000_start_xmit函数 static int dm9000_start_xmit(str ...

随机推荐

  1. leetcode刷题-74搜索二维矩阵

    题目 编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值.该矩阵具有如下特性: 每行中的整数从左到右按升序排列.每行的第一个整数大于前一行的最后一个整数.示例 1: 输入:matrix ...

  2. P1295 [TJOI2011]书架 线段树优化dp,单调栈

    P1295 [TJOI2011]书架 本题思路比较好想(对我来说不是),但代码细节很多,奈何洛谷的题解只有思路,然后就是 没有丝毫解释的代码,让人看起来很头疼(~~ 尤其是像我这样的蒟蒻~~),所以便 ...

  3. Java中“==”和 equals的区别

    “==”的作用: 判断两个变量栈内存中存储的值是否相等,如果相等返回true,如果不相等返回false. 有两种形式的比较需要用到比较运算符“==”,一是两个基本数据类型之间的比较,二是两个引用数据类 ...

  4. 在思科三层交换机上配置DHCP,不同网段/VLAN间互通

    摘要: 描述:在三层交换机上配置DHCP,实现DHCP为PC1/PC3分配192.168.1.X网段:实现DHCP为PC2/PC4分配192.168.2.X网段:并且各个PC间要可以互相通信.(文末附 ...

  5. 听说这四个概念,很多 Java 老手都说不清

    Java 是很多人一直在用的编程语言,但是有些 Java 概念是非常难以理解的,哪怕是一些多年的老手,对某些 Java 概念也存在一些混淆和困惑. 所以,在这篇文章里,会介绍四个 Java 中最难理解 ...

  6. 优雅的在React组件中注册事件

    前言 在React的开发中,我们经常需要在 window 上注册一些事件, 比如按下 Esc 关闭弹窗, 按上下键选中列表内容等等.比较常见的操作是在组件 mount 的时候去 window 上监听一 ...

  7. spring ioc 源码分析(三)--finishBeanFactoryInitialization(beanFactory)

    之前的博客专门分析了一个类到BeanDefinition的创建过程,现在分析BeanDefinition 到一个bean的创建过程:从refresh() 方法的---->finishBeanFa ...

  8. SpringBoot-03-JSR303数据校验和多环境切换

    3.3 JSR303数据校验 先看如何使用 ​ Springboot中可以用@Validated来校验数据,如果数据异常则统一抛出异常,方便异常中心统一处理. ​ 这里我们写个注解让name只支持Em ...

  9. Python-维护排序好的序列模块-bisect

    bisect模块 处理已经排序的序列,升序,从小到大,分插入数据和查看插入数据的位置两大核心,类似于插入排序算法 插入数据 # 首先这个序列按升序规则已经排序好的 # 查找规则是二分查找,当数据相等的 ...

  10. Centos-切换用户身份-su

    su 切换用户身份 相关选项 - 加载相应用户下环境变量 -c   使用某个身份执行一个指令 -m  改变用户身份不改变环境变量 切换为超级用户 su - 普通用户切换为超级用户需要输入密码,超级用户 ...