1、 OTG 控制器
OTG 的基本概念
首先,提出一个问题, OTG 和 EHCI/OHCI/UHCI 是同一类概念吗?
那我们先看一看 OTG 能做些什么。
在 OTG 中,我们一般不把设备叫做主设备或从设备,而称作 A-DEVICE 和 B-DEVICE 。一般而言, A-DEVICE 作主, B-DEVICE 作从,但也不能这样绑定, A-DEVICE 也可以作从,这时 A-DEVICE 仍要为总线提供电力。
OTG 设备使用插头中的 ID 引脚来区分 A/B Device , ID 接地被称作为 A-Device, 为连接时候的 USB Host , A-Device 始终为总线提供电力。 ID 悬空被称作为 B-Device, 为连接时候的 USB Device( 作从 ) ,设备的 USB Host/USB Device 角色可以通过 HNP 切换。
OTG Device :使用 Micro AB 插座,可以在运行时切换 Host/Device 。
仅外设 B-Device :仅仅能作为外设的 B-Device (分为插头一体和插头线缆分离的)。
可见, OTG 主要是负责控制器状态的切换,这种切换要根据接入的设备来判断。 OTG 主要使用在嵌入式设备中,说到嵌入式不能不提降低功耗了,所以仅有 ID 线的检测还是不够的。
OTG 中的三大协议
SRP ( Session Request Protocol ):
B-Device 使用。通过数据线上的脉冲,请求 A-Device 打开 VBUS 并且开始-个 Session 。 Session 为从 VBUS 打开到关闭这一段时间。
支持: A-Device 允许回应 SRP , B-Device (包括仅能作为外设的 B-Device ),允许发起 SRP 。一个能够支持 HNP 的 B- Device 应该能够发起 SRP 。当 A 插头插入时关闭 VBus 的 Host 必须支持回应 SRP , VBus 总是打开的 Host 不必响应 SRP 。
ADP ( Attach Detection Protocol ):
提供设备检测是否有对端设备插入。
HNP ( Host Negotiation Protocol ):
OTG 设备通过 HNP 来切换 Host/Device 角色。
OTG 不同连接方式的不同过程
OTG Device /Embedded Host 与 仅作为外设的 B-device (带 A 插头型)
Host 端检测到 A 插头插入,停止 ADP ,打开 VBus ,因为 B-Device 的 A 插头与设备作为一体,此时 B-Device 必定与 A 插头连接, Host 检测到外设连接,开始枚举。
OTG Device/Embedded Host 与 仅作为外设的 B-device ( A 插头为线缆连接)
Host 段检测到 A 插头插入,停止 ADP ,打开 VBus ,如果 B-Device 是线缆连接完毕在将 A 插头插入则整个连接过程与上面无异,因为此 时 B-Device 可能还没有插入插头,则设备连接超时, VBus 再次关闭,等待下一次 ADP 的改变(线缆连接完毕),再次打开 VBus ,此时开始正常总 线枚举。
OTG Device 与 OTG Device
Host 端检测到插头插入,则打开 VBus ,如果没有外设检测到,则关闭 VBus ,打开 ADP Probing , Device 端检测到插头插入,则打开 SRP ,如果线缆没有插入,则 SRP 超时, Device 端开始进行 ADP Probing ,当线缆连接完毕, Device 端侦测到 ADP 变化,发送 SRP 请求 Host 打开 VBus , Host 回应 SRP 并且打开 VBus ,完成设备 连接。
从上面的过程可以看出, ADP 和 SRP 的目的都是为了节能,平时 VBus 上的供电是并没有打开的,而且在空闲一段时间后 VBus 也会自动关闭。在 VBus 不供电的情 况下就需要靠 ADP 和 SRP 来检测外设并打开 VBus 的供电。如果 VBus 上一直有电流供应, ADP 和 SRP 就无用武之地了。可见,在嵌入式的世界里,确实要精打细算, ADP 和 SRP 是何等的复杂,这么复杂的设计仅是为了省几毫安的电流。
回来我们前面的问题, OTG 和 EHCI/UHCI/OHCI 是同一类的概念吗?
OTG 的作用只是负责切换主从状态的切换,同时,在功耗方面也有要求, OTG 要求 vbus 不能像 PC 那样永远供电,所以这样就需要有一套设备发现机制,这就是 SRP 和 ADP 了。 OTG 也允许同进充许同类设备进行数据传输( A TO A ) , 这就是 HNP 发挥作用的时候了。
当 OTG 己经发现设备, VBUS 供电开启,系统处于 HOST 或 DEVICE 状态,这时 OTG 的使命就完成了,接下来的工作就交给主控制器( EHCI/OHCI/UHIC )或从控制器了。
所以 OTG 的主要是在设备接入的那一刻起作用,此后 USB 还是要按传统的 HOST/DEVICE 的方式来通讯。当然,有些 OTG 控制器会集成一些 HOST 控制器的功能,这些控制器并不符合任何一种标准,一旦遇到这种 OTG 控制器,驱动开发人员就要倒霉了。 USB 系统中最复杂的就是主控制器了,如果与主控制器与 USB 标准有出入,就无法重用大量成熟的控制代码,驱动开发人员就需要重新去研究整个 USB 协义,这无疑是一份耗时耗力不讨好的活。
Linux 下的 OTG 架构
内核 定义了一个 struct otg_transceiver 的结构体,这个结构体描述的 OTG 需要支持的接口
struct otg_transceiver { struct device *dev; const char *label;
u8 default_a; enum usb_otg_state state; // 记录 OTG 控制器的状态,在实际的处理中这个比较重要。
struct usb_bus *host; struct usb_gadget *gadget;
/* to pass extra port status to the root hub */ u16 port_status; u16 port_change;
/* bind/unbind the host controller */ int (*set_host)(struct otg_transceiver *otg, struct usb_bus *host);// 这个接口用来启用或禁用主控制器,是关键的接口
/* bind/unbind the peripheral controller */ int (*set_peripheral)(struct otg_transceiver *otg, struct usb_gadget *gadget);
/* effective for B devices, ignored for A-peripheral */ int (*set_power)(struct otg_transceiver *otg, unsigned mA);// 一般用来设置 vbus 上的供电
/* for non-OTG B devices: set transceiver into suspend mode */ int (*set_suspend)(struct otg_transceiver *otg, int suspend); // 下面是 OTG 的三大高级功能的接口。 /* for B devices only: start session with A-Host */ int (*start_srp)(struct otg_transceiver *otg);
/* start or continue HNP role switch */ int (*start_hnp)(struct otg_transceiver *otg);
/* b device disconnect during hnp */ int (*disconnect)(struct otg_transceiver *otg);
/* b device connect */ int (*connect)(struct otg_transceiver *otg, struct usb_device *udev);
/* host suspend the bus during hnp */ int (*host_suspend)(struct otg_transceiver *otg);
/* hand interrupt related to usb otg */ int (*otg_interrupt)(struct otg_transceiver *otg);// 中断处理接口 }; |
上表的结构体很清晰的描述了 OTG 的功能,只要实现几个重要的接口,就能把你的 OTG 控制器和 linux 系统联接起来。
系统中作了如下定义:
struct otg_transceiver *xceiv;
这个定义就是一个 OTG 控制器的对像,然后使用 otg_set_transceiver 来实现这两者之间的联接。
注:转载请注明出处 datangsoc@hotmail.com