網卡驅動程序設計

Linux網絡子系統

這裏寫圖片描述

系統調用接口層
爲應用程序提供訪問網絡子系統的統一方法。

協議無關層
提供通用的方法來使用傳輸層協議,對不同的協議有統一的接口。

協議棧的實現
實現具體的網絡協議。

設備無關層
協議與設備驅動之前通信的通用接口,對於不同的網絡通信設備有統一的接口。

重要的數據結構

網卡描述結構:
在Linux內核中,每個網卡都由一個 net_device結構 來描述,其中的一些重要成員有:
這裏寫圖片描述

網卡操作集合:
類似於字符設備驅動中的file_operations結構, net_device_ops結構 記錄了網卡所支持的操作。

static const struct net_device_ops dm9000_netdev_ops =
{
    .ndo_open = dm9000_open,
    .ndo_stop = dm9000_stop,
    .ndo_start_xmit = dm9000_start_xmit,
    .ndo_do_ioctl = dm9000_ioctl,
    .ndo_validate_addr = eth_validate_addr,
    .ndo_set_mac_address = eth_mac_addr,
};

網絡數據包:
Linux內核中的每個網絡數據包都由一個套接字緩衝區結構 struct sk_buff 描述,即一個 sk _ buff 結構就是一個網絡包,指向sk_buff 的指針通常被稱做skb

網卡驅動模型

網卡初始化:
這裏寫圖片描述

數據發送:
這裏寫圖片描述

數據接收:
這裏寫圖片描述

迴環網卡驅動設計

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/if_ether.h> /* For the statistics structure. */

unsigned long bytes = 0;
unsigned long packets = 0;

static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
//數據發送函數,skb是數據包
{
    //對於迴環網卡,不需要暫停和重啓協議棧發送數據,也不需要寫入和釋放skb

    skb->protocol = eth_type_trans(skb,dev);//標明協議
    bytes += skb->len;//數據量
    packets++;        //包的數目
    netif_rx(skb);    //將包發走
    return 0;        
}

static struct net_device_stats *loopback_get_stats(struct net_device *dev)
//獲取網卡狀態信息
{
    struct net_device_stats *stats = &dev->stats;   
    stats->rx_packets = packets;
    stats->tx_packets = packets;
    stats->rx_bytes = bytes;
    stats->tx_bytes = bytes;
    return stats;
}

//定義ops結構
static const struct net_device_ops loopback_ops = {
    .ndo_start_xmit= loopback_xmit, //發送函數
    .ndo_get_stats = loopback_get_stats, //獲取網卡狀態
};

static void loopback_setup(struct net_device *dev) 
//2、初始化net_device結構
{
    dev->mtu         =  (16 * 1024) + 20 + 20 + 12; //網卡能接受的包的最大尺寸,16K數據+tcp頭+ip頭+以太網頭
    dev->flags       =  IFF_LOOPBACK;    //迴環網卡專有標誌
    dev->header_ops  =  &eth_header_ops; //構造頭的函數,系統已經提供
    dev->netdev_ops  =  &loopback_ops;   //迴環網卡的操作集
}

/* Setup and register the loopback device. */
static __net_init int loopback_net_init(struct net *net) //入口函數
{
    struct net_device *dev;

    //1、分配 net_device 結構  2、初始化 net_device 結構
    dev = alloc_netdev(0, "lo", loopback_setup); 

    //3、迴環網卡沒有硬件結構,不需要初始化硬件

    //4、註冊網卡驅動
    register_netdev(dev);

    net->loopback_dev = dev;
    return 0;
}

static __net_exit void loopback_net_exit(struct net *net)//出口函數
{
    struct net_device *dev = net->loopback_dev;
    unregister_netdev(dev); //註銷 dev 結構
}

/* Registered in net/core/dev.c */
struct pernet_operations __net_initdata loopback_net_ops = 
{
    .init = loopback_net_init,
    .exit = loopback_net_exit,
};

DM9000網卡驅動設計

參考內核源代碼:linux-ok6410\drivers\net\dm9000.c
和 linux-ok6410\drivers\net\dm9000.h

DM9000網卡 數據發送 代碼:

//dm9000芯片的發送數據代碼
static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
    board_info_t *db = netdev_priv(dev);

    //1、通知協議棧,暫停向驅動發送數據
    netif_stop_queue(dev);

    //2、將skb中的數據寫入寄存器
    iow(db, DM9000_TXPLL, skb -> len);
    iow(db, DM9000_TXPLH, skb -> len >> 8);

    writeb(DM9000_MWCMD, db->io_addr);
    (db->outblk)(db->io_data, skb->data, skb->len);

    iow(db, DM9000_TCR, TCR_TXREQ);

    //3、釋放skb
    dev_kfree_skb(skb);

    //4、通知協議棧繼續發送數據,在中斷處理函數中寫,不在這個函數中

    return 0;
}
發佈了5 篇原創文章 · 獲贊 60 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章