`
thecloud
  • 浏览: 877861 次
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多
<style type="text/css"> <!-- @page { margin: 0.79in } P { margin-bottom: 0.08in } PRE.cjk { font-family: "AR PL UMing HK", monospace } A:link { so-language: zxx } --> </style>

硬件平台: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网卡驱动分析(二)

下面开始看网卡设备的打开、关闭函数和操作函数

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,/* io操作函数 */
	.ndo_change_mtu		= eth_change_mtu,/* 改变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
};

1DM9000的打开函数

由于在函数alloc_netdev_mq()中分配net_device和网卡的私有数据是一起分配的,详见函数的实现

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) {
		/* ensure 32-byte alignment of private area */
		alloc_size = ALIGN(alloc_size, NETDEV_ALIGN);
		alloc_size += sizeof_priv;
	}
	/* ensure 32-byte alignment of whole construct */
	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()函数返回的是网卡的私有数据的地址,函数的实现如下:

    /**
     *      netdev_priv - access network device private data
     *      @dev: network device
     *
     * Get network device private data
     */
    static inline void *netdev_priv(const struct net_device *dev)
    {
            return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN);
    }

    这样两者会同时生存和消失。

dm9000_open()函数

/*
 *  Open the interface.
 *  The interface is opened whenever "ifconfig" actives it.
 */
static int
dm9000_open(struct net_device *dev)
{
        board_info_t *db = netdev_priv(dev);/* 返回board_info_t的地址 */
        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 there is no IRQ type specified, default to something that
         * may work, and tell the user that this is a problem */

        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;

        /* Initialize DM9000 board */
        dm9000_reset(db);/* 复位DM9000 */
        dm9000_init_dm9000(dev);/* 根据net_device的数据初始化DM9000 */

        /* Init driver variable */
        db->dbug_cnt = 0;

        mii_check_media(&db->mii, netif_msg_link(db), 1);/* 检测mii接口的状态 */
        netif_start_queue(dev);/* 用来告诉上层网络协定这个驱动程序还有空的缓冲区可用,请把下 一个封包送进来。*/
        
        /*在probe函数中初始化的等待队列 INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);   
        *初始化定时器,调用等待队列*/
        dm9000_schedule_poll(db);

        return 0;
}

    2、网卡关闭函数

    /*
     * Stop the interface.
     * The interface is stopped when it is brought.
     */
    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);/* 终止phy_poll队列中被延迟的任务 */
    
            netif_stop_queue(ndev);/* 关闭发送队列 */
            netif_carrier_off(ndev);/*通知该内核设备载波丢失,大部分涉及实际的物理连接的网络技术提供有一个载波状态,载波存在说明硬件存在并准备好*/
    
            /* free interrupt */
            free_irq(ndev->irq, ndev);/* 释放中断 */
    
            dm9000_shutdown(ndev);/* 关闭DM9000网卡 */
    
            return 0;
    }


    下面是调用的dm9000_shutdown(ndev)函数,该函数的功能是复位phy,配置寄存器GPR01,关闭dm9000电源,配置寄存器IMR71disable中断,配置寄存器RCRdisable接收

函数如下:

static void
dm9000_shutdown(struct net_device *dev)
{
        board_info_t *db = netdev_priv(dev);/* 获取网卡私有信息的地址 */

        /* RESET device */
        dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET ,复位PHY*/
        iow(db, DM9000_GPR, 0x01);      /* Power-Down PHY ,关闭PHY*/
        iow(db, DM9000_IMR, IMR_PAR);   /* Disable all interrupt ,关闭所有的中断*/
        iow(db, DM9000_RCR, 0x00);      /* Disable RX ,不再接受数据*/
}


    3、接下来了解一下数据的发送函数dm9000_start_xmit

上图可以看出DM9000SRAM中地址0x00000x0BFFTXBuffer,从0x0C000x3FFFRXBuffer,包的有效数据必须提前放到TXBuffer缓冲区,使用端口命令来选择MWCMD寄存器。最后设置TXCR寄存器的bit[0]TXREQ来自动发送包。
发送包的步骤如下:

1)检查存储器宽度,通过读取ISRbit[7:6]来确定位数
2)写数据到TXSRAM
3)写传输长度到TXPLLTXPLH寄存器
4)设置TXCRbit[0]TXREQ来发送包

/*
 *  Hardware start transmission.
 *  Send a packet to media from the upper layer.
 */
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);/* 获得自旋锁 */

        /* Move data to DM9000 TX RAM */
        /*MWCMD 即 Memory data write command with address increment Register(F8H)
        * 根据 IO 操作模式(8-bit or 16-bit)来增加写指针 1 或 2
        */
        writeb(DM9000_MWCMD, db->io_addr);

        (db->outblk)(db->io_data, skb->data, skb->len);/* 将数据从sk_buff中copy到网卡的TX SRAM中 */
        
        dev->stats.tx_bytes += skb->len;/* 统计发送的字节数 */
        
        db->tx_pkt_cnt++;/* 待发送计数 */
        /* TX control: First packet immediately send, second packet queue */
        if (db->tx_pkt_cnt == 1) {
                dm9000_send_packet(dev, skb->ip_summed, skb->len);/* 如果计数为1,直接发送 */
        } else {/* 如果是第2个,则 */
                /* Second packet */
                db->queue_pkt_len = skb->len;
                db->queue_ip_summed = skb->ip_summed;
                netif_stop_queue(dev);/* 告诉上层停止发送 */
        }
        spin_unlock_irqrestore(&db->lock, flags);/* 解锁 */
        /* free this SKB ,释放SKB*/
        dev_kfree_skb(skb);

        return NETDEV_TX_OK;
}

    上面函数调用下面的函数dm9000_send_packet来发送数据

    static void dm9000_send_packet(struct net_device *dev,
                                   int ip_summed,
                                   u16 pkt_len)
    {
            board_info_t *dm = to_dm9000_board(dev);
    
            /* The DM9000 is not smart enough to leave fragmented packets alone. */
            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;
            }
    
            /* Set TX length to DM9000 */
            /* 设置TX数据的长度到寄存器TXPLL和TXPLH */
            iow(dm, DM9000_TXPLL, pkt_len);
            iow(dm, DM9000_TXPLH, pkt_len >> 8);
    
            /* Issue TX polling command */
            /* 设置发送控制寄存器的发送请求位 */
            iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
    }

    5、下面看一下当一个数据包发送完成后的中断处理函数dm9000_tx_done

    /*
     * DM9000 interrupt handler
     * receive the packet to upper layer, free the transmitted packet
     */
    
    static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
    {
            int tx_status = ior(db, DM9000_NSR);    /* Got TX status */
    
            if (tx_status & (NSR_TX2END | NSR_TX1END)) {/* 第一个或第二个数据包发送完毕 */
                    /* One packet sent complete */
                    db->tx_pkt_cnt--;/* 待发送的数据包个数减1 */
                    dev->stats.tx_packets++;/* 发送的数据包加1 */
    
                    if (netif_msg_tx_done(db))
                            dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status);
    
                    /* Queue packet check & send */
                    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网卡驱动分析(四)



分享到:
评论

相关推荐

    dm9000网卡驱动程序分析

    arm9开发板上 dm9000网卡驱动程序分析

    dm9000网卡驱动

    linux dm9000网卡完全驱动 实现基本的网络通信经过大量测试 适合移植使用

    基于ARM_LINUX的多功能视频监控系统研究与实现.caj

    研究分析了Linux内核中经典的bus-device-driver框架结构及Linux内核中提供的输入子系统框架,以及LCD、触摸屏、网卡、摄像头驱动框架等,分别设计并实现了LCD、触摸屏、摄像头、按键四种设备驱动程序,并对DM9000网卡...

    Linux内核移植笔记 | 06 – 移植Linux 3.4.2 内核到JZ2440(移植DM9000网卡驱动,支持网络,支持NFS挂载)

    1. 移植DM9000网卡驱动 之前配置使用的SMDK2440开发板,默认不支持DM9000网卡驱动,但是其中的MINI2440开发板支持,所以要将MINI2440中的DM9000驱动移植到SMDK2440中。 进入内核源码目录里面,找到 arch/arm/mach-s3...

    单片机驱动DM9000

    本文主要介绍单片机驱动DM9000E网卡芯片的详细过程。从网卡电路的连接,到网卡初始化相关程序调试,再到ARP协议的实现,一步一步详细介绍调试过程。如果有时间也会把UDP和TCP通讯实验过程写出来。当然,会用单片机...

    嵌入式Linux之我行系列

    ·嵌入式Linux之我行——Linux-2.6.30.4在2440上的移植之DM9000E网卡驱动 ·嵌入式Linux之我行——Linux-2.6.30.4在2440上的移植之USB驱动 ·嵌入式Linux之我行——Linux-2.6.30.4在2440上的移植之MMC/SD卡驱动 ·...

    ENC28J60 SPI网卡移植 linux 2.6.28 SAMSUNG 6410 ARM11

    linux2.6.28 开发板:飞凌TE6410 (256M RAM 2G NAND) 网卡:ENC28J60 SPI 测试用的工具:Saleae logic (逻辑分析仪),Iris 抓包工具 6410作为一颗强大的ARM11处理器,网卡模块已经是相当的成熟(如:DM9000/3 ...

    基于ARM和DM9000的网卡接口设计与实现

    1 引言要实现小型嵌入式设备的Internet接入,TCP/IP首先要解决的是底层硬件问题,即协议的物理层。Ethernet具有成熟的技术...寄存器操作简单有效,有成熟的Linux驱动程序支持;3.3V接口电平;成本相当低廉;还可以使用

    PDF 资料 ENC28J60 SPI网卡移植 linux 2.6.28 SAMSUNG 6410 ARM11

    linux2.6.28 开发板:飞凌TE6410 (256M RAM 2G NAND) 网卡:ENC28J60 SPI 测试用的工具:Saleae logic (逻辑分析仪),Iris 抓包工具 6410作为一颗强大的ARM11处理器,网卡模块已经是相当的成熟(如:DM9000/3 ...

    Tiny6410内核移植及文件系统搭建的详细步骤

    涵盖2.6.36内核和文件系统搭建...注意:arm-none-linux-guneabi version 4.5.2;NAND FLASH 256M (SLC);DM9000 的网卡;yaffs2 文件系统。NAND FLASH是SLC 256M,并非MLC 2G,否则需要修改相应的nand flash 驱动。

    AT91SAM9263开发板SBC6300X.rar

    10/100M以太网卡DM9000驱动 以太网口2 CPU内部自带MAC层的以太网驱动 LCD 320x240,480x272,640x480,800x480四种屏的驱动 touch screen 触摸屏驱动 音频 音频驱动 MMC/SD SDIO模式驱动 USB host 可支持USB接口的...

    基于ARM的矿井综采面无线传感器网络的网关设计

    介绍了一种基于ARM的综采面无线传感器网络的网关设计。...阐述了网关的硬件设计,重点论述了无线收发模块和以太网接口模块,并介绍了DM9000以太网卡的移植,CC2420无线模块驱动的开发,以及上层应用程序等软件设计。

Global site tag (gtag.js) - Google Analytics