新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > ARM-Linux驅動--DM9000網卡驅動分析(三)

        ARM-Linux驅動--DM9000網卡驅動分析(三)

        作者: 時間:2016-11-20 來源:網絡 收藏
        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 %sn", 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 %sn", 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 xn", tx_status);
        if (db->tx_pkt_cnt > 0)
        dm9000_send_packet(dev, db->queue_ip_summed,
        db->queue_pkt_len);
        netif_wake_queue(dev);
        }
        }


        評論


        技術專區

        關閉
        主站蜘蛛池模板: 定安县| 茶陵县| 漠河县| 麟游县| 南充市| 根河市| 马龙县| 微山县| 深州市| 万年县| 克什克腾旗| 沛县| 昌乐县| 云梦县| 千阳县| 饶平县| 蒙山县| 镇安县| 皋兰县| 宾阳县| 宝丰县| 梅河口市| 郯城县| 根河市| 澄城县| 高密市| 秦皇岛市| 阳原县| 陆川县| 新绛县| 资阳市| 霸州市| 安丘市| 玉树县| 如东县| 郁南县| 吴川市| 江达县| 微山县| 凤庆县| 陇川县|