十一.网络设备驱动介绍

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 }

学习三境界:
学不动;
学进去了;
学出来了。

 

posted @ 2017-09-18 21:38  bkycrmn  阅读(776)  评论(0)    收藏  举报