嵌入式系统 第十三讲 网络设备驱动程序开发
• 网络设备是Linux三大设备之一(另外两类是字符设备,块 设备)。
• 由于网络设备的特殊工作方式,网络驱动程序的开发与字 符设备、块设备驱动的开发有很大的不同。
• 13.1 以太网基础知识
• 以太网(Ethernet):最早由Xerox(施乐)公司创建,于1980年DEC、 lntel和Xerox三家公司联合开发成为一个标准。
• 以太网是应用最为广泛的局域网,包括标准的以太网(10Mbit/s)、 快速以太网(100Mbit/s)和10G(10Gbit/s)以太网,采用的是 CSMA/CD访问控制法,它们都符合IEEE 802.3标准。
• CSMA/CD(Carrier Sense Multiple Access/Collision Detection,带有冲突检测的载波 侦听多路存取)是IEEE 802.3使用的一种媒体访问控制方法。
– IEEE 802.3标准:规定了包括物理层的连线、电信号和介质访问层协议的内容。
• 1、早期的以太网
– 1Base-5:使用双绞线电缆,最大网段长度为500m,传输速度为1Mbps。
• 2、10Mb/s以太网
– 10Base-T:使用双绞线电缆,最大网段长度为100m。拓扑结构为星型;10Base-T组网主要硬件设备有:3类或5类非屏蔽双绞线、带有RJ-45插口的以太网卡、 集线器、交换机、RJ-45插头等。
• 3、快速以太网
– 100BASE-TX:是一种使用5类数据级无屏蔽双绞线或屏蔽双绞线的快速以太网技 术。它使用两对双绞线,一对用于发送,一对用于接收数据。
• 4、千兆以太网
– 1000Base-T:带宽1Gb/s,使用超5类双绞线或6类双绞线。
• 5、万兆以太网
– 10GBASE-SR 和10GBASE-SW:主要支持短波(850 nm)多模光纤(MMF),光纤 距离为2m 到300 m。
• 6、4万兆以太网和10万兆以太网
– 标准尚在起草中,尚未发布。
• 13.1.1 CSMA/CD协议
– CSMA/CD(Carrier Sense Multiple Access/Collision Detection,带有冲突检 测的载波侦听多路存取)是IEEE 802.3使用的一种媒体访问控制方法。从 逻辑上可以划分为两大部分:数据链路层的媒体访问控制子层(MAC) 和物理层。它严格对应于ISO开放系统互连模式的最低两层。LLC子层和 MAC子层在一起完成OSI模式的数据链路层的功能。
• CS:载波侦听,Carrier Sense
• MA:多点接入(多路存取),Multiple Access
• CD:冲突检测,Collision Detection
– CSMA/CD的基本原理是:所有节点都共享网络传输信道,节点在发送数 据之前,首先检测信道是否空闲,如果信道空闲则发送,否则就等待; 在发送出信息后,再对冲突进行检测,当发现冲突时,则取消发送。
– CSMA/CD协议的侦听发送策略有三种: ① 非坚持CSMA ② 1-坚持CSMA ③ p-坚持CSMA
– CSMA/CD的控制规程主要包括以下四个处理内容: ① 侦听 ② 数据发送 ③ 冲突检测 ④ 冲突处理
• 13.1.2 以太网帧结构
– 以太网帧结构(帧格式),即在以太网帧头、帧尾中用于实现以 太网功能的域。在以太网的帧头和帧尾中有几个用于实现以太网 功能的域,每个域也称为字段,有其特定的名称和目的。
① Ethernet V2:ARPA,由DEC,Intel和Xerox在1982年公布其标准。
② Ethernet 802.3 RAW:这是1983年Novell发布其划时代的Netware/86 网络套件时采用的私有以太网帧格式。
③ Ethernet 802.3/802.2 SNAP:这是IEEE为保证在802.2 LLC上支持更多 的上层协议同时更好的支持IP协议而发布的标准。
• 13.1.3 嵌入式系统中常用的网络协议
– ARP:地址解析协议,Address Resolution Protocol,是根据IP地址获取物 理地址的一个TCP/IP协议。
– RARP:反向地址转换协议,Reverse Address Resolution Protocol,允许局 域网的物理机器从网关服务器的ARP 表或者缓存上请求其IP 地址。
– IP:网际协议,Internet Protocol,网际协议也就是为计算机网络相互连 接进行通信而设计的协议。
– ICMP:Internet Control Message Protocol,互联网控制消息协议。它是 TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。
– TCP:Transmission Control Protocol,传输控制协议。是一种面向连接 (连接导向)的、可靠的、基于字节流的运输层(Transport layer)通信 协议,由IETF的RFC 793说明(specified)。
– UDP :User Datagram Protocol,用户数据报协议,是OSI(Open System Interconnection,开放式系统互联)参考模型中一种无连接的传输层协议, 提供面向事务的简单不可靠信息传送服务,IETF RFC 768是UDP的正式规 范。
– FTP:File Transfer Protocol,文件传输协议。是TCP/IP 协议组中的协议之 一。FTP协议包括两个组成部分,其一为FTP服务器,其二为FTP客户端。
– TFTP:Trivial File Transfer Protocol,简单文件传输协议。是TCP/IP协议族 中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不 复杂、开销不大的文件传输服务,端口号为69。
• 13.2 嵌入式网络设备驱动开发概述
• 1、硬件描述
– 以太网对应于ISO网络分层中的数据链路层和物理层
– 使用嵌入式以太网接口的两种方式:
① 嵌入式处理器集成MAC控制器,但是不集成物理层接收器 (PHY),此时需要外接PHY芯片,如RTL8201BL、VT6103等芯 片。
② 嵌入式处理器既不集成MAC控制器,又不集成物理层接收器 (PHY),此时需要外接同时具有MAC控制器和PHY接收器的芯 片,如DM9000、CS8900、SIS900等芯片。
• 2、驱动框架
– 在/dev目录下没有对应的设备文件。
– 对网络设备的访问必须使用套接字(Socket),而非读写设备文件。
• 13.3 网络设备驱动基本数据结构
• struct net_device(网络设备结构体):包含具体网络设 备的各种信息和操作接口。
• struct sk_buff(套接字缓冲结构体):是Linux网络子系统 的核心,在Linux网络子系统各层协议中的数据传递实际 上传递的是struct sk_buff结构,它为各层之间的数据交换 单元提供了统一的定义。
• 13.3.1 struct net_device数据结构
struct net_device(网络设备结构体)
– 1、全局信息
• 网络设备的名称
– char name[IFNAMSIZ];
• 设备初始化函数指针
– int (*init)(struct net_device *dev);
– 2、硬件信息
• 设备使用的共享内存的起始地址
– unsigned long mem_end;
• 设备使用的共享内存的终止地址
– unsigned long mem_start;
• 设备I/O基址
– unsigned long base_addr;
• 设备中断号
– unsigned int irq;
• 指定多端口设备使用哪个端口
– unsigned char if_port;
• 保存分配给设备的DMA通道
– unsigned char dma;
• 设备状态
– unsigned long state;
– 3、接口信息
• 保存最大传输单元大小
– unsigned mtu;
• 接口类型
– unsigned short type;
• 硬件头长度
– unsigned short hard_header_len;
• 存放设备硬件地址(MAC地址)
– unsigned char dev_addr[MAX_ADDR_LEN];
• 存放广播地址
– unsigned char broadcast[MAX_ADDR_LEN];
• 接口标志
– unsigned short flags;
– 4、设备操作函数
• 打开接口
– int(*open)(struct net_device *dev);
• 关闭接口
– int(*stop)(struct net_device *dev);
• 启动数据包的发送
– int (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev);
• 设置设备的组播列表
– void (*set_multicast_list)(struct net_device *dev);
• 设置设备的MAC地址
– int(*set_mac_address)(struct net_device *dev, void *addr);
• 执行接口特有的I/O控制命令
– int(*do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);
• 改变接口的配置
– int (*set_config)(struct net_device *dev, struct ifmap *map);
• 在接口的MTU改变时,采取相应的设置
– int (*change_mtu)(struct net_device *dev, int new_mtu);
• 如果数据包传送超时,则调用该函数解决问题并重新发送数据
– void (*tx_timeout) (struct net_device *dev);
• 用于返回设备状态信息
– struct net_device_stats* (*get_stats)(struct net_device *dev);
• 在禁止中断的情况下,要求驱动程序检测接口下的事件
– viod(*poll_controller)(struct net_devices *dev)
– 5、工具成员
• 记录数据最后一次接收到数据包的时间戳
– unsigned long last_rx;
• 记录数据开始发送时的时间戳
– unsigned long trans_start;
• 在网络层驱动传输已超时,并调用tx_timout之前的最小时间
– intwatchdog_timeo
• 13.3.2 struct sk_buff数据结构
struct sk_buff套接字缓冲结构体
– 1、网络协议头
• sk_buff_data_t transport_header;
• sk_buff_data_t network_header;
• sk_buff_data_t mac_header;
– 2、缓冲区指针
• sk_buff_data_t tail;
• sk_buff_data_t end;
• unsigned char *head, *data;
– 3、操作函数
• static inline struct sk_buff *alloc_skb(unsigned int size, gfp_t priority);
• static inline struct sk_buff *dev_alloc_skb(unsigned int length);
• void kfree_skb(struct sk_buff *skb);
• void kfree_skb(struct sk_buff *skb);
• void dev_kfree_skb(struct sk_buff *skb);
• void dev_kfree_skb_irq(struct sk_buff *skb);
• void dev_kfree_skb_any(struct sk_buff *skb);
• unsigned char *skb_put(structsk_buff *skb, unsigned int len);
• unsigned char *__skb_put(struct sk_buff *skb, unsigned int len);
• unsigned char *skb_push(struct sk_buff *skb, unsigned int len);
• unsigned char *__skb_push(struct sk_buff *skb, unsigned int len);
• int skb_tailroom(const struct sk_buff *skb);
• unsigned int skb_headroom(const struct sk_buff *skb)
• void skb_reserve(struct sk_buff *skb, int len);
• char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len);
• 13.4 网络设备初始化
• 网络设备初始化由struct net_device数据结构的init函数指针指向的函 数完成:
– int (*init)(struct net_device *dev);
• 初始化工作包括以下几个方面的任务:
① 检测网络设备的硬件特征,检查物理设备是否存在;
② 如果检测到网络设备存在,则进行资源配置;
③ 对struct net_device成员变量进行赋值。
• 13.5 打开和关闭接口
• 打开接口的工作由struct net_device数据结构的open函数指针指向的函数完成:
– int (*open)(struct net_device *dev);
• 该函数负责的工作包括请求系统资源,如申请I/O区域、DMA通道及中断等资 源,并告知接口开始工作,调用netif_start_queue函数激活网络设备发送队列:
– void netif_start_queue(struct net_device *dev); 打开队列
• 关闭接口的工作由struct net_device数据结构的stop函数指针指向的函数完成:
– int (*stop)(struct net_device *dev);
• 该函数需要调用netif_stop_queue函数停止数据包传送:
– void netif_stop_queue(struct net_device *dev); 停止队列
• 13.6 数据接收与发送
• 1、数据发送
– 数据在实际发送的时候会调用struct net_device数据结构的 hard_start_transmit函数指针指向的函数,该函数会将要发送的数据放入 外发队列,并启动数据包发送。
• 2、并发控制
– 发送函数可利用struct net_device数据结构的xmit_lock自旋锁来保护临界 区资源。
• 3、传输超时
– 驱动程序需要处理超时带来的问题,调用struct net_device数据结构的 tx_timeout函数,并调用netif_wake_queue函数重启设备发送队列。
• 4、数据接收
– 在Linux中有两种方式实现数据接收:
• 第一种是中断方式:调用netif_rx函数实现数据接收;
• 第二种是轮询方式:调用netif_receive_skb函数实现数据接收。
• 13.7 查询状态与参数设置
• 1、链路状态
– 驱动程序需要掌握当前链路的状态,当链路状态改变时,驱动程序需要 通知内核:
• void netif_carrier_off(struct net_device *dev);
• void netif_carrier_on(struct net_device *dev);
• int netif_carrier_ok(const struct net_device *dev);
• 2、设备状态
– 驱动程序的get_stats()函数用于向用户返回设备的状态和统计信息,这些 信息保存在struct net_device_stats结构体中。
• 3、设置MAC地址
– 调用set_mac_address函数,设置新的MAC地址。
• 4、接口参数设置
• 调用set_config函数,设置I/O地址、中断等信息。
• 13.8 AT91SAM9G45网卡驱动
• 13.8.1 EMAC模块简介
– AT91SAM9G45:嵌入式微处理器
– AT91SAM9G45的EMAC模块是一个完全兼容IEEE 802.3标准的10/100M的以 太网控制器,它包含一个地址检查模块、统计和控制寄存器组、接收和 发送模块,以及一个DMA接口
• 13.8.2 模块图
• 13.8.3 功能描述
– 1、时钟
• 系统总线时钟
• 发送时钟
• 接收时钟
– 2、内存接口
• 帧数据在内存和EMAC之间的传输是通过DMA接口实现的。
– 3、接收模块
• 接收模块检查以太网帧的前导帧、FCS、对齐和长度。
– 4、发送模块
• 发送模块从DMA接口获取数据,填充前导帧、FCS等字段。
• 13.8.4 寄存器描述
– 1、网络控制寄存器(NCR)
– 2、网络配置寄存器(NCFG)
– 3、网络状态寄存器(NSR)
– 4、发送状态寄存器(TSR)
– 5、接收缓冲队列指针寄存器(RBQP)
– 6、发送缓冲队列指针寄存器(TBQP)
– 7、接收状态寄存器(RSR)
– 8、中断状态寄存器(ISR)
• 13.8.5 AT91SAM9G45芯片EMAC控制器驱动 分析
– 1、设备侦测
• 设备侦测主要完成各种资源的初始化工作:
① 获取I/O内存的地址,并进行I/O重定向;
② 获取设备中断号,注册中断处理程序;
③ 初始化net_device结构,并注册该结构;
④ 初始化时钟,并设置分频器。
– 2、设备打开与关闭
• 设备打开时主要完成以下任务:
① 分配DMA缓冲区,初始化缓冲区;
② 初始化硬件;
③ 打开PHY(物理层);
④ 通知上层开启传输。
– 3、数据的接收
– 4、数据的发送
– 5、中断处理