SEP6200平台上Linux内核的USB OTG驱动设计
扫描二维码
随时随地手机看文章
摘要:为了满足两个USB设备之间直接进行数据通信的需求,通过对现有USB OTG协议和相关应用的研究,在国产SoC芯片SEP6200平台上设计并实现了基于Linux内核的USB OTG模块驱动。首先介绍了OTG标准中的对话请求协议(SRP)和主机交换协议(HNP),然后制定并设计了基于USB控制芯片USB3343的硬件模块方案,最后根据Linux内核中已有的USB驱动架构完成了USB OTG设备驱动的设计,并最终实现了SEP6200嵌入式平台USB Host和Device角色的自由转换功能。
关键词:USB OTG;SEP6200;USB3343;Linux;设备驱动
引言
传统的USB协议(USB 2.0)规定了两个设备之间进行数据通信时,必须有一个Host设备作为固定的主机,通过这个主机来控制设备问的数据传输。在日常应用中,基本都是将USB设备连接到PC,并在PC的控制下进行数据交换。这种交换方式,一旦离开了PC,各设备间就无法利用USB口进行直接操作。随着嵌入式设备的快速发展,两个USB设备之间直接进行数据交换的需求变得越来越迫切。USB On—The—Go(USB OTG)技术便应运而生。OTG技术实现了在没有Host的情况下,设备之间点对点的数据控制与传输。本文通过研究USB 2.0协议和USB OTG补充规范,结合具体应用需求,建立了基于国产SoC的嵌入式USB OTG模块硬件平台,并在Linux操作系统平台上设计并实现了基于国产内核主控芯片SEP6200的USB OTG设备驱动。
1 USB OTG协议与实现方式概述
USB OTG标准在完全兼容USB2.0标准的基础上,增添了电源管理(节省功耗)功能,并可提供一定的主机检测能力,支持对话请求协议(SRP)和主机交换协议(HNP)。在OTG中,初始主机设备称为A—device,外设称为B—device。
对话请求协议(Session Request Protocol,SRP):为了节省功耗,A—device在总线不被使用时允许VBUS总线关断,此时B设备就会检测到该状态并进入功低耗模式。当外部B—device需要向A—device发起对话时,它会通过SRP向A—device发出申请,请求A—device向VBUS供电并启动一次对话。对话将随VBUS的开启而开始,随VBUS的关闭而结束。
主机交换协议(Host Negotiation Protocol,HNP):该协议允许两个直接相连的OTG设备进行主机Host功能的切换,它能够根据电缆的连接方式来决定初始化角色,从而允许设备在通信时能够改变控制信号。当用户模式或应用程序下B—device有输入时,HNP将作初始响应。
OTG两用设备使用新型mini—AB插座,从而使mini—A插头、mini—B插头和mini—AB插座增添了第5个引脚(ID),以用于识别不同的电缆端点。mini—A插头中的ID引脚接地,mini—B插头中的ID引脚浮空。当OTG设备检测到接地的ID引脚时,表示默认的是A—device(主机);而检测到ID引脚浮着的设备,则认为是B—device(外设)。系统一旦连接后,OTG的角色还可以更换。A-Device作为默认主机并提供VBUS电源,并在检测到有设备连接时复位总线、枚举并配置B-device。
2 USB OTG模块硬件方案
为了后期USB OTG驱动设计需要,首先对OTG硬件模块作一些简单的介绍。本文设计的USB OTG模块在硬件上由主控芯片SEP6200以及USB控制芯片USB3343构成。SEP6200是东南大学国家ASIC工程中心自主研发的一款定位于手持视频播放设备、卫星导航产品的高性能应用处理器,它内部集成了ULPI总线接口,支持SRP和HNP协议,拥有USB2.0 OTG功能。USB控制芯片USB3343是SMSC公司生产的一款高速USB收发器,支持主机、设备和OTG三种功能,非常适合用于要求低功耗工作和待机工作的便携式设备。SEP6200内部的OTG Controller和USB3343之间通过otg_transceiver接口来完成交互。
在本模块中,SEP6200处理器通过自带的ULPI接口与USB3343进行连接和通信,而USB3343收发控制器则是通过外接USB MiniAB插座与外部USB设备进行连接。其硬件连接结构图如图1所示。
此硬件平台以SEP6200处理器为核心,处理器除了ULPI接口的12根总线与USB3343相连接外,另外分别通过两根GPIO接口线来控制实现OTG的低功耗功能。其中一根(GPIO_RESETB)用来对USB3343进行软件复位,另一根(GPIO_EN)用来控制对VBUS总线供电。当核心板作为device与PC进行连接时,软件检测到ID信号状态为浮空后将GPIO_EN引脚置0,切断电源模块,使5 V供电电压与VBUS总线隔绝。相反,当核心板作为Host与U盘等外设进行通信时,软件检测到ID信号状态为接地,然后将GPIO_EN引脚置位,通过电源使能模块将5 V电压加载到VBUS总线上,实现核心板作为主机对外设进行供电,从而实现对外部设备的检测和枚举等后续操作。
3 USB OTG驱动架构的设计与实现
3.1 OTG设备驱动程序架构
本设计的软件驱动开发基于Linux操作系统平台。作为开源操作系统,Linux有良好的兼容性和强大的USB技术支持。OTG设备驱动程序主要由USB目标设备软件包和USB主设备软件包构成。OTG驱动通过连接器中“ID”信号的不同连接,根据SRP和HNP协议的内部机制,确定使用USB主设备软件包还是USB目标设备软件包。图2是OTG没备驱动程序架构框图。
当OTG设备以从机方式工作时,USB目标设备功能模块工作。目标设备控制驱动完成USB目标设备软件包与OTG硬件问的数据交换。USB协议层完成USB协议规范,USB目标设备类驱动的功能取决于OTG设备的功能。
当OTG设备以主机方式工作时,USB主设备功能模块丁作。主控制驱动完成USB主设备软件包与OTG硬件间的数据交换,USB总线驱动保存设备的信息。OTG提供通用的主设备类驱动程序,驱动支持的这些目标主设备包含在目标设备的列表里。
基于以上分析,驱动软件设计的总体任务主要分为:USB从机设备驱动设计、USB主机控制器驱动设计以及USB OTG驱动设计。其中从机设备驱动模块和主机控制器驱动模块互相独立,OTG驱动依赖于从机设备驱动和主机控制器驱动。
3.2 USB从机设备驱动设计
基于SEP6200的核心板系统在作为USB从机设备时,要应答PC主机的标准请求,处理USB总线事务和用户功能。因此从机驱动包括3层:UD C驱动程序、Gadget驱动程序和Gadget API。UDC驱动程序负责直接访问硬件,控制USB设备与主机间的底层通信,向上层提供与硬件相关操作的回调函数。Gadget驱动程序具体控制USB设备功能的实现。Gadget API则是提供给UDC驱动程序回调函数的简单封装。
Linux内核首先通过musb_init_controller()函数初始化USB设备控制器,OTG驱动提供的状态机根据硬件信息将USB OTG工作模式配置成从机模式。接着内核会初始化Gadget驱动,完成Gadget驱动和UDC驱动的绑定,并配置控制器使其开始工作。然后调用底层GadgetAPI函数来激活端点进行数据传输。USBOTG定义了三个端点;程序中定义端点0在控制传输中应答设备枚举,端点1的功能为向PC机发送数据,端点2的功能为接收PC机发送的数据。最后,通过中断响应和中断处理函数来完成核心板作为设备与PC机的通信操作。内核使用struct musb结构体描述UCD驱动实例的各种信息。
3.3 USB主机控制器驱动设计
核心板系统的主机驱动分为几个部分:Host controller drive、USB core和Class driver。在本设计中,Hostcontroiler drive与所应用的USB主控芯片USB3343相关,而USB Core和Class driver在Linux内核中提供了相应的支持。
Linux内核使用usb_hcd结构描述USB主机控制器驱动Host controller drive。usb_hcd结构描述了USB主机控制器的硬件信息、状态和操作函数,其定义如下:
软件根据HNP协议执行完所有的HNP状态后,OTG驱动进入USB Host模式。在对底层硬件初始化后,注册Hub和USB存储类设备,随后加载hub_probe对根Hub进行初始化和枚举。当外部USB设备插入后,系统将对USB类设备进行枚举,查找对应的USB存储类设备驱动,并加载stora ge_probe,然后读取插入的USB存储类设备的文件系统结构,将该存储设备注册为一个scsidisk。使用mount命令将该设备挂载到相应目录后,即可完成对USB存储设备的读写操作。
3.4 USB OTG驱动设计
OTG驱动维护着一个OTG状态机,从而支持HNP和SRP协议,转换主机端和设备端功能,上文中硬件状态的检测和驱动模式转化即由此实现。在模块初始化的时候,首先对OTG驱动进行注册,OTG驱动将自身注册为一个char设备。当找到设备时,在注册函数中执行设备控制器驱动对应的probe函数,初始化OTG模块,随后调用中断申请函数申请中断,并设置相应的中断处理函数。在本设计中,当有OTG中断产生时,首先执行硬件访问层的中断处理函数phy3343_hal_isr(),在这个函数中读取中断来源,若判断是OTG中断,则调用OTG驱动的中断处理例程usb_ otg_isr(),启动OTG状态机。
OTG驱动还需要向文件系统提供相应的file operations接口,供上层的application调用,这些接口函数包括:usb_otgdev_open、usb_ otgdev_close、usb_otgdev_ioctl、usb_otgdev_fasync等。usb_otgdev_open函数负责OTGapplication在打开OTG设备文件时,通过Linux文件系统接口调用该函数,进行OTG驱动自身参数的初始化;usb_otgdev_close函数负责OTG application在关闭OTG设备文件时,通过Linux文件系统接口调用该函数,进行OTG驱动自身参数重启;usb_otgdev_ioctl函数是在OTGapplication调用OTG设备文件的ioctl函数时,Linux文件系统接口调用该函数;usb_otgdev_fasync函数则是当OTG的application设置或者重设异步通知时,对该函数进行调用,当异步通知模式设置成功返回值为0,失败时返回负值。
Linux内核中通过定义struet otg_transceiver结构体,提供给开发者一个与USB硬件进行直接交互的接口。在本设计中,即通过该结构体实现了软件与USB主控芯片USB3343的交互通信功能。
结语
USB OTG技术满足了两个设备之间直接进行数据通信的要求。在对现有的OTG协议和相关应用进行深入研究的基础上,本文在国产SoC芯片SEP6200平台上设计并实现了基于Linux内核的USB OTG模块驱动。整个SEP6200核心板系统能够支持USB主机模式、USB设备模式,并且能够实现两个模式间的切换。