ARM-Linux驱动--DM9000网卡驱动分析(三)

发布者:ohp991养生的香菇最新更新时间:2016-04-27 来源: eefocus关键字:ARM  Linux驱动  DM9000  网卡驱动 手机看文章 扫描二维码
随时随地手机看文章
ARM-Linux驱动--DM9000网卡驱动分析(二)硬件平台:FL2440(s3c2440)
内核版本:2.6.35
主机平台:Ubuntu11.04
内核版本:2.6.39
交叉编译器:arm-linuc-gcc4.3.2
原创作品,转载请标明出处http://blog.csdn.net/yming0221/article/details/6615027
本文接上文
ARM-Linux驱动--DM9000网卡驱动分析(一)
ARM-Linux驱动--DM9000网卡驱动分析(二)
下面开始看网卡设备的打开、关闭函数和操作函数
view plainprint?
static const struct net_device_ops dm9000_netdev_ops = {  
    .ndo_open       = dm9000_open,  
    .ndo_stop       = dm9000_stop,  
    .ndo_start_xmit     = dm9000_start_xmit,  
    .ndo_tx_timeout     = dm9000_timeout,  
    .ndo_set_multicast_list = dm9000_hash_table,  
    .ndo_do_ioctl       = dm9000_ioctl,  
    .ndo_change_mtu     = eth_change_mtu,  
    .ndo_validate_addr  = eth_validate_addr,  
    .ndo_set_mac_address    = eth_mac_addr,  
#ifdef CONFIG_NET_POLL_CONTROLLER  
    .ndo_poll_controller    = dm9000_poll_controller,  
#endif  
};  
1、DM9000的打开函数
由于在函数alloc_netdev_mq()中分配net_device和网卡的私有数据是一起分配的,详见函数的实现
view plainprint?
struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,  
        void (*setup)(struct net_device *), unsigned int queue_count)  
{  
...................  
alloc_size = sizeof(struct net_device);  
    if (sizeof_priv) {  
         
        alloc_size = ALIGN(alloc_size, NETDEV_ALIGN);  
        alloc_size += sizeof_priv;  
    }  
     
    alloc_size += NETDEV_ALIGN - 1;  
  
    p = kzalloc(alloc_size, GFP_KERNEL);  
    if (!p) {  
        printk(KERN_ERR "alloc_netdev: Unable to allocate device.\n");  
        return NULL;  
    }  
  
    tx = kcalloc(queue_count, sizeof(struct netdev_queue), GFP_KERNEL);  
    if (!tx) {  
        printk(KERN_ERR "alloc_netdev: Unable to allocate "  
               "tx qdiscs.\n");  
        goto free_p;  
    }  
  
#ifdef CONFIG_RPS  
    rx = kcalloc(queue_count, sizeof(struct netdev_rx_queue), GFP_KERNEL);  
    if (!rx) {  
        printk(KERN_ERR "alloc_netdev: Unable to allocate "  
               "rx queues.\n");  
        goto free_tx;  
    }  
..............  
}  
所以使用函数netdev_priv()函数返回的是网卡的私有数据的地址,函数的实现如下:
view plainprint?
 
static inline void *netdev_priv(const struct net_device *dev)  
{  
        return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN);  
}  
这样两者会同时生存和消失。
dm9000_open()函数
view plainprint?
 
static int  
dm9000_open(struct net_device *dev)  
{  
        board_info_t *db = netdev_priv(dev);  
        unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;  
  
        if (netif_msg_ifup(db))  
                dev_dbg(db->dev, "enabling %s\n", dev->name);  
  
         
  
        if (irqflags == IRQF_TRIGGER_NONE)  
                dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");  
  
        irqflags |= IRQF_SHARED;  
          
         
        if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))  
                return -EAGAIN;  
  
         
        dm9000_reset(db);  
        dm9000_init_dm9000(dev);  
  
         
        db->dbug_cnt = 0;  
  
        mii_check_media(&db->mii, netif_msg_link(db), 1);  
        netif_start_queue(dev);  
          
         
        dm9000_schedule_poll(db);  
  
        return 0;  
}  
 
2、网卡关闭函数
view plainprint?
 
static 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);  
  
        netif_stop_queue(ndev);  
        netif_carrier_off(ndev);  
  
         
        free_irq(ndev->irq, ndev);  
  
        dm9000_shutdown(ndev);  
  
        return 0;  
}  
 
 
下面是调用的dm9000_shutdown(ndev)函数,该函数的功能是复位phy,配置寄存器GPR位0为1,关闭dm9000电源,配置寄存器IMR位7为1,disable中断,配置寄存器RCR,disable接收
函数如下:
view plainprint?
static void  
dm9000_shutdown(struct net_device *dev)  
{  
        board_info_t *db = netdev_priv(dev);  
  
         
        dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET);  
        iow(db, DM9000_GPR, 0x01);        
        iow(db, DM9000_IMR, IMR_PAR);    
        iow(db, DM9000_RCR, 0x00);        
}  
 
 
3、接下来了解一下数据的发送函数dm9000_start_xmit
上图可以看出DM9000的SRAM中地址0x0000到0x0BFF是TXBuffer,从0x0C00到0x3FFF是RXBuffer,包的有效数据必须提前放到TXBuffer缓冲区,使用端口命令来选择MWCMD寄存器。最后设置TXCR寄存器的bit[0]TXREQ来自动发送包。
发送包的步骤如下:
(1)检查存储器宽度,通过读取ISR的bit[7:6]来确定位数
(2)写数据到TXSRAM
(3)写传输长度到TXPLL和TXPLH寄存器
(4)设置TXCR的bit[0]TXREQ来发送包
view plainprint?
 
static int  
dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)  
{  
        unsigned long flags;  
        board_info_t *db = netdev_priv(dev);  
  
        dm9000_dbg(db, 3, "%s:\n", __func__);  
  
        if (db->tx_pkt_cnt > 1)  
                return NETDEV_TX_BUSY;  
  
        spin_lock_irqsave(&db->lock, flags);  
  
         
         
        writeb(DM9000_MWCMD, db->io_addr);  
  
        (db->outblk)(db->io_data, skb->data, skb->len);  
          
        dev->stats.tx_bytes += skb->len;  
          
        db->tx_pkt_cnt++;  
         
        if (db->tx_pkt_cnt == 1) {  
                dm9000_send_packet(dev, skb->ip_summed, skb->len);  
        } else {  
                 
                db->queue_pkt_len = skb->len;  
                db->queue_ip_summed = skb->ip_summed;  
                netif_stop_queue(dev);  
        }  
        spin_unlock_irqrestore(&db->lock, flags);  
         
        dev_kfree_skb(skb);  
  
        return NETDEV_TX_OK;  
}  
上面函数调用下面的函数 dm9000_send_packet来发送数据
view plainprint?
static void dm9000_send_packet(struct net_device *dev,  
                               int ip_summed,  
                               u16 pkt_len)  
{  
        board_info_t *dm = to_dm9000_board(dev);  
  
         
        if (dm->ip_summed != ip_summed) {  
                if (ip_summed == CHECKSUM_NONE)  
                        iow(dm, DM9000_TCCR, 0);  
                else  
                        iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP);  
                dm->ip_summed = ip_summed;  
        }  
  
         
         
        iow(dm, DM9000_TXPLL, pkt_len);  
        iow(dm, DM9000_TXPLH, pkt_len >> 8);  
  
         
         
        iow(dm, DM9000_TCR, TCR_TXREQ);  
}  
5、下面看一下当一个数据包发送完成后的中断处理函数dm9000_tx_done
view plainprint?
 
  
static void dm9000_tx_done(struct net_device *dev, board_info_t *db)  
{  
        int tx_status = ior(db, DM9000_NSR);      
  
        if (tx_status & (NSR_TX2END | NSR_TX1END)) {  
                 
                db->tx_pkt_cnt--;  
                dev->stats.tx_packets++;  
  
                if (netif_msg_tx_done(db))  
                        dev_dbg(db->dev, "tx done, NSR x\n", tx_status);  
  
                 
                if (db->tx_pkt_cnt > 0)  
                        dm9000_send_packet(dev, db->queue_ip_summed,  
                                           db->queue_pkt_len);  
                netif_wake_queue(dev);  
        }  
}  
关键字:ARM  Linux驱动  DM9000  网卡驱动 引用地址:ARM-Linux驱动--DM9000网卡驱动分析(三)

上一篇:ARM-Linux驱动--DM9000网卡驱动分析(三)
下一篇:ARM-Linux驱动--DM9000网卡驱动分析(二)

推荐阅读最新更新时间:2024-03-16 14:52

基于DSP+ARM的便携式电能质量分析仪设计
  随着国家工业规模的扩大和科学技术的发展,电网负荷结构发生了很大的变化,一方面,非线性、冲击性和不平衡负荷的大量增长使得电能质量恶化;另一方面,随着信息技术的发展。越来越多的敏感负载对电能质量的要求也越来越高。这就要求电能质量检测分析设备具有实时检测、快速分析、实时显示的能力。采用高性能数字信号处理器( DSP )和嵌入式计算机系统( ARM )双处理器架构设计电能质量分析仪能满足上述要求。 DSP 系统实现电压、电流信号的实时采集处理,通过加窗傅里叶变换和小波算法得到电能质量参数; ARM 嵌入式平台运行WinCE操作系统完成人机交互、数据存储、实时显示等功能。该系统为仪器的可扩展性和智能化建立了良好的软硬件平
[嵌入式]
基于DSP+<font color='red'>ARM</font>的便携式电能质量分析仪设计
基于tiny4412的Linux内核移植 -- eMMC驱动移植(六)
平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本:Linux-4.4.0 (支持device tree) u-boot版本:友善之臂自带的 U-Boot 2010.12 (为支持uImage启动,做了少许改动) busybox版本:busybox 1.25 eMMC:KLMxGxFE3x-x00x 交叉编译工具链: arm-none-linux-gnueabi-gcc (gcc version 4.8.3 20140320 (prerelease) (Sourcery CodeBench Lite 2014.05-29)) 概述 eMMC驱动在内核中也已经支持好了,代码在:
[单片机]
基于tiny4412的<font color='red'>Linux</font>内核移植 -- eMMC<font color='red'>驱动</font>移植(六)
基于S3C2440的嵌入式Linux驱动——看门狗(watchdog)驱动解读
本文将介绍看门狗驱动的实现。 目标平台:TQ2440 CPU:s3c2440 内核版本:2.6.30 1. 看门狗概述 看门狗其实就是一个定时器,当该定时器溢出前必须对看门狗进行 喂狗“,如果不这样做,定时器溢出后则将复位CPU。 因此,看门狗通常用于对处于异常状态的CPU进行复位。 具体的概念请自行百度。 2. S3C2440看门狗 s3c2440的看门狗的原理框图如下: 可以看出,看门狗定时器的频率由PCLK提供,其预分频器最大取值为255+1;另外,通过MUX,可以进一步降低频率。 定时器采用递减模式,一旦到0,则可以触发看门狗中断以及RESET复位信号。 看门狗定时器的频率的计算公式如下
[单片机]
基于S3C2440的嵌入式<font color='red'>Linux</font><font color='red'>驱动</font>——看门狗(watchdog)<font color='red'>驱动</font>解读
关于ARM7的键盘与VFD显示器接口技术
  引 言   仪表行业以及工业生产过程对实时性、处理速度、智能化等方面有了更高的要求,而ARM微处理器具有功耗低、指令吞吐量高、实时中断响应、处理器宏单元性价比高等特点,因此,将ARM微处理器引入产品和工业生产的开发设计中已经成为一种必然趋势。   在工业控制和产品设计中,一般都要求具有供操作的键盘和可视化界面。传统显示模块的设计一般都是采用I/O口外扩驱动电路连接而成,显示器一般都采用LED或LCD,要么成本低但实现起来比较复杂,要么实现起来简单成本却很高。笔者综合考虑了成本、实现的难易程度、功能以及稳定性等方面的要求,提出了一种实现起来较容易且具有较高对比度和精度的VFD显示的方法。   1 硬件电路的实现   考虑到
[单片机]
关于<font color='red'>ARM</font>7的键盘与VFD显示器接口技术
linux串口终端驱动——s3c6410平台(二)
1、终端设备 在Linux系统中,终端是一种字符型设备,它有多种类型,通常使用tty来简称各种类型的终端设备。tty是Teletype的缩写,Teletype是最早出现的一种终端设备,很像电传打字机,是由Teletype公司生产的。 Linux中包含如下几类终端设备: 1).串行端口终端(/dev/ttySn) 使用计算机串行端口连接的终端设备。串行端口对应的设备名称是/dev/ttySn。如/dev/ttyS0、/dev/ttyS1等,设备号分别是(4,0)、(4,1) 2).伪终端(/dev/pty/) 显示器通常称为控制台终端,若当前进程有控制终端,则/dev/tty就是当前进程的控制终端的设备特殊文件。可
[单片机]
<font color='red'>linux</font>串口终端<font color='red'>驱动</font>——s3c6410平台(二)
建立在ARM基础上的ADSL2+测试仪的设计
引言 近几年来,不对称数字用户线(ADSL)作为网络“最后一公里”问题的理想解决方案在世界范围内得到了广泛运用。在我,ADSL业务已成为运营商收入的主要增点之一。但由于现有电话线路专门为传送低频语音信号所设计,不利于高频信号传输,线路周边环境恶劣且复杂多变,无论ADSL业务的开通还是正常的运营维护,都需进行一系列复杂的测试工作。 现有测试仪表多为国外品牌且价格昂贵,国内产品普遍存在测试频段有限,测试结果片面的问题;而且由于核心芯片处理能力有限,嵌入式操作系统不先进,软件包功能不够完善,对测试结果的管理也比较混乱。随着市场不断壮大,尤其是基于ITU G.992.3/ G.992.5标准的ADSL2/ 2+推出后,价格合理、功能完
[单片机]
建立在<font color='red'>ARM</font>基础上的ADSL2+测试仪的设计
英特尔进军 Arm 芯片领域,并追赶台积电提高代工市场份额
2 月 27 日消息,近日在接受 Tom's Hardware 采访时,英特尔代工负责人斯图尔特・潘(Stu Pann)表示将会进军 Arm 芯片,并不断追赶台积电的代工市场份额。 代工愿景 英特尔希望在 2030 年成为全球第二代代工厂,并希望能成为一家有弹性的代工厂,能够缓解地缘政治、战争冲突等各种问题导致的供应链中断问题。 英特尔会重新平衡其半导体业务,计划产业链的 50% 布局放在美洲 / 欧洲、50% 放在亚洲。 加强和 Arm 合作 Arm 首席执行官雷内・哈斯(Rene Hass)通过远程连接的方式出席 IFS 活动,表示世界似乎正在摆脱独占硬件的想法,转而希望为微软或 Faraday 这样的大公司打造最
[半导体设计/制造]
英特尔进军 <font color='red'>Arm</font> 芯片领域,并追赶台积电提高代工市场份额
负债也要疯狂收购ARM:孙正义的又一次豪赌
       新浪科技 郑峻发自美国硅谷   对于孙正义来说,疯狂从来都是一个褒义词。这位自称孙子后人的日本企业家,在商场上的运筹帷幄令人惊叹。在过去的25年时间里,孙正义用一笔笔令人惊叹的交易,从白手起家打造了一个全球性科技帝国。310亿美元收购英国移动芯片巨头ARM,是他疯狂投资史上的又一个大手笔,但毫无疑问也不是最后一笔。   每两三年爆发一次   “我总是有一些大的想法,每两到三年就会爆发一次”,孙正义如是说。虽然已经年近六十,但他身上那种冒险的基因却从未改变。   的确,每隔几年,孙正义总会以一笔天价收购震惊业界。上个月孙正义先后抛售部分阿里股份和出售游戏开发商SuperCell,总计套现近186亿美元,
[手机便携]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved