文章目錄
- OMAP H2 Platform
- OTG
- Outline
- Peripheral Side: USB Device Controller
- Peripheral Side: Gadget Drivers
- Host Side: usbcore
The new USB "On-The-Go" (OTG) capabilities are not yet widely
understood, or even generally available. The most visible feature of
OTG is that it defines the behavior of intelligent "Dual-Role" USB
devices, such as cameras or wireless handsets, which act either as USB
host or as USB peripheral. That role choice is made each time the
device is used, rather than once when it's designed, giving a
flexibility previously unknown with USB. Using a new kind of USB
connector, OTG lets USB support more "peer to peer" style application
models. You could
- Hook a cell phone to a laptop to synchronize schedules, get new audio recordings, or swap other documents;
- Print a picture from a camera to a USB printer;
- Connect a USB keyboard to your PDA;
- Update game data on your portable console over USB.
This document should be useful to developers investigating the use
of Linux to implement OTG-capable products. It presents the USB OTG
support contributed by Texas Instruments for the OMAP
H2 software development platform running an Linux 2.6 kernel. That
builds on the standard Linux USB host and peripheral side driver
frameworks, making small additions as described here. It also includes
drivers implementing OTG support on OMAP platforms.
OMAP H2 Platform
The H2 software development platform includes a Texas Instruments
OMAP 5912/16xx series processor, with an ARM 926TEJ cpu, a DSP, battery
power management, and a wealth of other features often used in cell
phones. USB support includes:
- Three integrated USB controllers: OHCI host, USB Device Controller
(UDC), and an OTG controller, all supporting full speed USB (12
Mbit/s).
- "Mini-AB" connector on the H2 sample board. All "dual-role" OTG devices should have exactly one such external USB connector.
- External USB OTG transceiver, Philips ISP1301 (controlled over I2C), with an alternate software-visible wiring option.
- USB VBUS is hooked up to a TI TPS65010 power controller
(controlled over I2C) so that an A-role system can supply up to 500mA
of current for battery charging to a B-role (default peripheral) H2. In
A-role (default host), the H2 itself supplies 8mA.
The "Mini-AB" connector is compatible with standard USB 2.0 "Mini-B" connectors, which appear in some new USB peripherals.
Most OMAP processors support this and similar product designs.
Register interfaces to the different USB controllers are largely
source-compatible, although older chips don't support OTG.
OTG
It's reasonable to think about OTG support as revolving around that
"Mini-AB" connector, since that's what demands the highly visible
"dual-role" capability implemented by the OTG drivers. OTG uses two
methods to chose device role:
- The simplest is built into the special Mini-A to Mini-B cables that
OTG uses: the Mini-A connector grounds the ID pin, while the Mini-B end
of the cable doesn't. That controls startup in A-Host or B-Peripheral
role, and is the only method needed
unless you're hooking up
to another dual-role device. Call this "cable based role switching";
some incomplete OTG implementations stop at this point.
- When connected to a dual-role device, a fancier software-driven method can be used later: switching roles using the Host Negotiation Protocol
(HNP). That protects against the inevitable cases where the cable gets
hooked up going the "wrong" direction for at least one of the tasks at
hand.
That dynamic role selection is the most procedurally visible aspect
of OTG, but there's more to OTG than that; see the OTG specification
(and errata). The primary target of OTG is battery powered devices, so
several aspects of the specification support reduced power usage. These
include a new Session Request Protocol (SRP), which may be supported
even by single-role USB devices.
To someone providing hardware-level drivers, an OTG solution
starts with support for the standard Linux-USB host side and peripheral
side driver stacks. Add protocol support for SRP and HNP, match the
state machines in the OTG specification well enough to pass OTG
hardware and software compliance testing, and then your product can use
the OTG logo.
|
USB OTG Logo full-speed version |
Outline
The current Linux kernel updates for OTG support break down as follows:
- Programming Interfaces
have been updated; mainstream Linux 2.6.9 kernels have all of these changes.
- USB Device Controller Drivers export some new interfaces.
- USB Gadget Drivers have some new responsibilities that involve
using those new interfaces. Some still need to be updated accordingly,
to work on dual-role systems.
- The Linux-USB Host side "usbcore" module acquired a few new
OTG-specific responsibilities affecting enumeration, which are mostly
invisible to device drivers. It also needed to learn about USB
suspend/resume and remote wakeup to fully support HNP. These relate to
Linux power management interfaces.
- The host side also needs to define an OTG "Targeted
Peripheral List". Each product must define its own such list of "good"
devices. Some component should probably also suspend inactive devices,
saving power and/or initiating HNP protocol.
- USB Controller Drivers
are in Linux 2.6.8 and later OMAP kernels:
- Responsibility for USB initialization belongs to the board-specific
INIT_MACHINE call. This knows about chip-specific setup and creates
platform devices as needed, making platform_data available to the
various USB controller drivers.
- Core OTG protocol support is wrapped in a otg_transceiver
object. On H2, the isp1301_omap
driver ties the transceiver the OMAP OTG controller, and talks to the OHCI and UDC drivers using the usb_bus
and usb_gadget
programming interfaces. Other boards might need to implement this differently.
- The UDC needed a new omap_udc
driver in the "USB
Gadget" framework, providing immediate access to several standard
gadget drivers (including Ethernet/RNDIS, Mass Storage, serial/ACM, and
more). This UDC is quite full-featured, supporting numerous endpoints,
DMA, and isochronous transfers; it can easily implement composite
multi-function devices.
- The OHCI host controller was already supported by Linux 2.6 kernels using ohci_hcd
to access a large and growing set of Linux-USB device drivers.
These points are addressed in the rest of this document, in that same order.
Programming Interface Updates
It was a goal to keep these interface changes small, and to have
them be useful outside of OTG support where possible. That way the new
code paths can get better testing, rather than being used only for
(currently uncommon) OTG devices.
In particular, this doesn't change the existing programming models or calls for host side USB (still uses urb
and usb_device
) or for peripheral side USB (still uses usb_request
and usb_gadget
).
At some point it might become desirable to move away from "URB" to a
lighter weight model like "usb_request", and maybe to a more symmetric
programming interface; but that's not necessary at this time.
Peripheral Side: USB Device Controller
Several OTG state flags, and a few new usb_gadget_*()
calls, are all the changes needed in the gadget programming interfaces.
The flags support user interface reporting requirements for OTG
devices, and the calls support new USB state transitions (some of which
are also useful for non-OTG systems). Except for the flag reporting
whether the gadget is_otg
, the state flags are current only
when the gadget driver could participate in HNP: after it receives the
SET_CONFIGURATION request, or before it suspends. In addition, if HNP
is ever enabled, it can't be disabled without re-enumerating the
device.
struct usb_gadget { ... unsignedis_otg:1; unsignedis_a_peripheral:1; unsignedb_hnp_enable:1; unsigneda_hnp_support:1; unsigneda_alt_hnp_support:1; ... };
/* used by external USB transceiver */ int usb_gadget_vbus_connect(struct usb_gadget *gadget); int usb_gadget_vbus_disconnect(struct usb_gadget *gadget);
/* call this during SET_CONFIGURATION */ int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA);
/* these logically control the USB D+ pullup */ int usb_gadget_connect(struct usb_gadget *gadget); int usb_gadget_disconnect(struct usb_gadget *gadget); |
In addition, usb_gadget_wakeup()
is now defined as the
way SRP may be invoked. If the device is in a USB suspend state, remote
wakeup is used (and OTG peripherals don't always need hosts to enable
wakeup). If there's no VBUS power, SRP may be used instead.
There's kerneldoc for all of those, and many of the symbols
have the same meaning as in the OTG specification. For example,
b_hnp_enable is the device feature flag that may be set by the USB
A-Host; if it's set, the B-Peripheral device may be well into an
HNP-driven role switch when suspend() is called.
Peripheral Side: Gadget Drivers
To see how those are used in drivers, see the small changes to Gadget Zero
which, using omap_udc
,
were sufficient to pass the USBCV OTG tests. All USB gadget drivers
that will be used on OTG-capable hardware should have corresponding
changes; at this writing, some of the gadget drivers still haven't been
modified to know about OTG.
- Provide an OTG descriptor in each configuration, when gadget->is_otg
is true.
- Report HNP availability "through the user interface" (printk, LED, etc) at SET_CONFIGURATION
- Report start of HNP role switch (B-Peripheral to B-Host, or
A-Peripheral to A-Host) "through the user interface" as suspend starts.
This framework is currently not set up to handle the SRP-only subset
of OTG; that would need another gadget flag. Also, so far there's no
gadgetfs support for OTG: OTG feature flags aren't exported to user
mode drivers, though user mode drivers can certainly provide OTG
descriptors if they know (out of band) that they're appropriate.
Host Side: usbcore
There are several updates that affect host side support for OTG dual-role devices.
OTG Enumeration and the Targeted Peripherals List
USB enumeration (khubd and usb_new_device
) needed updates:
- When an OTG A-host enumerates an OTG dual-role device, and it's
directly connected to a root hub port, it's responsible for setting one
of the HNP device features before it issues any SET_CONFIGURATION. For
now, it immediately sets b_hnp_enable
on the B-Peripheral (unless a_alt_hnp_support
is appropriate instead, because it's not on the OTG port).
- Check the OTG Targeted Peripheral List, which is kept in the drivers/usb/core/otg_whitelist.h
file. In addition to a whitelist of device IDs, this holds a single
blacklist entry for the OTG HNP test device (which always triggers HNP
from a dual-role device).
- Devices on the whitelist are allowed to configure.
- Devices not on the whitelist trigger a diagnostic, and
normally disable the device. Instead of being disabled, dual-role
devices may be immediately switched to host role using HNP, in case
this device is on the other's whitelist. (For developer/tester
convenience, the "disable" step can be prevented with a Kconfig
option.)
- The OTG controller driver needs to be able to ask the HCD to
start enumeration "immediately", starting at least the port reset
before a one millisecond HNP timer expires.
So that the updated enumeration code can set OTG device features appropriately, the usb_bus
interface reports which port has the Mini-AB connector. It also
provides more visibility of key HNP protocol state, reporting if this
is a B-Host rather than an A-Host (so that it shouldn't set OTG device
features during enumeration); and whether the A-Host has set b_hnp_enable
on the B-Peripheral (needed by OTG controllers and drivers). (This information is not currently visible in sysfs.)
struct usb_bus { ... u8 otg_port;/* 0, or index of OTG/HNP port */ unsigned is_b_host:1;/* true during some HNP roleswitches */ unsigned b_hnp_enable:1;/* OTG: did A-Host enable HNP? */ ... }; |
CONFIG_USB_SUSPEND
The CONFIG_USB_SUSPEND patch adds generic experimental support for USB suspend/resume to Linux, as needed to implement HNP.
/* selective suspend/resume */ extern int usb_suspend_device(struct usb_device *dev, u32 state); extern int usb_resume_device(struct usb_device *dev); |