随着移动终端的普及,为了不使用PC,直接在移动终端间进行数据交换,提出了OTG技术。USB OTG(On-the-Go) 标准在完全兼容USB2.0的基础上,追加了HNP(Host Negotiation Protocol)和SRP(Session Request Protocol)协议。在硬件方面增添了更小的连接器和电缆,包括袖珍型的A插头和插槽(Mini-A),袖珍型的AB插槽(Mini-AB)。通过HNP和SRP协议可以实现主从设备的交换,从而实现脱离PC的移动设备间数据的直接交换。
ISP1362芯片的结构
飞利浦的ISP1362有OTG控制器,高级主机控制器和一个基于ISP1181的外设控制器。同时通过一个数据总线接口与外部CPU相连。主机与外设控制器都配有缓冲USB通信流量的内置存储器。ISP1362用软件执行HNP和SRP,一系列的寄存器提供支持HNP和SRP控制和状态的监视能力。OTG有一般的收发器,还有内置充电泵,电压比较器,数据线上的上拉/下拉电。结构如图1。
OTG规范的HNP和SRP
HNP的事件序列
图2给出了HNP的事件序列图。
(1)A设备使用完总线并停止所有的总线活动(即挂起总线)。
(2)B设备检测到总线处于空闲状态,启动HNP序列。
(3)A设备在总线上检测到B设备要成为主机的请求,连接其D+线上拉电阻以作为响应。
(4)B设备发现D+线是高电平D 线是低电平,这表示A设备识别来自B设备的HNP请求,此时,B设备成为主机而且发送总线复位信号,开始使用总线。
(5)当B设备使用完总线后,它停止所有的总线活动。
(6)A设备在一定的时间内检测到没有总线活动时就会断开其D+线上的上拉电阻。
(7)B设备连接其上拉电阻。
(8)A设备发现D+线是高电平D 线是低电平,表示B设备正在发送连接信号并准备作为外围设备响应,此时,A设备变为主机,并发送总线复位信号开始使用总线。
SRP
OTG规范定义了两种B设备向A设备请求开始会话的方式,称为数据线脉冲调制(data-line pulsing)和Vbus脉冲调制(Vbus pulsing)。这两种方法组成了会话请求协议(SRP)。SRP 的初始条件是:B设备必须在确定A设备前一次会话结束以后才能尝试启动新的会话。A设备通过检测到Vbus下降到低于其会话有效阈值来确定会话结束。B设备在检测到D+和D 线至少在2ms的时间内为低电平(SE0),这确保A设备检测到设备的断开。数据线脉冲调制时,B设备等待满足上述条件后,接入其数据线上拉电阻(D+或D )。双重角色B设备只能在全速初始化SRP,因此只能上拉D+。Vbus脉冲调制时在满足初始条件后驱动Vbus。B设备先执行数据线脉冲调制,然后执行Vbus脉冲调制,A设备设计为能响应其中一种SRP的方式。
Linux操作环境下驱动程序的编写
当OTG双角色设备以主机方式工作时(如图5),USB主设备软件包工作,以从机方式工作时,USB设备软件包工作。OTG通过驱动连接器中的ID的不同连接,或通过是否有主设备转换协议SPR以确定双角色设备的工作方式,并确定使用USB主设备软件包或USB设备软件包。
USB驱动程序由主机驱动程序,USB子系统,USB设备驱动程序组成。在Linux操作系统中,存在一个连接USB设备驱动程序和主控制器驱动程序的子系统USBCore,它通过定义一些数据结构,宏和功能函数来抽象所有的硬件设备。USBCore提供了为硬件处理的所有下层接口。包含所有USB设备驱动和主机控制的通用程序,可称为UpperAPI和LowerAPI。USB子系统提供与设备驱动程序的接口,读取并解释USB设备描述符,配置描述符。为USB设备分配唯一的地址,使用默认的配置来配置设备,支持基本的USB命令请求,连接设备与相应的驱动程序,转发设备驱动程序的数据包。
设备驱动程序是内核的一部分,它完成以下的功能:
(1)对设备初始化和释放。
(2)把数据从内核传送到硬件和从硬件读取数据。
(3)读取应用程序传送给设备文件的数据和会送应用程序请求的数据。
(4)监测和处理设备出现的错误。
用户对设备的访问,主要有以下的函数:
Open 打开函数,Read、Write读写函数,ioltrl设备控制函数,用户各类设备的特殊控制。设备驱动程序的设计就是实现上述四个函数与外加一个设备初始化的函数,这些函数在设备驱动程序中可以skel_init()、skel_open()、skel_read()、skel_ioctrl()等调用。声明一个称之为file operation的结构体将用户级的open等函数与设备skel_open()等函数联系起来。
static struct file_operations skel_fops = {
.owner = THIS_MODULE,
.read = skel_read,
.write = skel_write,
.open = skel_open,
.release = skel_release,
};
打开设备:
static int skel_open(struct inode *inode, struct file *file)
{ struct u***_skel *dev;
struct u***_interface *interface;
int subminor;
int retval = 0;
subminor = iminor(inode);
interface = u***_find_interface(&skel_driver, subminor);
if (!interface) {
err ("%s - error, can't find device for minor %d", __FUNCTION__, subminor);
retval = -ENODEV;
goto exit;
}
dev = u***_get_intfdata(interface);
if (!dev) {
retval = -ENODEV;
goto exit;
}
/* increment our usage count for the device */
kref_get(&dev->kref);
/* save our object in the file's private structure */
file->private_data = dev;
exit:
return retval;
}
read 函数与write 函数稍有不同:程序并没有用urb 将数据从设备传送到驱动程序,而是用u***_bulk_msg 函数代替,这个函数能够在不需要创建urbs 和操作urb函数的情况下来发送数据给设备,或者从设备来接收数据。调用u***_bulk_msg函数并传递一个存储空间,用来缓冲和放置驱动收到的数据,若没收到数据,就失败并返回一个错误信息。
static ssize_t skel_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{ struct u***_skel *dev;
int retval = 0;
dev = (struct u***_skel *)file->private_data;
/* do a blocking bulk read to get data from the device */
retval = u***_bulk_msg(dev->udev,
u***_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
dev->bulk_in_buffer,
min(dev->bulk_in_size, count),
&count, HZ*10);
/* if the read was successful, copy the data to userspace */
if (!retval) {
if (copy_to_user(buffer, dev->bulk_in_buffer, count))
retval = -EFAULT;
else
retval = count;
}
return retval;
}
skel_disconnect函数
当我们释放设备文件句柄时,这个函数会被调用。
static void skel_disconnect(struct u***_interface *interface)
{ struct u***_skel *dev;
int minor = interface->minor;
lock_kernel();
dev = u***_get_intfdata(interface);
u***_set_intfdata(interface, NULL);
/* give back our minor */
u***_deregister_dev(interface, &skel_class);
unlock_kernel();
/* decrement our usage count */
kref_put(&dev->kref, skel_delete);
info("USB Skeleton #%d now disconnected", minor);
}
结束语
本文是在基于ARM9开发板linux操作系统下实现USB接口的OTG应用技术,实现了双角色设备的开发。随着OTG技术的发展,USB的应用将会更为广泛,并且移动设备间的直接数据传输成为可能。
| |
|