十一.网络设备驱动介绍
5.11.1.网络设备驱动概述
5.11.1.1、什么是网络设备
(1)网络设备
//软件概念 eg:ifconfig查看的eth0,eth1
(2)物理网卡: 真正的硬件网卡设备
//eg:台式机的可插拔的360免费wifi
5.11.1.2、网络设备接口
(1)/dev下没有设备文件,也不通过/sys下的属性文件访问。直观看来,应用层都是通过一些特殊的命令(如ifconfig、ping等)来访问网卡硬件(调用驱动)的。本质上应用调用驱动的方法可以通过分析ping、ifconfig等命令的实现来得知。实际就是通过:socket、bind、listen、connect、send、recv等API来实现的。
(2)网络设备被抽象成一个能够发送和接收数据包的“网络接口”
(3)struct net_device来管理所有网络接口
//驱动设备的套路:将设备抽象成一个结构体,在驱动中定义这个结构体指针,然后为其分配内存,实例化,接着填充这个结构体,最后调用一个接口去注册这个结构体。
5.11.1.3、学习方法
(1)注意网络设备的访问方法和前两种不同
(2)2个数据结构(net_device和sk_buff)
//net_device是网络设备;
//sk_buff是数据包的抽象;通过这个sk_buff结构体发送和接收数据。
//网络设备就是一个可以接受和发送数据包的网络接口。
(3)一个虚拟网卡案例代码分析 + DM9000驱动源码分析
5.11.2.虚拟网卡驱动分析 //虚拟网卡重点是把框架搞清楚!
5.11.2.1、虚拟网卡安装、卸载、打开、关闭、设置IP地址等实践:
//ifconfig -a 查看所有网卡
//[root@localhost 11_net_demo]# ls
built-in.o modules.order net.c net.mod.c net.o
Makefile Module.symvers net.ko net.mod.o
[root@localhost 11_net_demo]# pwd
/linux-3.5/drivers/uea_drv/11_net_demo
[root@localhost 11_net_demo]# cp net.ko /rootfs
[root@FriendlyARM /]# insmod net.ko
[ 108.850000] aston_net_init
[ 108.860000] astoncnet_init
[root@FriendlyARM /]# ifconfig -a
astonnet0 Link encap:Ethernet HWaddr 00:00:00:00:00:00 //新加载的虚拟网卡
BROADCAST NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
eth0 Link encap:Ethernet HWaddr 00:00:FF:FF:00:00
inet addr:192.168.1.100 Bcast:192.168.1.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:12762 errors:0 dropped:0 overruns:0 frame:0
TX packets:5647 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:14995907 (14.3 MiB) TX bytes:935840 (913.9 KiB)
[root@FriendlyARM /]# ifconfig //没有激活新加载的虚拟网卡
eth0 Link encap:Ethernet HWaddr 00:00:FF:FF:00:00
inet addr:192.168.1.100 Bcast:192.168.1.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:12792 errors:0 dropped:0 overruns:0 frame:0
TX packets:5672 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:14998733 (14.3 MiB) TX bytes:943140 (921.0 KiB)
[root@FriendlyARM /]# ifconfig astonnet0 up//使能新加载的虚拟网卡
[ 282.910000] astonnet_open
[ 282.915000] astonnet tx
[root@FriendlyARM /]# [ 286.920000] astonnet tx
[ 290.930000] astonnet tx
[root@FriendlyARM /]# ifconfig//新加载的虚拟网卡激活了
astonnet0 Link encap:Ethernet HWaddr 9E:1C:7B:AC:E7:B2
UP BROADCAST RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
[root@FriendlyARM /]# ifconfig astonnet0 192.168.1.14
[root@FriendlyARM /]# ifconfig//测试后可以设置IP;连带广播等。//但是没有物理网卡,不能用,可以演示和分析。
astonnet0 Link encap:Ethernet HWaddr 9E:1C:7B:AC:E7:B2
inet addr:192.168.1.14 Bcast:192.168.1.255 Mask:255.255.255.0
UP BROADCAST RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
eth0 Link encap:Ethernet HWaddr 00:00:FF:FF:00:00
inet addr:192.168.1.100 Bcast:192.168.1.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:12924 errors:0 dropped:0 overruns:0 frame:0
TX packets:5798 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:15012257 (14.3 MiB) TX bytes:975832 (952.9 KiB)
[root@FriendlyARM /]# ifconfig astonnet0 down
[ 687.305000] astonnet_release
[root@FriendlyARM /]# rmmod net
[ 696.690000] aston_plat_net_release
rmmod: module 'net' not found
5.11.2.2、代码分析
#include <linux/module.h> #include <linux/sched.h> #include <linux/kernel.h> /* printk() */ #include <linux/slab.h> /* kmalloc() */ #include <linux/errno.h> /* error codes */ #include <linux/types.h> /* size_t */ #include <linux/interrupt.h> /* mark_bh */ #include <linux/in.h> #include <linux/netdevice.h> /* struct device, and other headers */ #include <linux/etherdevice.h> /* eth_type_trans */ #include <linux/ip.h> /* struct iphdr */ #include <linux/tcp.h> /* struct tcphdr */ #include <linux/skbuff.h> #include <linux/if_ether.h> #include <linux/in6.h> #include <asm/uaccess.h> #include <asm/checksum.h> #include <linux/platform_device.h> // 如果需要随机MAC地址则定义该宏 #define MAC_AUTO static struct net_device *astonnet_devs;//抽象定义一个网络设备指针 //网络设备结构体,作为net_device->priv
//该结构体将当前网卡的各种信息定义出来,使网卡可以在各个函数之间传输信息。
struct astonnet_priv { struct net_device_stats stats; //有用的统计信息 int status; //网络设备的状态信息,是发完数据包,还是接收到网络数据包 int rx_packetlen; //接收到的数据包长度 u8 *rx_packetdata; //接收到的数据 int tx_packetlen; //发送的数据包长度 u8 *tx_packetdata; //发送的数据 struct sk_buff *skb; //socket buffer结构体,网络各层之间传送数据都是通过这个结构体来实现的 spinlock_t lock; //自旋锁 }; //网络接口的打开函数 int astonnet_open(struct net_device *dev) //up后可以调用open函数 { printk("astonnet_open\n"); #ifndef MAC_AUTO //假如没有自动分配MAC地址则使用指定的 int i; for (i=0; i<6; i++) dev->dev_addr[i] = 0xaa;//指定的 #else random_ether_addr(dev->dev_addr); //随机函数分配MAC源地址 #endif netif_start_queue(dev); //打开传输队列,这样才能进行数据传输 return 0; } //网络接口的关闭函数 int astonnet_release(struct net_device *dev) { printk("astonnet_release\n"); //当网络接口关闭的时候,调用stop方法,这个函数表示不能再发送数据 netif_stop_queue(dev); //关闭传输队列 return 0; } //接包函数;这里永远得不到执行!因为这里的虚拟网卡无法中断调用中断! //(其他网卡发送、本网卡接收到一个数据包才触发网卡中断(接收是异步事件,是利用中断实现的),通过中断处理程序间接地调用该函数) void astonnet_rx(struct net_device *dev, int len, unsigned char *buf) { struct sk_buff *skb; struct astonnet_priv *priv = (struct astonnet_priv *) dev->ml_priv; skb = dev_alloc_skb(len+2);//分配一个socket buffer,并且初始化skb->data,skb->tail和skb->head if (!skb) { printk("gecnet rx: low on mem - packet dropped\n"); priv->stats.rx_dropped++; return; } skb_reserve(skb, 2); /* align IP on 16B boundary */ memcpy(skb_put(skb, len), buf, len);//skb_put是把数据写入到socket buffer /* Write metadata, and then pass to the receive level */ skb->dev = dev; skb->protocol = eth_type_trans(skb, dev);//返回的是协议号 skb->ip_summed = CHECKSUM_UNNECESSARY; //此处不校验 priv->stats.rx_packets++;//接收到包的个数+1 priv->stats.rx_bytes += len;//接收到包的长度 printk("astonnet rx \n"); netif_rx(skb);//通知内核已经接收到包,并且封装成socket buffer传到上层 return; } //真正的处理的发送数据包 //模拟从一个网络向另一个网络发送数据包;属于框架! void astonnet_hw_tx(char *buf, int len, struct net_device *dev) { struct net_device *dest;//目标设备结构体,net_device存储一个网络接口的重要信息,是网络驱动程序的核心 struct astonnet_priv *priv; if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) { printk("astonnet: Hmm... packet too short (%i octets)\n", len); return; } dest = astonnet_devs; priv = (struct astonnet_priv *)dest->ml_priv; //目标dest中的priv priv->rx_packetlen = len; // priv->rx_packetdata = buf;//buf是从应用层传过来要发送到另一网络的数据;这里无实际网卡,不发送。 printk("astonnet tx \n"); dev_kfree_skb(priv->skb); } //发包函数 int astonnet_tx(struct sk_buff *skb, struct net_device *dev) { int len; char *data; struct astonnet_priv *priv = (struct astonnet_priv *)dev->ml_priv; //该结构体将当前网卡的各种信息定义出来,可以网卡在各个函数之间传输信息。 if (skb == NULL) { printk("net_device %p, skb %p\n", dev, skb); return 0; } len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;//ETH_ZLEN是所发的最小数据包的长度 data = skb->data;//将要发送的数据包中数据部分 priv->skb = skb; astonnet_hw_tx(data, len, dev);//硬件层面的真正的发送函数;如有硬件网卡要调用。 return 0; } //设备初始化函数 int astonnet_init(struct net_device *dev) { printk("astoncnet_init\n"); ether_setup(dev);//填充一些以太网中的设备结构体的项 /* keep the default flags, just add NOARP */ dev->flags |= IFF_NOARP; //为priv分配内存 dev->ml_priv = kmalloc(sizeof(struct astonnet_priv), GFP_KERNEL); if (dev->ml_priv == NULL) return -ENOMEM; memset(dev->ml_priv, 0, sizeof(struct astonnet_priv)); spin_lock_init(&((struct astonnet_priv *)dev->ml_priv)->lock); return 0; } static const struct net_device_ops astonnet_netdev_ops = { //类似于字符设备驱动里的file_operations结构体 .ndo_open = astonnet_open, // 打开网卡 对应 ifconfig xx up .ndo_stop = astonnet_release, // 关闭网卡 对应 ifconfig xx down .ndo_start_xmit = astonnet_tx, // 开启数据包传输 .ndo_init = astonnet_init, // 初始化网卡硬件 }; static void aston_plat_net_release(struct device *dev) { printk("aston_plat_net_release\n"); } static int __devinit aston_net_probe(struct platform_device *pdev) { int result=0; astonnet_devs = alloc_etherdev(sizeof(struct net_device));//调用内核分配内存函数来分配内存空间;实例化 astonnet_devs->netdev_ops = &astonnet_netdev_ops;//绑定驱动函数集 strcpy(astonnet_devs->name, "astonnet0"); //名字可以人为设置! if ((result = register_netdev(astonnet_devs))) //注册填充;这里不是真正的网络驱动所以填充比较少,骨架,只做分析! printk("astonnet: error %i registering device \"%s\"\n", result, astonnet_devs->name); return 0; } static int __devexit aston_net_remove(struct platform_device *pdev) //设备移除接口 { kfree(astonnet_devs->ml_priv); unregister_netdev(astonnet_devs); return 0; } static struct platform_device aston_net= { .name = "aston_net", //设备名字 .id = -1, .dev = { .release = aston_plat_net_release, }, }; static struct platform_driver aston_net_driver = { .probe = aston_net_probe, .remove = __devexit_p(aston_net_remove), .driver = { .name ="aston_net", //驱动名字;两者名字匹配后会匹配调用probe函数 .owner = THIS_MODULE, }, }; static int __init aston_net_init(void) { printk("aston_net_init \n"); platform_device_register(&aston_net); //使用平台总线;为了实现适配,去执行probe函数! return platform_driver_register(&aston_net_driver ); } static void __exit aston_net_cleanup(void) { platform_driver_unregister(&aston_net_driver ); platform_device_unregister(&aston_net); } module_init(aston_net_init); module_exit(aston_net_cleanup); MODULE_LICENSE("GPL"); ---------------------------------------------------- [root@crmn linux-3.5]# ls net/core/ //linux发展比较好大多受益于网络的发展。 built-in.o flow_dissector.c netevent.o secure_seq.c datagram.c flow_dissector.o net_namespace.c secure_seq.o datagram.o flow.o net_namespace.o skbuff.c dev_addr_lists.c gen_estimator.c netpoll.c skbuff.o dev_addr_lists.o gen_estimator.o netprio_cgroup.c sock.c dev.c gen_stats.c net-sysfs.c sock_diag.c dev.o gen_stats.o net-sysfs.h sock_diag.o drop_monitor.c iovec.c net-sysfs.o sock.o dst.c iovec.o net-traces.c stream.c dst.o link_watch.c net-traces.o stream.o ethtool.c link_watch.o pktgen.c sysctl_net_core.c ethtool.o Makefile request_sock.c sysctl_net_core.o fib_rules.c modules.builtin request_sock.o timestamping.c fib_rules.o modules.order rtnetlink.c user_dma.c filter.c neighbour.c rtnetlink.o utils.c filter.o neighbour.o scm.c utils.o flow.c netevent.c scm.o [root@crmn linux-3.5]# ls net/core/skbuff.c net/core/skbuff.c

DM9000驱动源码分析:
DM9000是一款完全集成的和符合成本效益的,单芯片快速以太网MAC控制器;DM9000A是一款由中国台湾DAVICOM公司推出的一款高速以太网接口芯片。
[root@crmn linux-3.5]# vim drivers/net/ethernet/davicom/dm9000.c 1679 static struct platform_driver dm9000_driver = { 1680 .driver = { 1681 .name = "dm9000", 1682 .owner = THIS_MODULE, 1683 .pm = &dm9000_drv_pm_ops, 1684 }, 1685 .probe = dm9000_probe, 1686 .remove = __devexit_p(dm9000_drv_remove), 1687 }; // 搜寻“dm9000”来找到相应文件: platform_device xx_device_dm9000 = { //包含在mach-xxx.c中 .name = "dm9000", .id = 0, .num_resources = ARRAY_SIZE(xx+dm9000_resources), .resource = xx_dm9000_resources, //硬件信息 .dev = { .platform_data = &xx_dm9000_platdata, //硬件信息 } ...... }; xx_device_dm9000包含在mach-xxx.c中: static struct platform_device *smdkxxx_devices[] __initdata = { &xx_device_dm9000, } 匹配成功后执行dm9000_probe函数: 1359 /* 1360 * Search DM9000 board, allocate space and register it 1361 */ 1362 static int __devinit 1363 dm9000_probe(struct platform_device *pdev) 1364 { 1365 struct dm9000_plat_data *pdata = pdev->dev.platform_data; //信息传递 1366 struct board_info *db; /* Point a board information structure */ 1367 struct net_device *ndev; 1368 const unsigned char *mac_src; 1369 int ret = 0; 1370 int iosize; 1371 int i; 1372 u32 id_val; 1373 1374 /* Init network device */ 1375 ndev = alloc_etherdev(sizeof(struct board_info));//分配内存 1376 if (!ndev) 1377 return -ENOMEM; 1378 1379 SET_NETDEV_DEV(ndev, &pdev->dev);//挂接 1380 1381 dev_dbg(&pdev->dev, "dm9000_probe()\n");//调试 1382 1383 /* setup board info structure */ 1384 db = netdev_priv(ndev); 1386 db->dev = &pdev->dev; 1387 db->ndev = ndev; 1388 1389 spin_lock_init(&db->lock);// 1390 mutex_init(&db->addr_lock);// 1391 1392 INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work); 1393 1394 db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);//从硬件那里获取相关信息 1395 db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 1396 db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 1397 1398 if (db->addr_res == NULL || db->data_res == NULL || 1399 db->irq_res == NULL) { 1400 dev_err(db->dev, "insufficient resources\n"); 1401 ret = -ENOENT; 1402 goto out; 1403 } 1405 db->irq_wake = platform_get_irq(pdev, 1);//获取中断号 1406 if (db->irq_wake >= 0) { 1407 dev_dbg(db->dev, "wakeup irq %d\n", db->irq_wake); 1408 1409 ret = request_irq(db->irq_wake, dm9000_wol_interrupt, 1410 IRQF_SHARED, dev_name(db->dev), ndev);//绑定中断处理程序dm9000_wol_interrupt;网卡接收到数据包自动触发中断自动执行中断程序! 1411 if (ret) { 1412 dev_err(db->dev, "cannot get wakeup irq (%d)\n", ret); 1413 } else { 1414 1415 /* test to see if irq is really wakeup capable */ 1416 ret = irq_set_irq_wake(db->irq_wake, 1); 1417 if (ret) { 1418 dev_err(db->dev, "irq %d cannot set wakeup (%d )\n", 1419 db->irq_wake, ret); 1420 ret = 0; 1421 } else { 1422 irq_set_irq_wake(db->irq_wake, 0); 1423 db->wake_supported = 1; 1424 } 1425 } 1426 } 1428 iosize = resource_size(db->addr_res);//通过内存映射把dm9000映射到主CPU中的地址空间来 1429 db->addr_req = request_mem_region(db->addr_res->start, iosize, 1430 pdev->name);//申请物理地址 1431 1432 if (db->addr_req == NULL) { 1433 dev_err(db->dev, "cannot claim address reg area\n"); 1434 ret = -EIO; 1435 goto out; 1436 } 1437 1438 db->io_addr = ioremap(db->addr_res->start, iosize);//映射到对应的虚拟地址 1439 1440 if (db->io_addr == NULL) { 1441 dev_err(db->dev, "failed to ioremap address reg\n"); 1442 ret = -EINVAL; 1443 goto out; 1444 } 。。。。。。 1343 static const struct net_device_ops dm9000_netdev_ops = { 1344 .ndo_open = dm9000_open, 1345 .ndo_stop = dm9000_stop, 1346 .ndo_start_xmit = dm9000_start_xmit, 1347 .ndo_tx_timeout = dm9000_timeout, 1348 .ndo_set_rx_mode = dm9000_hash_table, 1349 .ndo_do_ioctl = dm9000_ioctl, 1350 .ndo_change_mtu = eth_change_mtu, 1351 .ndo_set_features = dm9000_set_features, 1352 .ndo_validate_addr = eth_validate_addr, 1353 .ndo_set_mac_address = eth_mac_addr, 1354 #ifdef CONFIG_NET_POLL_CONTROLLER 1355 .ndo_poll_controller = dm9000_poll_controller, 1356 #endif 1357 }; 1164 static int 1165 dm9000_open(struct net_device *dev) 1166 { 1167 board_info_t *db = netdev_priv(dev); 1168 unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK; 1169 1170 if (netif_msg_ifup(db)) 1171 dev_dbg(db->dev, "enabling %s\n", dev->name); 1172 1173 /* If there is no IRQ type specified, default to something that 1174 * may work, and tell the user that this is a problem */ 1175 1176 if (irqflags == IRQF_TRIGGER_NONE) 1177 dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n"); 1178 1179 irqflags |= IRQF_SHARED; 1180 1181 /* GPIO0 on pre-activate PHY, Reg 1F is not set by reset */ 1182 iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */ 1183 mdelay(1); /* delay needs by DM9000B */ 1184 1185 /* Initialize DM9000 board */ 1186 dm9000_reset(db); 1187 dm9000_init_dm9000(dev); 1188 //中断处理: 1189 if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev)) 1190 return -EAGAIN; 1192 /* Init driver variable */ 1193 db->dbug_cnt = 0; 1194 1195 mii_check_media(&db->mii, netif_msg_link(db), 1); 1196 netif_start_queue(dev); 1197 1198 dm9000_schedule_poll(db);// 1199 1200 return 0; 1201 } //硬件决定了性能的上限,软件程序决定了性能的下限。 880 /* 881 * Hardware start transmission. 882 * Send a packet to media from the upper layer. 883 */ 884 static int //发送数据包: 885 dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) 886 { 887 unsigned long flags; 888 board_info_t *db = netdev_priv(dev); 889 890 dm9000_dbg(db, 3, "%s:\n", __func__); 891 892 if (db->tx_pkt_cnt > 1) 893 return NETDEV_TX_BUSY; 894 895 spin_lock_irqsave(&db->lock, flags); 896 897 /* Move data to DM9000 TX RAM */ 898 writeb(DM9000_MWCMD, db->io_addr); 899 900 (db->outblk)(db->io_data, skb->data, skb->len); 901 dev->stats.tx_bytes += skb->len; 902 903 db->tx_pkt_cnt++; 904 /* TX control: First packet immediately send, second packet queue */ 905 if (db->tx_pkt_cnt == 1) { 906 dm9000_send_packet(dev, skb->ip_summed, skb->len); 907 } else { 908 /* Second packet */ 909 db->queue_pkt_len = skb->len; 910 db->queue_ip_summed = skb->ip_summed; 911 netif_stop_queue(dev); 912 } 913 914 spin_unlock_irqrestore(&db->lock, flags); 915 916 /* free this SKB */ 917 dev_kfree_skb(skb); 918 919 return NETDEV_TX_OK; 920 } //中断函数 1059 static irqreturn_t dm9000_interrupt(int irq, void *dev_id) 1060 { 1061 struct net_device *dev = dev_id; 1062 board_info_t *db = netdev_priv(dev); 1063 int int_status; 1064 unsigned long flags; 1065 u8 reg_save; 1066 1067 dm9000_dbg(db, 3, "entering %s\n", __func__); 1068 1069 /* A real interrupt coming */ 1070 1071 /* holders of db->lock must always block IRQs */ 1072 spin_lock_irqsave(&db->lock, flags); 1073 1074 /* Save previous register address */ 1075 reg_save = readb(db->io_addr); 1076 1077 /* Disable all interrupts */ 1078 iow(db, DM9000_IMR, IMR_PAR); 1079 1080 /* Got DM9000 interrupt status */ 1081 int_status = ior(db, DM9000_ISR); /* Got ISR */ 1082 iow(db, DM9000_ISR, int_status); /* Clear ISR status */ 1083 1084 if (netif_msg_intr(db)) 1085 dev_dbg(db->dev, "interrupt status %02x\n", int_status); 1086 1087 /* Received the coming packet */ 1088 if (int_status & ISR_PRS) 1089 dm9000_rx(dev); //接收数据包 1090 1091 /* Trnasmit Interrupt check */ 1092 if (int_status & ISR_PTS) 1093 dm9000_tx_done(dev, db); 1094 1095 if (db->type != TYPE_DM9000E) { 1096 if (int_status & ISR_LNKCHNG) { 1097 /* fire a link-change request */ 1098 schedule_delayed_work(&db->phy_poll, 1); 1099 } 1100 } 1101 1102 /* Re-enable interrupt mask */ 1103 iow(db, DM9000_IMR, db->imr_all); 1104 1105 /* Restore previous register address */ 1106 writeb(reg_save, db->io_addr); 1107 1108 spin_unlock_irqrestore(&db->lock, flags); 1109 1110 return IRQ_HANDLED; 1111 } 953 /* 954 * Received a packet and pass to upper layer 955 */ 956 static void 957 dm9000_rx(struct net_device *dev) 958 { 959 board_info_t *db = netdev_priv(dev); 960 struct dm9000_rxhdr rxhdr; 961 struct sk_buff *skb; 962 u8 rxbyte, *rdptr; 963 bool GoodPacket; 964 int RxLen; 965 966 /* Check packet ready or not */ 967 do { 968 ior(db, DM9000_MRCMDX); /* Dummy read */ 969 970 /* Get most updated data */ 971 rxbyte = readb(db->io_data); 973 /* Status check: this byte must be 0 or 1 */ 974 if (rxbyte & DM9000_PKT_ERR) { 975 dev_warn(db->dev, "status check fail: %d\n", rxbyte); 976 iow(db, DM9000_RCR, 0x00); /* Stop Device */ 977 iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */ 978 return; 979 } 980 981 if (!(rxbyte & DM9000_PKT_RDY)) 982 return; 983 984 /* A packet ready now & Get status/length */ 985 GoodPacket = true; 986 writeb(DM9000_MRCMD, db->io_addr); 987 988 (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr)); 989 990 RxLen = le16_to_cpu(rxhdr.RxLen); 991 992 if (netif_msg_rx_status(db)) 993 dev_dbg(db->dev, "RX: status %02x, length %04x\n", 994 rxhdr.RxStatus, RxLen); 995 996 /* Packet Status check */ 997 if (RxLen < 0x40) { 998 GoodPacket = false; 999 if (netif_msg_rx_err(db)) 1000 dev_dbg(db->dev, "RX: Bad Packet (runt)\n"); 1001 } 1002 1003 if (RxLen > DM9000_PKT_MAX) { 1004 dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen); 1005 } 1006 1007 /* rxhdr.RxStatus is identical to RSR register. */ 1008 if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE | 1009 RSR_PLE | RSR_RWTO | 1010 RSR_LCS | RSR_RF)) { 1011 GoodPacket = false; 1012 if (rxhdr.RxStatus & RSR_FOE) { 1013 if (netif_msg_rx_err(db)) 1014 dev_dbg(db->dev, "fifo error\n"); 1015 dev->stats.rx_fifo_errors++; 1016 } 1017 if (rxhdr.RxStatus & RSR_CE) { 1018 if (netif_msg_rx_err(db)) 1019 dev_dbg(db->dev, "crc error\n"); 1020 dev->stats.rx_crc_errors++; 1021 } 1025 dev->stats.rx_length_errors++; 1026 } 1027 } 1028 //网络设备驱动的底层驱动以及网络驱动的上层(框架层)以及应用层(socket接口)三者之间交互的接口函数sk_buff,网卡硬件收到数据包后封装成sk_buff然后丢给上层(框架层)继续丢给应用层(socket接口),谁调用应用层的read函数(或者receive函数)就证明发给谁了! 1029 /* Move data from DM9000 */ 1030 if (GoodPacket && 1031 ((skb = netdev_alloc_skb(dev, RxLen + 4)) != NULL)) {// 1032 skb_reserve(skb, 2); 1033 rdptr = (u8 *) skb_put(skb, RxLen - 4); 1034 1035 /* Read received packet from RX SRAM */ 1036 1037 (db->inblk)(db->io_data, rdptr, RxLen); 1038 dev->stats.rx_bytes += RxLen; 1039 1040 /* Pass to upper layer */ 1041 skb->protocol = eth_type_trans(skb, dev); 1042 if (dev->features & NETIF_F_RXCSUM) { 1043 if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0) 1044 skb->ip_summed = CHECKSUM_UNNECESSARY; 1045 else 1046 skb_checksum_none_assert(skb); 1047 } 1048 netif_rx(skb); 1049 dev->stats.rx_packets++; // 1050 1051 } else { 1052 /* need to dump the packet's data */ 1053 1054 (db->dumpblk)(db->io_data, RxLen); 1055 } 1056 } while (rxbyte & DM9000_PKT_RDY); 1057 } 学习三境界: 学不动; 学进去了; 学出来了。
浙公网安备 33010602011771号