`
djsl6071
  • 浏览: 593456 次
  • 性别: Icon_minigender_1
  • 来自: 厦门
社区版块
存档分类
最新评论

基于Linux的USB主/从设备之间的三种通信方式

阅读更多
 
随着简单易用的USB接口日益流行,在嵌入式系统中添加对USB接口的支持已成为大势所趋。本文通过介绍Linux中支持USB的各种模块和库,分析了在Linux上利用USB实现高速串口和以太网连接等通信方式的具体方法。

通用串行总线(USB,Universal Serial Bus)是一种非常实用的通信接口,其应用日益广泛。有三种方法可以使运行Linux操作系统的嵌入式系统支持USB接口,本文将对这三种方法逐一进行介绍。

基 于Linux的USB设备与USB主机一般有以下三种通信方式:1.一些功能最完备结构也最复杂的设备采用用户定制内核模块来实现在标准USB总线上运行 复杂的高级协议,而由USB主机上相应的用户驱动程序和应用来完成连接。2.另一些基于Linux的USB设备则利用USB总线来实现与主机上所运行的某 个应用的简单的点对点串行连接。主机上的应用虽然利用了主操作系统所提供的USB编程接口,但表面看来却似乎是在通过一个典型的串口进行通信。3.最后, 还有些设备以主计算机作为网关,将USB设备连接到办公局域网或互联网上,从而使USB设备看起仿佛构成了一个以太网。这种方法专业性较强,但通常可行, 是主机驱动程序使该方法成为可能。

在这三种方法中,您可以根据预留给开发的时间长短和期望USB接口在嵌入式应用中所扮演的角色来决定 选用那一种方法比较恰当。为了帮助您做出正确的选择,下一节将向您介绍这三种方法分别应用于基于Linux的USB设备时的情况,但首先让我们对USB接 口做一个大致介绍。

USB概述

USB是一种方便快捷的接口,可用于为计算机工作站连接一些小配件。根据USB规范的定 义,鼠标、键盘、音频播放和录音设备、照相机、大容量存储设备以及许多其他设备均可以通过USB接口,以高达480Mbps的速度连接到一台主计算机。协 议定制者对USB上运行的这种复杂的主从式协议做出了仔细的说明,这就帮助保证了所有这些设备之间具备互操作性和兼容性。例如,该协议规定,USB设备只 有在被询问时才可以回答,并且USB主机会根据所连接的USB设备类型的不同,采用某些特定的格式,在某些特定的时间段从不同的设备获取数据。

USB 设备和主机之间通常通过专用的总线控制芯片建立连接。在USB主机上,名为UHCI或OHCI等的控制芯片通过插卡形式加入主机或直接集成到工作站的主板 上。在主机一端的总线控制驱动程序管理着主机控制芯片,它同时还跟踪监视着主机目前连接的是哪些USB设备,从而决定应如何与它们通信。

可 用于连接照相机和鼠标之类USB设备的总线控制器有很多种。其中的一种就在一块芯片上同时集成了USB接口以及另一端的串口、I2C接口或并口。USB控 制器(包括主机上的和USB设备上的控制器)也可能集成到英特尔StrongARM或 Hitachi H8之类的微控制器中去。这些芯片及其外围部件有点类似以太网和CAN控制器,不同的是他们用于连接USB设备,并运行USB协议。

很 多人都知道Linux操作系统中包含了USB主机控制器的驱动程序,因而USB键盘、数码相机以及其他一些USB设备都可以在一个运行Linux操作系统 的桌面工作站上使用。但很少有人知道Linux中还包含了一组USB设备控制器的驱动程序,尤其是集成到StrongARM SA1110处理器中的控制器。有了这些控制器驱动程序,基于Linux的嵌入式系统就能利用USB接口来与主计算机(运行Linux或其他操作系统)通 信。大多数USB通信的实现过程都是双端的。主机利用一个内核模块或驱动程序来与USB设备通信,而USB设备则通过其自身的驱动程序来与主机通信。根据 主机和USB设备所采用的通信风格的不同,驱动程序可以很简单明白,也可以很复杂,很具挑战性。本文主要关注USB设备端的通信过程,但也在适当的地方包 含了关于主机端通信过程实现的信息。

以下讨论的技术应当引起读者的注意。本文的目的是介绍如何在数码相机和PDA等基于Linux的 USB设备上使用Linux。此处所指的USB设备是严格意义上的USB设备,即带正方形连接器的完整的设备,而不是哪些连接器形状为扁平矩形的设备。此 外,USB连接的另一端(通常是一台PC工作站),应该是一台USB主机。

关于USB信息包的格式和通信参数的详细信息,见本文的参考文献。

通过编写内核模块添加USB接口

1. USB设备端通信过程

向一个基于Linux的设备中添加USB接口的第一种方法是编写一个用户定制的Linux内核模块,这也是可实现最完备功能的一种做法。采用这种方法时通常需要针对主机的操作系统(Windows, Linux等)开发相应的驱动程序。

一 旦在设备中实现了用户定制的内核模块,就可以使该设备完成相当复杂的功能,例如仿真一个文件系统,从而允许嵌入式应用将其USB主机当作一个远程存储设 备。除此以外,采用这种方法之后,设备还可以具备存储转发(store-and-forward)的功能,因而能够在与USB主机的连接建立之前对来自嵌 入式应用的数据流进行缓冲。

在基于StrongARM的Linux设备中,内核代码用于管理芯片所携带的USB设备控制器外设,通过调 用函数sa1100_usb_open()来初始化。在初始化之后,内核模块还会调用函数sa1100_usb_get_descriptor_ptr () 和sa1100_usb_set_string_descriptor()来设置在设备查询期间传送给USB主机的描述符,其中包含设备的数字厂商号和产 品标识符,以及可以让主机用来识别设备的字符串,甚至还有一个序列号域,以便主机可以唯一地识别一个连接在USB接口上的设备,或者在同种型号的多个设备 中进行区分。

设备查询过程是由USB设备控制器驱动的,并且一旦和USB主机连上之后会自动执行,所以内核模块必须在USB通信开始之 前设置好每个设备的描述符。当准备工作就绪之后,USB设备模块就会调用函数sa1100_usb_start()来通知内核接收主机发来的USB连接请 求。如果设备模块在连上USB 主机之前调用了函数sa1100_set_configured_callback(),那么接着内核模块就会在查询过程结束时调用回调函数。回调函数很 适合用来在设备上发出警告或给出一些形象的暗示,说明连接已经建立。

如果不再需要进行USB通信,那么设备的内核模块就会先调用函数sa1100_usb_stop(),然后调用sa1100_usb_close(),来关闭SA1100上的USB控制器。

StrongARM 的 USB控制器支持bulk-in和bulk-out两种数据传送方式。当接收来自USB主机的数据包时,内核模块会调用sa1100_usb_recv (),将一个数据缓冲区的地址和一个回调函数送给它。然后内核中的USB设备控制代码会从主机取回一个bulk-out数据包,将其内容存入制定的缓冲 区,接着调用回调函数。

下一步,回调函数从接收缓冲区中提取出数据,将其存放到其他地方,或者将缓冲区空间添加到一个队列中,然后分配一个新的缓冲区来接收下一个数据包。然后,如果还有数据需要接收,那么回调函数会重新调用sa1100_usb_recv(),准备接收另一个数据包。

向USB 主机发送数据的过程与此类似。内核模块收集了一帧数据之后,将数据的存放地址、数据长度和回调函数的地址送给sa1100_usb_send()函数。接着,在数据传送结束之后,内核模块会调用回调函数。

在www.embedded.com/code.htm (arch/arm/mach-sa1100/usb-char.c)可以找到一个叫做usb-char的模块,这是一个很好的设备端SA1110 Linux USB模块的例子。该模块将USB设备与USB 主机之间的连接变成一种高速串行链接。此外, usb-eth( arch/arm/mach-sa1100/usb-eth.c)模块也是个不错的例子,该模块将USB变成了一种虚拟的以太型网络。后面会深入探讨这两 种模块。

2. USB主机端通信过程

有些很好的主机端USB驱动程序的例子是随主流Linux操作系统的发布而提供 的,位于The Linux Kernel Archives (kernel.org)发布的原始内核源代码中。其中,Handspring Visor 模块(drivers/usb/serial/visor.c)是一个编写得更清晰,也更易理解的模块,它同时也是USB 主机端模块(drivers/usb/usb-skeleton.c)的模板。

利用USB实现高速串行通信

1. USB设备端通信过程

为 了达到最实用的效果,我们可以将USB总线简单地看作一个高速串口,然后,在一些嵌入式设备和应用中,我们就可以用USB接口来模拟串口。 StrongARM处理器的Linux内核就提供了一个名为usb-char的USB设备驱动程序,它所完成的恰好就是用USB模拟串口的功能。

当 需要与USB 主机通信时,Linux操作系统中的USB设备应用只是简单地打开一个与其usb-char设备节点的连接(连接类型为字符型,major number 为10, minor 为240),然后就开始读写数据。在与USB 主机的连接建立之前,read()和write()操作均返回一个错误信息。一旦连接建立好,并且设备查询完成之后,USB接口就开始象一个点对点的串口 一样与主机进行通信。

这种进行USB数据传送的方法非常简单有效,因而usb-char设备模块发布之后一直很受欢迎。而且,该模块还为通过其他方法进行USB通信提供了一个参考。

在usb -char中,真正的操作开始于usbc_open()函数,列表1给出了函数的一部分代码。笔者由于临时的兴趣,对该代码做了一点修改,取消了错误和超 时句柄。在此向代码的原作者Brad Parker、Nicolas Pitre 和Ward Willats致歉。

twiddle_descriptors()函数用于设置设备的USB描述符。在描述符设置好之后,我们就可以开始进行设备查询,并从USB 主机接收一帧数据。kick_start_rx()函数段的代码主要用于调用sa1100_usb_recv(),建立回调。

在USB主机发送一个数据包时,设备的内核模块会通过回调方式调用rx_done_callback_packet_buffer()函数,将数据包的内容送入一个FIFO队列,以便能通过read()函数将该数据包返回给usb-char设备节点。

2. USB主机端通信过程

对 于运行Linux操作系统的USB 主机,与usb-char相应的USB 主机模块叫做usbserial。大多数Linux版本中都包含了该模块,但它并不总能自动加载。通常应在主机与USB设备之间的连接建立之前利用 modprobe 或insmod加载该模块。

USB设备查询完成之后,主机上的一项应用就会利用某个usbserial设备节点(字 符型, major 为188, minor 大于等于0)与其通信。这些节点通常叫做/dev/ttyUSBn。Usbserial模块会报告它将哪一个节点分配给了哪一台USB设备,并将这一信息 按如下方式记载在内核消息记录中: =================================== usbserial.c:检测到一般转换器 usbserial.c:将一般转换器加入ttyUSB0 ==================================

这种连接一旦建立,USB 主机上的应用就可以通过向特定的节点读或写的方式与某USB设备通信。

此 时,笔者并未考虑在运行Win32或其他类型操作系统的主机上已有类似usbserial的模块。但用于这些主机上的任何USB驱动程序,只要能够进行 bulk-in 和 bulk-out数据传输,就很可能是一个近乎完整的驱动程序,只需进行一定的产品调整,并添加与产品绑定的厂商ID。

Linux 主机上还有另一种类似usbserial模块的库,叫做libusb (参见libusb.sourceforge.net)。该库通过低级的内核系统调用而不是通过usbserial模块来完成USB数据传输,因而在 Linux kernel版本上更容易设置和使用。同时,该库还能提供大量实用的调试功能,十分利于对USB链接上运行的复杂的通信协议进行调试。

为 了通过libusb与一个采用了usb-char模块的USB设备进行通信,Linux主机应用首先通过库中的usb_open()函数与设备建立连接, 然后利用函数usb_bulk_read()和usb_bulk_write()与设备交换数据。Libusb中含有几个程序范例。

利用USB实现以太网连接

1. USB 设备端通信过程

如 果利用USB连接来实现高速串口并非您所希望,那么您还可以将所有USB连接用作一个以太网。不论在主机端还是在设备端,Linux均有模块能实现这一功 能。iPAQ(掌上电脑)的Linux内核就独一无二地采用了这种通信策略,因为iPAQ硬件中既没有可访问的串口也没有专门的网络接口。

StrongARM Linux内核中,有一个叫做usb-eth的模块(arch/arm/mach-sa1100/usb-eth.c),它利用USB作为物理媒介,模拟 出一个虚构的以太网设备。一旦这种网络接口创建起来之后,就可以为它分配IP地址,并且外部环境均将其作为一个普通的以太网硬件对待。一旦USB 主机连接建立起来,usb-eth模块就允许USB设备“浏览”因特网,拼其他的IP地址,甚至通过DHCP、HTTP、NFS或者远程网“交谈”,以及 收发电子邮件。简而言之,任何能够在真正的以太网接口上运行的应用都可以原封不动地在usb-eth 上运行,因为这些应用无法识别它们所使用的其实并非真正的以太网硬件。

2. USB 主机端通信过程

相应的,在运行 Linux操作系统的主机一端,可用来在USB上实现以太网连接的内核模块叫做usbnet。安装了该模块之后,一旦主机与USB设备的连接建立起来,它 就会创建一个虚拟的以太网接口,在主机一端的内核模块以及用户应用看来,这个虚拟的接口与真正的以太网接口别无二致。主机端的应用可以通过拼一个USB设 备的IP地址来检查该设备是否已经连上,如果拼操作成功,那么就表示设备已经连接成功。

最近出现了一种针对Win32主机的usbnet风格的驱动,叫做Bahia网络驱动,关于该驱动的详细信息请访问www.bahia21.com/download.htm。

USB通信的调试

遗 憾的是,在USB 主机与Linux USB设备之间进行通信时,能够帮助我们跟踪通信过程中出现的问题的工具实在不多。除了libusb所提供的调试功能以外(该功能十分强大,但对于内核的 系统调用接口则无能为力),在一次失败的设备查询或数据传输的尝试过程中发生了什么问题?只有内核源代码和记录能够提供一些线索。笔者尝试在开发过程中向 USB 主机和设备代码中大量添加printk()函数调用,但这种方法会引入额外开销,从而改变USB代码自身的性能,这在有些情况下反而是事与愿违。

对 那些希望对 USB设备接口进行逆向工程处理,或者希望查找其产品缺陷的Linux开发者而言,一个叫做USB Snoopy (home.jps.net/~koma)的程序是个不错的选择。只是USB Snoopy仅能在Win32主机上运行。关于USB Snoopy的详细信息或关于常规的USB调试,请参看本文末给出的参考文献中Jan Axelson撰写的 “USB Debug Tips”。

Linux已成为通用型操作系统

如今Linux已不再是USB 主机专用的操作系统了,USB设备也可以方便地选择它。而且Linux下的USB通信太灵活易用了,因而笔者采用其他易用型串口(RS-232)的日子很可能就此结束,对我而言,这是件好事。

作者:Bill Gatliff,Email: bgat@billgatliff.com

参 考文献: 1. Ganssle, Jack. "An Introduction to USB Development," Embedded Systems Programming, March 2000, p.79. 2. Axelson, Jan. "HIDs Up," Embedded Systems Programming, October 2000, p.61. 3. Axelson, Jan. "USB Debug Tips," Embedded Systems Programming, April 2002, p.36

 

 

此文章源自《电子系统设计》网站:
http://www.ed-china.com/ART_8800012688_400010_500007_TS.HTM
分享到:
评论

相关推荐

    基于Linux的USB主、从设备之间的三种通信方式.pdf

    "基于Linux的USB主、从设备之间的三种通信方式" 本文主要介绍了基于Linux的USB主、从设备之间的三种通信方式。USB(Universal Serial Bus)是一种非常实用的通信接口,其应用日益广泛。有三种方法可以使运行Linux...

    基于Linux主机的USB设备安全监控系统设计.pdf

    总结来说,基于Linux主机的USB设备安全监控系统设计是一项重要的安全保障措施,通过结合Linux的内核特性、Hook技术以及Netlink通信,实现了对USB设备的细粒度监控。该系统不仅提高了系统的安全性,也为用户提供了...

    基于Linux的USB设备.pdf

    本文主要介绍了基于Linux的USB设备的相关知识点。下面是对标题、描述、标签和部分内容的详细...本文介绍了基于Linux的USB设备的相关知识点,包括USB设备概述、基于Linux的USB设备的三种实现方法和内核模块方法的实现。

    基于Linux的主机间USB通信的实现.pdf

    基于Linux的主机间USB通信的实现.pdf

    基于Linux的USB主机设备驱动程序的开发.pdf

    【基于Linux的USB主机设备驱动程序的开发】 在Linux操作系统中,开发USB主机设备驱动程序是一项复杂的任务,涉及与硬件和内核之间的交互。设备驱动程序作为硬件与内核之间的接口,是操作系统不可或缺的一部分。在...

    基于嵌入式linux的USB驱动设计.pdf

    本文主要介绍了基于嵌入式Linux的USB驱动设计,包括USB总线简介、Linux下的USB驱动整体结构、USB主机控制器驱动、USB设备驱动等内容。本文还详细介绍了USB描述符层次结构、Linux下的USB驱动整体结构、USB主机控制器...

    基于Linux的USB设备重定向研究.pdf

    "基于Linux的USB设备重定向研究" 本文研究的是基于Linux的USB设备重定向问题。Linux操作系统具有良好的移植性和较好的稳定性,在终端和服务器领域都得到极广的应用。而USB总线也具有很强的通用性,是目前最为流行的...

    Linux下基于python的USB通信程序开发.pdf

    Linux 下基于 Python 的 USB 通信程序开发 本文档旨在介绍 Linux 下基于 Python 的 USB 通信程序开发,详细介绍了 libusb 库的应用、Python 语法的简洁性和 CY7C68013 芯片的通信方法。 Linux 操作系统通过 libusb...

    基于Linux的USB主机设备驱动程序的开发

    ### 基于Linux的USB主机设备驱动程序的开发 #### 概述 在现代计算环境中,设备驱动程序作为连接硬件与操作系统的关键桥梁,对于确保系统稳定性和性能至关重要。特别是对于像USB这样的广泛使用的接口,其驱动程序的...

    基于Linux的USB设备驱动程序实现.pdf

    【基于Linux的USB设备驱动程序实现】 在嵌入式系统中,USB(通用串行总线)设备的正常工作依赖于对应的USB驱动程序。本文详细阐述了如何在Linux操作系统环境下,针对特定的开发板(例如56789: 24;5)实现USB设备的...

    基于Linux的USB从设备驱动研究.pdf

    本文将探讨基于Linux的USB从设备驱动的实现流程和关键结构。 首先,USB设备主要由配置、接口和端点构成。端点是通信的基本单位,分为输入和输出端点,分别对应从设备到主机和从主机到设备的数据传输。USB支持四种...

    基于嵌入式Linux的USB键盘驱动设计

    本文主要讨论基于嵌入式Linux的USB键盘驱动设计,涵盖了嵌入式Linux的USB设备驱动结构和USB键盘驱动的设计方法。 第一个知识点:嵌入式Linux的USB设备驱动结构 在嵌入式Linux中,USB设备驱动结构可以分为四个层次...

    嵌入式Linux下USB主机设备驱动开发

    USB通信主要分为三个阶段:枚举阶段、配置阶段和操作阶段。枚举阶段是USB设备插入后与主机进行初始化的过程;配置阶段是主机根据设备的能力对其进行配置;操作阶段是设备正常工作的阶段。 #### 3. Linux 2.6内核下...

    论文研究-基于Linux的主机间USB通信的实现.pdf

    网络隔离器在隔离了可信网络和不可信网络的同时,允许信息在两个...首先介绍了USB系统、USB通信模型和数据传输类型,然后介绍了Linux的USB子系统及主要数据结构,重点说明了使用libusb库实现两台USB主机间的数据传输。

    电信设备-基于USB端口的多台设备之间通信装置.zip

    USB通信的基本原理是建立一个主设备(Host)和一个或多个从设备(Device)之间的连接。在电信设备的上下文中,主设备通常是一个中央控制系统,如计算机或交换机,而从设备可以是各种通信模块、传感器或者其他数据...

    Tina linux USB转串口通信实现方法-已验证

    1. **USB转串口设备原理**:USB转串口设备通常基于CH340、FTDI或PL2303等芯片,它们在USB接口和串行接口之间起桥梁作用,使得传统串口设备可以通过USB接口与计算机进行通信。 2. **Tina Linux系统**:Tina Linux是...

    基于Linux系统的USB主机接口设计与实现.pdf

    USB(Universal Serial Bus)是一种通用串行总线标准,由微软、Compaq、IBM等公司在1995年制定,旨在简化PC和其他设备之间的通信。USB接口以其易用性、高速度和灵活性而广受欢迎,成为个人电脑的标准接口。USB设备...

Global site tag (gtag.js) - Google Analytics