嵌入式Linux网络驱动程序的开发及实现原理

发布者:EuphoricMelody最新更新时间:2013-03-06 来源: dzsc关键字:Linux  网络驱动  S3C2410 手机看文章 扫描二维码
随时随地手机看文章
    引言

  随着人们对开放源代码软件热情的日益增高,Linux作为一个功能强大而稳定的开源操作系统,越来越受到成千上万的计算机专家和爱好者的青睐。在嵌入式领域,通过对Linux进行小型化裁剪后,使其能够固化在容量只有几十兆字节的存储器芯片或单片机中,成为应用于特定场合的嵌入式Linux系统。Linux强大的网络支持功能实现了对包括TCP/IP在内的多种协议的支持,满足了面向21世纪的嵌入式系统应用联网的需求。因此,在嵌入式系统开发调试时,网络接口几乎成为不可或缺的模块。

  1 嵌入式Linux网络驱动程序介绍

  Linux网络驱动程序作为Linux网络子系统的一部分,位于TCP/IP网络体系结构的网络接口层,主要实现上层协议栈与网络设备的数据交换。Linux的网络系统主要是基于BSD Unix的套接字(socket)机制,网络设备与字符设备和块设备不同,没有对应地映射到文件系统中的设备节点。

  通常,Linux驱动程序有两种加载方式:一种是静态地编译进内核,内核启动时自动加载;另一种是编写为内核模块,使用insmod命令将模块动态加载到正在运行的内核,不需要时可用rmmod命令将模块卸载。Linux 2.6内核引入了kbuild机制,将外部内核模块的编译同内核源码树的编译统一起来,大大简化了特定的参数和宏的设置。这样将编写好的驱动模块加入内核源码树,只需要修改相应目录的Kconfig文件,把新的驱动加入内核的配置菜单,然后需要修改相应子目录中与模块编译相关的Kbuild Makefile,即可使新的驱动在内核源码树中被编译。在嵌入式系统驱动开发时,常常将驱动程序编写为内核模块,方便开发调试。调试完毕后,就可以将驱动模块编译进内核,并重新编译出支持特定物理设备的Linux内核。

  2 嵌入式Linux网络驱动程序的体系结构和实现原理

  2.1 Linux网络设备驱动的体系结构

  如图1所示,Linux网络驱动程序的体系结构可划分为4个层次。Linux内核源代码中提供了网络设备接口及以上层次的代码,因此移植特定网络硬件的驱动程序的主要工作就是完成设备驱动功能层的相应代码,根据底层具体的硬件特性,定义网络设备接口struct net_device类型的结构体变量,并实现其中相应的操作函数及中断处理程序。


  Linux中所有的网络设备都抽象为一个统一的接口,即网络设备接口,通过struct net_device类型的结构体变量表示网络设备在内核中的运行情况,这里既包括回环(loopback)设备,也包括硬件网络设备接口。内核通过以dev_base为头指针的设备链表来管理所有的网络设备。

  2.2 net_device 数据结构

  struct net_device结构体是整个网络驱动结构的核心,其中定义了很多供网络协议接口层调用设备的标准方法,该结构在2.6内核源码树文件中定义,下面只列出其中主要的成员。

  2.2.1全局信息及底层硬件信息

  name:网络设备名称,默认是以太网;

  *next:指向全局链表下一个设备的指针,驱动程序中不修改;

  mem_,rmem_:发送和接收缓冲区的起始,结束位置;

  base_addr,irq:网络设备的I/O基地址,中断号,ifconfig命令可显示和修改;

  hard_header_len:硬件头的长度,以太网中值为14;

  mtu:最大传输单元,以太网中值为1500B;

  dev_addr[MAX_ADDR_LEN]:硬件(MAC)地址长度及设备硬件地址,以太网地址长度是48bit,ether_setup会对其进行正确的设置;[page]

  2.2.2 主要的操作方法

  int (*init)(struct net_device *dev); 设备初始化和向系统注册的函数,仅调用一次;

  int (*open)(struct net_device *dev);设备打开接口函数,当用ifconfig激活网络设备时被调用,注册所用的系统资源(I/O端口,IRQ,DMA等)同时激活硬件并增加使用计数;

  int (*stop)(struct net_device *dev);执行open方法的反操作;

  *hard_start_xmit;初始化数据包传输的函数;

  *hard_header;该函数(在hard_start_xmit前被调用)根据先前检索到的源和目标硬件地址建立硬件头。    eth_header是以太网类型接口的默认函数;

  2.3网络驱动程序的编写及实现原理

  Linux网络系统各个层次之间的数据传送都是通过套接字缓冲区sk_buff完成的,sk_buff数据结构是各层协议数据处理的对象。sk_buff是驱动程序与网络之间交换数据的媒介,驱动程序向网络发送数据时,必须从其中获取数据源和数据长度;驱动程序从网络上接收到数据后也要将数据保存到sk_buff中才能交给上层协议处理。

  对于实际开发以太网驱动程序,可以参照内核源码树中的相应模板程序,重点理解网络驱动的实现原理和程序的结构框架,然后针对开发的特定硬件改写代码,实现相应的操作函数。下面结合作者利用Linux2.6.18内核在深圳优龙公司的FS2410开发板(SAMSUNG S3C2410处理器)上移植编写嵌入式CS8900A网卡驱动程序的实例,说明网络驱动程序的实现原理。

  2.3.1网络设备初始化

  网络设备的初始化是由net_device结构中的init函数实现的,内核加载网络驱动模块后,就会调用初始化过程。实例中初始化函数_init cs8900_probe中主要完成的工作:

  a.调用内核中通用的设置以太网接口的函数ether_setup();

  b.填充net_device结构体变量dev中其它大部分成员;

  c.调用check_mem_region()检测I/O地址空间,然后调用request_mem_region()申请以dev->base_addr为起始地址的16个连续的 I/O地址空间;

  d.通过cs8900_read()探测网卡CS8900A,读取ID信息;

  e.设置CS8900A的INTRQ0作为中断信号输出引脚;

  f.将MAC地址写入CS8900A的IA寄存器中;

  g.通过register_netdev()将CS8900A注册到Linux全局网络设备链表中;

  2.3.2打开(或关闭)网络设备

  系统响应ifconfig命令时,打开(关闭)一个网络接口。ifconfig命令开始会调用ioctl(SIOCSIFADDR)来将地址赋予接口。响应SIOCSIFADDR由内核来完成,与设备无关。接着,ifconfig命令会调用ioctl(SIOCSIFFLAGS)设置dev->flag的IFF_UP位来打开设备,这个调用会使设备的open方法得到调用。(当ifconfig调用ioctl(SIOCSIFFLAGS)清除dev->flag的IFF_UP位时,设备的stop方法将被调用)

  实例中利用cs8900_start()函数打开网络设备,主要完成的工作:

  a.通过set_irq_type()向内核注册网络设备的中断处理程序;

  b.通过cs8900_set()设置CS8900A网卡中各控制寄存器和配置寄存器;

  c.通过内核中netif_start_queue()函数开启网络接口的数据传输队列;

  2.3.3网络数据包的发送

  数据包的发送和接收是网络驱动程序中实现的两个最重要的任务。当网络设备被激活时,net_device结构中的open方法被调用,它负责打开设备并调用net_device结构中的hard_header函数指针建立硬件帧头信息。最后通过函数dev_queue_xmit()来调用net_device结构中的hard_start_xmit方法把存放在sk_buff中的数据发送到网络物理设备。如果发送成功,则在hard_start_xmit中释放sk_buff并返回0;如果硬件设备忙暂时无法处理,则返回1。网络硬件在发送完数据包后会产生中断,把dev->tbusy置0,通知系统可以再次发送。

  实例中,hard_start_xmit方法即为网络设备数据发送函数cs8900_send_start(),该函数实现把数据发送到以太网上,由网络协议接口层函数dev_queue_xmit()对其调用。cs8900_send_start()中主要完成的工作:

  a.发送数据前关闭中断,中止网络设备的数据传输队列;

  b.向CS8900A寄存器TxCMD中写入传送数据命令控制字,向寄存器TxLength中写入待发送数据帧长度;

  c.通过cs8900_read()反复读取CS8900A总线状态寄存器BusST信息,直到其已经准备好接收来自主机的数据;

  d.调用cs8900_frame_write()将待发数据送入CS8900A的sk_buff中,硬件设备会将数据帧发送到以太网上;

  e.记录数据帧的发送时刻,打开中断,释放sk_buff缓存,函数返回0;

  2.3.4网络数据包的接收和中断处理

  网络设备是异步地接收外来的数据包并且主动的“请求”将硬件获得的数据包压入内核。网络设备接收数据包是通过中断实现的。对于网络接口,接收到新数据包,发送完成或者报告错误信息及连接状态等都会触发中断,通常中断处理程序通过检测硬件状态寄存器判断是哪种情况。[page]

  当设备收到数据后会产生一个中断,由硬件通知驱动程序有数据包到达。在中断处理程序中驱动程序申请一块sk_buff(一般定义为skb)缓冲区,然后从硬件读出数据放到申请好的缓冲区里,接下来填充sk_buff中的部分信息:包括接收到数据的设备结构体指针填入skb->dev;收到数据帧的类型填入skb->protocol;把指针skb->mac.raw指向硬件数据并丢弃硬件针头(skb_pull);设置skb->pkt_type,标明链路层数据类型。最后调用协议接口层函数netif_rx() 把接收到的数据包传输到网络上层协议处理。这里,netif_rx()只是负责把数据放入工作队列就返回,真正的处理是在中断返回以后,这样可减少中断处理的时间。几乎每个中断处理程序的编写都要涉及底半部机制,这样可以保证中断的高效处理。

  实例中数据接收函数cs8900_receive()由网络驱动的中断处理函数调用,主要完成如下工作:

  a.通过从I/O口读取RxStatus和RxLength的值,确定接收数据帧的状态信息和长度;

  b.判断接收数据帧的状态是否正常,若异常则记录相关错误信息,然后函数返回;

  c.正常情况下,在内存中申请一块sk_buff缓存,并将数据从CS8900A的片内存储器传送到sk_buff缓存中;d.从数据帧中获取协议头并赋给skb->protocol;

  e.通过调用netif_rx()函数将接收到的数据送往上层协议栈进行处理;

  f.记录接收数据的时间并更新统计信息;

  3将设备驱动模块编译进内核

  设计好模块化的网络驱动程序后,我们就可以编译这个内核模块,并将这个自定义的内核模块作为Linux系统源码的一部分编译出新的系统。下面介绍的内容均在Linux2.6.18内核上编译通过,可以在2.6.x版本内核中通用。如前所述,由于Linux2.6内核引入了kbuild的新机制,使得编译新的内核模块或者将自己编写的内核模块集成到内核源码中都变得非常简单了。

  Linux2.6内核中,编译内核模块首先要在/usr/src下正确配置和构造内核源码树,即把需要版本的内核源码解压在/usr/src/,并在内核源码的主目录下(这里为/usr/src/linux-2.6.18.3),使用make menuconfig或者make gconfig命令配置内核,然后使用make all完整编译内核。

  下面以作者开发的CS8900A网卡驱动为实例,介绍如何将网络设备驱动模块编译进内核。

  a.在系统源码树drivers目录下创建新目录Cs8900;

  b.将编写好的文件cs8900.c和cs8900.h拷贝到drivers/Cs8900目录下;

  c.在drivers/Cs8900目录下,编写Makefile文件:

  #Makefile for CS8900A Network Driver

  obj -$(CONFIG_DRIVER_CS8900A)  +=cs8900.o

  d.在drivers/Cs8900目录下,编写Kconfig文件:

  #Just for CS8900A Network Interface

  menu "CS8900A Network Interface support"

  config DRIVER_CS8900A

  tristate "CS8900A support"

  --------help--------

  This is a network driver module for CS8900A.

  endmenu

  e.在driver目录下的Kconfig文件endmenu语句前,加入一行:

  source "drivers/Cs8900/Kconfig"

  这样在内核源码树的主目录下,通过make menuconfig或者make gconfig命令就可以在Device Drivers选项的下面找到CS8900A Network Interface support选项,并找到CS8900A support的选择菜单,它有三种状态:未选中(不编译)、选中(M)一编译为模块、选中(*)一编译为新系统一部分。

  重新编译内核即可得到支持CS8900A网卡的内核,然后将内核下载到FS2410的开发板上,通过配置网络参数,就可以测试网卡驱动程序的行为了。

  4 结束语

  在这个信息爆炸的时代,人们对于网络的需求愈发强烈,越来越多的嵌入式设备都需要具有以太网的接入功能,因此开发网络驱动程序对于很多嵌入式产品的研发至关重要。具体开发嵌入式Linux网络驱动程序时,可以参照内核中已经支持的网络驱动源代码,在重点理解Linux网络驱动实现原理的基础上,按照模块设计较为固定的开发模式,结合具体物理设备的硬件手册,移植编写需要的模块化的网络驱动程序。

关键字:Linux  网络驱动  S3C2410 引用地址:嵌入式Linux网络驱动程序的开发及实现原理

上一篇:基于蓝牙技术的无线显示屏系统设计
下一篇:基于uC/GUI的数据显示系统的设计

推荐阅读最新更新时间:2024-03-16 13:19

linux 2.6.24.4及根文件系统在S3C2410上的移植(使用4.3.2编译器支持eabi)(基于GEC2410)
之前移植了linux-2.6.24.4和根文件系统(使用busybox-1.10.1创建)在GEC2410平台上运行。可参考之前的笔记: 内核配置: http://blog.csdn.net/shevsten/archive/2010/05/17/5599790.aspx 根文件系统: http://blog.csdn.net/shevsten/archive/2010/05/26/5625133.aspx 在测试一个用4.3(支持EABI)编译的应用程序时开始出现找不到库,将4.3.2编译器目录/usr/local/arm/compiler/arm-none-linux-gnueabi/libc/armv4t/lib中所
[单片机]
ARM-Linux GPIO操作事宜
1.在嵌入式Linux GPIO表示为 S3C2410_GPx(n) ,其中x的取值为 A,B,C,D,E,F,G,H..... ,表示那个GPIO口,n的取值为 1,2,3,..... 表示第几个管脚。 例如 B口的第六管教:S3C2410_GPB(6) D口的第12管教:S3C2410_GPD(12) ..... 注 这些宏定义在arch/arm/mach-s3c2410/include/mach/gpio-nrs.h,使用#include mach/gpio-nrs.h 以下包含#include mach/hardware.h linux/gpio.h mach/regs-gpio.h 2.设置gpio的工作模
[单片机]
基于嵌入式Linux的视频循环录制系统解析
引言 视频采集系统以其直观的视频影像数据,对现场场景进行记录,目前已经在各行各业得到广泛应用。对于特定运用场合,如汽车行进过程,由于其环境的不确定性和多样性,以及事故的突发性和偶然性,要求采集系统能够稳定、连续地实时记录事发过程。行车过程事故发生时,需要掌握的事故原因往往在事故发生前短短的一段时间内。因此,分清事故责任和分析事故原因所需要的视频信息,往往是在事故时间点之前的一小段时间内。 日常生活中常见的交通纠纷,往往是因为没有直接证据造成取证困难。基于此,结合嵌入式系统低功耗、低成本等优点,本文利用嵌入式Linux系统实现行车视频存储,存储的视频可以为交通纠纷的调解以及交通事故认定,提供现场录像证据。 1 系统概述 1.
[单片机]
基于嵌入式<font color='red'>Linux</font>的视频循环录制系统解析
OK6410A 开发板 (八) 35 linux-5.11 OK6410A 内存管理第三阶段
C setup_arch- paging_init- bootmem_init- memblock_allow_resize返回 - mm_init- mem_init返回 ----此时memblock消亡,buddy初始化完成,开启了基于虚拟内时代的 buddy内存管理器时代 流程 setup_arch(&command_line);- paging_init bootmem_init find_limits(&min_low_pfn, &max_low_pfn, &max_pfn); sparse_init zone_sizes_init(min_low_pfn, max_low_pfn, max_p
[单片机]
基于S3C2410的GPRS/CQT测试系统设计研究
GPRS作为中国移动据数业务的承载网,支持多种数据业务,涉及不同的网元,任何一个网元出故障都会直接影响数据业务的正常使用,保证用户端到端使用就显得非常重要。 GPRSDT/CQT测试模拟终端用户的使用情况,将数据业务的使用过程用时间图、事件列表、层三信令等工具来表述,有助于工程师对测试中遇到的问题进行准确定位与分析。以往CQT测试主要是以人工测试的方式进行,先制定测试计划交由测试人员到指定地点进行测试,测试工具一般为信号测试专用手机,这种测试所得的数据都是由测试人员手工记录而来,再进行统计整理、制作分析报告,存在很大的主观性,缺乏真实性和准确性。目前移动通信中基站架设的特点是数量大、分布广,不可能对大量的基站和其覆盖的范围进行信号
[单片机]
基于<font color='red'>S3C2410</font>的GPRS/CQT测试系统设计研究
基于Linux的嵌入式车载导航系统的设计
1.前言 HMS30C7202 嵌入式微处理器是目前性价比交优秀的芯片,由于其优良的性能用于替代早期的芯片,在车辆导航方面的开发应用有着广阔的应用前景。在诸多的操作系统中,由于Windows CE 、Vxwork 等操作系统都是商业化产品,其价格高昂、源代码封闭。另外,对于上层应用开发者而言,嵌入式系统需要的是一套高度简练、质量可靠、应用广泛、易开发、多任务,并且价格低廉的操作系统。源码开放的Linux 正好可以满足这些要求。由于嵌入式系统的应用多种多样,并且标准Linux 操作系统比较庞大,因此,需要根据实际应用对标准Linux 进行重新的移植、裁剪和配置,生成代码紧凑、代码量小的特定操作系统。 2.导航系统的硬件组成 车载导航
[嵌入式]
Linux之父炮轰英特尔Spectre修补是全然的垃圾
集微网消息,Spectre漏洞阴影余波荡漾,Linux操作系统机器安装修补程序后频频出包。 Linux之父Linux Torvalds周一在Linux群组论坛公开炮轰,英特尔提供给Linux的Spectre修补程序是全然的垃圾(complete and utter garbage)。   Linux Torvalds认为英特尔在修补Spectre上的做法相当糟,采用间接分支限制推测会造成系统效能大幅下滑,因此英特尔不默认启用这项功能,却将责任推诿至他人身上,等于试图将垃圾推给他人。 Torvalds指出,从推测执行控制CPU ID这件事显示,英特尔在Meltdown上做了对的事,但这也不令人意外,因为修补并不是太难,而且也是比较明
[手机便携]
基于ARM处理器和Linux操作系统的电磁流量计设计方案
  0 引 言   电磁流量计是一种测量导电介质体积流量的计量仪表,具有测量精度高、稳定性好、可靠性高等特点。电磁流量计除可测量一般导电液体的流量外,还可测量液固两相液体、高粘度液体及盐类、强酸、强碱液体的体积流量,可广泛应用于水泥、化工、轻纺、冶金、矿山、造纸、医药、给排水、食品饮料、环保等工业技术部门,其产品的性能、质量和可靠性对上述企业的经济效益有着重要的影响。   传统电磁流量计一般采用8 位或16 位的单片机,由于单片机性能较弱和外围接口少,无法完成复杂算法或者多项并行任务; 在显示方式上一般采用LED 或段式LCD,只能显示数字、字母、汉字和一些粗糙的图案;在数据存储方面一般采用小容量的EPROM 存储器,流量数据
[单片机]
基于ARM处理器和<font color='red'>Linux</font>操作系统的电磁流量计设计方案
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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