由于IrDA不是单纯的串口物理通信规范,而是一种网络传输控制标准。Linux必须按网络设备驱动方法来组织红外数据的网络传输。Linux网络驱动程序的体系结构如图1所示。

20070325233000132.JPG

体系结构划分为四层,自上而下分别为协议接口层,网络设备接口层,提供实际功能的设备驱动功能层,以及网络设备和网络媒介层。网络驱动程序的设计,最主要的工作就是完成设备驱动功能层,使其满足应用中所需的功能。Linux对所有网络设备都抽象为一个接口,这个接口提供了对所有网络设备的操作集合。由数据结构structdevice来表示网络设备在内核中的运行情况,即网络设备接口,它既包括纯软件网络设备接口,也包括硬件网络设备接口,由以devbase为头指针的设备链表来集体管理所有网络设备,该设备链表中的每个元素代表一个网络设备接口。数据结构device(在内核中也就是net_device)中有很多供系统访问和协议层调用的设备方法,包括供设备初始化和进行系统注册用的init函数,打开和关闭网络设备的open和stop函数,处理数据包发送的函数hard_start_xmit,以及中断处理函数等。
3.1 初始化
网络设备的初始化主要是由device数据结构中的init函数指针所指的初始化函数来完成的,当内核启动或加载网络驱动模块的时候,就会调用初始化过程。首先检测网络物理设备是否存在,这是通过检测物理设备的硬件特征来完成(系统中的红外串行接口),然后再对设备进行资源配置,随后构造设备的device数据结构,用检测到的数值对device中的变量初始化。最后向Linux内核中注册该设备并申请内存空间。
3.2 数据包的发送和接收
数据包的发送和接收是实现Linux网络驱动程序中两个最关键的过程。图1中明确反映了网络数据包的传输过程:首先在网络设备驱动加载时,通过device域中的init函数指针调用网络设备的初始化函数对设备进行初始化,如果操作成功就可以通过device域中的open函数指针调用网络设备的打开函数打开设备,再通过device域中的建立硬件包头函数指针hard_header来建立硬件包头信息。最后通过协议接口层函数dev_queue_xmit来调用device域中的hard_start_xmit函数指针来完成数据包的发送。该函数将把存放在套接字缓冲区中的数据发送到物理设备,该缓冲区是由数据结构sk_buff来表示的。

数据包的接收是通过中断机制来完成的,当有数据到达时,就产生中断信号,网络设备驱动功能层就调用中断处理程序,该中断处理的核心工作是数据包的接收,然后网络协议接口层调用netifrx函数,把接收到的数据包传输到网络协议的上层进行处理。
3.3 实现模式
实现Linux网络设备驱动功能主要有两种形式。一是通过内核来进行加载,内核启动时即加载网络设备驱动程序,内核启动完成后,网络驱动功能随之实现;二是通过模块加载的形式。在此着重对灵活性更强的模块加载形式进行讨论。

模块设计是Linux中特有的技术,它使Linux内核功能更容易扩展和裁剪,并使各类设备驱动的开发模式化。模块加载网络驱动程序的设计步骤是:首先通过模块加载命令insmod把网络设备驱动程序插入到内核之中,然后insmod将调用init_module()函数对网络设备的init函数指针初始化,通过调用register_netdev()函数在Linux系统中注册该网络设备。如果成功,再调用init函数指针所指的网络设备初始化函数对设备初始化,并将设备的device数据结构插入到dev_base链表的末尾。最后通过执行模块卸载命令rmmod来调用网络驱动程序中的cleanup_module()函数对网络驱动程序模块卸载。具体实现过程如图2所示。

20070325233010185.JPG

用模块初始化网络接口是在编译内核时标记编译为模块的,系统在启动时并不知道该接口的存在,需要用户在/etc/rc d/目录中定义的初始启动脚本中写入命令或手动将模块插入内核空间来激活网络接口。这样可灵活地决定在何时加载网络设备驱动程序,这也是与内核加载形式的最大区别。
4 应用实例

下面以在PXA255处理器实现红外网络通信的实例,介绍基于Linux开发的流程和实现方法。
4.1 PXA255的红外通信接口
PXA255是InterlXScale构架系列中的一款CPU,我们使用的IntelPXA250开发板提供了全面的软硬件开发环境。PXA255处理器提供了对红外通信的支持,其与红外口相关的板级寄存器如表1所示。 
20070325233018387.JPG

该CPU上的3个串行接口,包含符合IrDA串行红外物理连接标准的红外发送编码器和接收×××,且都可工作于64字节长度的FIFO缓冲方式。每个串行接口有13个寄存器,其中12个用作UART,与常规的PC16550没有大的区别,如数据接收缓冲寄存器/发送保持寄存器、波特率分频寄存器、中断控制及标志寄存器、线路/Modem控制及状态寄存器等,红外选择寄存器则专门用于选择IrDA的工作方式。
4.2 红外口的驱动程序
4.2.1 红外模块加载和红外设备的初始化
把红外模块加载到Linux系统网络设备中,并定义红外设备的中断,初始化红外接口,其实现函数pxa250irdainit的代码为:
20070325233040627.JPG 
4.2.2 数据包的接收
采用中断进行红外数据外的接收,数据不易丢失和溢出,实时性更强。任一新的接受数据到达都触发中断,其波特率值决定触发的中断类型是SIR还是FIR。中断处理程序首先判断传输中是否出错,随后根据LSR中接受数据位的标志DR,将接收数据存入接收缓冲区rxbuff。
20070325233054520.JPG

4.2.3 数据包的发送
当内核要发送一个数据包时,调用pxa250sirtransmit函数(假设采用SIR发送),首先禁止接收,并关闭中断,随后根据LSR中发送数据请求位TDRQ状态,将发送缓冲区txbuff中数据逐一发送。
20070325233104186.JPG
4.3 红外口的网络应用程序
红外口网络应用的开发与常规网络设备的应用极为相似,采用套接字,建立通信双方的虚拟连接。支持IrDA的Socket称为IrSock,在Linux中,每一种协议都有自己的网络地址数据结构,均以sockaddr_开头。

IrSock的数据结构与一般网络设备的套接字结构稍有不同,在net/irda.h中定义:
20070325233115235.JPG
红外口的网络应用程序开发的流程与一般网络设备的套接字开发方式几乎一样,不再赘述。
5 结  论

目前各类嵌入式设备的开发大量应用无线通信技术,在需要个人特制网络、点到点交换的场合,采用Ir2DA技术无疑是最合适的。许多小型移动设备,如PDA、手机、信息家电等都广泛应用红外通信技术。基于Linux对红外网络通信的开发对当今嵌入式系统的应用研究具有较强的实用性和借鉴作用。