USB API
This API details the programming interface through which device drivers
can communicate with devices via the USB bus.
| Version | | Date | | Author | | Change
| | 0.92 | | 27/9/2003 | | JWB | | Added link to header file USBDevFS.txt
| | 0.91 | | 11/4/2003 | | JWB | | Minor corrections.
| | 0.90 | | 10/4/2003 | | JWB | | Major modifications to reflect the capabilities
| | | | | | | built into RISC OS 5 and the IYONIX pc. This
| | | | | | | reflects a significant change in the manner in
| | | | | | | which the USB driver is called, but does lead to
| | | | | | | a significant simplification of the whole
| | | | | | | process.
|
Where differences in the current implementations exist, these are noted.
Sections:
- DeviceFS interface
- DeviceFS calls
- Service calls
- Alias matching
- Commands
The Universal Serial Bus (USB) is a simple interconnect system widely
standardised and for which a large range of devices is available. For use
on RISCOS specific drivers will (always) need to be adapted or written.
It is useful, however, to provide a relatively simple programming interface(API) that will permit developers of device drivers to create
drivers that will operate on a variety of different USB host adaptor
cards within the RISCOS environment. This document describes such an
API which is compatible with both RISCOS 5 as shipped on the IYONIX pc,
and version 0.90 and later of Castle's 4 port USB podule.
No attempt is made to describe how to control devices over the USB bus
using USB protocols. It merely describes the low level interface through
which these commands may be issued in a manner that is not directly
dependant on the hardware providing the USB host interface.
The naming convention used for devices is USBxxnnn, where all device
names start USB, followed by 0 or more vendor specific characters (nn)
and a number (nnn) in the range 0 to 999.
The IYONIX pc uses "USBnnn" e.g. "USB2".
Castle's USB podule uses "USBDnnn" e.g. "USBD2".
Examples given in this document use "USBD" as the driver name.
Device specific drivers communicate with the low level USB host driver,
and thence the USB hardware and attached devices, via FileSwitch and
DeviceFS_CallDevice. Streams are opened to or from an endpoint using
special fields to define requirements.
The special field can have some or all of the following:
| Value | | Meaning | | IYONIX? | | Podule?
| | interface/N | | Interface to use. Defaults to the first suitable one. | | Yes | | Yes
| | alternate/N | | Interface alternate to use. Defaults to the first suitable | | Yes | | Yes
| | | one. | | | |
| | endpoint/N | | Desired endpoint. Defaults to the first suitable one. | | Yes | | Yes
| | report/N | | Desired HID report. If specified,only this information will | | Yes | | No
| | | be made available. | | | |
| | control | | The type of transfer required. Defaults to bulk, or what a | | Yes | | Yes
| | isochronous | | specified endpoint requires. (Isochronous is not fully | | | |
| | bulk | | supported at present.) | | | |
| | interrupt/S | | | | | |
| | nosync | | Synchronisation type. Only relevant to isochronous | | No | | No
| | async | | transfers. | | | |
| | adaptive | | | | | |
| | sync/S | | | | | |
| | data | | Only relevant to isochronous transfers. | | No | | No
| | feedback | | | | | |
| | implicit/S | | | | | |
| | usbtimeout/N | | Command timeout in milliseconds. Default is no timeout. | | Yes | | No
| | size/N | | The preferred stream buffer size to use. Some devices may | | Yes | | Yes
| | | benefit from a larger buffer than the default. | | | |
|
Numbers are converted using OS_ReadUnsigned so if the string starts with base_,
this base is used or if the string starts with & then it is hexadecimal. If
there is no prefix then it is decimal.
Two special fields have been added that are acted on by later versions of
DeviceFS. The same functionality is also available via an IOCTL call.
| Value | | IOCTL | | Action IYONIX? Podule?
| | Nosleep | | 4 | | true/false. Any DeviceFS stream, if opened with the special Yes No
| | sleep/S | | | | field entry 'sleep' will issue OS_UpCall 6 when it would
| | | | | otherwise block thus allowing Taskwindows to continue
| | | | | multitasking. Default nosleep. (Note.. in currently
| | | | | available versions of DeviceFS, without this sleep
| | | | | ability, the same effect can be achieved by polling the
| | | | | buffer associated with the stream and only making such a
| | | | | 'blocking' call if there is data (or space as relevant)
| | | | | in the buffer. If no data/space is available, then an
| | | | | UpCall 6 can be issued. (See later for details of a
| | | | | call to provide this information)
| | timeout/N | | 5 | | Time in cs This will cause the stream to issue a timeout Yes No
| | | | | error if it sleeps for too long. The default is 0 meaning
| | | | | sleep for ever.
|
Each USB device, when plugged in, is "enumerated" and a separate device is
created within DeviceFS. Each time a device is "enumerated" it has a new
device number created. Devices thus range from "USBD0" to "USBD999" (or
"USB0" to "USB999") before starting at 0 again.
Examples:
To open an interrupt in connection to USBD3 endpoint 1 from BASIC:
port% = OPENIN"devices#interrupt;endpoint1:usbd3"
To open a bulk (by default) out connection to USB3 endpoint 2 from BASIC:
out% = OPENOUT"devices#endpoint2:usb3"
To open a bulk (by default) in connection from USBD3 endpoint 1 from BASIC:
in% = OPENIN"devices#endpoint1:usbd3"
There are 4 extension calls into the DeviceFS driver which are passed
directly to the USB driver and are shown in the table below.
| Register Value | | Entry | | IYONIX? | | Podule?
| | USB Control Request | | | | Yes | | Yes
| | R0 1<<31 + 0 | | Send request to a device's default control pipe and | | | |
| | | return the reply. | | | |
| | R1 | | Device name eg "usbd" | | | |
| | R3 Byte 0 | | BmRequestType | | | |
| | Byte 1 | | BRequest | | | |
| | Bytes 2,3 | | WValue | | | |
| | R4 Bytes 0,1 | | WIndex | | | |
| | Bytes 2,3 | | WLength | | | |
| | R5 | | Pointer to data buffer. | | | |
| | R6 0 | | Return on command completion, command failure, | | | |
| | | or command timeout. | | | |
| | Bit 0 = 1 | | Return after commencing the command with R7 containing | | | |
| | | the address of a pollable status byte. See | | | |
| | | below for details of return values | | | |
| | Bit 1 = 1 | | On entry, R7 contains the address of a routine to be | | | |
| | | called on command completion. R8 will contain the | | | |
| | | value to be used for the R12 value when this is | | | |
| | | called. See below for details of this call. | | | |
| | R7 | | Callback address if R6 bit 1 set. | | | |
| | R8 | | Private word for Callback address in R7 if | | | |
| | | R6 bit 1 set. | | | |
| | Check buffer space | | | | Yes | | Yes
| | R0 1<<31 + 2 | | Interrogate the free space and data available in the | | | |
| | | buffer associated with a DeviceFS stream. (note: | | | |
| | | not all drivers will implement this, as the | | | |
| | | information can be directly discovered) | | | |
| | R1 | | Device name eg "usbd" | | | |
| | R2 | | Stream handle as returned by fileswitch. | | | |
| | Returns:R3 | | Bytes available in buffer | | | |
| | Returns:R4 | | Bytes free in buffer | | | |
| | Return handles | | | | Yes | | Yes
| | R0 1<<31 + 3 | | Return the buffer handle and DeviceFS stream | | | |
| | | handle for this stream | | | |
| | R1 | | Device name eg "usbd" | | | |
| | R2 | | Stream handle as returned by fileswitch. | | | |
| | Returns:R3 | | Buffer handle | | | |
| | Returns:R4 | | DeviceFS stream handle | | | |
| | Get Location | | | | Yes | | No
| | R0 1<<31 + 4 | | Get Device Location on bus. | | | |
| | R1 | | Device name eg "usbd" | | | |
| | R3 | | Pointer to 6 byte block. | | | |
| | Returns: | | Block filled in with 6 byte array: bus, port1, port2, | | | |
| | | port3, port4, port5. This indicates the physical | | | |
| | | location of the usb device. This provides a method | | | |
| | | of identifying the same device across reboots. | | | |
|
Note: The Check Buffer Space call has been added to enable users to code simple drivers in higher level languages such as BASIC. On RISC OS 4 and earlier, commands such as BGET of BPUT will not return if there is no data or space in the stream's buffer. With this call the user can only make such blocking calls when they wont be blocked.
(Podule only)
There are currently 2 defined status values detectable in the pollable byte.
0 command not completed.
1 command completed successfully.
2 command currently receiving a NAK.
3 command has received a STALL and finished.
4 command retrying.
5 command has received a USB timeout.
6 command is set inactive.
If a callback on completion is requested, the routine will be called back with registers set as follows:
| R0 | | completion status as above
| | R12 | | set to the value passed through in R8 when the callback was requested
| | | Your routine may be called within an interrupt service routine, so
| | | care should be taken to ensure that non re-entrant SWIs are not
| | | called, and that you spend the minimum time in your callback routine.
|
There is 1 defined service call at present, Service_USB (0xD2). It has 3 variants, distinguished by the value in R0 on entry. It is issued by the hub controller within the driver, once it has successfully "enumerated" a device, to report the presence of a newly connected device. It can also be issued by other parties wishing to find what devices are available if they are unable to receive service calls (e.g are applications), or if they arrived after a device was connected.
Service_USB
| Register | | Value | | Meaning
| | R1 | | 0xD2 | | Service_USB service call number. R1 should be passed
| | | | | onwards without claiming the call. The value in R0
| | | | | determines the usage of this.
| | R2 | | name | | Name driver uses (reason codes 3 and 4) e.g. "USB"
| | R0 | | 0 | | New device connected. Issued by the USB controller,
| | | | | this call reports that a new device has been connected
| | | | | and is available for use. R2 is a pointer to a structure
| | | | | of type USBServiceCall. The format of this is specified
| | | | | in the USBDevFS.txt header file . The current version
| | | | | of this header file is 0.75 (8 March 2003). Access to
| | | | | a device can be claimed by opening a file for that
| | | | | device/endpoint. Please see the sample drivers for
| | | | | an example of this.
| | R0 | | 1 | | Report connected devices. Issued with R2 set to zero.
| | | | | Each controller adds USBServiceAnswer pointers in a
| | | | | linked list. If R2 = NULL, then the controller sets
| | | | | R2 to point to a chunk of RMA containing a
| | | | | USBServiceAnswer structure, with the link field set
| | | | | to NULL. Subsequent devices are reported by scanning
| | | | | the list of pointers until a NULL next pointer is found
| | | | | and replacing the NULL with a pointer to a further
| | | | | chunk of RMA, with its link pointer set to NULL. It
| | | | | is the responsibility of the issuer of this service
| | | | | call to free the memory chunks returned.
| | R0 | | 2 | | Device has gone. (not used) R2 is a pointer to a
| | | | | structure of type USBServiceCall, such as would
| | | | | have been issued when the device was originally
| | | | | announced using reason code 0 - New device connected.
| | | | | This call announces the fact that the device is no
| | | | | longer available for use. Note that this call is
| | | | | not used. Since each USB device is a unique DeviceFS
| | | | | device, the DeviceFS_DeviceDead service call will
| | | | | provide this information.
| | R0 | | 3 | | USB driver module starting.
| | R0 | | 4 | | USB driver module dying.
|
A powerful Alias matching system is employed to provide a system for locating and launching specific applications and tools when relevant USB devices become available.
Once a device is connected and "enumerated" several things happen:
- A device is created for it within DeviceFS.
- The USB_Connected service call is issued.
- An Alias is created for it with just vendor and product IDs in place.
- A check is made for a matching alias, and if found it is launched.
- If no alias was launched, a second Alias is created with additional
configuration information.
- A new check is made for an alias match.
The alias created is of the form USB$Device_LL_SS_TT_VVVV_PPPP_CC_II_RRRR_USBDnnn (or USBnnn)
| Code | | Meaning | | Value at first check | | Value at second check | |
| | LL | | class | | 00 | | class | |
| | SS | | subclass | | 00 | | subclass | |
| | TT | | protocol | | 00 | | protocol | |
| | VVVV | | vendorID | | vendorID | | vendorID | |
| | PPPP | | productID | | productID | | productID | |
| | CC | | current | | -1 | | configuration | |
| | | configuration | | | | | |
| | II | | interface | | -1 | | interface | |
| | RRRR | | release number | | -1 | | product release number | |
| | nnn | | device number | | usb device number | | usb device number | |
|
When first created this is set to the number nnn. The second time around it has 3 numbers: nnn interface alternate. In the descriptions and examples below device USBDnnn is used. This is correct for the podule. IYONIX uses USBnnn.
Aliases are searched in accordance with the USB Common Class Specification (revision 1.0). This means that the following searches shall be done:
Alias@USBD$Device_*_*_*_V_P___R
Alias@USBD$Device_*_*_*_V_P___*
Alias@USBD$Device_L_S_T_V_*___*
Alias@USBD$Device_L_S_*_V_*___*
Alias@USBD$Device_L_S_T_*_*___*
Alias@USBD$Device_L_S_*_*_*___*
If a driver is found at that stage then it can participate in choosing the configuration for the driver. Otherwise the system software chooses an appropriate configuration and the search is proceeded using the following, taking each interface in turn, taking the class and subclass data from the interface descriptor:
Alias$@USBD$Device_*_*_*_V_P_C_I_R
Alias$@USBD$Device_*_*_*_V_P_C_I_*
Alias$@USBD$Device_L_S_T_V_*_*_*_*
Alias$@USBD$Device_L_S_*_V_*_*_*_*
Alias$@USBD$Device_L_S_T_*_*_*_*_*
Alias$@USBD$Device_L_S_*_*_*_*_*_*
If a match is made, the alias will be executed. This permits (e.g.) an obey
file to be created containing lines such as:
Alias @USBDDevice____03F0_0417____ Do Path HPLJ1220
USBD%%0#usbtimeout10000;size16384:|mUSBDSetInterface %%0 0 1|m||%%*0
If "<USBD$Device_*_*_*_03F0_0417_*_*_*_*>" <> "" Then Do
@usbddevice____03F0_0417____ <USBD$Device_*_*_*_03F0_0417_*_*_*_*>
Note that though each command appears to take 2 or more lines, each is one line only.
The first line sets up an alias for a device (vendor)03F0 and (product)0417
(which is an HPLJ1220C printer) which will create a path variable "HPLJ1220:"
and choose interface 0 alternate 1 as the desired interface to use. The
second line will execute the alias if it is already set up when the obey file
is run.
| Command | | Usage | | IYONIX? | | Podule? | |
| | USBDBuses | | Displays a list of available USB buses | | Yes | | No | |
| | USBBuses | | | | | | | |
| | USBDDevices | | Displays a list of available USB devices | | Yes | | No | |
| | USBDevices | | | | | | | |
| | USBDDevInfo <n> | | Displays device information on device <n> | | Yes | | No | |
| | USBdevInfo | | | | | | | |
| | USBDConfInfo <n> | | Displays configuration information on device <n> | | Yes | | No | |
| | USBConfInfo | | | | | | | |
| | USBDSetConfig <n><m> | | Set configuration value for device <n> to | | Yes | | Yes | |
| | USBSetConfig | | configuration <m> | | | | | |
| | USBDSetInterface <n><m><p> | | Set device <n> to interface <m> | | Yes | | Yes | |
| | USBSetInterface | | and alternate <p> | | | | | |
| | USBDReset <n> | | Force device <n> to be reset and | | Yes | | No | |
| | USBReset | | "enumerated" again. | | | | | |
|
This is for others intending to provide a DeviceFS interface to their USB
cards.. When writing a DeviceFS driver the DeviceFS driver entry 0
(initialise) is missing a vital parameter on versions of DeviceFS prior to
that shipped with RISC OS 4. The RISC OS 4 (or 5) entry provides the
fileswitch stream handle in R4. For earlier DeviceFS versions, this handle
may be found as a 32 bit value at offset 44 from the pointer supplied in R2.
 |
| © 2006 IYONIX Ltd |
32-bit RISC OS |
|